diff --git a/README.md b/README.md index a6346f04f..fdacc4878 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![MySQL Version](https://img.shields.io/badge/MySQL-5.6%2B-4479A1.svg)](https://www.mysql.com/) [![MariaDB Version](https://img.shields.io/badge/MariaDB-10.3%2B-003545.svg)](https://mariadb.org/) [![PSR-12](https://img.shields.io/badge/PSR--12-Compliant-2C2C2C.svg)](https://www.php-fig.org/psr/psr-12/) -[![Tests](https://img.shields.io/badge/Tests-246-44B273.svg)](https://phpunit.de/) +[![Tests](https://github.com/cakmoel/Scriptlog/actions/workflows/tests.yml/badge.svg)](https://github.com/cakmoel/Scriptlog/actions/workflows/tests.yml) Scriptlog is a simple, secure, modular, and robust personal blogging platform. It is a refactored fork of Piluscart 1.4.1, engineered to emphasize simplicity, privacy, and security without the overhead of a complex Content Management System. diff --git a/composer.json b/composer.json index e31932311..7f3ea0058 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,8 @@ "laminas/laminas-feed": "^2.17", "catfan/medoo": "^2.1", "symfony/mailer": "^5.4", - "symfony/mime": "^5.4" + "symfony/mime": "^5.4", + "vlucas/phpdotenv": "^5.6" }, "require-dev": { "phpunit/phpunit": "^9.5", diff --git a/composer.lock b/composer.lock index 31bd4fcb4..316754112 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "17bae043719c385d5271740c688554c1", + "content-hash": "0cfbf2ec56aa8a8fb6636016bb6c32ff", "packages": [ { "name": "catfan/medoo", @@ -364,6 +364,68 @@ ], "time": "2025-08-08T12:00:00+00:00" }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.4", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:43:20+00:00" + }, { "name": "guzzlehttp/psr7", "version": "2.9.0", @@ -1210,6 +1272,81 @@ }, "time": "2020-10-15T08:29:30+00:00" }, + { + "name": "phpoption/phpoption", + "version": "1.9.5", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:41:33+00:00" + }, { "name": "psr/container", "version": "1.1.2", @@ -1956,6 +2093,89 @@ ], "time": "2024-10-23T20:18:32+00:00" }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, { "name": "symfony/polyfill-iconv", "version": "v1.33.0", @@ -2611,6 +2831,90 @@ ], "time": "2024-09-25T14:11:13+00:00" }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.3", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "955e7815d677a3eaa7075231212f2110983adecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.4", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:49:13+00:00" + }, { "name": "voku/anti-xss", "version": "4.1.42", diff --git a/phpunit.xml b/phpunit.xml index 6414278b2..6475f9585 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,7 +1,7 @@ - src/tests - src/tests/TablePrefixTest.php + tests + tests/TablePrefixTest.php diff --git a/src/admin/403.php b/src/admin/403.php index d99a3d15f..957bd2678 100755 --- a/src/admin/403.php +++ b/src/admin/403.php @@ -1,6 +1,6 @@ +if (isset($_GET['forbidden']) && ($_GET['forbidden'] === md5(APP_HOSTNAME . get_ip_address()))) : + ?>
@@ -37,9 +37,7 @@
- \ No newline at end of file diff --git a/src/admin/404.php b/src/admin/404.php index 2e4d66972..27d32cb92 100755 --- a/src/admin/404.php +++ b/src/admin/404.php @@ -1,6 +1,6 @@ +if ((isset($_GET['notfound']) && ($_GET['notfound'] === md5(app_key() . get_ip_address())))) : + ?>
@@ -37,8 +37,7 @@
- \ No newline at end of file diff --git a/src/admin/activate-user.php b/src/admin/activate-user.php index 20ee002d2..b423a6178 100755 --- a/src/admin/activate-user.php +++ b/src/admin/activate-user.php @@ -1,37 +1,28 @@ activateUserAccount($userActivationKey) : ""; - + // activate user + is_a($app->authenticator, 'Authentication') ? $app->authenticator->activateUserAccount($userActivationKey) : ""; } - - - diff --git a/src/admin/admin-layout.php b/src/admin/admin-layout.php index ebc7f2902..828a32895 100755 --- a/src/admin/admin-layout.php +++ b/src/admin/admin-layout.php @@ -1,9 +1,11 @@ - + - + @@ -31,6 +33,10 @@ function admin_header($stylePath, $breadcrumb = null) + + + + @@ -96,20 +102,20 @@ function admin_header($stylePath, $breadcrumb = null)
- + + ?>
Thank you for creating with @@ -117,7 +123,7 @@ function admin_footer($stylePath, $ubench = null) - getTime() . " Memory usage: ".$ubench->getMemoryUsage() : "" ?> + getTime() . " Memory usage: " . $ubench->getMemoryUsage() : "" ?>
@@ -152,15 +158,15 @@ function admin_footer($stylePath, $ubench = null) - - - - - - - - - - - - + ?> @@ -56,13 +56,13 @@ function login_header($stylePath) @@ -82,5 +82,5 @@ function login_footer($stylePath) -authenticator, $ip, $loginId, $uniqueKey, $errors, $login_data); } else { $errors['errorMessage'] = "Please fill in all required fields."; } @@ -81,14 +82,18 @@
- - + +
@@ -97,18 +102,18 @@
- +
- " - required autofocus> + " + required autofocus>
@@ -124,7 +129,7 @@
- captcha + captcha
@@ -150,7 +155,7 @@ - + Register | diff --git a/src/admin/logout.php b/src/admin/logout.php index bd667d50c..2cf1cff45 100755 --- a/src/admin/logout.php +++ b/src/admin/logout.php @@ -1,55 +1,41 @@ -userAccessControl()) { - + if (false === $app->authenticator->userAccessControl()) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); - } else { - $valid_logout = !empty($logOutId) && verify_logout_id($logOutId); if (!$valid_logout) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); throw new AppException("URL Redirection to Untrusted Site"); - } else { - - $authenticator->logout(); + $app->authenticator->logout(); } } break; default: - - if (false === $authenticator->userAccessControl()) { - + if (false === $app->authenticator->userAccessControl()) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); - } else { - direct_page('index.php?load=dashboard', 302); } } - } catch (\Throwable $th) { - if (class_exists('LogError')) { LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($th); } } catch (AppException $e) { - LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($e); } diff --git a/src/admin/medialib.php b/src/admin/medialib.php index 160950dce..38d5199d3 100755 --- a/src/admin/medialib.php +++ b/src/admin/medialib.php @@ -1,129 +1,86 @@ -validator, $app->sanitizer) : ""; $mediaController = class_exists('MediaController') ? new MediaController($mediaService) : ""; try { - switch ($action) { - case ActionConst::NEWMEDIA: // new media - - if (false === $authenticator->userAccessControl(ActionConst::MEDIALIB)) { - - direct_page('index.php?load=403&forbidden='.forbidden_id(), 403); - - } else { - - if ((!check_integer($mediaId)) && (gettype($mediaId) !== "integer")) { - - header($_SERVER["SERVER_PROTOCOL"]." 400 Bad Request", true, 400); - header("Status: 400 Bad Request"); - throw new AppException("Invalid ID data type!"); - - } - - if ($mediaId == 0) { - + if (false === $app->authenticator->userAccessControl(ActionConst::MEDIALIB)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); + } else { + if ((!check_integer($mediaId)) && (gettype($mediaId) !== "integer")) { + header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); + header("Status: 400 Bad Request"); + throw new AppException("Invalid ID data type!"); + } + + if ($mediaId == 0) { $mediaController->insert(); - } else { - direct_page('index.php?load=dashboard', 302); - } - - } - - break; - + } + + break; + case ActionConst::EDITMEDIA: - - if (false === $authenticator->userAccessControl(ActionConst::MEDIALIB)) { - - direct_page('index.php?load=403&forbidden='.forbidden_id(), 403); - - } else { - - if ((!check_integer($mediaId)) && (gettype($mediaId) !== "integer")) { - - header($_SERVER["SERVER_PROTOCOL"]." 400 Bad Request", true, 400); - header("Status: 400 Bad Request"); - throw new AppException("Invalid ID data type!"); - - } - - if ($mediaDao->checkMediaId($mediaId, $sanitizer)) { - - $mediaController->update((int)$mediaId); - - } else { - - direct_page('index.php?load=404¬found='.notfound_id(), 404); - - } - - } - - break; - + if (false === $app->authenticator->userAccessControl(ActionConst::MEDIALIB)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); + } else { + if ((!check_integer($mediaId)) && (gettype($mediaId) !== "integer")) { + header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); + header("Status: 400 Bad Request"); + throw new AppException("Invalid ID data type!"); + } + + if ($mediaDao->checkMediaId($mediaId, $app->sanitizer)) { + $mediaController->update((int)$mediaId); + } else { + direct_page('index.php?load=404¬found=' . notfound_id(), 404); + } + } + + break; + case ActionConst::DELETEMEDIA: - - if (false === $authenticator->userAccessControl(ActionConst::MEDIALIB)) { - - direct_page('index.php?load=403&forbidden='.forbidden_id(), 403); - - } else { - - if ((!check_integer($mediaId)) && (gettype($mediaId) !== "integer")) { - - header($_SERVER["SERVER_PROTOCOL"]." 400 Bad Request", true, 400); - header("Status: 400 Bad Request"); - throw new AppException("Invalid ID data type!"); - - } - - if ($mediaDao->checkMediaId($mediaId, $sanitizer)) { - - $mediaController->remove((int)$mediaId); - - } else { - - direct_page('index.php?load=404¬found='.notfound_id(), 404); - - } - - } - - break; - + if (false === $app->authenticator->userAccessControl(ActionConst::MEDIALIB)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); + } else { + if ((!check_integer($mediaId)) && (gettype($mediaId) !== "integer")) { + header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); + header("Status: 400 Bad Request"); + throw new AppException("Invalid ID data type!"); + } + + if ($mediaDao->checkMediaId($mediaId, $app->sanitizer)) { + $mediaController->remove((int)$mediaId); + } else { + direct_page('index.php?load=404¬found=' . notfound_id(), 404); + } + } + + break; + default: - - if (false === $authenticator->userAccessControl(ActionConst::MEDIALIB)) { - - direct_page('index.php?load=403&forbidden='.forbidden_id(), 403); - + if (false === $app->authenticator->userAccessControl(ActionConst::MEDIALIB)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - - $mediaController->listItems(); + $mediaController->listItems(); } - + break; - } - } catch (Throwable $th) { - LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($th); - } catch (AppException $e) { - LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($e); - -} \ No newline at end of file +} diff --git a/src/admin/menu.php b/src/admin/menu.php index 69cb7b031..2ce09f1e3 100755 --- a/src/admin/menu.php +++ b/src/admin/menu.php @@ -1,34 +1,29 @@ -validator, $app->sanitizer) : ""; $menuController = class_exists('MenuController') ? new MenuController($menuService) : ""; try { - switch ($action) { - case ActionConst::NEWMENU: # Add New Menu - if (false === $authenticator->userAccessControl(ActionConst::NAVIGATION)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::NAVIGATION)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - if ((!check_integer($menuId)) && (gettype($menuId) !== "integer")) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("invalid ID data type!"); } if ($menuId == 0) { - $menuController->insert(); } else { - direct_page('index.php?load=dashboard', 302); } } @@ -36,24 +31,18 @@ break; case ActionConst::EDITMENU: - if ((!check_integer($menuId)) && (gettype($menuId) !== "integer")) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("Invalid ID data type!"); } - if (false === $authenticator->userAccessControl(ActionConst::NAVIGATION)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::NAVIGATION)) { direct_page('index.php?load=403&error=forbidden=' . forbidden_id(), 403); } else { - if ($menuDao->checkMenuId($menuId, $sanitizer)) { - $menuController->update((int)$menuId); } else { - direct_page('index.php?load=404¬found=' . notfound_id(), 404); } } @@ -61,24 +50,18 @@ break; case ActionConst::DELETEMENU: - if ((!check_integer($menuId)) && (gettype($menuId) !== "integer")) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("Invalid ID data type!"); } - if (false === $authenticator->userAccessControl(ActionConst::NAVIGATION)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::NAVIGATION)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - if ($menuDao->checkMenuId($menuId, $sanitizer)) { - $menuController->remove((int)$menuId); } else { - direct_page('index.php?load=404¬found=' . notfound_id(), 404); } } @@ -86,23 +69,18 @@ break; default: - - if (false === $authenticator->userAccessControl(ActionConst::NAVIGATION)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::NAVIGATION)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - $menuController->listItems(); } } } catch (Throwable $th) { - if (class_exists('LogError')) { LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($th); } } catch (AppException $e) { - LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($e); -} \ No newline at end of file +} diff --git a/src/admin/navigation.php b/src/admin/navigation.php index d1cf8800f..cabb521d8 100755 --- a/src/admin/navigation.php +++ b/src/admin/navigation.php @@ -2,7 +2,7 @@
- '; } - + /** * Frontend display * Display content on frontend @@ -96,20 +98,20 @@ public function frontendDisplay($content = '')

This content is rendered by the Hello World plugin!

'; } - + /** * Get plugin info - * + * * @return array */ public function getInfo() { $iniFile = $this->pluginDir . DIRECTORY_SEPARATOR . 'plugin.ini'; - + if (file_exists($iniFile)) { return parse_ini_file($iniFile); } - + return []; } } diff --git a/src/admin/plugins/hello-world/functions.php b/src/admin/plugins/hello-world/functions.php index 347003c84..2e62dc69a 100644 --- a/src/admin/plugins/hello-world/functions.php +++ b/src/admin/plugins/hello-world/functions.php @@ -1,35 +1,37 @@ -validator, $app->sanitizer) : ""; $postController = class_exists('PostController') ? new PostController($postService) : ""; try { - switch ($action) { - case ActionConst::NEWPOST: - - if (false === $authenticator->userAccessControl(ActionConst::POSTS)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::POSTS)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); - } else { - if ((!check_integer($postId)) && (gettype($postId) !== "integer")) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("Invalid ID data type!"); } if ($postId == 0) { - $postController->insert(); } else { - direct_page('index.php?load=dashboard', 302); } } @@ -37,26 +30,18 @@ break; case ActionConst::EDITPOST: - - if (false === $authenticator->userAccessControl(ActionConst::POSTS)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::POSTS)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); - } else { - if ((!check_integer($postId)) && (gettype($postId) !== "integer")) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("Invalid ID data type!"); } - - if ($postDao->checkPostId($postId, $sanitizer)) { + if ($postDao->checkPostId($postId, $app->sanitizer)) { $postController->update((int)$postId); - } else { - direct_page('index.php?load=404¬found=' . notfound_id(), 404); } } @@ -64,24 +49,18 @@ break; case ActionConst::DELETEPOST: - if ((!check_integer($postId)) && (gettype($postId) !== "integer")) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("Invalid ID data type!"); } - if (false === $authenticator->userAccessControl(ActionConst::POSTS)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::POSTS)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - - if ($postDao->checkPostId($postId, $sanitizer)) { - + if ($postDao->checkPostId($postId, $app->sanitizer)) { $postController->remove((int)$postId); } else { - direct_page('index.php?load=404¬found=' . notfound_id(), 404); } } @@ -89,24 +68,18 @@ break; default: - - if (false === $authenticator->userAccessControl(ActionConst::POSTS)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::POSTS)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - $postController->listItems(); } - } } catch (\Throwable $th) { - if (class_exists('LogError')) { LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($th); } } catch (AppException $e) { - LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($e); -} \ No newline at end of file +} diff --git a/src/admin/privacy-policy.html b/src/admin/privacy-policy.html deleted file mode 100644 index 96054917d..000000000 --- a/src/admin/privacy-policy.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - Privacy policy - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - - - - - - - -
- -
-

- Blank page - it all starts here -

- -
- - -
- - -
-
-

Title

- -
- - -
-
-
- Start creating your amazing application! -
- - - -
- - -
- -
- - -
- - Thank you for creating with Scriptlog -
- - -
- - - - - - - - - - - - - - - diff --git a/src/admin/privacy.php b/src/admin/privacy.php new file mode 100644 index 000000000..1a22d82e3 --- /dev/null +++ b/src/admin/privacy.php @@ -0,0 +1,179 @@ +authenticator->userAccessControl(ActionConst::PRIVACY)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); +} + +$dataRequestDao = null; +$privacyLogDao = null; +$dataRequestService = null; + +if (class_exists('DataRequestDao')) { + $dataRequestDao = new DataRequestDao(); +} + +if (class_exists('PrivacyLogDao')) { + $privacyLogDao = new PrivacyLogDao(); +} + +if (class_exists('DataRequestService') && $dataRequestDao !== null && $privacyLogDao !== null && $app->sanitizer !== null) { + $dataRequestService = new DataRequestService($dataRequestDao, $privacyLogDao, $app->sanitizer); +} + +$errors = []; +$status = []; + +try { + if ($page === 'data-export' && $action === 'export') { + if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['export_email']) && $dataRequestService !== null) { + $email = filter_input(INPUT_POST, 'export_email', FILTER_VALIDATE_EMAIL); + + if (!$email) { + if (empty($errors)) { + $errors = []; + } + $errors[] = "Please enter a valid email address."; + } else { + $options = [ + 'export_profile' => true, + 'export_comments' => isset($_POST['export_comments']), + 'export_posts' => isset($_POST['export_posts']), + 'export_activity' => isset($_POST['export_activity']) + ]; + + try { + $exportData = $dataRequestService->exportUserData($email, $options); + + header('Content-Type: application/json'); + header('Content-Disposition: attachment; filename="user_data_' . time() . '.json"'); + echo json_encode($exportData, JSON_PRETTY_PRINT); + exit; + } catch (AppException $e) { + if (empty($errors)) { + $errors = []; + } + $errors[] = $e->getMessage(); + } + } + } + } + + if ($page === 'data-deletion' && $action === 'delete') { + if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_email']) && $dataRequestService !== null) { + $email = filter_input(INPUT_POST, 'delete_email', FILTER_VALIDATE_EMAIL); + + if (!$email) { + if (empty($errors)) { + $errors = []; + } + $errors[] = "Please enter a valid email address."; + } else { + try { + $dataRequestService->createRequest('deletion', $email, ['note' => 'User requested data deletion']); + if (empty($status)) { + $status = []; + } + $status[] = "Your data deletion request has been submitted. We will process it within 30 days."; + } catch (AppException $e) { + if (empty($errors)) { + $errors = []; + } + $errors[] = $e->getMessage(); + } + } + } + } + + switch ($page) { + case 'data-export': + $pageTitle = "Export Your Data"; + include dirname(__FILE__) . DS . 'ui' . DS . 'privacy' . DS . 'data-export.php'; + break; + + case 'data-deletion': + $pageTitle = "Delete Your Data"; + include dirname(__FILE__) . DS . 'ui' . DS . 'privacy' . DS . 'data-deletion.php'; + break; + + case 'data-requests': + if ($dataRequestService !== null) { + if ($action === 'update') { + $requestId = isset($_GET['Id']) ? intval($_GET['Id']) : 0; + $newStatus = isset($_GET['status']) ? $_GET['status'] : 'processing'; + if ($requestId > 0) { + try { + $dataRequestService->updateRequestStatus($requestId, $newStatus); + if (empty($status)) { + $status = []; + } + $status[] = "Request status updated."; + } catch (AppException $e) { + if (empty($errors)) { + $errors = []; + } + $errors[] = $e->getMessage(); + } + } + } + + $dataRequests = $dataRequestService->getAllRequests(); + $requestsTotal = $dataRequestService->getTotalRequests(); + $pendingCount = $dataRequestService->getPendingCount(); + } else { + $dataRequests = []; + $requestsTotal = 0; + $pendingCount = 0; + } + $pageTitle = "Data Requests"; + include dirname(__FILE__) . DS . 'ui' . DS . 'privacy' . DS . 'data-requests.php'; + break; + + case 'audit-logs': + if ($privacyLogDao !== null) { + $privacyLogs = $privacyLogDao->getAllLogs(); + $logsTotal = $privacyLogDao->totalLogRecords(); + } else { + $privacyLogs = []; + $logsTotal = 0; + } + $pageTitle = "Audit Logs"; + include dirname(__FILE__) . DS . 'ui' . DS . 'privacy' . DS . 'audit-logs.php'; + break; + + default: + if ($dataRequestService !== null) { + $pendingCount = $dataRequestService->getPendingCount(); + $totalRequests = $dataRequestService->getTotalRequests(); + } else { + $pendingCount = 0; + $totalRequests = 0; + } + + if ($privacyLogDao !== null) { + $totalLogs = $privacyLogDao->totalLogRecords(); + $recentLogs = $privacyLogDao->getRecentLogs(5); + } else { + $totalLogs = 0; + $recentLogs = []; + } + $pageTitle = "Privacy Settings"; + include dirname(__FILE__) . DS . 'ui' . DS . 'privacy' . DS . 'index.php'; + } +} catch (\Throwable $th) { + if (class_exists('LogError')) { + LogError::setStatusCode(http_response_code()); + LogError::exceptionHandler($th); + } +} catch (AppException $e) { + LogError::setStatusCode(http_response_code()); + LogError::exceptionHandler($e); +} diff --git a/src/admin/recover-password.php b/src/admin/recover-password.php index a7fc51c35..208dd62b7 100755 --- a/src/admin/recover-password.php +++ b/src/admin/recover-password.php @@ -1,74 +1,55 @@ -getUserByResetKey($tempKey); +$user = $app->userDao->getUserByResetKey($tempKey); if (empty($user['user_reset_key'])) { - - $stop = "Temporary key is not valid."; - + $stop = "Temporary key is not valid."; } elseif ($user['user_reset_complete'] == 'Yes') { $stop = "Your password has been changed"; } if (isset($_POST['Change']) && $_POST['Change'] == 'Change Password') { - - $password = isset($_POST['pass1']) ? prevent_injection($_POST['pass1']) : ""; - $confirmPass = isset($_POST['pass2']) ? prevent_injection($_POST['pass2']) : ""; - $csrf = isset($_POST['csrf']) ? $_POST['csrf'] : ''; - $valid = !empty($csrf) && verify_form_token('recover_pwd', $csrf); - - if (!$valid) { - - $errors['errorMessage'] = "Sorry, there was a security issue"; - - } - - if (empty($password) || empty($confirmPass)) { - - $errors['errorMessage'] = "All column must be filled"; - - } elseif ($password !== $confirmPass) { - - $errors['errorMessage'] = "Password does not match"; - - } elseif (check_common_password($password) === true ) { - - $errors['errorMessage'] = "Your password seems to be the most hacked password, please try another"; - - } elseif (false === check_pwd_strength($password) ) { - - $errors['errorMessage'] = "Password requires at least 8 characters with lowercase, uppercase letters, numbers and special characters"; - - } else { - - $authenticator->updateNewPassword($password, abs((int)$user['ID']), $user['user_email']); - direct_page('login.php?status=changed', 302); - - } - + $password = isset($_POST['pass1']) ? prevent_injection($_POST['pass1']) : ""; + $confirmPass = isset($_POST['pass2']) ? prevent_injection($_POST['pass2']) : ""; + $csrf = isset($_POST['csrf']) ? $_POST['csrf'] : ''; + $valid = !empty($csrf) && verify_form_token('recover_pwd', $csrf); + + if (!$valid) { + $errors['errorMessage'] = "Sorry, there was a security issue"; + } + + if (empty($password) || empty($confirmPass)) { + $errors['errorMessage'] = "All column must be filled"; + } elseif ($password !== $confirmPass) { + $errors['errorMessage'] = "Password does not match"; + } elseif (check_common_password($password) === true) { + $errors['errorMessage'] = "Your password seems to be the most hacked password, please try another"; + } elseif (false === check_pwd_strength($password)) { + $errors['errorMessage'] = "Password requires at least 8 characters with lowercase, uppercase letters, numbers and special characters"; + } else { + $app->authenticator->updateNewPassword($password, abs((int)$user['ID']), $user['user_email']); + direct_page('login.php?status=changed', 302); + } } ?> @@ -117,30 +98,29 @@ diff --git a/src/admin/register-layout.php b/src/admin/register-layout.php index 4f2a06194..242931c11 100644 --- a/src/admin/register-layout.php +++ b/src/admin/register-layout.php @@ -1,7 +1,7 @@ + ?> @@ -58,13 +58,13 @@ function register_header($stylePath)
- + ?>
@@ -99,5 +99,5 @@ function register_footer($stylePath) -validator, $app->sanitizer); +$replyController = new ReplyController($replyService); try { - switch ($action) { - case ActionConst::REPLY: - - if ( false === $authenticator->userAccessControl(ActionConst::REPLY)) { - - direct_page('index.php?load=403&forbidden='.forbidden_id(), 403); + case 'newReply': + // New reply - Id is the PARENT comment ID, not a reply ID + // Id=0 means we're creating a reply without a specific parent + // Id>0 means we're replying to a specific comment + if (false === $app->authenticator->userAccessControl(ActionConst::REPLY)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - - if((!check_integer($replyId)) && (gettype($replyId) != "integer")) { - - header($_SERVER["SERVER_PROTOCOL"]." 400 Bad Request", true, 400); - header("Status: 400 Bad Request"); - throw new AppException("Invalid ID data type"); - + // If POST, process form submission + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $replyController->insert(); + } else { + // GET request - show reply form + $replyController->insert(); } + } + break; - if ($replyId === 0) { + case ActionConst::EDITREPLY: + // Edit existing reply - Id is the reply ID - $replyController->insert(); + if (false === $app->authenticator->userAccessControl(ActionConst::REPLY)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); + } else { + if ($replyId === 0) { + direct_page('index.php?load=comments', 302); + } + if ($replyService->checkReplyExists($replyId)) { + $replyController->update($replyId); } else { + direct_page('index.php?load=404¬found=' . notfound_id(), 404); + } + } + break; - direct_page('index.php?load=dashboard', 302); + case ActionConst::DELETEREPLY: + // Delete reply - Id is the reply ID + if (false === $app->authenticator->userAccessControl(ActionConst::REPLY)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); + } else { + if ((!check_integer($replyId)) && (gettype($replyId) != "integer")) { + header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); + header("Status: 400 Bad Request"); + throw new AppException("Invalid ID data type"); } + if ($replyService->checkReplyExists($replyId)) { + $replyController->remove($replyId); + } else { + direct_page('index.php?load=404¬found=' . notfound_id(), 404); + } } - break; default: - - if (false === $authenticator->userAccessControl(ActionConst::REPLY)) { - - direct_page('index.php?load=403&forbidden='.forbidden_id(), 403); - - } else { - - direct_page('index.php?load=comments', 302); - } - + if (false === $app->authenticator->userAccessControl(ActionConst::REPLY)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); + } else { + direct_page('index.php?load=comments', 302); + } } - } catch (Throwable $th) { - LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($th); - } catch (AppException $e) { - LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($e); - -} \ No newline at end of file +} diff --git a/src/admin/request.php b/src/admin/request.php index 5b7e68467..4609cc371 100644 --- a/src/admin/request.php +++ b/src/admin/request.php @@ -1,14 +1,8 @@ -userAccessControl()) { + if (!$app->authenticator->userAccessControl()) { http_response_code(403); throw new AppException("403 - Forbidden"); } @@ -58,18 +47,13 @@ } if (function_exists('realpath')) { - require realpath($file_path); - } else { - require basename(absolute_path($file_path)); } - } } else { - // Handle default load case - if (!$authenticator->userAccessControl()) { + if (!$app->authenticator->userAccessControl()) { http_response_code(403); throw new AppException("403 - Forbidden"); } @@ -82,18 +66,16 @@ direct_page('index.php?load=dashboard', 302); } } catch (AppException $e) { - // Log and handle application exceptions LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($e); } catch (\Throwable $th) { - // Log and handle generic exceptions if (class_exists('LogError')) { LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($th); } } -// Benchmarking for development environment -if (isset($ubench) && APP_DEVELOPMENT === true) { - $ubench->end(); +// FIXED: Use $app->ubench +if (isset($app->ubench) && APP_DEVELOPMENT === true) { + $app->ubench->end(); } diff --git a/src/admin/reset-password.php b/src/admin/reset-password.php index 21f62cb23..e7c039cee 100755 --- a/src/admin/reset-password.php +++ b/src/admin/reset-password.php @@ -1,77 +1,56 @@ 0 && $captcha_code !== Session::getInstance()->forgot_pwd) { - - $captcha = false; - $errors['errorMessage'] = "Please enter correct captcha code"; - - } + $captcha_code = isset($_POST['captcha_code']) ? $_POST['captcha_code'] : ''; + $captcha = true; - if (empty($user_email)) { - - $errors['errorMessage'] = "Please enter email address"; - - } elseif (!filter_var($user_email, FILTER_VALIDATE_EMAIL)) { - - $errors['errorMessage'] = "Please enter a valid email address"; - - } elseif ($authenticator->checkEmailExists($user_email) == false) { - - $errors['errorMessage'] = "No user account was found with the email address you entered"; - - } else { - - if ($captcha === true) { - - $authenticator->resetUserPassword($user_email); - - direct_page('reset-password.php?status=reset', 200); - + if (!$valid) { + $errors['errorMessage'] = "Sorry, there was a security issue"; } - - } - - if (scriptpot_validate($_POST) === false) { - $errors['errorMessage'] = "anomaly behaviour detected!"; + if (count($_POST) > 0 && $captcha_code !== Session::getInstance()->forgot_pwd) { + $captcha = false; + $errors['errorMessage'] = "Please enter correct captcha code"; + } - } + if (empty($user_email)) { + $errors['errorMessage'] = "Please enter email address"; + } elseif (!filter_var($user_email, FILTER_VALIDATE_EMAIL)) { + $errors['errorMessage'] = "Please enter a valid email address"; + } elseif ($app->authenticator->checkEmailExists($user_email) == false) { + $errors['errorMessage'] = "No user account was found with the email address you entered"; + } else { + if ($captcha === true) { + $app->authenticator->resetUserPassword($user_email); + + direct_page('reset-password.php?status=reset', 200); + } + } + if (scriptpot_validate($_POST) === false) { + $errors['errorMessage'] = "anomaly behaviour detected!"; + } } ?> @@ -118,29 +97,28 @@
- + @@ -181,17 +159,17 @@ Log in - - | Register + | Register + -
diff --git a/src/admin/sidebar-nav.php b/src/admin/sidebar-nav.php index d14a3ef4e..79f1a6910 100755 --- a/src/admin/sidebar-nav.php +++ b/src/admin/sidebar-nav.php @@ -1,155 +1,276 @@ - + ?> - - \ No newline at end of file diff --git a/src/admin/signup.php b/src/admin/signup.php index 15ebd6eed..73a35d52b 100644 --- a/src/admin/signup.php +++ b/src/admin/signup.php @@ -1,31 +1,30 @@ * @license MIT * @version 1.0 * @since Since Release 1.0 - * + * */ if (file_exists(__DIR__ . '/../config.php')) { + require __DIR__ . '/../lib/main.php'; - require __DIR__ . '/../lib/main.php'; - - $ip = get_ip_address(); + $ip = get_ip_address(); - include __DIR__ . '/register-layout.php'; + include __DIR__ . '/register-layout.php'; - $stylePath = preg_replace("/\/signup\.php.*$/i", "", current_load_url()); + $stylePath = preg_replace("/\/signup\.php.*$/i", "", current_load_url()); } else { - - header("Location: ../install"); - exit(); + header("Location: ../install"); + exit(); } $action = isset($_GET['action']) ? safe_html($_GET['action']) : ""; @@ -33,32 +32,26 @@ $uniqueKey = isset($_GET['uniqueKey']) ? safe_html($_GET['uniqueKey']) : null; if (($action == 'SignUp') && (block_request_type(current_request_method(), ['POST']) === false)) { - - if (function_exists('processing_signup')) { - - // Sanitize and validate input - $signup_data = filter_input_array(INPUT_POST, [ - 'user_login' => FILTER_SANITIZE_SPECIAL_CHARS, - 'user_email' => FILTER_VALIDATE_EMAIL, - 'user_pass' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, - 'user_pass2' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, - 'iagree' => FILTER_SANITIZE_NUMBER_INT, - 'csrf' => FILTER_SANITIZE_SPECIAL_CHARS - ]); - - // Ensure data is valid - if ($signup_data && !in_array(false, $signup_data, true)) { - - list($errors, $signup_success) = processing_signup($ip, $signupId, $uniqueKey, $errors, $signup_data); + if (function_exists('processing_signup')) { + // Sanitize and validate input + $signup_data = filter_input_array(INPUT_POST, [ + 'user_login' => FILTER_SANITIZE_SPECIAL_CHARS, + 'user_email' => FILTER_VALIDATE_EMAIL, + 'user_pass' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, + 'user_pass2' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, + 'iagree' => FILTER_SANITIZE_NUMBER_INT, + 'csrf' => FILTER_SANITIZE_SPECIAL_CHARS + ]); + + // Ensure data is valid + if ($signup_data && !in_array(false, $signup_data, true)) { + list($errors, $signup_success) = processing_signup($ip, $signupId, $uniqueKey, $errors, $signup_data); + } else { + scriptlog_error("Invalid signup data received."); + } } else { - - scriptlog_error("Invalid signup data received."); + scriptlog_error("Function processing_signup not found"); } - - } else { - - scriptlog_error("Function processing_signup not found"); - } } register_header($stylePath); @@ -77,21 +70,21 @@ + ?>
- +
- + + if (is_registration_unable() === false) : + ?>
@@ -100,9 +93,8 @@
Log In - +

@@ -111,9 +103,8 @@
Log In - + @@ -150,7 +141,7 @@
@@ -158,8 +149,8 @@
+ $block_csrf = function_exists('generate_form_token') ? generate_form_token('signup_form', 40) : ''; + ?>
@@ -167,19 +158,19 @@
- + Log in | - + Lost your password? - \ No newline at end of file + register_footer($stylePath); + ?> \ No newline at end of file diff --git a/src/admin/templates.php b/src/admin/templates.php index 51b087614..7744a487e 100755 --- a/src/admin/templates.php +++ b/src/admin/templates.php @@ -1,34 +1,28 @@ -validator, $app->sanitizer) : ""; $themeController = class_exists('ThemeController') ? new ThemeController($themeService) : ""; try { - switch ($action) { - case ActionConst::NEWTHEME: - - if (false === $authenticator->userAccessControl(ActionConst::THEMES)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::THEMES)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - if ((!check_integer($themeId)) && (gettype($themeId) !== "integer")) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("invalid ID data type!"); } if ($themeId == 0) { - $themeController->insert(); } else { - direct_page('index.php?load=dashboard', 302); } } @@ -36,21 +30,15 @@ break; case ActionConst::INSTALLTHEME: - - if (false === $authenticator->userAccessControl(ActionConst::THEMES)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::THEMES)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - if ((!check_integer($themeId)) && (gettype($themeId) !== "integer")) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("invalid ID data type!"); } else { - if ($themeId == 0) { - $themeController->setupTheme(); } } @@ -59,24 +47,18 @@ break; case ActionConst::EDITTHEME: - - if (false === $authenticator->userAccessControl(ActionConst::THEMES)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::THEMES)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - if ((!check_integer($themeId)) && (gettype($themeId) !== "integer")) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("Invalid ID data type!"); } - if ($themeDao->checkThemeId($themeId, $sanitizer)) { - + if ($themeDao->checkThemeId($themeId, $app->sanitizer)) { $themeController->update((int)$themeId); } else { - direct_page('index.php?load=404¬found=' . notfound_id(), 404); } } @@ -84,24 +66,18 @@ break; case ActionConst::DELETETHEME: - if ((!check_integer($themeId)) && (gettype($themeId) !== "integer")) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("Invalid ID data type!"); } - if (false === $authenticator->userAccessControl(ActionConst::THEMES)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::THEMES)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - - if ($themeDao->checkThemeId($themeId, $sanitizer)) { - + if ($themeDao->checkThemeId($themeId, $app->sanitizer)) { $themeController->remove((int)$themeId); } else { - direct_page('index.php?load=404¬found=' . notfound_id(), 404); } } @@ -109,24 +85,18 @@ break; case ActionConst::ACTIVATETHEME: - if ((!check_integer($themeId)) && (gettype($themeId) !== "integer")) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("Invalid ID data type!"); } - if (false === $authenticator->userAccessControl(ActionConst::THEMES)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::THEMES)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - - if ($themeDao->checkThemeId($themeId, $sanitizer)) { - + if ($themeDao->checkThemeId($themeId, $app->sanitizer)) { $themeController->enableTheme((int)$themeId); } else { - direct_page('index.php?load=404¬found=' . notfound_id(), 404); } } @@ -134,25 +104,18 @@ break; default: - - if (false === $authenticator->userAccessControl(ActionConst::THEMES)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::THEMES)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - $themeController->listItems(); // show list of all themes - } - } } catch (Throwable $th) { - if (class_exists('LogError')) { LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($th); } } catch (AppException $e) { - LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($e); -} \ No newline at end of file +} diff --git a/src/admin/terms-of-use.html b/src/admin/terms-of-use.html deleted file mode 100644 index f73779317..000000000 --- a/src/admin/terms-of-use.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - Terms of Use - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - - - - - - - -
- -
-

- Terms of Use - compliance -

- -
- - -
- - -
-
-

Terms of Use

- -
- - -
-
-
- Start creating your amazing personal weblog with ScriptLog! -
- - - -
- - -
- -
- - -
- - Thank you for creating with Scriptlog -
- - -
- - - - - - - - - - - - - - - diff --git a/src/admin/topics.php b/src/admin/topics.php index c740451fa..018dc1c61 100755 --- a/src/admin/topics.php +++ b/src/admin/topics.php @@ -1,34 +1,28 @@ -validator, $app->sanitizer) : ""; $topicController = class_exists('TopicController') ? new TopicController($topicService) : ""; try { - switch ($action) { - case ActionConst::NEWTOPIC: - - if (false === $authenticator->userAccessControl(ActionConst::TOPICS)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::TOPICS)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - if ((!check_integer($topicId)) && (gettype($topicId) != "integer")) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("Invalid ID data type"); } if ($topicId == 0) { - $topicController->insert(); } else { - direct_page('index.php?load=dashboard', 302); } } @@ -36,24 +30,18 @@ break; case ActionConst::EDITTOPIC: - - if (false === $authenticator->userAccessControl(ActionConst::TOPICS)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::TOPICS)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - if ((!check_integer($topicId)) && (gettype($topicId) !== "integer")) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("Invalid ID data type"); } - if ($topicDao->checkTopicId($topicId, $sanitizer)) { - + if ($topicDao->checkTopicId($topicId, $app->sanitizer)) { $topicController->update((int)$topicId); } else { - direct_page('index.php?load=404¬found=' . notfound_id(), 404); } } @@ -61,24 +49,18 @@ break; case ActionConst::DELETETOPIC: - if ((!check_integer($topicId)) && (gettype($topicId) !== "integer")) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("Invalid ID data type"); } - if (false === $authenticator->userAccessControl(ActionConst::TOPICS)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::TOPICS)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - - if ($topicDao->checkTopicId($topicId, $sanitizer)) { - + if ($topicDao->checkTopicId($topicId, $app->sanitizer)) { $topicController->remove((int)$topicId); } else { - direct_page('index.php?load=404¬found=' . notfound_id(), 404); } } @@ -86,25 +68,18 @@ break; default: - - if (false === $authenticator->userAccessControl(ActionConst::TOPICS)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::TOPICS)) { direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - $topicController->listItems(); } - } } catch (\Throwable $th) { - if (class_exists('LogError')) { - LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($th); } } catch (AppException $e) { - LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($e); } diff --git a/src/admin/translations.php b/src/admin/translations.php new file mode 100644 index 000000000..7b5a6d6e6 --- /dev/null +++ b/src/admin/translations.php @@ -0,0 +1,106 @@ + true]); + exit(); + + case ActionConst::NEWTRANSLATION: + if (false === $app->authenticator->userAccessControl(ActionConst::CONFIGURATION)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); + } else { + $translationController = new TranslationController(); + $translationController->create(); + } + + break; + + case ActionConst::DELETETRANSLATION: + if (false === $app->authenticator->userAccessControl(ActionConst::CONFIGURATION)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); + } else { + if ((!check_integer($translationId)) && (gettype($translationId) !== "integer")) { + header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); + header("Status: 400 Bad Request"); + throw new AppException("Invalid ID data type"); + } + + if ($translationId > 0) { + $translationController = new TranslationController(); + $translationController->delete((int)$translationId); + } else { + direct_page('index.php?load=translations', 302); + } + } + + break; + + case 'export': + if (false === $app->authenticator->userAccessControl(ActionConst::CONFIGURATION)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); + } else { + $translationController = new TranslationController(); + $translationController->export(); + } + + break; + + case 'import': + if (false === $app->authenticator->userAccessControl(ActionConst::CONFIGURATION)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); + } else { + $translationController = new TranslationController(); + $translationController->import(); + } + + break; + + case 'regenerateCache': + if (false === $app->authenticator->userAccessControl(ActionConst::CONFIGURATION)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); + } else { + $translationController = new TranslationController(); + $translationController->regenerateCache(); + } + + break; + + case 'update': + if (false === $app->authenticator->userAccessControl(ActionConst::CONFIGURATION)) { + http_response_code(403); + echo json_encode(['error' => 'Forbidden']); + } else { + $translationController = new TranslationController(); + $translationController->update(); + } + + break; + + default: + if (false === $app->authenticator->userAccessControl(ActionConst::CONFIGURATION)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); + } else { + $translationController = new TranslationController(); + $translationController->index(); + } + } +} catch (\Throwable $th) { + if (class_exists('LogError')) { + LogError::setStatusCode(http_response_code()); + LogError::exceptionHandler($th); + } +} catch (AppException $e) { + LogError::setStatusCode(http_response_code()); + LogError::exceptionHandler($e); +} diff --git a/src/admin/ui/appearance/all-menus.php b/src/admin/ui/appearance/all-menus.php index d0ed0a692..962aa4bac 100755 --- a/src/admin/ui/appearance/all-menus.php +++ b/src/admin/ui/appearance/all-menus.php @@ -1,4 +1,6 @@ - +
@@ -22,33 +24,33 @@
+ ?>

Error!

- + ?>

Success!

- @@ -77,10 +79,10 @@ + $no = 0; + $parents = null; + while ($menu = array_shift($menus)) : + ?> @@ -92,15 +94,11 @@ $total = $parent->num_rows; if ($total > 0) { - - while ($data_parent = nav_nested($parent)) { - - echo htmlout(strtolower($data_parent['menu_label'])); - - } + while ($data_parent = nav_nested($parent)) { + echo htmlout(strtolower($data_parent['menu_label'])); + } } else { - - echo "parent"; + echo "parent"; } ?> @@ -110,9 +108,8 @@ disabled - + enabled @@ -127,9 +124,9 @@ - diff --git a/src/admin/ui/appearance/all-templates.php b/src/admin/ui/appearance/all-templates.php index 2b7dbac06..79b0af84a 100755 --- a/src/admin/ui/appearance/all-templates.php +++ b/src/admin/ui/appearance/all-templates.php @@ -1,4 +1,6 @@ - +
@@ -20,37 +22,37 @@
- +

Error!

- +
- + - +

Success!

- +
- +
@@ -75,12 +77,12 @@ - + @@ -95,21 +97,21 @@ - + - + - + - + @@ -138,17 +140,17 @@ \ No newline at end of file diff --git a/src/admin/ui/appearance/edit-menu.php b/src/admin/ui/appearance/edit-menu.php index 5e2c6b545..732d6d8c1 100755 --- a/src/admin/ui/appearance/edit-menu.php +++ b/src/admin/ui/appearance/edit-menu.php @@ -1,4 +1,6 @@ - +
@@ -23,17 +25,17 @@ + ?>

Invalid Form Data!

-' . $e . '

'; -endforeach; -?> + ' . $e . '

'; + endforeach; + ?>
- " >

- -ex: /post/id/your-friendly-neighborhood.Please check out documentation for more information. +if (function_exists('is_permalink_enabled') && is_permalink_enabled() === 'yes') : + ?> +ex: /post/id/your-friendly-neighborhood.Please check out documentation for more information. + ex: ?p=1. Please check out documentation for more information. -

@@ -84,8 +85,8 @@
@@ -93,14 +94,14 @@
- @@ -109,6 +110,11 @@
+
+ + +
+
@@ -25,17 +27,17 @@ + ?>

Invalid Form Data!

-' . $e . '

'; -endforeach; -?> + ' . $e . '

'; + endforeach; + ?>
- "> "> - -')" + +')" title="Delete Theme" class="btn btn-danger pull-right"> Delete -
@@ -107,9 +109,9 @@ \ No newline at end of file diff --git a/src/admin/ui/appearance/install-template.php b/src/admin/ui/appearance/install-template.php index 41d2c884d..261916caf 100755 --- a/src/admin/ui/appearance/install-template.php +++ b/src/admin/ui/appearance/install-template.php @@ -1,4 +1,6 @@ - +
@@ -23,31 +25,31 @@ + ?>

Invalid Form Data!

-' . $e . '

'; -endforeach; -?> + ' . $e . '

'; + endforeach; + ?>
- + ?>

Alert!

- +
- +
@@ -17,96 +19,113 @@
- + ?>
-

Alert!

- +

Alert!

+
- + - +
-

Success!

- +

Success!

+
- +
-

+

in Total -

+
- -
- + +
+
- - - - - - + + + + + + - + foreach ($comments as $comment) : + $no++; + $replyCount = isset($commentService) ? $commentService->countReplies($comment['ID']) : 0; + ?> - - - - - + - + + + - - + endif + ?> - - - - - - + + + + + +
#CommentIn Response ToSubmited OnEditDelete#CommentActions
"> - " class="btn btn-warning" title="Edit comment"> - + "> + 60) ? '...' : ''; ?> + +
+ by
- - + +
#CommentIn Response ToSubmited OnEditDelete#CommentActions
@@ -125,9 +144,17 @@ \ No newline at end of file diff --git a/src/admin/ui/comments/edit-comment.php b/src/admin/ui/comments/edit-comment.php index 6f09a5aa9..72745b5d8 100755 --- a/src/admin/ui/comments/edit-comment.php +++ b/src/admin/ui/comments/edit-comment.php @@ -1,4 +1,6 @@ - +
@@ -17,25 +19,30 @@
-
-
-
- +if (isset($errors)) : + ?> +
-

Invalid Form Data!

-' . $e . '

'; - endforeach; +

Invalid Form Data!

+ ' . $e . '

'; + endforeach; + ?> +
+
+ +
+
+
+

Edit Comment

- + @@ -46,16 +53,13 @@
- -" required> + +" required>
- - + +
@@ -69,16 +73,21 @@
- + -
+
diff --git a/src/admin/ui/comments/reply-list.php b/src/admin/ui/comments/reply-list.php new file mode 100644 index 000000000..b6eee3c40 --- /dev/null +++ b/src/admin/ui/comments/reply-list.php @@ -0,0 +1,172 @@ + + +
+ +
+

+ + Control Panel +

+ +
+ + +
+
+ + +
+
+ +

Alert!

+ +
+
+ + + +
+
+ +

Success!

+ +
+
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#Reply ContentActions
+ 70) ? '...' : ''; ?> + + +
#Reply ContentActions
+ +
+

No replies found for this comment.

+ " class="btn btn-primary btn-sm"> + Add First Reply + +
+ +
+ +
+ +
+ +
+ +
+ +
+ + diff --git a/src/admin/ui/comments/reply.php b/src/admin/ui/comments/reply.php index 8a9fc3426..9bacf19d2 100755 --- a/src/admin/ui/comments/reply.php +++ b/src/admin/ui/comments/reply.php @@ -1,16 +1,18 @@ - + -

- Mailbox - 13 new messages + + Control Panel

@@ -18,70 +20,175 @@
-
+ +
+
+ +

Alert!

+ +
+
+ + + +
+
+ +

Success!

+ +
+
+ + +
-

Reply to Comment

+

+ + Edit Reply + + Reply to Comment + +

-
-
- -
-
- + + + +
+ + +
+
+ + " required maxlength="60"> +
+ +
+ + +

Maximum 1000 characters

+
+ +
+ + +
-
- + + + -
-
- Attachment - + +
+ +
+ + +
+ +
+
+

Parent Comment Information

+
+
+ +
+ +

-

Max. 32MB

-
+
+ +
+ +
+
+
+ +

+ " . time_elapsed_string($parentComment['comment_date']) . "" : ""; ?> +

+
+
+ +

+
+ +
+ +

+
+
+ +
+ +
+
+ +
+

Parent comment information not available

+
+
- - +
-
- \ No newline at end of file +
+ diff --git a/src/admin/ui/dashboard/home-admin.php b/src/admin/ui/dashboard/home-admin.php index 2979558f0..a1d57b845 100755 --- a/src/admin/ui/dashboard/home-admin.php +++ b/src/admin/ui/dashboard/home-admin.php @@ -1,5 +1,7 @@ -
diff --git a/src/admin/ui/dashboard/home-user.php b/src/admin/ui/dashboard/home-user.php index 264bc9eb5..2fc130b9a 100755 --- a/src/admin/ui/dashboard/home-user.php +++ b/src/admin/ui/dashboard/home-user.php @@ -1,4 +1,8 @@ - +
diff --git a/src/admin/ui/downloads/all-downloads.php b/src/admin/ui/downloads/all-downloads.php new file mode 100644 index 000000000..71d2ebf20 --- /dev/null +++ b/src/admin/ui/downloads/all-downloads.php @@ -0,0 +1,182 @@ + + + +
+ +
+

+ +

+ +
+ + +
+
+
+ + +
+ +

Success!

+ +
+ + + +
+ +

Error!

+ +
+ + +
+
+

+ Download Records +

+
+ +
+ + +
+
+ + + 0 selected +
+ + + + + + + + + + + + + + + + isDownloadExpired($download['media_identifier']) : false; + $downloadCount = ($downloadService !== null) ? $downloadService->getDownloadCountByMedia($download['media_id']) : 0; + ?> + + + + + + + + + + + + + + + + +
IDFileTypeIdentifierExpiresCreatedActions
+ +
+
... + + Expired + + Active +
+ +
+ + + + + + + + + +
No download records found.
+
+
+
+
+
+
+
+ + diff --git a/src/admin/ui/downloads/download-history.php b/src/admin/ui/downloads/download-history.php new file mode 100644 index 000000000..1f8b8b2f4 --- /dev/null +++ b/src/admin/ui/downloads/download-history.php @@ -0,0 +1,83 @@ + + + + + \ No newline at end of file diff --git a/src/admin/ui/downloads/download-stats.php b/src/admin/ui/downloads/download-stats.php new file mode 100644 index 000000000..a7d91067f --- /dev/null +++ b/src/admin/ui/downloads/download-stats.php @@ -0,0 +1,90 @@ + + + + +
+
+
+
+

+

Total Downloads

+
+
+ +
+
+
+ +
+
+
+

+

Active Links

+
+
+ +
+
+
+ +
+
+
+

+

Expired Links

+
+
+ +
+
+
+ +
+
+
+

+

Total Files

+
+
+ +
+
+
+
+ + +
+
+
+
+

File Type Distribution

+
+
+
+ + + + + + + + + + + + + + + +
File TypeDownloads
+
+
+
+
+
+ diff --git a/src/admin/ui/export/index.php b/src/admin/ui/export/index.php new file mode 100644 index 000000000..7c8017f09 --- /dev/null +++ b/src/admin/ui/export/index.php @@ -0,0 +1,156 @@ + + +
+ +
+

+ Export Content +

+ +
+ + +
+
+
+ + +
+ +

Error!

+ ' . $e . '

'; + endforeach; + ?> +
+ + + +
+ +

Success!

+ ' . nl2br($s) . '

'; + endforeach; + ?> +
+ + +
+
+

Export Content

+
+ +
+
+

Export Options

+

Export your Blogware content to various formats for migration or backup.

+
+ +
+ "> + +
+ + +

Choose the platform you want to export content to.

+
+ +
+ + +

Select a specific author to export only their content, or leave blank to export all content.

+
+ + + +
+ +
+ +
+ +
+
+

Information

+
+
+ +

What gets exported:

+
    +
  • Posts (including featured images)
  • +
  • Pages
  • +
  • Categories/Tags
  • +
  • Comments (approved only)
  • +
  • Users (optional, based on author filter)
  • +
  • Navigation menus
  • +
  • Site settings
  • +
+ +

Supported Formats:

+
    +
  • Scriptlog / Blogware JSON - Native format for Scriptlog/Blogware import (recommended for Scriptlog to Scriptlog transfers)
  • +
  • WordPress WXR XML - Compatible with WordPress import
  • +
  • Ghost JSON - Compatible with Ghost import
  • +
  • Blogspot/Blogger XML - Compatible with Blogger import
  • +
+ +
+

Tip: When exporting content from one Scriptlog installation to another, always use the Scriptlog / Blogware JSON format. It preserves all your data including menus, categories, tags, and settings.

+
+ +

Note: Media files (images, documents, etc.) are NOT included in the export. You'll need to manually transfer your media files or use the media library export/import feature if available.

+
+
+ +
+
+
+ + +
\ No newline at end of file diff --git a/src/admin/ui/import/index.php b/src/admin/ui/import/index.php new file mode 100644 index 000000000..9efd143d3 --- /dev/null +++ b/src/admin/ui/import/index.php @@ -0,0 +1,179 @@ + + +
+ +
+

+ Import Content +

+ +
+ + +
+
+
+ + +
+ +

Error!

+ ' . $e . '

'; + endforeach; + ?> +
+ + + +
+ +

Success!

+ ' . nl2br($s) . '

'; + endforeach; + ?> +
+ + +
+
+

Import Content

+
+ +
+
+

Supported Platforms

+

Import content from WordPress (WXR), Ghost (JSON), Blogspot/Blogger (XML), or Scriptlog/Blogware (JSON) export files.

+
+ +
+ "> + +
+ + +

Choose the platform your content is exported from.

+
+ +
+ + +

Upload your export file (JSON for Scriptlog/Ghost, XML for WordPress/Blogspot).

+
+ +
+ + +

Select the author to assign imported content to.

+
+ + + +
+ +
+
+ +
+
+

Instructions

+
+
+ +

Scriptlog / Blogware

+
    +
  1. Go to Tools > Export in another Scriptlog/Blogware installation
  2. +
  3. Select "Scriptlog / Blogware (JSON)" as the destination
  4. +
  5. Click "Export" to download the JSON file
  6. +
  7. Upload the downloaded JSON file here
  8. +
+ +

WordPress

+
    +
  1. Go to your WordPress admin panel
  2. +
  3. Navigate to Tools > Export
  4. +
  5. Select "Posts" or "Pages" (or "All content")
  6. +
  7. Click "Download Export File"
  8. +
  9. Upload the downloaded XML file here
  10. +
+ +

Ghost

+
    +
  1. Go to your Ghost admin panel
  2. +
  3. Navigate to Labs > Export
  4. +
  5. Click "Export Content"
  6. +
  7. Upload the downloaded JSON file here
  8. +
+ +

Blogspot / Blogger

+
    +
  1. Go to your Blogger dashboard
  2. +
  3. Go to Settings > Other
  4. +
  5. Click "Export blog"
  6. +
  7. Download the XML file
  8. +
  9. Upload the XML file here
  10. +
+ +
+
+ +
+
+
+ + +
diff --git a/src/admin/ui/import/preview.php b/src/admin/ui/import/preview.php new file mode 100644 index 000000000..4a63dc402 --- /dev/null +++ b/src/admin/ui/import/preview.php @@ -0,0 +1,164 @@ + + +
+ +
+

+ Import Preview +

+ +
+ + +
+
+
+ +
+

Preview Information

+

This is a preview of the data that will be imported. No data has been imported yet.

+
+ +
+
+

Source Information

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Title
URL
Site URL
Platform
+ + +
+
+ +
+
+

Content Summary

+
+
+ +
+
+
+ +
+ Posts + +
+
+
+ + +
+
+ +
+ Pages + +
+
+
+ + +
+
+ +
+ Categories + +
+
+
+ + +
+
+ +
+ Tags + +
+
+
+ +
+ +
+
+ + +
+
+

Items to be Imported (Sample)

+
+
+ + + + + + + + + + + + + + + + + + + + + +
TitleSlugTypeStatusDate
+ 10) : ?> +


... and more items.

+ +
+
+ + +
+ +
+ +
+
+
+
diff --git a/src/admin/ui/medialib/all-media.php b/src/admin/ui/medialib/all-media.php index 33ce35202..493685f90 100755 --- a/src/admin/ui/medialib/all-media.php +++ b/src/admin/ui/medialib/all-media.php @@ -1,4 +1,6 @@ - +
@@ -21,37 +23,37 @@
- +

Error!

- +
- + - +

Success!

- +
- +
@@ -76,12 +78,12 @@ - + @@ -103,10 +105,10 @@ - + @@ -135,9 +137,9 @@ diff --git a/src/admin/ui/medialib/edit-media.php b/src/admin/ui/medialib/edit-media.php index 2a45e8f86..a31cc8466 100755 --- a/src/admin/ui/medialib/edit-media.php +++ b/src/admin/ui/medialib/edit-media.php @@ -1,4 +1,12 @@ - + + + +
@@ -8,7 +16,7 @@ Control Panel @@ -19,25 +27,24 @@
-
+
+

Media Details

+
-
- -

Invalid Form Data!

-' . $e . '

'; -endforeach; -?> + ?> + -
@@ -46,26 +53,22 @@
- + if ($image_src || $webp_src) : + ?>
-
- + -
-

Maximum upload file size: .

+

Maximum upload file size: .

- - +
- - - + +
- - -

Maximum upload file size: .

+ + +

Supported formats: Images, Audio, and Video. Max size: .

- -" maxlength="200" > +" maxlength="200" aria-describedby="captionHelp"> +

A brief description or title for the media.

@@ -142,30 +138,29 @@
-
+
- - +
- +
-
-
@@ -177,8 +172,13 @@ @@ -187,9 +187,9 @@
- +
@@ -200,10 +200,10 @@
- +
File name
@@ -216,14 +216,14 @@
Uploaded on
Dimension
-
+
+ endif; + ?>
diff --git a/src/admin/ui/pages/all-pages.php b/src/admin/ui/pages/all-pages.php index 2773b0d35..9819d996f 100755 --- a/src/admin/ui/pages/all-pages.php +++ b/src/admin/ui/pages/all-pages.php @@ -1,4 +1,6 @@ - +
@@ -18,37 +20,37 @@
- +

Alert!

- +
- + - +

Alert!

- +
- +
@@ -73,12 +75,12 @@ - $page) : - $no++; - ?> + $page) : + $no++; + ?> @@ -95,9 +97,9 @@ - @@ -126,9 +128,9 @@ \ No newline at end of file diff --git a/src/admin/ui/pages/edit-page.php b/src/admin/ui/pages/edit-page.php index ff1fade23..31455f707 100755 --- a/src/admin/ui/pages/edit-page.php +++ b/src/admin/ui/pages/edit-page.php @@ -1,11 +1,19 @@ - + + + +

Control Panel

@@ -18,29 +26,27 @@
-
+
+

Page Content

+
-
- -

Invalid Form Data!

- -' . $e . '

'; -endforeach; -?> + ?> + - @@ -49,38 +55,33 @@
- +
- - -" maxlength="200" required> + +" maxlength="200" required aria-required="true">
- +
- - + +
- +
- +

This will keep the page link prominently displayed in your navigation.

-
-
@@ -88,31 +89,24 @@
- +
- +
-" class="form-control" placeholder="Date" value=" - -" class="form-control" placeholder="YYYY-MM-DD HH:MM:SS" value="">
+

Set the date this page will be publicly available.

@@ -124,23 +118,22 @@
- +
- +
-
+
+

Page Settings

+
- -

Maximum 320 characters

+ +

Maximum 320 characters. This summary appears in search results.

@@ -148,11 +141,23 @@
+
+ + +

Select the language for this page.

+
+ - +
@@ -168,7 +173,7 @@ \ No newline at end of file diff --git a/src/admin/ui/plug-in/all-plugins.php b/src/admin/ui/plug-in/all-plugins.php index 508f8f088..6de52c175 100755 --- a/src/admin/ui/plug-in/all-plugins.php +++ b/src/admin/ui/plug-in/all-plugins.php @@ -1,4 +1,6 @@ - +
@@ -20,37 +22,37 @@
- +

Error!

- +
- + - +

Success!

- +
- +
@@ -75,40 +77,40 @@ - $plugin) : - $no++; - ?> + $plugin) : + $no++; + ?> - +

- ')" title="Delete Plugin" class="btn btn-danger"> + ')" title="Delete Plugin" class="btn btn-danger"> Delete - + Enabled - + Disabled - + - + @@ -137,26 +139,26 @@ diff --git a/src/admin/ui/plug-in/install-plugin.php b/src/admin/ui/plug-in/install-plugin.php index d4a653535..2a982c09a 100755 --- a/src/admin/ui/plug-in/install-plugin.php +++ b/src/admin/ui/plug-in/install-plugin.php @@ -1,4 +1,6 @@ - +
@@ -23,17 +25,17 @@ + ?>

Invalid Form Data!

-' . $e . '

'; -endforeach; -?> + ' . $e . '

'; + endforeach; + ?>
- +
@@ -22,35 +24,35 @@
+ ?>

Error!

- + ?>

Success!

- @@ -78,10 +80,10 @@ $post) : - $no++; - ?> + $no = 0; + foreach ($posts as $p => $post) : + $no++; + ?> @@ -100,8 +102,8 @@ - diff --git a/src/admin/ui/posts/all-topics.php b/src/admin/ui/posts/all-topics.php index e7e76ad0f..e8bd450c0 100755 --- a/src/admin/ui/posts/all-topics.php +++ b/src/admin/ui/posts/all-topics.php @@ -1,4 +1,6 @@ - +
@@ -6,8 +8,8 @@

Add New - + class="btn btn-primary"> Add New +

+ + + + + + + + diff --git a/src/admin/ui/users/all-users.php b/src/admin/ui/users/all-users.php index 20aa143ef..c185f4d78 100755 --- a/src/admin/ui/users/all-users.php +++ b/src/admin/ui/users/all-users.php @@ -1,4 +1,6 @@ - +
@@ -19,39 +21,39 @@
- +

Error!

- +
- + - +

Success!

- +
- +
@@ -76,12 +78,10 @@ - $user) : - - ?> + $user) : + ?> @@ -98,9 +98,9 @@ - @@ -130,9 +130,9 @@ \ No newline at end of file diff --git a/src/admin/ui/users/edit-myprofile.php b/src/admin/ui/users/edit-myprofile.php index 66f600d19..97cb1a4e3 100755 --- a/src/admin/ui/users/edit-myprofile.php +++ b/src/admin/ui/users/edit-myprofile.php @@ -1,5 +1,5 @@
@@ -36,13 +36,11 @@ + ?> - @@ -95,45 +93,43 @@ + if (isset($errors)) : + ?>

Invalid form data!

- ' . $e . '

'; - endforeach; - ?> + ' . $e . '

'; + endforeach; + ?>
- + + if (isset($status)) : + ?>

- + $action = isset($formAction) ? $formAction : null; + $user_id = isset($userData['ID']) ? safe_html((int)$userData['ID']) : 0; + $session_id = isset($userData['user_session']) ? safe_html($userData['user_session']) : null; + ?>
@@ -141,15 +137,15 @@
+ if ((isset($userData['user_login'])) && ($userData['user_login'] != '')) : + ?>
" > + " >

This username can not be changed.

- +
@@ -171,7 +167,6 @@
-
diff --git a/src/admin/ui/users/edit-user.php b/src/admin/ui/users/edit-user.php index c22aff6f5..25da9e8c4 100755 --- a/src/admin/ui/users/edit-user.php +++ b/src/admin/ui/users/edit-user.php @@ -1,5 +1,5 @@
@@ -26,26 +26,26 @@
+ if (isset($errors)) : + ?>

Invalid form data!

- ' . $e . '

'; - endforeach; - ?> + ' . $e . '

'; + endforeach; + ?>
- + + $action = (isset($formAction)) ? $formAction : null; + $user_id = (isset($userData['ID'])) ? safe_html((int)$userData['ID']) : 0; + $session_id = (isset($userData['user_session'])) ? safe_html($userData['user_session']) : substr(hash('sha256', bin2hex(openssl_random_pseudo_bytes(ceil(32 / 2)))), 0, 32); + ?> @@ -53,15 +53,15 @@
+ if (isset($userData['user_registered'])) : + ?>
- +
- +
@@ -91,7 +91,6 @@
-
@@ -117,30 +116,30 @@
+ if (empty($userData['user_email'])) : + ?>
- + + if (!empty($userData['user_level']) && $userData['user_level'] != 'administrator') : + ?>
- +
diff --git a/src/admin/ui/users/remove-profile.php b/src/admin/ui/users/remove-profile.php index 0383d21a0..50cbd4830 100755 --- a/src/admin/ui/users/remove-profile.php +++ b/src/admin/ui/users/remove-profile.php @@ -1,4 +1,6 @@ - +
@@ -21,21 +23,21 @@ + ?>

Invalid Form Data!

-' . $e . '

'; -endforeach; -?> + ' . $e . '

'; + endforeach; + ?>
- -userDao, $app->validator, $app->userToken, $app->sanitizer) : ""; $userController = class_exists('UserController') ? new UserController($userService) : ""; try { - switch ($action) { - case ActionConst::NEWUSER: - - if (false === $authenticator->userAccessControl(ActionConst::USERS)) { - - direct_page('index.php?load=403&forbidden='.forbidden_id(), 403); - } else { - - if ((!check_integer($userId)) && (gettype($userId) !== "integer")) { - - header($_SERVER["SERVER_PROTOCOL"]." 400 Bad Request", true, 400); - header("Status: 400 Bad Request"); - throw new AppException("invalid ID data type!"); - - } - - if ($userId === 0) { - - $userController->insert(); - + if (false === $app->authenticator->userAccessControl(ActionConst::USERS)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - - direct_page('index.php?load=dashboard', 302); - + if ((!check_integer($userId)) && (gettype($userId) !== "integer")) { + header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); + header("Status: 400 Bad Request"); + throw new AppException("invalid ID data type!"); + } + + if ($userId === 0) { + $userController->insert(); + } else { + direct_page('index.php?load=dashboard', 302); + } } - - } - - break; - + + break; + case ActionConst::EDITUSER: - if ((!check_integer($userId)) && (gettype($userId) !== "integer")) { - - header($_SERVER["SERVER_PROTOCOL"]." 400 Bad Request", true, 400); + header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("Invalid ID data type!"); - } - if (!$userDao->checkUserId($userId, $sanitizer)) { - - if (false === $authenticator->userAccessControl(ActionConst::USERS)) { - - direct_page('index.php?load=403&forbidden='.forbidden_id(), 403); - + if (!$app->userDao->checkUserId($userId, $app->sanitizer)) { + if (false === $app->authenticator->userAccessControl(ActionConst::USERS)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - - direct_page('index.php?load=404¬found='.notfound_id(), 404); - + direct_page('index.php?load=404¬found=' . notfound_id(), 404); } - } else { - - if (false === $authenticator->userAccessControl(ActionConst::USERS)) { - + if (false === $app->authenticator->userAccessControl(ActionConst::USERS)) { $userController->updateProfile($user_login); - } else { - $userController->update((int)$userId); - } - } - + break; - + case ActionConst::DELETEUSER: - if ((!check_integer($userId)) && (gettype($userId) !== "integer")) { - - header($_SERVER["SERVER_PROTOCOL"]." 400 Bad Request", true, 400); + header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); throw new AppException("Invalid ID data type!"); - } - if (!$userDao->checkUserId($userId, $sanitizer)) { - - if (false === $authenticator->userAccessControl(ActionConst::USERS)) { - - direct_page('index.php?load=403&forbidden='.forbidden_id(), 403); - + if (!$app->userDao->checkUserId($userId, $app->sanitizer)) { + if (false === $app->authenticator->userAccessControl(ActionConst::USERS)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); } else { - - direct_page('index.php?load=404¬found='.notfound_id(), 404); - + direct_page('index.php?load=404¬found=' . notfound_id(), 404); } - } else { - - if (false === $authenticator->userAccessControl(ActionConst::USERS)) { - - $userController->removeProfile($user_login, $authenticator); - + if (false === $app->authenticator->userAccessControl(ActionConst::USERS)) { + $userController->removeProfile($user_login, $app->authenticator); } else { - $userController->remove((int)$userId); - } - } - + break; - + default: - - if (false === $authenticator->userAccessControl(ActionConst::USERS)) { - - $userController->showProfile($user_login); - - } else { - - $userController->listItems(); - - } - + if (false === $app->authenticator->userAccessControl(ActionConst::USERS)) { + $userController->showProfile($user_login); + } else { + $userController->listItems(); + } } - } catch (\Throwable $th) { - if (class_exists('LogError')) { - LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($th); } - } catch (AppException $e) { - LogError::setStatusCode(http_response_code()); LogError::exceptionHandler($e); - -} \ No newline at end of file +} diff --git a/src/api/index.php b/src/api/index.php index a7810eb4b..9699761f2 100644 --- a/src/api/index.php +++ b/src/api/index.php @@ -1,20 +1,21 @@ get('posts', 'PostsApiController@index'); @@ -85,7 +100,7 @@ $router->post('posts', 'PostsApiController@store'); $router->put('posts/([0-9]+)', 'PostsApiController@update'); $router->delete('posts/([0-9]+)', 'PostsApiController@destroy'); - + // Categories/Topics API $router->get('categories', 'CategoriesApiController@index'); $router->get('categories/([0-9]+)', 'CategoriesApiController@show'); @@ -93,21 +108,50 @@ $router->post('categories', 'CategoriesApiController@store'); $router->put('categories/([0-9]+)', 'CategoriesApiController@update'); $router->delete('categories/([0-9]+)', 'CategoriesApiController@destroy'); - + // Comments API $router->get('comments', 'CommentsApiController@index'); $router->get('comments/([0-9]+)', 'CommentsApiController@show'); $router->post('comments', 'CommentsApiController@store'); $router->put('comments/([0-9]+)', 'CommentsApiController@update'); $router->delete('comments/([0-9]+)', 'CommentsApiController@destroy'); - + // Archives API $router->get('archives', 'ArchivesApiController@index'); $router->get('archives/([0-9]{4})', 'ArchivesApiController@year'); $router->get('archives/([0-9]{4})/([0-9]{2})', 'ArchivesApiController@month'); - + + // Search API + $router->get('search', 'SearchApiController@index'); + $router->get('search/posts', 'SearchApiController@posts'); + $router->get('search/pages', 'SearchApiController@pages'); + + // GDPR API + $router->post('gdpr/consent', 'GdprApiController@consent'); + $router->get('gdpr/consent', 'GdprApiController@getConsentStatus'); + + // Languages API + $router->get('languages', 'LanguagesApiController@index'); + $router->get('languages/active', 'LanguagesApiController@index'); + $router->get('languages/default', 'LanguagesApiController@default'); + $router->get('languages/([a-z]{2})', 'LanguagesApiController@show'); + $router->post('languages', 'LanguagesApiController@store'); + $router->put('languages/([a-z]{2})', 'LanguagesApiController@update'); + $router->delete('languages/([a-z]{2})', 'LanguagesApiController@destroy'); + $router->post('languages/([a-z]{2})/default', 'LanguagesApiController@setDefault'); + + // Translations API + $router->get('translations/([a-z]{2})', 'TranslationsApiController@index'); + $router->get('translations/([a-z]{2})/([a-zA-Z0-9._-]+)', 'TranslationsApiController@show'); + $router->post('translations/([a-z]{2})', 'TranslationsApiController@store'); + $router->put('translations/([0-9]+)', 'TranslationsApiController@update'); + $router->delete('translations/([0-9]+)', 'TranslationsApiController@destroy'); + $router->get('translations/([a-z]{2})/export', 'TranslationsApiController@export'); + $router->post('translations/([a-z]{2})/import', 'TranslationsApiController@import'); + $router->post('translations/([a-z]{2})/cache', 'TranslationsApiController@cache'); + // API OpenAPI spec endpoint - $router->get('openapi.json', function($params) { + $router->get('openapi.json', function ($params) { $specFile = __DIR__ . '/../docs/API_OPENAPI.json'; if (file_exists($specFile)) { header('Content-Type: application/json'); @@ -117,14 +161,13 @@ } ApiResponse::notFound('OpenAPI specification not found'); }); - + // API Info endpoint $router->get('', 'ApiController@info'); $router->get('/', 'ApiController@info'); - + // Dispatch the request $router->dispatch($method, $uri, $queryParams); - } catch (\Throwable $e) { // Handle any uncaught exceptions ApiResponse::error($e->getMessage(), 500, 'INTERNAL_SERVER_ERROR'); diff --git a/src/composer.json b/src/composer.json deleted file mode 100644 index b8602c76f..000000000 --- a/src/composer.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/composer/composer/master/res/composer-schema.json", - "name": "cakmoel/scriptlog", - "type": "project", - "description": "Just another blog engine", - "license": "MIT", - "authors": [ - { - "name": "M Noermoehammad", - "email": "alanmoehammad@gmail.com", - "homepage": "https://github.com/cakmoel", - "role": "Developer" - } - ], - "config": { - "platform-check": false, - "platform": { - "php": "7.4.33" - } - }, - - "require": { - "sinergi/browser-detector": "^6.1", - "intervention/image": "^2.5", - "ircmaxell/random-lib": "^1.2", - "egulias/email-validator": "^2.1", - "voku/anti-xss": "^4.1", - "defuse/php-encryption": "^2.2", - "filp/whoops": "^2.9", - "psr/log": "^1.1", - "melbahja/seo": "^2.0", - "laminas/laminas-escaper": "^2.12", - "laminas/laminas-crypt": "^3.3", - "laminas/laminas-feed": "^2.17", - "catfan/medoo": "^2.1" - }, - "require-dev": { - "phpunit/phpunit": "^9.5" - }, - "minimum-stability": "stable", - "prefer-stable": true, - "autoload": { - "classmap": ["lib/"] - } -} diff --git a/src/docs/API_DOCUMENTATION.md b/src/docs/API_DOCUMENTATION.md old mode 100644 new mode 100755 index 6ed4e0b2d..f232f82a0 --- a/src/docs/API_DOCUMENTATION.md +++ b/src/docs/API_DOCUMENTATION.md @@ -1,4 +1,4 @@ -# Blogware RESTful API Documentation +# ScriptLog RESTful API Documentation ## Table of Contents @@ -21,7 +21,7 @@ ## Introduction -The Blogware RESTful API provides programmatic access to your blog's content, allowing other platforms, operating systems, and devices to interact with your blog data. The API follows REST architectural principles and returns JSON responses. +The ScriptLog RESTful API provides programmatic access to your blog's content, allowing other platforms, operating systems, and devices to interact with your blog data. The API follows REST architectural principles and returns JSON responses. **API Version:** 1.0.0 **Format:** JSON diff --git a/src/docs/API_OPENAPI.json b/src/docs/API_OPENAPI.json old mode 100644 new mode 100755 diff --git a/src/docs/API_OPENAPI.yaml b/src/docs/API_OPENAPI.yaml old mode 100644 new mode 100755 diff --git a/src/docs/DEVELOPER_GUIDE.md b/src/docs/DEVELOPER_GUIDE.md old mode 100644 new mode 100755 index be201583f..dd8f35a75 --- a/src/docs/DEVELOPER_GUIDE.md +++ b/src/docs/DEVELOPER_GUIDE.md @@ -22,6 +22,18 @@ 14. [API Reference](#14-api-reference) 15. [Testing](#15-testing) 16. [Troubleshooting](#16-troubleshooting) +17. [Asset Management](#17-asset-management) +18. [GDPR Compliance](#18-gdpr-compliance) +19. [Internationalization (i18n)](#19-internationalization-i18n) +20. [Comment-Reply System](#20-comment-reply-system) +21. [Content Import System](#21-content-import-system) +22. [Content Export System](#22-content-export-system) +23. [UI Asset Management](#23-ui-asset-management) +24. [Dynamic SMTP System](#24-dynamic-smtp-system) +25. [Search Functionality](#25-search-functionality) +26. [Premium UI Standards](#26-premium-ui-standards) + +> **NOTE:** For comprehensive testing documentation including PHPStan setup and CI/CD integration, see [TESTING_GUIDE.md](TESTING_GUIDE.md). --- @@ -50,7 +62,7 @@ | 4. Run install/index.php (system requirements) | | 5. Run install/setup-db.php (create tables) | | 6. Run install/finish.php (complete setup) | -| 7. Configuration saved to config.php | +| 7. Configuration saved to config.php and .env | +---------------------------------------------------------------+ ``` @@ -58,7 +70,7 @@ ```bash # Clone repository -git clone https://github.com/blogware/scriptlog.git +git clone https://github.com/ScriptLog/scriptlog.git cd scriptlog # Install dependencies @@ -81,9 +93,232 @@ chmod -R 777 public/cache/ public/log/ --- +## 2.1 Configuration System + +### Overview + +ScriptLog supports both `.env` and `config.php` files for configuration. During first-time installation, both files are automatically generated and kept in sync. + +### Configuration Files + +#### config.php + +The main configuration file uses `$_ENV` pattern with fallback values: + +```php + [ + 'host' => $_ENV['DB_HOST'] ?? 'localhost', + 'user' => $_ENV['DB_USER'] ?? '', + 'pass' => $_ENV['DB_PASS'] ?? '', + 'name' => $_ENV['DB_NAME'] ?? '', + 'port' => $_ENV['DB_PORT'] ?? '3306', + 'prefix' => $_ENV['DB_PREFIX'] ?? '' + ], + + 'app' => [ + 'url' => $_ENV['APP_URL'] ?? 'http://example.com', + 'email' => $_ENV['APP_EMAIL'] ?? '', + 'key' => $_ENV['APP_KEY'] ?? '', + 'defuse_key' => 'lib/utility/.lts/lts.txt' + ], + + 'mail' => [ + 'smtp' => [ + 'host' => $_ENV['SMTP_HOST'] ?? '', + 'port' => $_ENV['SMTP_PORT'] ?? 587, + 'encryption' => $_ENV['SMTP_ENCRYPTION'] ?? 'tls', + 'username' => $_ENV['SMTP_USER'] ?? '', + 'password' => $_ENV['SMTP_PASS'] ?? '', + ], + 'from' => [ + 'email' => $_ENV['MAIL_FROM_ADDRESS'] ?? '', + 'name' => $_ENV['MAIL_FROM_NAME'] ?? 'Blogware' + ] + ], + + 'os' => [ + 'system_software' => $_ENV['SYSTEM_OS'] ?? 'Linux', + 'distrib_name' => $_ENV['DISTRIB_NAME'] ?? '' + ], +]; +``` + +#### .env File + +Auto-generated environment file: + +```bash +# --- DATABASE CONFIGURATION --- +DB_HOST=localhost +DB_USER=blogwareuser +DB_PASS=yourpassword +DB_NAME=blogwaredb +DB_PORT=3306 +DB_PREFIX= + +# --- APPLICATION CONFIGURATION --- +APP_URL=https://example.com +APP_EMAIL=admin@example.com +APP_KEY=XXXXXX-XXXXXX-XXXXXX-XXXXXX + +# --- MAIL / SMTP CONFIGURATION --- +SMTP_HOST= +SMTP_PORT=587 +SMTP_USER= +SMTP_PASS= +SMTP_ENCRYPTION=tls +MAIL_FROM_ADDRESS=admin@example.com +MAIL_FROM_NAME=Blogware + +# --- SYSTEM --- +SYSTEM_OS=Linux +DISTRIB_NAME="Linux Mint" +``` + +### Automatic Defuse Key Generation + +During first-time installation, the system automatically: +- Generates a Defuse encryption key using `Defuse\Crypto\Key::createNewRandomKey()` +- Saves the key to `lib/utility/.lts/lts.txt` +- Stores the key path in `config.php` under `app.defuse_key` +- This key is used for authentication cookie encryption + +### Installation Fixes + +During development, the following bugs were discovered and fixed: + +#### 1. write_config_file() Argument Order Bug + +**Problem**: The `write_config_file()` function in `install/include/setup.php` has the signature: +```php +function write_config_file($protocol, $server_name, $dbhost, $dbpassword, $dbuser, $dbname, $dbport, ...) +``` + +But `install/index.php` was calling it with `$dbuser` and `$dbpass` in the wrong order, causing "Access denied" errors when creating config.php. + +**Fix**: In `install/index.php` line 168, corrected the argument order: +```php +// BEFORE (WRONG): +write_config_file($protocol, $server_host, $dbhost, $dbuser, $dbpass, $dbname, ...) + +// AFTER (CORRECT): +write_config_file($protocol, $server_host, $dbhost, $dbpass, $dbuser, $dbname, ...) +``` + +#### 2. popper.min.js Path Bug + +**Problem**: The install layout was loading popper.js from a non-existent path `assets/vendor/bootstrap/js/vendor/popper.min.js`. + +**Fix**: In `install/install-layout.php`, corrected the path to `assets/vendor/bootstrap/js/popper.min.js`. + +#### 3. Database Tables Created + +The installation now creates 21 tables: +- Core: tbl_users, tbl_user_token, tbl_login_attempt, tbl_posts, tbl_topics, tbl_post_topic, tbl_comments +- Media: tbl_media, tbl_mediameta, tbl_media_download +- System: tbl_menu, tbl_plugin, tbl_settings, tbl_themes +- GDPR: tbl_consents, tbl_data_requests, tbl_privacy_logs, tbl_privacy_policies +- i18n: tbl_languages, tbl_translations +- Downloads: tbl_download_log + +#### 4. Database Column Fixes + +**Problem**: The `PostModel` class references a `post_keyword` column that didn't exist in the database, causing errors when accessing post data. + +**Fix**: Added `post_keyword` column to `tbl_posts` in `install/include/dbtable.php`: +```sql +ALTER TABLE tbl_posts ADD COLUMN post_keyword VARCHAR(255) DEFAULT NULL AFTER post_tags; +``` + +#### 5. Db Class KnownTables Array + +**Problem**: The `Db` class (`lib/core/Db.php`) had an incomplete `knownTables` array, missing several tables that the application uses. This caused issues with prefix handling. + +**Fix**: Added all 21 tables to the `knownTables` array in `lib/core/Db.php`: +```php +private $knownTables = [ + 'users', 'user_token', 'login_attempt', 'posts', 'topics', + 'post_topic', 'comments', 'media', 'mediameta', 'media_download', + 'menu', 'plugin', 'settings', 'themes', 'consents', + 'data_requests', 'privacy_logs', 'privacy_policies', + 'languages', 'translations', 'download_log' +]; +``` + +### Post-Installation Fixes + +After initial installation, several issues were discovered and fixed: + +#### 6. Table Prefix Compatibility + +**Problem**: The application uses table prefixes (e.g., `urmpnj_posts`) but utility functions using Medoo were creating new database connections without applying the prefix. + +**Fixes**: + +1. **medooin.php**: Modified to use the Registry connection (`Registry::get('dbc')`) instead of creating a new Medoo connection, ensuring table prefix is applied. + +2. **db-mysqli.php**: Updated to work with both PDO and mysqli connections - checks connection type and handles accordingly. + +#### 7. Null Safety and Compatibility Fixes + +The following utility functions were fixed for null safety and PDO/mysqli compatibility: + +1. **membership.php** (`lib/utility/membership.php`): + - Added null checks for `$user['user_fullname']` and `$user['user_login']` + - Fixed array access patterns + +2. **app-info.php** (`lib/utility/app-info.php`): + - Fixed array/object compatibility issues + - Added type checking for different return formats + +3. **theme-navigation.php** (`lib/utility/theme-navigation.php`): + - Added PDO/mysqli compatibility handling + - Fixed result fetching for both connection types + +4. **login-attempt.php** (`lib/utility/login-attempt.php`): + - Added PDO/mysqli compatibility handling + - Fixed result fetching patterns + +#### 8. Hello World Plugin Installation + +**Problem**: The sample Hello World plugin existed in `admin/plugins/hello-world/` but was not being added to the database during installation. + +**Fix**: Added the plugin to the installation process: + +1. **dbtable.php**: Added `savePlugin` SQL query: +```php +$savePlugin = "INSERT INTO {$prefix}tbl_plugin (plugin_name, plugin_link, plugin_directory, plugin_desc, plugin_status, plugin_level, plugin_sort) VALUES (?, ?, ?, ?, ?, ?, ?)"; +``` + +2. **setup.php**: Added code to insert Hello World plugin during installation: +```php +$plugin_name = "Hello World"; +$plugin_link = "#"; +$plugin_directory = "hello-world"; +$plugin_desc = "A simple Hello World plugin to demonstrate the plugin system"; +$plugin_status = "N"; // disabled by default +$plugin_level = "administrator"; +$plugin_sort = 1; +``` + +The plugin is inserted as disabled (`plugin_status = 'N'`) by default, allowing users to enable it from the admin panel after installation. + +### Key Files + +| File | Location | Purpose | +|------|----------|---------| +| `config.php` | Root | Main configuration with `$_ENV` fallbacks | +| `.env` | Root | Environment variables (auto-generated) | +| `defuse_key` | `lib/utility/.lts/lts.txt` | Encryption key for authentication | + +--- + ## 2. Architecture Overview -Blogware uses a **multi-layer architecture** designed for maintainability and scalability: +ScriptLog uses a **multi-layer architecture** designed for maintainability and scalability: ``` +---------------------------------------------------------------+ @@ -104,7 +339,7 @@ Blogware uses a **multi-layer architecture** designed for maintainability and sc | | | | v | | +---------------------+ | -| | Dispatcher | (lib/core/Dispatcher.php) | +| | Dispatcher | (lib/core/Dispatcher.php) | | +----------+----------+ | | | | | v | @@ -144,34 +379,176 @@ Blogware uses a **multi-layer architecture** designed for maintainability and sc > **WARNING:** Never bypass the DAO layer when accessing the database. Always use prepared statements to prevent SQL injection. +### 404 Handling + +All 404 handling is done in the Dispatcher, NOT in theme templates. This prevents "headers already sent" errors: + +- **Dispatcher** (`lib/core/Dispatcher.php`): Contains `validateContentExists()` method that checks if content exists in database before rendering +- **Validation happens BEFORE header output**: Ensures proper 404 status code is set +- **Route parameter names**: Use correct named parameters from route patterns (`id` for posts, `page` for pages, `category` for categories) +- **Custom 404 template**: Uses theme's `404.php` template +- **HandleRequest** (`lib/core/HandleRequest.php`): Handles query string URLs when permalinks are disabled, renders custom 404 template for invalid paths + +```php +// Example: validateContentExists in Dispatcher +private function validateContentExists($routeKey, $requestPath) +{ + switch ($routeKey) { + case 'single': + $postId = isset($requestPath->id) ? $requestPath->id : null; + $postSlug = isset($requestPath->post) ? $requestPath->post : null; + + if (empty($postId) || empty($postSlug)) { + return false; + } + + $post = class_exists('FrontHelper') ? FrontHelper::grabPreparedFrontPostById($postId) : null; + + if (empty($post) || !is_array($post)) { + return false; + } + + // Validate slug matches - redirect to 404 if slug is incorrect + $dbSlug = isset($post['post_slug']) ? $post['post_slug'] : ''; + return ($dbSlug === $postSlug); + // ... other cases + } +} +``` + +**Important**: A `.htaccess` file is required for Apache to route all requests to `index.php`. This ensures the PHP-based routing works regardless of permalink settings. + +```apache +# .htaccess - Required for Apache + + RewriteEngine On + RewriteBase / + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule ^(.*)$ index.php [L,QSA] + +``` + +Do NOT add http_response_code() in theme templates - let the Dispatcher handle 404s. + +### Canonical URL Validation + +The Dispatcher validates that the URL slug matches the database slug for posts and pages. This ensures canonical URL enforcement and prevents duplicate content: + +- `/post/2/cicero` → post exists with slug "cicero" → renders post +- `/post/2/ciceros` → post ID 2 exists but slug is "cicero" (not "ciceros") → returns 404 +- `/page/about-us` → page exists with slug "about-us" → renders page +- `/page/about-us-extra` → page slug doesn't match → returns 404 + +This prevents SEO issues from duplicate content when users access pages with incorrect slugs. + +### Tag URLs + +Tags are stored as comma-separated values in `tbl_posts.post_tags` column (e.g., "cicero,lorem ipsum,MariaDB"). The tag system works as follows: + +| Aspect | Details | +|--------|---------| +| **Route Pattern** | `/tag/(?'tag'[\w\- ]+)` - supports spaces and hyphens | +| **URL Encoding** | Spaces encoded as `%20` (e.g., `/tag/lorem%20ipsum`) | +| **URL Decoding** | `RequestPath` class decodes automatically for SEO-friendly; `HandleRequest::isQueryStringRequested()` decodes for query string | +| **Validation** | Dispatcher uses `FrontHelper::simpleSearchingTag()` to verify posts exist | +| **Search** | Uses LIKE query (`%tag%`) to match tags in comma-separated list | + +**SEO-Friendly URL (Enabled)**: +- Pattern: `/tag/your-tag` (supports spaces via URL encoding) +- Parameters extracted via `request_path()` object (tag property) +- Use `is_permalink_enabled()` to check if SEO-friendly URLs are enabled + +**Query String URL (Disabled)**: +- Pattern: `?tag=your-tag` (spaces encoded as %20) +- Parameters extracted via `HandleRequest::isQueryStringRequested()`['value'] +- Use `urldecode()` in HandleRequest to handle URL-encoded values + +**Examples:** +- `/tag/cicero` - shows posts with tag "cicero" (SEO-friendly) +- `/tag/lorem%20ipsum` - shows posts with tag "lorem ipsum" (SEO-friendly) +- `?tag=lorem` - shows posts with tag "lorem" (query string) +- `?tag=lorem%20ipsum` - shows posts with tag "lorem ipsum" (query string) + +**Key Files:** +- `lib/core/Bootstrap.php` - Route pattern definition +- `lib/core/Dispatcher.php` - Tag validation in `validateContentExists()` +- `lib/core/RequestPath.php` - URL decoding for `%20` spaces +- `lib/core/HandleRequest.php` - `isQueryStringRequested()` for query string URLs +- `lib/core/FrontHelper.php` - `simpleSearchingTag()` method +- `lib/utility/permalinks.php` - `is_permalink_enabled()` function +- `lib/model/TagModel.php` - `getPostsPublishedByTag()` method +- `public/themes/blog/tag.php` - Tag archive template + +### Archive URLs + +Archive functionality allows users to browse posts by month/year: + +| Aspect | Details | +|--------|---------| +| **Route Patterns** | `/archive/[0-9]{2}/[0-9]{4}` for monthly archives, `/archives` for index | +| **Archive Index** | Groups archives by year, shows month name and post count | +| **Pagination** | Uses `post_per_archive` setting | +| **Validation** | Dispatcher checks if posts exist in archive before rendering | + +**SEO-Friendly URL (Enabled)**: +- Pattern: `/archive/03/2025` (month/year format) +- Parameters extracted via `request_path()` object (param1 = month, param2 = year) +- Use `is_permalink_enabled()` to check if SEO-friendly URLs are enabled + +**Query String URL (Disabled)**: +- Pattern: `?a=032025` (6-digit format: year + month) +- Parameters extracted via `HandleRequest::isQueryStringRequested()`['value'] +- Use `preg_split("//", ...)` to split the string and extract year (indices 0-3) and month (indices 4-5) + +**Examples:** +- `/archives` - Shows all archive dates grouped by year +- `/archive/03/2025` - Shows posts from March 2025 (SEO-friendly) +- `?a=032025` - Shows posts from March 2025 (query string) + +**Key Files:** +- `lib/core/Bootstrap.php` - Route patterns for `archive` and `archives` +- `lib/core/Dispatcher.php` - Archive validation in `validateContentExists()` +- `lib/model/ArchivesModel.php` - `getPostsByArchive()`, `getArchiveIndex()` +- `lib/model/FrontContentModel.php` - `frontPostsByArchive()`, `frontArchiveIndex()` +- `lib/utility/permalinks.php` - `listen_query_string()` for archive URL generation +- `public/themes/blog/archive.php` - Archive month template +- `public/themes/blog/archives.php` - Archive index template + --- ## 3. Directory Structure ``` -blogware/public_html/ +ScriptLog/public_html/ | |-- index.php # Public front controller |-- config.php # Application configuration | -|-- admin/ # Admin panel +|-- admin/ # Admin panel | |-- index.php # Admin entry point | |-- login.php # Login page | |-- posts.php # Post management | |-- pages.php # Page management | |-- topics.php # Category management | |-- comments.php # Comment management +| |-- reply.php # Reply management | |-- users.php # User management | |-- menu.php # Menu management | |-- templates.php # Theme management | |-- plugins.php # Plugin management | |-- medialib.php # Media library | +-- ui/ # Admin UI components +| +-- comments/ # Comment UI templates +| |-- all-comments.php +| |-- edit-comment.php +| |-- reply.php +| +-- reply-list.php | |-- api/ # RESTful API | +-- index.php # API entry point | -|-- lib/ # Core library +|-- lib/ # Core library | |-- main.php # Application bootstrap | |-- common.php # Constants and functions | |-- options.php # PHP configuration @@ -181,16 +558,16 @@ blogware/public_html/ | +-- core/ # Core classes (80+ files) | |-- Bootstrap.php # Application initialization | |-- Dispatcher.php # URL routing -| |-- DbFactory.php # PDO database connection +| |-- DbFactory.php # PDO database connection | |-- Authentication.php # User authentication | |-- SessionMaker.php # Custom session handler -| |-- View.php # View rendering -| |-- ApiResponse.php # API response handler -| |-- ApiAuth.php # API authentication -| |-- ApiRouter.php # API routing +| |-- View.php # View rendering +| |-- ApiResponse.php # API response handler +| |-- ApiAuth.php # API authentication +| |-- ApiRouter.php # API routing | +-- ... | -| +-- dao/ # Data Access Objects +| +-- dao/ # Data Access Objects | |-- PostDao.php # Posts CRUD | |-- UserDao.php # Users CRUD | |-- CommentDao.php # Comments CRUD @@ -253,9 +630,9 @@ blogware/public_html/ | |-- email-validation.php | +-- ... | -| +-- vendor/ # Composer dependencies +| +-- vendor/ # Composer dependencies | -|-- public/ # Public web root +|-- public/ # Public web root | +-- themes/ # Theme templates | +-- blog/ # Default theme | +-- files/ # Uploaded files @@ -266,8 +643,9 @@ blogware/public_html/ | +-- cache/ # Cache directory | +-- log/ # Log directory | -|-- docs/ # Documentation +|-- docs/ # Documentation | |-- DEVELOPER_GUIDE.md +| |-- TESTING_GUIDE.md | |-- PLUGIN_DEVELOPER_GUIDE.md | |-- API_DOCUMENTATION.md | |-- API_OPENAPI.yaml @@ -304,7 +682,7 @@ $vars = Bootstrap::initialize(APP_ROOT); ### Dispatcher (`lib/core/Dispatcher.php`) -Handles URL routing and dispatches requests to appropriate controllers. +Handles URL routing and dispatches requests to appropriate controllers. Also validates content exists before rendering to handle 404s properly. ```php // Route patterns defined in Bootstrap @@ -312,21 +690,30 @@ $rules = [ 'home' => "/", 'category' => "/category/(?'category'[\w\-]+)", 'archive' => "/archive/[0-9]{2}/[0-9]{4}", + 'archives' => "/archives", 'blog' => "/blog([^/]*)", 'page' => "/page/(?'page'[^/]+)", 'single' => "/post/(?'id'\d+)/(?'post'[\w\-]+)", 'search' => "(?'search'[\w\-]+)", - 'tag' => "/tag/(?'tag'[\w\-]+)" + 'tag' => "/tag/(?'tag'[\w\- ]+)" ]; ``` +#### Content Validation + +The Dispatcher validates content exists in the database before rendering templates to ensure proper 404 handling: + +- Uses named parameters from route patterns (`id`, `page`, `category`) +- Checks database via FrontHelper methods +- Calls `errorNotFound()` before any output if content not found + ### DbFactory (`lib/core/DbFactory.php`) Creates PDO database connections. ```php $dbc = DbFactory::connect([ - 'mysql:host=localhost;port=3306;dbname=blogwaredb', + 'mysql:host=localhost;port=3306;dbname=ScriptLogdb', 'username', 'password' ]); @@ -336,6 +723,47 @@ $dbc = DbFactory::connect([ Handles user authentication, login, logout, and session management. +#### Key Features + +- **Login**: Accepts email or username, validates credentials, creates session +- **Remember Me**: Uses three cookies (scriptlog_auth, scriptlog_validator, scriptlog_selector) with token-based authentication +- **Session Fingerprinting**: Stores IP address and HMAC-hashed user agent for session validation +- **Cookie Encryption**: Uses Defuse/php-encryption for secure cookie storage +- **Access Control**: `userAccessControl()` method implements role-based permissions + +#### Session Data + +When a user logs in, these session variables are set: +- `scriptlog_session_id` - User ID +- `scriptlog_session_email` - User email +- `scriptlog_session_level` - User level (administrator, manager, editor, author, contributor, subscriber) +- `scriptlog_session_login` - Username +- `scriptlog_session_fullname` - Full name +- `scriptlog_session_agent` - User agent fingerprint +- `scriptlog_session_ip` - Client IP address +- `scriptlog_fingerprint` - HMAC-based session fingerprint +- `scriptlog_last_active` - Last activity timestamp + +#### User Levels and Access Control + +| Level | Permissions | +|-------|-------------| +| **administrator** | Full access - PRIVACY, USERS, IMPORT, PLUGINS, THEMES, CONFIGURATION, PAGES, NAVIGATION, TOPICS, COMMENTS, MEDIALIB, REPLY, POSTS, DASHBOARD | +| **manager** | PLUGINS, THEMES, CONFIGURATION, PAGES, NAVIGATION, TOPICS, COMMENTS, MEDIALIB, REPLY, POSTS, DASHBOARD | +| **editor** | TOPICS, COMMENTS, MEDIALIB, REPLY, POSTS, DASHBOARD | +| **author** | COMMENTS, MEDIALIB, REPLY, POSTS, DASHBOARD | +| **contributor** | POSTS, DASHBOARD | +| **subscriber** | DASHBOARD only | + +#### Access Control Implementation + +```php +// In admin pages, check authorization before processing +if (false === $authenticator->userAccessControl(ActionConst::PRIVACY)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); +} +``` + ### SessionMaker (`lib/core/SessionMaker.php`) Custom session handler with secure cookie management. @@ -929,6 +1357,126 @@ Utility functions are loaded via `lib/utility-loader.php` and include: | **Media** | `invoke-frontimg.php`, `upload-video.php` | | **Session** | `turn-on-session.php`, `regenerate-session.php` | +### Image Handling Functions + +The blog includes comprehensive image display functions with WebP support and responsive images. + +#### Image Storage Structure + +``` +public/files/pictures/ +├── small/ # Thumbnail images (640x450) +│ └── small_*.jpg +├── medium/ # Medium images (730x486) +│ └── medium_*.jpg +├── large/ # Large images (1200x630) +│ └── large_*.jpg +├── *.webp # WebP versions (shared with main folder) +└── *.jpg # Original JPEG versions +``` + +#### Key Constants (lib/common.php) + +```php +// Defined in lib/common.php: +define('APP_IMAGE', APP_PUBLIC . DS . 'files' . DS . 'pictures' . DS); +define('APP_IMAGE_LARGE', APP_IMAGE . 'large' . DS); +define('APP_IMAGE_MEDIUM', APP_IMAGE . 'medium' . DS); +define('APP_IMAGE_SMALL', APP_IMAGE . 'small' . DS); +``` + +#### Image Functions + +| Function | Purpose | Location | +|----------|---------|----------| +| `invoke_webp_image()` | Returns WebP URL if available, else returns original | `lib/utility/invoke-webp-image.php` | +| `invoke_frontimg()` | Primary function for displaying featured images | `lib/utility/invoke-frontimg.php` | +| `invoke_responsive_image()` | Generates `` element with WebP support | `lib/utility/invoke-responsive-image.php` | +| `invoke_hero_image()` | Hero/LCP images with fetchpriority="high" | `lib/utility/invoke-responsive-image.php` | +| `invoke_gallery_image()` | Gallery images with lazy loading | `lib/utility/invoke-responsive-image.php` | + +#### Function Signatures + +```php +// Basic featured image +invoke_frontimg(string $media_filename, bool $image_thumb = true): string + +// Responsive image with full options +invoke_responsive_image( + string $media_filename, + string $size = 'thumbnail', // 'thumbnail', 'medium', 'large' + bool $image_thumb = true, + string $alt = '', + string $class = 'img-fluid', + bool $fetchpriority = false, + string $decoding = 'auto' +): string +``` + +#### Image Dimensions + +| Size | Width | Height | Folder | Prefix | +|------|-------|--------|--------|--------| +| thumbnail | 640 | 450 | small/ | small_ | +| medium | 730 | 486 | medium/ | medium_ | +| large | 1200 | 630 | large/ | large_ | + +#### Usage Examples + +```php +// Basic featured image +echo invoke_frontimg('image123.jpg'); + +// Responsive image with specific size +echo invoke_responsive_image('image123.jpg', 'medium', true, 'My Image', 'img-fluid'); + +// Hero image for LCP optimization +echo invoke_hero_image('hero-image.jpg', '', 'Hero Title'); + +// Gallery image with lazy loading +echo invoke_gallery_image('gallery-1.jpg', 'Gallery Image'); +``` + +#### Output Examples + +**With WebP support:** +```html + + + My Image + +``` + +**Without WebP (fallback):** +```html +My Image +``` + +#### Common Issues and Solutions + +**1. esc_attr() Not Defined** +- Symptom: PHP error "Call to undefined function esc_attr()" +- Cause: Using WordPress function in theme files +- Solution: Replace with `htmlout()` + +```php +// WRONG +esc_attr($value); + +// CORRECT +htmlout($value); +``` + +**2. Empty src Attributes** +- Symptom: `` in HTML output +- Cause: Incorrect path construction +- Solution: Always use APP_IMAGE constants or test path construction + +**IMPORTANT:** When modifying image functions: +- Always use APP_IMAGE constants defined in lib/common.php +- Test changes on live site before committing +- Ask permission before changing existing working code + ### Example: Using Utility Functions ```php @@ -943,7 +1491,7 @@ if (!email_validation($email)) { $safeHtml = escape_html($userInput); // Check CSRF token -if (!csrf_defender_verify($token)) { +if (!csrf_check_token($token)) { throw new \Exception("Invalid CSRF token"); } @@ -957,99 +1505,280 @@ $ip = get_ip_address(); ## 12. Theming -### Theme Structure - -``` -public/themes/[theme-name]/ -|-- functions.php # Theme functions and hooks -|-- header.php # Site header -|-- footer.php # Site footer -|-- home.php # Homepage template -|-- single.php # Single post template -|-- page.php # Page template -|-- category.php # Category archive template -|-- archive.php # Archive template -|-- tag.php # Tag archive template -|-- comment.php # Comment form/template -|-- sidebar.php # Sidebar -|-- 404.php # 404 error page -|+-- assets/ # CSS, JS, images -| |-- css/ -| |-- js/ -| +-- img/ -+-- theme.ini # Theme metadata -``` +### Theme Directory Structure -### Theme Functions (functions.php) +The default theme is located at `public/themes/blog/` and contains: -```php - 'Primary Menu', - 'footer' => 'Footer Menu' - ]); -} -add_action('after_setup_theme', 'theme_setup'); +``` +public/themes/blog/ +├── theme.ini # Theme metadata configuration +├── functions.php # Theme functions and template tags +├── header.php # Site header with navigation +├── footer.php # Site footer with scripts and cookie consent +├── home.php # Homepage template +├── single.php # Single post view with comments +├── page.php # Static page template +├── category.php # Category archive template +├── tag.php # Tag archive template +├── archive.php # Monthly archive template +├── archives.php # Archive index (all archives by year) +├── blog.php # Blog listing page +├── sidebar.php # Sidebar with widgets +├── comment.php # Comment form (legacy) +├── privacy.php # Privacy policy page template +├── 404.php # 404 error page +├── cookie-consent.php # GDPR cookie consent banner +├── download.php # Download page template +├── download_file.php # Download file handler +├── render-comments.php # Comments rendering function +├── index.php # Entry point (usually empty) +├── lang/ # Language files +│ └── en.json # English translations (i18n) +└── assets/ # Theme assets + ├── css/ # Stylesheets + ├── js/ # JavaScript files + ├── vendor/ # Third-party libraries + ├── fonts/ # Custom fonts + └── img/ # Images +``` -// Enqueue scripts and styles -function theme_scripts() -{ - wp_enqueue_style('theme-style', get_theme_file_uri('/assets/css/style.css')); - wp_enqueue_script('theme-script', get_theme_file_uri('/assets/js/script.js'), [], '1.0', true); -} -add_action('wp_enqueue_scripts', 'theme_scripts'); +### theme.ini Configuration -// Template functions -function get_post_thumbnail($postId, $size = 'medium') -{ - $mediaDao = new MediaDao(); - $post = $postDao->findPostById($postId); - - if ($post && $post['media_id']) { - return invoke_frontimg($post['media_filename'], $size); - } - - return get_theme_file_uri('/assets/img/default.jpg'); -} +```ini +[info] +theme_name = Bootstrap Blog +theme_designer = Ondrej Svetska +theme_description = Scriptlog default theme +theme_directory = blog ``` -### Theme Template Tags +### Theme Functions (functions.php) -```php -// In template files +The theme provides functions in the following categories: -// Header and footer -call_theme_header(); -call_theme_footer(); +#### i18n Functions -// Post loop -if (have_posts()) { - while (have_posts()) { - the_post(); - - // Display post data - echo get_the_title(); - echo get_the_content(); - echo get_the_date(); - echo get_the_author(); - echo get_the_tags(); - } -} +| Function | Description | +|----------|-------------| +| `t($key, $params)` | Translate a string | +| `locale_url($path, $locale)` | Get URL with locale prefix | +| `get_locale()` | Get current locale | +| `available_locales()` | Get available locales | +| `is_rtl()` | Check if current locale is RTL | +| `get_html_dir()` | Get HTML dir attribute | +| `language_switcher($args)` | Generate language switcher HTML | -// Pagination -front_paginator($wp_query); +#### Model Initialization Functions -// Comments -comments_template(); -``` +| Function | Description | +|----------|-------------| +| `request_path()` | Get request path object | +| `initialize_post()` | Initialize PostModel | +| `initialize_page()` | Initialize PageModel | +| `initialize_comment()` | Initialize CommentModel | +| `initialize_archive()` | Initialize ArchivesModel | +| `initialize_topic()` | Initialize TopicModel | +| `initialize_tag()` | Initialize TagModel | +| `initialize_gallery()` | Initialize GalleryModel | + +#### Post Retrieval Functions + +| Function | Description | +|----------|-------------| +| `featured_post()` | Get random headline posts | +| `get_slideshow($limit)` | Get posts with media for slideshow | +| `sticky_page()` | Get random sticky page | +| `random_posts($start, $end)` | Get random posts | +| `latest_posts($limit, $position)` | Get latest posts | +| `retrieve_blog_posts()` | Get all published blog posts | +| `retrieve_detail_post($id)` | Get single post by ID | +| `posts_by_archive($values)` | Get posts by archive month/year | +| `archive_index()` | Get all archives for index | +| `posts_by_tag($tag)` | Get posts by tag | +| `searching_by_tag($tag)` | Full-text tag search | +| `posts_by_category($topicId)` | Get posts by category | +| `retrieve_page($arg, $rewrite)` | Get page by ID or slug | +| `retrieve_archives()` | Get archives for sidebar | + +#### Navigation and Utility Functions + +| Function | Description | +|----------|-------------| +| `front_navigation($parent, $menu)` | Render navigation menu recursively | +| `total_comment($id)` | Get total approved comments for post | +| `block_csrf()` | Generate CSRF token for comment form | +| `retrieves_topic_simple($id)` | Get topics for a post (simple) | +| `retrieves_topic_prepared($id)` | Get topics for a post (prepared) | +| `sidebar_topics()` | Get topics for sidebar | +| `retrieve_tags()` | Get tags for sidebar | +| `link_tag($id)` | Generate tag links for post | +| `link_topic($id)` | Generate topic links for post | +| `previous_post($id)` | Get previous post link | +| `next_post($id)` | Get next post link | +| `display_galleries($start, $limit)` | Get gallery images | +| `render_comments_section($postId, $offset)` | Render comments section HTML | +| `nothing_found()` | Display "no posts" message | +| `retrieve_site_url()` | Get site URL from config | + +### Theme Header (header.php) + +The header includes: +- HTML doctype with language and direction attributes from i18n +- Meta tags (viewport, charset, SEO via theme_meta()) +- RSS and Atom feed links +- Asset stylesheets (Bootstrap, Font Awesome, custom styles) +- Favicon +- Schema.org markup +- Navigation menu with collapsible mobile support (Sina Nav) + +### Theme Footer (footer.php) + +The footer includes: +- Copyright notice with dynamic year +- Template credits +- JavaScript assets (jQuery, Bootstrap, plugins) +- Cookie consent banner (GDPR) +- RTL script support + +### Supported Features + +| Feature | Implementation | +|---------|---------------| +| **RTL Support** | `is_rtl()` function, rtl.css, rtl.js | +| **Internationalization** | I18nManager class, lang/en.json | +| **Cookie Consent** | GDPR banner with API endpoint | +| **Comments** | AJAX loading, CSRF protection | +| **Download System** | UUID-based secure download links | +| **Archives** | Monthly archives with index | +| **Privacy Policy** | Static page template | +| **Responsive** | Bootstrap 4, mobile navigation | + +### Asset Locations + +| Asset Type | Location | +|------------|----------| +| Main CSS | `assets/css/style.sea.css` | +| Custom CSS | `assets/css/custom.css` | +| Cookie Consent | `assets/css/cookie-consent.css` | +| Comment CSS | `assets/css/comment.css` | +| RTL CSS | `assets/css/rtl.css` | +| 404 CSS | `assets/css/not-found.css` | +| Navigation CSS | `assets/css/sina-nav.css` | +| Front JS | `assets/js/front.js` | +| Comment JS | `assets/js/comment-submission.js`, `assets/js/load-comment.js` | +| Cookie JS | `assets/js/cookie-consent.js` | +| RTL JS | `assets/js/rtl.js` | +| Bootstrap | `assets/vendor/bootstrap/` | +| Font Awesome | `assets/vendor/font-awesome/` | +| jQuery | `assets/vendor/jquery/` | +| Fancybox | `assets/vendor/@fancyapps/fancybox/` | +| Popper.js | `assets/vendor/popper.js/` | + +### Theme Template Files + +#### home.php + +The homepage template includes: +- Hero section with featured post background +- Intro section with sticky page content +- Plugin invocation for "Hello World" plugin +- Random posts section (alternating left/right layout) +- Divider section with featured content background +- Latest posts grid (3 columns) +- Gallery section with Fancybox lightbox + +#### single.php + +Single post template displays: +- Featured image +- Post title with permalink +- Author, date, and comment count metadata +- Post content with htmLawed HTML filtering +- Post tags +- Previous/next post navigation +- Comments section (AJAX-loaded) +- Comment form with CSRF protection + +#### page.php + +Static page template includes: +- Featured image +- Page title with permalink +- Author and date metadata +- Page content with HTML filtering +- Tags display + +#### category.php, tag.php, archive.php, archives.php, blog.php + +Archive templates share common structure: +- Topic/tag/archive header +- Post grid layout (2 columns) +- Post metadata (thumbnail, title, excerpt, author, date, comments) +- Sidebar inclusion +- Pagination + +#### sidebar.php + +Sidebar widgets: +- Search form +- Latest posts (5 posts with thumbnails) +- Categories list with post counts +- Archives list with post counts +- Tags cloud + +#### 404.php + +Simple 404 error page with: +- 404 display +- "Page not found" message +- Back to home link + +#### privacy.php + +Static privacy policy page with: +- Privacy policy content +- Last updated date +- Contact information +- Back to home button + +#### cookie-consent.php + +GDPR cookie consent banner with: +- Privacy notice text +- Accept/Reject/Learn More buttons +- Privacy policy link +- API endpoint for consent management + +#### download.php, download_file.php + +Download page templates: +- File information display +- Download button with UUID-based URL +- Copy link functionality +- Expiration countdown +- Optional support URL + +### Creating Custom Themes + +1. Create directory: `public/themes/[theme-name]/` +2. Copy required templates from blog theme: + - `theme.ini` - Theme metadata + - `functions.php` - Theme functions + - `header.php` - Site header + - `footer.php` - Site footer + - `home.php` - Homepage + - `single.php` - Post view + - `page.php` - Page view + - `category.php` - Category archive + - `tag.php` - Tag archive + - `archive.php` - Monthly archive + - `archives.php` - Archive index + - `blog.php` - Blog listing + - `sidebar.php` - Sidebar + - `404.php` - Error page +3. Create `theme.ini` with metadata +4. Add assets to `assets/` subdirectory +5. Register theme in admin panel (admin/templates.php) > **TIP:** Use `public/themes/blog/` as a reference theme for creating new themes. @@ -1219,12 +1948,12 @@ Available in `lib/utility/plugin-validator.php`: ### RESTful API Overview -Blogware provides a RESTful API that allows external applications to interact with blog content. The API follows OpenAPI 3.0 specification and returns JSON responses. +ScriptLog provides a RESTful API that allows external applications to interact with blog content. The API follows OpenAPI 3.0 specification and returns JSON responses. | Environment | URL | |-------------|-----| -| **Production** | `http://blogware.site/api/v1` | -| **Development** | `http://localhost/blogware/public_html/api/v1` | +| **Production** | `http://ScriptLog.site/api/v1` | +| **Development** | `http://localhost/ScriptLog/public_html/api/v1` | > **NOTE:** The complete OpenAPI 3.0 specification is available at `/docs/API_OPENAPI.json` and `/docs/API_OPENAPI.yaml`. @@ -1236,7 +1965,7 @@ The API supports two authentication methods: ``` GET /api/v1/posts HTTP/1.1 -Host: blogware.site +Host: ScriptLog.site X-API-Key: your-api-key-here ``` @@ -1244,7 +1973,7 @@ X-API-Key: your-api-key-here ``` GET /api/v1/posts HTTP/1.1 -Host: blogware.site +Host: ScriptLog.site Authorization: Bearer your-token-here ``` @@ -1457,38 +2186,149 @@ $router->delete('resources/([0-9]+)', 'MyResourceApiController@destroy'); ## 15. Testing -### Test Suite Overview +> **NOTE:** For comprehensive testing documentation including PHPStan setup and CI/CD integration, see [TESTING_GUIDE.md](TESTING_GUIDE.md). + +### Testing Overview + +This project uses two complementary testing approaches: + +| Tool | Purpose | Coverage | +|------|---------|----------| +| **PHPUnit** | Unit and integration testing | Functional correctness | +| **PHPStan** | Static code analysis | Type safety, code quality | + +### Test Suite Metrics | Metric | Value | |--------|-------| -| **Total Tests** | 246 | -| **Assertions** | 290 | +| **Total Tests** | 868 | +| **Assertions** | ~1000+ | | **PHPUnit Version** | 9.6.34 | +| **Target Coverage** | 40% | +| **Completed Tests** | 407+ | + +### Test Coverage Plan + +The test coverage plan is organized into phases: + +#### Phase Status + +| Phase | Priority | Status | Tests | +|-------|----------|--------|-------| +| Phase 1: DAO Integration | HIGH | ✅ Complete | 92 | +| Phase 2: Service Layer | HIGH | ✅ Complete | 148 | +| Phase 3: Core Classes | MEDIUM | 🔄 Pending | 65 | +| Phase 4: Controllers | MEDIUM | 🔄 Pending | 34 | +| Phase 5: Utilities | LOW | ✅ Complete | 68 | + +### Test Categories + +| Category | Description | +|----------|-------------| +| **Unit Tests** | Utility function tests, class existence tests | +| **Integration Tests** | Database CRUD operations using `blogware_test` database | + +### Security Testing + +PostDao security tests verify critical security features: + +| Test | Purpose | +|------|---------| +| `testFindPostsHasOnlyPublishedParameter` | Verifies default filters for published posts only | +| `testFindPostHasOnlyPublishedParameter` | Verifies single post retrieval filters for published posts | +| `testFindPostsHasAuthorParameter` | Verifies author filtering support | +| `testFindPostsHasSanitizedOrderBy` | Verifies ORDER BY uses whitelist to prevent SQL injection | +| `testFindPostsFiltersByStatusAndVisibility` | Verifies post_status and post_visibility filters | +| `testFindPostFiltersByStatusAndVisibility` | Verifies single post respects status/visibility | + +**Location**: `tests/unit/PostDaoSecurityTest.php` ### Running Tests +#### PHPUnit Commands + ```bash # Run all tests -vendor/bin/phpunit +lib/vendor/bin/phpunit # Run with coverage (requires Xdebug) -vendor/bin/phpunit --coverage-html coverage +lib/vendor/bin/phpunit --coverage-html coverage # Run specific test file -vendor/bin/phpunit tests/EmailValidationTest.php +lib/vendor/bin/phpunit tests/EmailValidationTest.php # Run tests matching pattern -vendor/bin/phpunit --filter "EmailValidation" +lib/vendor/bin/phpunit --filter "EmailValidation" ``` -### Test Categories +#### PHPStan Commands -| Category | Description | -|----------|-------------| -| **Unit Tests** | Utility function tests, class existence tests | -| **Integration Tests** | Database CRUD operations using `blogware_test` database | +```bash +# Run static analysis +lib/vendor/bin/phpstan analyse + +# Run with specific config +lib/vendor/bin/phpstan analyse --configuration=phpstan.neon + +# Run with memory limit (recommended) +lib/vendor/bin/phpstan analyse --memory-limit=1G + +# Generate/update baseline +lib/vendor/bin/phpstan analyse --generate-baseline=phpstan.baseline.neon + +# Increase analysis level for stricter checks +lib/vendor/bin/phpstan analyse -l 5 +``` + +### Static Analysis with PHPStan + +PHPStan is a static analysis tool that finds bugs in your code without running it. + +#### Configuration Files + +| File | Purpose | +|------|---------| +| `phpstan.neon` | Main configuration | +| `phpstan.baseline.neon` | Baseline of known issues to ignore | + +#### PHPStan Configuration + +```neon +includes: + - phpstan.baseline.neon + +parameters: + phpVersion: 70400 + paths: + - lib/ + - index.php + excludePaths: + - lib/vendor/ + - lib/core/HTMLPurifier/ + level: 0 +``` + +#### Key Settings + +- **phpVersion**: Set to `70400` for PHP 7.4 compatibility +- **level**: Currently at level 0 (most lenient). Increase gradually for stricter checks +- **excludePaths**: Excludes vendor and third-party code + +### Test Database Setup + +Tests use a separate database (`blogware_test`) to avoid affecting production data. + +```bash +# Create test database +php tests/setup_test_db.php + +# Or manually +mysql -u root -p -e "CREATE DATABASE blogware_test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" +``` -#### Writing Tests +### Writing Tests + +#### PHPUnit Test Structure ```php userAccessControl(ActionConst::PRIVACY)) { + direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403); +} +``` + +Available permissions: +- `ActionConst::PRIVACY` - Privacy settings, GDPR data requests, audit logs. +- `ActionConst::USERS` - User management and profile deletion. + +### Database Tables + +The GDPR system relies on three core tables for consent, requests, and auditing: + +**1. tbl_consents** - Stores user choices for cookies and tracking. +```sql +CREATE TABLE tbl_consents ( + ID BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + consent_type VARCHAR(50) NOT NULL, + consent_status ENUM('accepted','rejected') NOT NULL, + consent_ip VARCHAR(45) NOT NULL, + consent_user_agent VARCHAR(255) DEFAULT NULL, + consent_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (ID) +); +``` + +**2. tbl_data_requests** - Tracks data export and deletion requests. +```sql +CREATE TABLE tbl_data_requests ( + ID BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + request_type VARCHAR(50) NOT NULL, + request_email VARCHAR(100) NOT NULL, + request_status ENUM('pending','processing','completed','rejected') DEFAULT 'pending', + request_ip VARCHAR(45) NOT NULL, + request_note TEXT DEFAULT NULL, + request_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + request_completed_date DATETIME DEFAULT NULL, + PRIMARY KEY (ID) +); +``` + +**3. tbl_privacy_logs** - Automated audit trail for all privacy-related actions. +```sql +CREATE TABLE tbl_privacy_logs ( + ID BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + log_action VARCHAR(50) NOT NULL, + log_type VARCHAR(50) NOT NULL, + log_user_id BIGINT(20) UNSIGNED DEFAULT NULL, + log_email VARCHAR(100) DEFAULT NULL, + log_details TEXT DEFAULT NULL, + log_ip VARCHAR(45) NOT NULL, + log_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (ID) +); +``` + +### Core Components + +| Component | Location | Purpose | +|-----------|----------|---------| +| `ConsentService` | `lib/service/ConsentService.php` | Manages user consent records. | +| `DataRequestService` | `lib/service/DataRequestService.php` | Handles data exports and anonymization logic. | +| `NotificationService` | `lib/service/NotificationService.php` | Orchestrates automated compliance emails. | +| `PrivacyLogDao` | `lib/dao/PrivacyLogDao.php` | Records audit trails for privacy actions. | + +### Data Subject Requests + +#### 1. Data Export +Administrators can process export requests via `DataRequestService::exportUserData()`. This method: +- Aggregates user profile data, comments, posts, and activity logs. +- Generates a structured JSON file for the user. +- Logs the export event to the privacy audit trail. + +#### 2. Data Deletion & Anonymization +To respect the "Right to be Forgotten," ScriptLog uses an anonymization approach rather than hard deletion to preserve database integrity: +- **Comments**: Name, email, and IP are anonymized. +- **Posts**: Reassigned to the primary administrator (ID: 1). +- **Profile**: Email is changed to a unique placeholder (`deleted_ID@user.local`). +- **Automation**: Managed via `UserService::removeUserWithAnonymization()`. + +### Automated Email Notifications + +The system sends automated notifications during the compliance lifecycle: +- **Confirmation**: Sent to the user when a request is received. +- **Admin Alert**: Notifies administrators of new pending requests. +- **Completion**: Sent when data has been exported or anonymized. +- **Transport**: Powered by the **Dynamic SMTP System** using Symfony Mailer. + +### Cookie Consent Banner + +The frontend provides a standard consent interface: +- **Banner**: `public/themes/blog/cookie-consent.php`. +- **Logic**: `public/themes/blog/assets/js/cookie-consent.js`. +- **Persistence**: Choices are stored in both cookies (frontend) and `tbl_consents` (backend). + +### GDPR API Endpoints + +| Method | Endpoint | Description | +|--------|----------|-------------| +| `POST` | `/api/v1/gdpr/consent` | Record user consent choice. | +| `GET` | `/api/v1/gdpr/consent` | Retrieve current consent status. | + +### Implementation Workflow + +To add new compliance features: +1. **Define Table**: Add to `install/include/dbtable.php`. +2. **Service Logic**: Implement in `lib/service/`. +3. **Audit Trail**: Call `PrivacyLogDao::createLog()` for every sensitive action. +4. **Notification**: Use `NotificationService` to inform users of the action. +5. **UI**: Add management forms to `admin/ui/privacy/`. + +### Testing Compliance + +```bash +# Verify privacy page accessibility +curl -I https://example.com/privacy + +# Test automated logging +# Perform a data export in Admin UI and check tbl_privacy_logs +``` + +--- + +## 19. Internationalization (i18n) + +### Overview + +ScriptLog includes a comprehensive i18n system for multi-language support, including: +- Language detection from browser, URL, or user preference +- Database-driven translation management +- RTL (Right-to-Left) language support +- Translation caching for performance +- RESTful API for managing languages and translations + +### Architecture + +``` ++---------------------------------------------------------------+ +| i18n REQUEST FLOW | ++---------------------------------------------------------------+ +| | +| Request | +| | | +| v | +| +---------------------+ | +| | LocaleDetector | Detect locale from: | +| | | - URL prefix (/ar/, /es/) | +| +----------+----------+ - Cookie (lang) | +| | - Accept-Language header | +| | - Default (en_US) | +| v | +| +---------------------+ | +| | I18nManager | Load translations & manage locale | +| +----------+----------+ | +| | | +| v | +| +---------------------+ | +| | TranslationLoader | Load from: | +| +----------+----------+ - Database (tbl_translations) | +| | - Cache file | +| v | +| +---------------------+ | +| | View/Theme | Output with lang/dir attributes | +| +---------------------+ | +| | ++---------------------------------------------------------------+ +``` + +### Core Components + +| Component | Location | Purpose | +|-----------|----------|---------| +| `I18nManager` | `lib/core/I18nManager.php` | Main i18n orchestrator | +| `LocaleDetector` | `lib/core/LocaleDetector.php` | Language detection | +| `LocaleRouter` | `lib/core/LocaleRouter.php` | URL-based routing | +| `TranslationLoader` | `lib/core/TranslationLoader.php` | Translation loading/caching | +| `LanguageDao` | `lib/dao/LanguageDao.php` | Language CRUD | +| `TranslationDao` | `lib/dao/TranslationDao.php` | Translation CRUD | +| `LanguageService` | `lib/service/LanguageService.php` | Language business logic | +| `TranslationService` | `lib/service/TranslationService.php` | Translation business logic | + +### Database Tables + +**tbl_languages** - Supported languages + +```sql +CREATE TABLE IF NOT EXISTS tbl_languages ( + ID BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + locale VARCHAR(10) NOT NULL UNIQUE, + language_name VARCHAR(100) NOT NULL, + native_name VARCHAR(100) NOT NULL, + is_rtl TINYINT(1) NOT NULL DEFAULT 0, + is_active TINYINT(1) NOT NULL DEFAULT 1, + is_default TINYINT(1) NOT NULL DEFAULT 0, + sort_order INT NOT NULL DEFAULT 0, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (ID), + KEY locale(locale), + KEY is_active(is_active) +) Engine=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +**tbl_translations** - Translation strings + +```sql +CREATE TABLE IF NOT EXISTS tbl_translations ( + ID BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + locale VARCHAR(10) NOT NULL, + translation_key VARCHAR(255) NOT NULL, + translation_value TEXT NOT NULL, + context VARCHAR(100) DEFAULT NULL, + is_active TINYINT(1) NOT NULL DEFAULT 1, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (ID), + UNIQUE KEY unique_key_locale(locale, translation_key), + KEY locale(locale), + KEY translation_key(translation_key) +) Engine=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +### Language Detection Priority + +1. **URL Prefix** - `/ar/`, `/es/`, `/fr/` (e.g., `example.com/ar/posts`) +2. **Cookie** - `lang` cookie set by language switcher +3. **Accept-Language Header** - Browser's language preference +4. **Default** - `en_US` (configurable) + +### URL Routing for Languages + +Languages are handled via URL prefixes in the existing routing system: + +```php +// lib/core/Bootstrap.php +$rules = [ + // ... existing rules + 'language_blog' => "/{lang}/blog", + 'language_single' => "/{lang}/post/(?'id'\d+)/(?'post'[\w\-]+)", + 'language_page' => "/{lang}/page/(?'page'[^/]+)", + 'language_category' => "/{lang}/category/(?'category'[\w\-]+)", + 'language_tag' => "/{lang}/tag/(?'tag'[\w\-]+)", +]; +``` + +### Translation Functions + +```php +// Basic translation +__('Hello World'); // Returns translated string +__('Welcome, %s', [$name]); // With placeholders + +// Echo translation +_e('Submit'); // Echoes translated string + +// With context +_x('Read', 'verb'); // Context disambiguates same key +_ex('Read', 'book title'); // Echo with context + +// Plural forms +_n('%d comment', '%d comments', $count); // Returns correct form +``` + +### RTL Support + +RTL languages (Arabic, Hebrew, Farsi, etc.) are automatically detected and styled: + +```php +// Automatic detection based on language +$isRtl = $i18nManager->isRtl(); // true for ar, he, fa, etc. + +// Theme files include RTL CSS +// public/themes/blog/assets/css/rtl.css +// public/themes/blog/assets/js/rtl.js +``` + +### i18n API Endpoints + +| Method | Endpoint | Auth | Description | +|--------|----------|------|-------------| +| `GET` | `/api/v1/languages` | No | List all languages | +| `GET` | `/api/v1/languages/active` | No | List active languages | +| `GET` | `/api/v1/languages/{locale}` | No | Get language details | +| `GET` | `/api/v1/translations` | No | Get translations for locale | +| `POST` | `/api/v1/languages` | Yes | Create language | +| `PUT` | `/api/v1/languages/{locale}` | Yes | Update language | +| `POST` | `/api/v1/translations` | Yes | Create translation | +| `PUT` | `/api/v1/translations/{key}` | Yes | Update translation | + +### Creating i18n Features + +1. **Add Language**: Use API or admin panel +2. **Add Translations**: Insert into `tbl_translations` with locale and key +3. **Use in Code**: Call translation functions +4. **Theme Support**: Ensure templates use translation functions + +### Translation Caching + +Translations are cached for performance: + +- **Cache Location**: `public/files/cache/translations/` +- **Cache Format**: `translations_{locale}.json` +- **Cache Invalidation**: On translation update via API + +### Adding New Translatable Content + +When adding new features that need translation: + +1. Use translation functions in templates: +```php +

+``` + +2. Add translations via API: +```bash +curl -X POST https://example.com/api/v1/translations \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer {token}" \ + -d '{"locale": "es", "key": "welcome_message", "value": "Bienvenido"}' +``` + +### Testing i18n + +```bash +# Test language detection +curl -H "Accept-Language: es" http://example.com/ + +# Test translation API +curl http://example.com/api/v1/translations?locale=es + +# Test RTL rendering +curl http://example.com/ar/ | grep 'dir="rtl"' +``` + +### Admin Panel Translations + +Admin panel uses a **hybrid translation system** via `lib/utility/admin-translations.php`: + +``` +Translation Request Flow: + admin_translate('key') + → Check database (tbl_translations) first + → If found, return database value + → If not found, check hardcoded arrays + → Return fallback or key +``` + +```php +// Usage in admin views +admin_translate('nav.dashboard'); // "Dashboard" +admin_translate('form.save'); // "Save" +admin_translate('status.publish'); // "Published" + +// With parameter interpolation +admin_t('welcome_message', ['name' => 'John']); // "Welcome, John" + +// Locale management +admin_get_locale(); // Get current locale +admin_set_locale('ar'); // Set locale +admin_is_rtl(); // Check RTL (true for Arabic) +``` + +**Key format**: Dot-notation with underscore separators (e.g., `nav.dashboard`, `form.save`, `status.publish`) + +The hybrid approach allows translations to be: +1. Managed via admin UI (Settings → Translations) +2. Stored in database for easy editing +3. Fallback to hardcoded arrays if not in database + +### Translation Editor + +The admin panel includes a translation editor at **Settings → Translations**: + +- **View**: Table listing all translations with filtering +- **Add New**: Add new translation keys via modal form +- **Edit**: Modify existing translations via modal form +- **Delete**: Remove translations (POST with CSRF protection) +- **Export**: Download translations as JSON +- **Import**: Upload translations from JSON +- **Cache**: Regenerate translation cache +- **Language Selector**: Switch between languages or view all + +### Common Issues and Fixes + +#### 1. Database Connection Charset (CRITICAL) + +The PDO database connection MUST use `charset=utf8mb4` in the DSN to properly load translations in non-English languages (Chinese, Arabic, etc.). + +**Files to check:** +- `lib/core/Bootstrap.php` - Database DSN configuration +- `lib/core/Db.php` - PDO connection options + +**Correct DSN format:** +```php +$dbc = DbFactory::connect([ + 'mysql:host=' . $host . ';port=' . $port . ';dbname=' . $dbname . ';charset=utf8mb4', + $user, + $pwd +]); +``` + +**WRONG (will show "???" for Chinese/Arabic):** +```php +'mysql:host=...;dbname=...' +``` + +#### 2. Translation Value Standards + +**Human-readable first**: Translation values should be natural, complete phrases in the target language, not abbreviations or technical terms. + +``` +✅ Good: "Choose your language", "Add New", "All Posts", "Error Server Error" +❌ Bad: "Language Settings", "addNew", "allPosts", "Error serverError" +``` + +**Example** - `nav.language_settings`: +| Language | Value | +|----------|-------| +| en | Choose your language | +| ar | اختر لغتك | +| zh | 选择您的语言 | +| fr | Choisissez votre langue | +| ru | Выберите язык | +| es | Elige tu idioma | +| id | Pilih bahasa Anda | + +When updating translations in the database, always clear the cache: + +```php +// Clear translation cache after database updates +$cacheFile = 'public/files/cache/translations/' . $locale . '.json'; +@unlink($cacheFile); +// System will regenerate on next request +``` + +#### 3. Translation Database Fixes + +When translations in the database show incorrect values (like "Nav addNew" instead of actual translations), fix directly via SQL: + +**Check broken translations:** +```sql +SELECT * FROM tbl_translations +WHERE translation_value LIKE 'Nav %' +``` + +#### 4. Language Selector Not Working + +The Translation Editor language dropdown must work with the session-based locale system: + +**Flow:** +1. User selects language in dropdown → JavaScript redirects with `?switch-lang=id` +2. `admin/index.php` processes `switch-lang` parameter → calls `admin_set_locale('id')` +3. `admin_set_locale()` saves to `$_SESSION['admin_locale']` and cookie +4. Translation Editor uses `admin_get_locale()` to determine which translations to show + +**Key files:** +- `admin/index.php` - Handles `switch-lang` parameter +- `lib/utility/admin-translations.php` - `admin_get_locale()` and `admin_set_locale()` functions +- `lib/controller/TranslationController.php` - Uses `admin_get_locale()` when `$_GET['lang']` not set + +**TranslationController locale logic (CORRECT):** +```php +if (isset($_GET['lang']) && $_GET['lang'] === 'all') { + $langCode = 'all'; +} elseif (isset($_GET['lang']) && in_array($_GET['lang'], ['en', 'ar', 'zh', 'fr', 'ru', 'es', 'id'])) { + $langCode = $_GET['lang']; +} else { + // Fall back to session/cookie locale + $langCode = admin_get_locale(); +} +``` + +#### 5. Translation Editor URL Parameters + +The Translation Editor uses these URL parameters: +- `?load=translations` - Main page +- `?load=translations&lang=en` - Show English translations +- `?load=translations&lang=id` - Show Indonesian translations +- `?load=translations&lang=all` - Show all languages (with pagination) +- `?load=translations&action=update` - Update translation (POST) +- `?load=translations&action=new-translation` - Create translation (POST) + +### Adding Content i18n Support + +To add locale support to a new content type: + +1. **Database**: Add `content_locale` column to table +2. **Dao**: Add `dropDownLocale()` method +3. **Service**: Add `setContentLocale()` method +4. **Controller**: Add locale filters and setters +5. **Admin UI**: Add locale dropdown to edit form + +### Populating Languages and Translations + +The system includes: +- 7 languages (en, ar, zh, fr, ru, es, id) +- 111 translation keys with 819 total translations +- Translation editor in admin panel (Settings → Translations) +- Translation cache in `public/files/cache/translations/` + +Use the admin panel (Settings → Languages and Settings → Translations) to manage languages and translations. + +### Configuration + +Default language settings are in `lib/core/I18nManager.php`: + +```php +private $defaultLocale = 'en_US'; +private $supportedLocales = ['en_US', 'ar', 'es', 'fr', 'de', 'zh_CN']; +``` + +### Documentation + +For comprehensive API documentation and testing, see: +- `docs/I18N_ARCHITECTURE.md` - Full architecture documentation +- `docs/I18N_API.md` - API reference +- `docs/I18N_TESTING_GUIDE.md` - Testing guide + +--- + +1. Fork the repository +2. Create a feature branch (`git checkout -b feature/amazing-feature`) +3. Commit your changes (`git commit -m 'Add amazing feature'`) +4. Push to the branch (`git push origin feature/amazing-feature`) 5. Open a Pull Request --- +## 20. Comment-Reply System + +### Overview + +ScriptLog includes a complete comment-reply system that allows threaded discussions on blog posts. Replies are stored in the same `tbl_comments` table using a self-referential `comment_parent_id` field. + +### Architecture + +``` +Comments (comment_parent_id = 0) + └── Reply 1 (comment_parent_id = parent_comment_id) + └── Reply 2 (comment_parent_id = parent_comment_id) +``` + +### Database Schema + +The reply system uses the existing `tbl_comments` table structure: + +| Field | Type | Description | +|-------|------|-------------| +| `ID` | BIGINT | Primary key | +| `comment_post_id` | BIGINT | FK to tbl_posts | +| `comment_parent_id` | BIGINT | Parent comment ID (0 for top-level comments) | +| `comment_author_name` | VARCHAR(60) | Author's name | +| `comment_author_ip` | VARCHAR(100) | Author's IP address | +| `comment_author_email` | VARCHAR(100) | Author's email | +| `comment_content` | text | Comment/reply content | +| `comment_status` | VARCHAR(20) | Status: approved, pending, spam, draft | +| `comment_date` | datetime | Creation timestamp | + +### Core Components + +| Component | Location | Purpose | +|----------|----------|---------| +| `ReplyDao` | `lib/dao/ReplyDao.php` | Reply CRUD operations | +| `ReplyService` | `lib/service/ReplyService.php` | Business logic for replies | +| `ReplyController` | `lib/controller/ReplyController.php` | HTTP request handling | +| `CommentDao` | `lib/dao/CommentDao.php` | Comment operations (includes `countReplies()`) | +| `CommentService` | `lib/service/CommentService.php` | Comment business logic | + +### Admin Panel Routing + +| Action | URL | Description | +|--------|-----|-------------| +| **List Comments** | `?load=comments` | View all comments | +| **Edit Comment** | `?load=comments&action=editComment&Id={id}` | Edit a comment | +| **Reply to Comment** | `?load=reply&action=reply&Id={parent_id}` | Create new reply | +| **Edit Reply** | `?load=reply&action=editReply&Id={reply_id}` | Edit existing reply | +| **Delete Reply** | `?load=reply&action=deleteReply&Id={reply_id}` | Delete reply | +| **Delete Comment** | `?load=comments&action=deleteComment&Id={id}` | Delete comment (also deletes replies) | + +### Whitelisting Routes + +To add a new admin route, update `lib/utility/admin-query.php`: + +```php +function admin_query() +{ + return array( + // ... existing routes ... + 'comments' => 'comments.php', + 'reply' => 'reply.php', // Add this line + // ... other routes ... + ); +} +``` + +### Action Constants + +Defined in `lib/core/ActionConst.php`: + +```php +// Comment constants +const COMMENTS = "comments"; +const EDITCOMMENT = "editComment"; +const DELETECOMMENT = "deleteComment"; + +// Reply constants +const REPLY = "reply"; +const EDITREPLY = "editReply"; +const DELETEREPLY = "deleteReply"; +``` + +### Access Control + +Reply functionality requires `ActionConst::REPLY` permission, available to: +- **administrator** - Full access +- **manager** - Full access +- **editor** - Full access +- **author** - Full access + +### ReplyDao Methods + +```php +class ReplyDao extends Dao +{ + // Create a new reply + public function createReply($bind); + + // Find all replies for a parent comment + public function findReplies($commentId, $orderBy = 'ID'); + + // Find a single reply by ID + public function findReply($id, $sanitize); + + // Update reply + public function updateReply($sanitize, $bind, $ID); + + // Delete reply + public function deleteReply($id, $sanitize); + + // Check if reply exists + public function checkReplyId($id, $sanitize); + + // Get parent comment info + public function getParentComment($parentId, $sanitize); + + // Count total replies + public function totalReplyRecords($data = null, $parentId = null); + + // Generate status dropdown + public function dropDownReplyStatement($selected = ''); +} +``` + +### ReplyService Methods + +```php +class ReplyService +{ + // Setters + public function setReplyId($reply_id); + public function setPostId($post_id); + public function setParentId($parent_id); + public function setAuthorName($author_name); + public function setAuthorIP($author_ip); + public function setAuthorEmail($author_email); + public function setReplyContent($content); + public function setReplyStatus($status); + + // Getters/Operations + public function grabReplies($parentId, $orderBy = 'ID'); + public function grabReply($id); + public function grabParentComment($parentId); + public function addReply(); + public function modifyReply(); + public function removeReply(); + public function checkReplyExists($id); + public function totalReplies($data = null, $parentId = null); +} +``` + +### ReplyController Methods + +```php +class ReplyController extends BaseApp +{ + // List all replies for a comment + public function listItems($parentId = null); + + // Create new reply (handles both GET for form and POST for submission) + public function insert(); + + // Update existing reply + public function update($id); + + // Delete reply + public function remove($id); +} +``` + +### Admin Page Implementation + +#### admin/reply.php Routing + +```php +userAccessControl(ActionConst::REPLY)) { + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $replyController->insert(); + } else { + $replyController->insert(); + } + } + break; + + case ActionConst::EDITREPLY: + // Edit existing reply + if ($authenticator->userAccessControl(ActionConst::REPLY)) { + $replyController->update($replyId); + } + break; + + case ActionConst::DELETEREPLY: + // Delete reply + if ($authenticator->userAccessControl(ActionConst::REPLY)) { + $replyController->remove($replyId); + } + break; + } +} catch (Throwable $th) { + LogError::exceptionHandler($th); +} +``` + +### Frontend Comment Submission + +Visitors can submit comments and replies via `comments-post.php`: + +```php +// From public/themes/blog/single.php + + + + + + + + +``` + +### Viewing Replies in Admin + +#### Comments List (all-comments.php) + +Shows reply counts per comment: + +```php +$replyCount = $commentService->countReplies($comment['ID']); +if ($replyCount > 0) { + echo '' . $replyCount . ' replies'; +} +``` + +#### Reply Form (reply.php) + +Form for creating/editing replies: + +```php +
+ + + + + +
+``` + +### Deleting Comments with Replies + +When deleting a parent comment, consider whether to: +1. Delete all child replies (cascade delete) +2. Keep replies and reassign to a system account + +Current implementation: Manual deletion required for each reply. + +### Testing the Reply System + +```bash +# Test comment listing with reply counts +curl http://example.com/admin/index.php?load=comments + +# Test reply form display +curl http://example.com/admin/index.php?load=reply&action=reply&Id=5 + +# Test reply submission (requires authentication) +curl -X POST http://example.com/admin/index.php \ + -d "load=reply&action=reply&Id=5" \ + -d "author_name=Test&reply_content=Test+reply&reply_status=pending&replyFormSubmit=1" +``` + +--- + +## 21. Content Import System + +### Overview + +ScriptLog includes a robust content import system that supports migrating data from WordPress (WXR), Ghost (JSON), Blogspot/Blogger (XML), and ScriptLog's native JSON format. The native format allows migration between ScriptLog installations, preserving menus, settings, and content relationships. + +### Architecture + +The import system follows the project's standard layered pattern: + +1. **UI Layer**: `admin/ui/import/index.php` (upload form) and `preview.php` (data verification). +2. **Controller Layer**: `ImportController` handles requests, CSRF validation, and user assignment. +3. **Service Layer**: `MigrationService` coordinates the import process and handles database interactions via `dbc`. +4. **Utility Layer**: Specific importer classes (`WordPressImporter`, `GhostImporter`, `BlogspotImporter`, `ScriptlogImporter`) handle file parsing. + +### Core Components + +| Component | Location | Purpose | +| :--- | :--- | :--- | +| `ImportController` | `lib/controller/ImportController.php` | Request handling and CSRF protection | +| `MigrationService` | `lib/service/MigrationService.php` | Main import logic and DB operations | +| `WordPressImporter` | `lib/utility/import-wordpress.php` | WXR (XML) parser | +| `GhostImporter` | `lib/utility/import-ghost.php` | Ghost JSON parser | +| `BlogspotImporter` | `lib/utility/import-blogspot.php` | Blogger XML parser | +| `ScriptlogImporter` | `lib/utility/import-scriptlog.php` | Native JSON parser | +| `ImportException` | `lib/core/ImportException.php` | Specialized import error handling | + +### Import Workflow + +1. **Upload**: User selects source platform and uploads export file. +2. **Preview**: `MigrationService::previewImport()` parses the file and returns a summary and sample data. +3. **Import**: + * Categories are created or mapped if they already exist. + * Posts/Pages are created with unique slugs. + * Comments are imported and linked to their respective posts. + * Content is assigned to the selected author. + +### Security and Validation + +* **CSRF Protection**: All import actions require a valid security token. +* **Access Control**: Only users with `administrator` level can access the import feature. +* **Sanitization**: Imported HTML is purified using `purify_dirty_html()` and input is sanitized via `prevent_injection()`. +* **Duplicate Prevention**: Existing posts with the same slug are skipped or renamed to ensure uniqueness. + +### Adding New Importers + +To add support for a new platform: + +1. Create a new importer class in `lib/utility/` (e.g., `MediumImporter.php`). +2. Run `php generate-utility-list.php` to register the new utility. +3. Update `MigrationService.php` to include the new source constant and handle the new importer. +4. Update the UI in `admin/ui/import/index.php` to add the new option. + +--- + +## 22. Content Export System + +### Overview + +ScriptLog includes a content export system that supports exporting data to WordPress (WXR), Ghost (JSON), Blogspot/Blogger (XML), and ScriptLog's native JSON format. The native format preserves menus, settings, and content relationships for seamless migration between installations. + +### Architecture + +The export system follows the project's standard layered pattern: + +1. **UI Layer**: `admin/ui/export/index.php` (format selection form). +2. **Controller Layer**: `ExportController` handles requests and format selection. +3. **Service Layer**: `ExportService` coordinates the export process and data retrieval. +4. **Utility Layer**: Specific exporter classes (`WordPressExporter`, `GhostExporter`, `BlogspotExporter`, `ScriptlogExporter`) handle format generation. + +### Core Components + +| Component | Location | Purpose | +| :--- | :--- | :--- | +| `ExportController` | `lib/controller/ExportController.php` | Request handling | +| `ExportService` | `lib/service/ExportService.php` | Main export logic and data retrieval | +| `WordPressExporter` | `lib/utility/export-wordpress.php` | WXR (XML) generator | +| `GhostExporter` | `lib/utility/export-ghost.php` | Ghost JSON generator | +| `BlogspotExporter` | `lib/utility/export-blogspot.php` | Blogger XML generator | +| `ScriptlogExporter` | `lib/utility/export-scriptlog.php` | Native JSON generator | +| `ExportException` | `lib/core/ExportException.php` | Specialized export error handling | + +### Export Workflow + +1. **Select Format**: User selects target platform (WordPress, Ghost, Blogspot, or Scriptlog). +2. **Generate**: `ExportService` retrieves posts, pages, categories, tags, and comments from the database. +3. **Transform**: Selected exporter formats the data according to target platform specifications. +4. **Download**: File is generated and sent to browser for download. + +### Native Scriptlog Format + +The Scriptlog native export format (`export-scriptlog.php`) preserves: + +- Posts, pages, categories, tags, and comments +- Navigation menus and menu items +- System settings and configuration +- Post-topic relationships +- Content metadata + +This format is ideal for migrating between Scriptlog installations or creating backups. + +### Security and Access Control + +* **Access Control**: Only users with `administrator` level can access the export feature. +* **Admin Route Only**: Export is not exposed as a public route - it's accessed via `admin/index.php?load=export`. +* **Whitelist**: Export is registered in `lib/utility/admin-query.php` for admin routing. + +### Adding New Exporters + +To add support for a new platform: + +1. Create a new exporter class in `lib/utility/` (e.g., `MediumExporter.php`). +2. Implement format generation logic in the exporter class. +3. Update `ExportController.php` to include the new format option. +4. Update the UI in `admin/ui/export/index.php` to add the new option. + +### Common Issues and Solutions + +#### XML Parse Error: Unexpected Identifier + +When generating XML files (WordPress WXR, Blogspot Atom), the XML declaration `` may cause a PHP parse error if placed inline with PHP code. This happens because PHP interprets ` + + **Note:** Minified versions are already committed to the repository. This script is for development workflow when adding or modifying theme assets. + +#### 2. Critical CSS +Inline above-the-fold CSS in `header.php` to prevent render-blocking. Essential layout, navigation, and hero styles should be inlined within ` - * + * * @category Function * @see https://www.php.net/manual/en/function.base64-encode.php#105200 * @param string $filename * @param string $filetype * @return string - * + * */ function image_encoder($filename, $filetype) { if ($filename) { - $imgbinary = fread(fopen($filename, "r"), filesize($filename)); return 'data:image/' . $filetype . ';base64,' . base64_encode($imgbinary); - } -} \ No newline at end of file +} diff --git a/src/lib/utility/import-blogspot.php b/src/lib/utility/import-blogspot.php old mode 100644 new mode 100755 index 5c44e7d9d..5bd9d8984 --- a/src/lib/utility/import-blogspot.php +++ b/src/lib/utility/import-blogspot.php @@ -1,9 +1,11 @@ -feedId = ''; - $this->title = ''; - $this->subtitle = ''; - $this->url = ''; - } - - /** - * Parse XML file from string - * - * @param string $content - * @return bool - * @throws ImportException - */ - public function parse($content) - { - $content = $this->cleanXmlContent($content); - - libxml_use_internal_errors(true); - $this->xml = simplexml_load_string($content); - - if ($this->xml === false) { - $errors = libxml_get_errors(); - libxml_clear_errors(); - $errorMsg = !empty($errors) ? $errors[0]->message : 'Invalid XML format'; - throw new ImportException('Failed to parse Blogger XML: ' . $errorMsg); + private $xml; + private $feedId; + private $title; + private $subtitle; + private $url; + + public function __construct() + { + $this->feedId = ''; + $this->title = ''; + $this->subtitle = ''; + $this->url = ''; } - - $this->extractFeedInfo(); - - return true; - } - - /** - * Extract feed information - * - * @return void - */ - private function extractFeedInfo() - { - $this->feedId = (string) $this->xml->id ?? ''; - $this->title = (string) ($this->xml->title ?? $this->xml->xpath('//a:title')[0] ?? ''); - $this->subtitle = (string) ($this->xml->subtitle ?? ''); - $this->url = ''; - - $links = $this->xml->link; - if (!empty($links)) { - foreach ($links as $link) { - $rel = (string) $link['rel'] ?? ''; - if ($rel === 'alternate') { - $this->url = (string) $link['href'] ?? ''; - break; + + /** + * Parse XML file from string + * + * @param string $content + * @return bool + * @throws ImportException + */ + public function parse($content) + { + $content = $this->cleanXmlContent($content); + + libxml_use_internal_errors(true); + libxml_disable_entity_loader(true); + $this->xml = simplexml_load_string($content, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_DTDLOAD); + + if ($this->xml === false) { + $errors = libxml_get_errors(); + libxml_clear_errors(); + $errorMsg = !empty($errors) ? $errors[0]->message : 'Invalid XML format'; + throw new ImportException('Failed to parse Blogger XML: ' . $errorMsg); } - } + + $this->extractFeedInfo(); + + return true; } - - if (empty($this->url)) { - $entries = $this->xml->entry ?? []; - if (!empty($entries)) { - foreach ($entries as $entry) { - $links = $entry->link; - foreach ($links as $link) { - $rel = (string) $link['rel'] ?? ''; - if ($rel === 'alternate') { - $href = (string) $link['href'] ?? ''; - $parsed = parse_url($href); - if (!empty($parsed['host'])) { - $this->url = $parsed['scheme'] . '://' . $parsed['host']; - break 2; - } + + /** + * Extract feed information + * + * @return void + */ + private function extractFeedInfo() + { + $this->feedId = (string) $this->xml->id ?? ''; + $this->title = (string) ($this->xml->title ?? $this->xml->xpath('//a:title')[0] ?? ''); + $this->subtitle = (string) ($this->xml->subtitle ?? ''); + $this->url = ''; + + $links = $this->xml->link; + if (!empty($links)) { + foreach ($links as $link) { + $rel = (string) $link['rel'] ?? ''; + if ($rel === 'alternate') { + $this->url = (string) $link['href'] ?? ''; + break; + } + } + } + + if (empty($this->url)) { + $entries = $this->xml->entry ?? []; + if (!empty($entries)) { + foreach ($entries as $entry) { + $links = $entry->link; + foreach ($links as $link) { + $rel = (string) $link['rel'] ?? ''; + if ($rel === 'alternate') { + $href = (string) $link['href'] ?? ''; + $parsed = parse_url($href); + if (!empty($parsed['host'])) { + $this->url = $parsed['scheme'] . '://' . $parsed['host']; + break 2; + } + } + } + } } - } } - } } - } - - /** - * Get site information - * - * @return array - */ - public function getSiteInfo() - { - return [ - 'feed_id' => $this->feedId, - 'title' => $this->title, - 'subtitle' => $this->subtitle, - 'url' => $this->url - ]; - } - - /** - * Extract all posts from Blogger XML - * - * @return array - */ - public function getPosts() - { - $posts = []; - - $namespaces = $this->xml->getNamespaces(true); - - $entries = $this->xml->entry ?? []; - - if (empty($entries)) { - return $posts; + + /** + * Get site information + * + * @return array + */ + public function getSiteInfo() + { + return [ + 'feed_id' => $this->feedId, + 'title' => $this->title, + 'subtitle' => $this->subtitle, + 'url' => $this->url + ]; } - - foreach ($entries as $entry) { - $entryNamespaces = $entry->getNamespaces(true); - - $categories = $entry->category ?? []; - $kind = ''; - $isPost = false; - - foreach ($categories as $cat) { - $scheme = (string) $cat['scheme'] ?? ''; - $term = (string) $cat['term'] ?? ''; - - if ($scheme === 'http://schemas.google.com/g/2005#kind') { - $kind = $term; - if (strpos($term, 'post') !== false) { - $isPost = true; - } + + /** + * Extract all posts from Blogger XML + * + * @return array + */ + public function getPosts() + { + $posts = []; + + $namespaces = $this->xml->getNamespaces(true); + + $entries = $this->xml->entry ?? []; + + if (empty($entries)) { + return $posts; } - } - - if (!$isPost && strpos($kind, 'post') === false) { - continue; - } - - $title = ''; - $titleElement = $entry->title ?? null; - if ($titleElement !== null) { - $titleType = (string) $titleElement['type'] ?? 'text'; - if ($titleType === 'html') { - $title = (string) $titleElement; - } else { - $title = (string) $titleElement; - } - } - - $id = ''; - $idElement = $entry->id ?? null; - if ($idElement !== null) { - $idText = (string) $idElement; - if (preg_match('/post-(\d+)/', $idText, $matches)) { - $id = $matches[1]; - } else { - $id = $idText; - } - } - - $published = ''; - $updated = ''; - $publishedElement = $entry->published ?? null; - $updatedElement = $entry->updated ?? null; - - if ($publishedElement !== null) { - $published = (string) $publishedElement; - } - if ($updatedElement !== null) { - $updated = (string) $updatedElement; - } - - $content = ''; - $contentElement = $entry->content ?? null; - if ($contentElement !== null) { - $contentType = (string) $contentElement['type'] ?? 'text'; - if ($contentType === 'html' || $contentType === 'xhtml') { - $content = (string) $contentElement; - } else { - $content = nl2br((string) $contentElement); + + foreach ($entries as $entry) { + $entryNamespaces = $entry->getNamespaces(true); + + $categories = $entry->category ?? []; + $kind = ''; + $isPost = false; + + foreach ($categories as $cat) { + $scheme = (string) $cat['scheme'] ?? ''; + $term = (string) $cat['term'] ?? ''; + + if ($scheme === 'http://schemas.google.com/g/2005#kind') { + $kind = $term; + if (strpos($term, 'post') !== false) { + $isPost = true; + } + } + } + + if (!$isPost && strpos($kind, 'post') === false) { + continue; + } + + $title = ''; + $titleElement = $entry->title ?? null; + if ($titleElement !== null) { + $titleType = (string) $titleElement['type'] ?? 'text'; + if ($titleType === 'html') { + $title = (string) $titleElement; + } else { + $title = (string) $titleElement; + } + } + + $id = ''; + $idElement = $entry->id ?? null; + if ($idElement !== null) { + $idText = (string) $idElement; + if (preg_match('/post-(\d+)/', $idText, $matches)) { + $id = $matches[1]; + } else { + $id = $idText; + } + } + + $published = ''; + $updated = ''; + $publishedElement = $entry->published ?? null; + $updatedElement = $entry->updated ?? null; + + if ($publishedElement !== null) { + $published = (string) $publishedElement; + } + if ($updatedElement !== null) { + $updated = (string) $updatedElement; + } + + $content = ''; + $contentElement = $entry->content ?? null; + if ($contentElement !== null) { + $contentType = (string) $contentElement['type'] ?? 'text'; + if ($contentType === 'html' || $contentType === 'xhtml') { + $content = (string) $contentElement; + } else { + $content = nl2br((string) $contentElement); + } + } + + $summary = ''; + $summaryElement = $entry->summary ?? null; + if ($summaryElement !== null) { + $summary = (string) $summaryElement; + } + + $link = ''; + $links = $entry->link ?? []; + foreach ($links as $l) { + $rel = (string) $l['rel'] ?? ''; + if ($rel === 'alternate') { + $link = (string) $l['href'] ?? ''; + break; + } + } + + $author = ''; + $authorElement = $entry->author ?? null; + if ($authorElement !== null) { + $author = (string) $authorElement->name ?? ''; + } + + $postCategories = []; + $postLabels = []; + + foreach ($categories as $cat) { + $scheme = (string) $cat['scheme'] ?? ''; + $term = (string) $cat['term'] ?? ''; + $label = (string) $cat['label'] ?? ''; + + if ( + $scheme === 'http://schemas.google.com/blogger/2008/kind#category' || + $scheme === 'http://www.blogger.com/atom.ns.tf/category' + ) { + $categoryName = !empty($label) ? $label : $term; + if (!empty($categoryName)) { + $postCategories[] = [ + 'name' => $categoryName, + 'slug' => make_slug($categoryName) + ]; + } + } + } + + $postTags = $postLabels; + + $commentStatus = 'open'; + $repliesCount = 0; + + $thr = $entry->children('http://purl.org/syndication/thread/1.0'); + $repliesCount = (int) ($thr->total ?? 0); + + $appControl = $entry->children('http://purl.org/atom/app#'); + $control = $appControl->control ?? null; + if ($control !== null) { + $draft = $control->draft ?? null; + if ($draft !== null && (string) $draft === 'yes') { + continue; + } + } + + $posts[] = [ + 'id' => $id, + 'title' => $title, + 'slug' => $this->generateSlug($title, $id), + 'content' => !empty($content) ? $content : $summary, + 'excerpt' => $summary, + 'type' => 'blog', + 'status' => 'publish', + 'date' => $this->formatDate($published), + 'modified' => $this->formatDate($updated), + 'author' => $author, + 'link' => $link, + 'comment_status' => $commentStatus, + 'categories' => $postCategories, + 'tags' => $postTags, + 'replies_count' => $repliesCount + ]; } - } - - $summary = ''; - $summaryElement = $entry->summary ?? null; - if ($summaryElement !== null) { - $summary = (string) $summaryElement; - } - - $link = ''; - $links = $entry->link ?? []; - foreach ($links as $l) { - $rel = (string) $l['rel'] ?? ''; - if ($rel === 'alternate') { - $link = (string) $l['href'] ?? ''; - break; + + return $posts; + } + + /** + * Extract all pages from Blogger XML + * + * @return array + */ + public function getPages() + { + $pages = []; + + $entries = $this->xml->entry ?? []; + + if (empty($entries)) { + return $pages; } - } - - $author = ''; - $authorElement = $entry->author ?? null; - if ($authorElement !== null) { - $author = (string) $authorElement->name ?? ''; - } - - $postCategories = []; - $postLabels = []; - - foreach ($categories as $cat) { - $scheme = (string) $cat['scheme'] ?? ''; - $term = (string) $cat['term'] ?? ''; - $label = (string) $cat['label'] ?? ''; - - if ($scheme === 'http://schemas.google.com/blogger/2008/kind#category' || - $scheme === 'http://www.blogger.com/atom.ns.tf/category') { - $categoryName = !empty($label) ? $label : $term; - if (!empty($categoryName)) { - $postCategories[] = [ - 'name' => $categoryName, - 'slug' => make_slug($categoryName) + + foreach ($entries as $entry) { + $categories = $entry->category ?? []; + $isPage = false; + + foreach ($categories as $cat) { + $term = (string) $cat['term'] ?? ''; + if (strpos($term, 'kind#page') !== false || strpos($term, 'page') !== false) { + $isPage = true; + break; + } + } + + if (!$isPage) { + continue; + } + + $title = (string) ($entry->title ?? ''); + $content = (string) ($entry->content ?? ''); + + $published = (string) ($entry->published ?? date('Y-m-d H:i:s')); + $updated = (string) ($entry->updated ?? $published); + + $link = ''; + $links = $entry->link ?? []; + foreach ($links as $l) { + $rel = (string) $l['rel'] ?? ''; + if ($rel === 'alternate') { + $link = (string) $l['href'] ?? ''; + break; + } + } + + $pages[] = [ + 'title' => $title, + 'slug' => $this->generateSlug($title), + 'content' => $content, + 'type' => 'page', + 'status' => 'publish', + 'date' => $this->formatDate($published), + 'modified' => $this->formatDate($updated), + 'link' => $link ]; - } - } - } - - $postTags = $postLabels; - - $commentStatus = 'open'; - $repliesCount = 0; - - $thr = $entry->children('http://purl.org/syndication/thread/1.0'); - $repliesCount = (int) ($thr->total ?? 0); - - $appControl = $entry->children('http://purl.org/atom/app#'); - $control = $appControl->control ?? null; - if ($control !== null) { - $draft = $control->draft ?? null; - if ($draft !== null && (string) $draft === 'yes') { - continue; } - } - - $posts[] = [ - 'id' => $id, - 'title' => $title, - 'slug' => $this->generateSlug($title, $id), - 'content' => !empty($content) ? $content : $summary, - 'excerpt' => $summary, - 'type' => 'blog', - 'status' => 'publish', - 'date' => $this->formatDate($published), - 'modified' => $this->formatDate($updated), - 'author' => $author, - 'link' => $link, - 'comment_status' => $commentStatus, - 'categories' => $postCategories, - 'tags' => $postTags, - 'replies_count' => $repliesCount - ]; + + return $pages; } - - return $posts; - } - - /** - * Extract all pages from Blogger XML - * - * @return array - */ - public function getPages() - { - $pages = []; - - $entries = $this->xml->entry ?? []; - - if (empty($entries)) { - return $pages; - } - - foreach ($entries as $entry) { - $categories = $entry->category ?? []; - $isPage = false; - - foreach ($categories as $cat) { - $term = (string) $cat['term'] ?? ''; - if (strpos($term, 'kind#page') !== false || strpos($term, 'page') !== false) { - $isPage = true; - break; + + /** + * Extract all categories/labels from Blogger XML + * + * @return array + */ + public function getCategories() + { + $categories = []; + $seen = []; + + $entries = $this->xml->entry ?? []; + + if (empty($entries)) { + return $categories; } - } - - if (!$isPage) { - continue; - } - - $title = (string) ($entry->title ?? ''); - $content = (string) ($entry->content ?? ''); - - $published = (string) ($entry->published ?? date('Y-m-d H:i:s')); - $updated = (string) ($entry->updated ?? $published); - - $link = ''; - $links = $entry->link ?? []; - foreach ($links as $l) { - $rel = (string) $l['rel'] ?? ''; - if ($rel === 'alternate') { - $link = (string) $l['href'] ?? ''; - break; + + foreach ($entries as $entry) { + $entryCategories = $entry->category ?? []; + + foreach ($entryCategories as $cat) { + $scheme = (string) $cat['scheme'] ?? ''; + $term = (string) $cat['term'] ?? ''; + $label = (string) $cat['label'] ?? ''; + + if ( + $scheme === 'http://schemas.google.com/blogger/2008/kind#category' || + $scheme === 'http://www.blogger.com/atom.ns.tf/category' + ) { + $categoryName = !empty($label) ? $label : $term; + $categorySlug = make_slug($categoryName); + + if (!empty($categoryName) && !isset($seen[$categorySlug])) { + $seen[$categorySlug] = true; + $categories[] = [ + 'name' => $categoryName, + 'slug' => $categorySlug + ]; + } + } + } } - } - - $pages[] = [ - 'title' => $title, - 'slug' => $this->generateSlug($title), - 'content' => $content, - 'type' => 'page', - 'status' => 'publish', - 'date' => $this->formatDate($published), - 'modified' => $this->formatDate($updated), - 'link' => $link - ]; + + return $categories; } - - return $pages; - } - - /** - * Extract all categories/labels from Blogger XML - * - * @return array - */ - public function getCategories() - { - $categories = []; - $seen = []; - - $entries = $this->xml->entry ?? []; - - if (empty($entries)) { - return $categories; - } - - foreach ($entries as $entry) { - $categories = $entry->category ?? []; - - foreach ($categories as $cat) { - $scheme = (string) $cat['scheme'] ?? ''; - $term = (string) $cat['term'] ?? ''; - $label = (string) $cat['label'] ?? ''; - - if ($scheme === 'http://schemas.google.com/blogger/2008/kind#category' || - $scheme === 'http://www.blogger.com/atom.ns.tf/category') { - - $categoryName = !empty($label) ? $label : $term; - $categorySlug = make_slug($categoryName); - - if (!empty($categoryName) && !isset($seen[$categorySlug])) { - $seen[$categorySlug] = true; - $categories[] = [ - 'name' => $categoryName, - 'slug' => $categorySlug - ]; - } + + /** + * Generate unique slug + * + * @param string $title + * @param string $id + * @return string + */ + private function generateSlug($title, $id = '') + { + $slug = make_slug($title); + + if (empty($slug)) { + $slug = 'post-' . ($id ?: time()); } - } + + return $slug; } - - return $categories; - } - - /** - * Generate unique slug - * - * @param string $title - * @param string $id - * @return string - */ - private function generateSlug($title, $id = '') - { - $slug = make_slug($title); - - if (empty($slug)) { - $slug = 'post-' . ($id ?: time()); - } - - return $slug; - } - - /** - * Format date string - * - * @param string $date - * @return string - */ - private function formatDate($date) - { - if (empty($date)) { - return date('Y-m-d H:i:s'); + + /** + * Format date string + * + * @param string $date + * @return string + */ + private function formatDate($date) + { + if (empty($date)) { + return date('Y-m-d H:i:s'); + } + + $timestamp = strtotime($date); + return $timestamp ? date('Y-m-d H:i:s', $timestamp) : date('Y-m-d H:i:s'); } - - $timestamp = strtotime($date); - return $timestamp ? date('Y-m-d H:i:s', $timestamp) : date('Y-m-d H:i:s'); - } - - /** - * Clean XML content - * - * @param string $content - * @return string - */ - private function cleanXmlContent($content) - { - $content = preg_replace('/<\?xml[^>]*encoding="[^"]*"[^>]*\?>/i', '', $content); - $content = preg_replace('/<\?xml[^>]*version="[^"]*"[^>]*\?>/i', '', $content); - - if (stripos($content, ''); - if ($firstTagEnd !== false) { - $content = substr($content, $firstTagEnd + 2); - } + + /** + * Clean XML content + * + * @param string $content + * @return string + */ + private function cleanXmlContent($content) + { + $content = preg_replace('/<\?xml[^>]*encoding="[^"]*"[^>]*\?>/i', '', $content); + $content = preg_replace('/<\?xml[^>]*version="[^"]*"[^>]*\?>/i', '', $content); + + if (stripos($content, ''); + if ($firstTagEnd !== false) { + $content = substr($content, $firstTagEnd + 2); + } + } + + return $content; } - - return $content; - } } diff --git a/src/lib/utility/import-ghost.php b/src/lib/utility/import-ghost.php old mode 100644 new mode 100755 index 33bcb8fa2..6c828082d --- a/src/lib/utility/import-ghost.php +++ b/src/lib/utility/import-ghost.php @@ -1,9 +1,11 @@ -data = null; - $this->schema = []; - } - - /** - * Parse JSON file from string - * - * @param string $content - * @return bool - * @throws ImportException - */ - public function parse($content) - { - $this->data = json_decode($content, true); - - if (json_last_error() !== JSON_ERROR_NONE) { - throw new ImportException('Failed to parse JSON: ' . json_last_error_msg()); + private $data; + private $schema; + + public function __construct() + { + $this->data = null; + $this->schema = []; } - - if (!is_array($this->data)) { - throw new ImportException('Invalid JSON structure: expected object or array'); - } - - $this->detectSchema(); - - return true; - } - - /** - * Detect Ghost schema version - * - * @return void - */ - private function detectSchema() - { - if (isset($this->data['posts'])) { - $this->schema = 'v3'; - } elseif (isset($this->data['db'])) { - $dbData = $this->data['db']; - if (isset($dbData['posts'])) { - $this->schema = 'v2'; - $this->data = $dbData; - } else { - $this->schema = 'v1'; - } - } else { - $this->schema = 'unknown'; + + /** + * Parse JSON file from string + * + * @param string $content + * @return bool + * @throws ImportException + */ + public function parse($content) + { + $this->data = json_decode($content, true); + + if (json_last_error() !== JSON_ERROR_NONE) { + throw new ImportException('Failed to parse JSON: ' . json_last_error_msg()); + } + + if (!is_array($this->data)) { + throw new ImportException('Invalid JSON structure: expected object or array'); + } + + $this->detectSchema(); + + return true; } - } - - /** - * Get detected schema version - * - * @return string - */ - public function getSchema() - { - return $this->schema; - } - - /** - * Get site information - * - * @return array - */ - public function getSiteInfo() - { - $title = ''; - $url = ''; - - if ($this->schema === 'v3') { - $title = $this->data['title'] ?? ''; - $url = $this->data['url'] ?? ''; - } elseif (isset($this->data['meta'])) { - $title = $this->data['meta']['title'] ?? ''; - $url = $this->data['meta']['url'] ?? ''; + + /** + * Detect Ghost schema version + * + * @return void + */ + private function detectSchema() + { + if (isset($this->data['posts'])) { + $this->schema = 'v3'; + } elseif (isset($this->data['db'])) { + $dbData = $this->data['db']; + if (isset($dbData['posts'])) { + $this->schema = 'v2'; + $this->data = $dbData; + } else { + $this->schema = 'v1'; + } + } else { + $this->schema = 'unknown'; + } } - - return [ - 'schema' => $this->schema, - 'title' => $title, - 'url' => $url - ]; - } - - /** - * Extract all posts/pages from Ghost export - * - * @return array - */ - public function getPosts() - { - $posts = []; - - $postsData = []; - - if ($this->schema === 'v3') { - $postsData = $this->data['posts'] ?? []; - } elseif ($this->schema === 'v2') { - $postsData = $this->data['db']['posts'] ?? []; - } else { - $postsData = $this->data['posts'] ?? []; + + /** + * Get detected schema version + * + * @return string + */ + public function getSchema() + { + return $this->schema; } - - if (empty($postsData)) { - return $posts; + + /** + * Get site information + * + * @return array + */ + public function getSiteInfo() + { + $title = ''; + $url = ''; + + if ($this->schema === 'v3') { + $title = $this->data['title'] ?? ''; + $url = $this->data['url'] ?? ''; + } elseif (isset($this->data['meta'])) { + $title = $this->data['meta']['title'] ?? ''; + $url = $this->data['meta']['url'] ?? ''; + } + + return [ + 'schema' => $this->schema, + 'title' => $title, + 'url' => $url + ]; } - - foreach ($postsData as $post) { - $title = $post['title'] ?? ''; - $slug = $post['slug'] ?? make_slug($title); - $htmlContent = $post['html'] ?? ''; - $plainContent = $post['plaintext'] ?? ''; - $content = !empty($htmlContent) ? $htmlContent : nl2br($plainContent); - - $status = isset($post['status']) ? $this->mapPostStatus($post['status']) : 'publish'; - - $publishedAt = isset($post['published_at']) ? $this->formatDate($post['published_at']) : date('Y-m-d H:i:s'); - $createdAt = isset($post['created_at']) ? $this->formatDate($post['created_at']) : $publishedAt; - $updatedAt = isset($post['updated_at']) ? $this->formatDate($post['updated_at']) : null; - - $featureImage = $post['feature_image'] ?? ''; - - $tags = []; - $categories = []; - - if (isset($post['tags'])) { - foreach ($post['tags'] as $tag) { - if (is_array($tag)) { - $tagName = $tag['name'] ?? ''; - $tagSlug = $tag['slug'] ?? make_slug($tagName); - $tagVisibility = $tag['visibility'] ?? 'public'; - } else { - $tagName = $tag; - $tagSlug = make_slug($tag); - $tagVisibility = 'public'; - } - - if (!empty($tagName)) { - if ($tagVisibility === 'internal') { - $categories[] = [ - 'name' => $tagName, - 'slug' => $tagSlug - ]; - } else { - $tags[] = $tagSlug; - } - } + + /** + * Extract all posts/pages from Ghost export + * + * @return array + */ + public function getPosts() + { + $posts = []; + + $postsData = []; + + if ($this->schema === 'v3') { + $postsData = $this->data['posts'] ?? []; + } elseif ($this->schema === 'v2') { + $postsData = $this->data['posts'] ?? []; + } else { + $postsData = $this->data['posts'] ?? []; } - } - - if (isset($post['primary_tag'])) { - $primaryTag = is_array($post['primary_tag']) ? $post['primary_tag']['name'] : $post['primary_tag']; - if (!empty($primaryTag)) { - $categories[] = [ - 'name' => $primaryTag, - 'slug' => make_slug($primaryTag) - ]; + + if (empty($postsData)) { + return $posts; } - } - - if (isset($post['primary_category'])) { - $primaryCat = is_array($post['primary_category']) ? $post['primary_category']['name'] : $post['primary_category']; - if (!empty($primaryCat)) { - $categories[] = [ - 'name' => $primaryCat, - 'slug' => make_slug($primaryCat) - ]; + + foreach ($postsData as $post) { + $title = $post['title'] ?? ''; + $slug = $post['slug'] ?? make_slug($title); + $htmlContent = $post['html'] ?? ''; + $plainContent = $post['plaintext'] ?? ''; + $content = !empty($htmlContent) ? $htmlContent : nl2br($plainContent); + + $status = isset($post['status']) ? $this->mapPostStatus($post['status']) : 'publish'; + + $publishedAt = isset($post['published_at']) ? $this->formatDate($post['published_at']) : date('Y-m-d H:i:s'); + $createdAt = isset($post['created_at']) ? $this->formatDate($post['created_at']) : $publishedAt; + $updatedAt = isset($post['updated_at']) ? $this->formatDate($post['updated_at']) : null; + + $featureImage = $post['feature_image'] ?? ''; + + $tags = []; + $categories = []; + + if (isset($post['tags'])) { + foreach ($post['tags'] as $tag) { + if (is_array($tag)) { + $tagName = $tag['name'] ?? ''; + $tagSlug = $tag['slug'] ?? make_slug($tagName); + $tagVisibility = $tag['visibility'] ?? 'public'; + } else { + $tagName = $tag; + $tagSlug = make_slug($tag); + $tagVisibility = 'public'; + } + + if (!empty($tagName)) { + if ($tagVisibility === 'internal') { + $categories[] = [ + 'name' => $tagName, + 'slug' => $tagSlug + ]; + } else { + $tags[] = $tagSlug; + } + } + } + } + + if (isset($post['primary_tag'])) { + $primaryTag = is_array($post['primary_tag']) ? $post['primary_tag']['name'] : $post['primary_tag']; + if (!empty($primaryTag)) { + $categories[] = [ + 'name' => $primaryTag, + 'slug' => make_slug($primaryTag) + ]; + } + } + + if (isset($post['primary_category'])) { + $primaryCat = is_array($post['primary_category']) ? $post['primary_category']['name'] : $post['primary_category']; + if (!empty($primaryCat)) { + $categories[] = [ + 'name' => $primaryCat, + 'slug' => make_slug($primaryCat) + ]; + } + } + + $commentStatus = ($post['comment_id'] ?? '') !== false ? 'open' : 'closed'; + + $excerpt = $post['custom_excerpt'] ?? $post['excerpt'] ?? ''; + if (empty($excerpt) && !empty($plainContent)) { + $excerpt = substr(strip_tags($plainContent), 0, 200); + } + + $author = ''; + if (isset($post['author'])) { + $author = is_array($post['author']) ? ($post['author']['name'] ?? '') : $post['author']; + } + + $comments = $this->extractComments($post); + + $posts[] = [ + 'id' => $post['id'] ?? '', + 'title' => $title, + 'slug' => $slug, + 'content' => $content, + 'excerpt' => $excerpt, + 'type' => ($post['type'] ?? 'post') === 'page' ? 'page' : 'blog', + 'status' => $status, + 'date' => $publishedAt, + 'created_at' => $createdAt, + 'modified' => $updatedAt, + 'author' => $author, + 'feature_image' => $featureImage, + 'comment_status' => $commentStatus, + 'categories' => $categories, + 'tags' => $tags, + 'url' => $post['url'] ?? '', + 'comments' => $comments + ]; } - } - - $commentStatus = ($post['comment_id'] ?? '') !== false ? 'open' : 'closed'; - - $excerpt = $post['custom_excerpt'] ?? $post['excerpt'] ?? ''; - if (empty($excerpt) && !empty($plainContent)) { - $excerpt = substr(strip_tags($plainContent), 0, 200); - } - - $author = ''; - if (isset($post['author'])) { - $author = is_array($post['author']) ? ($post['author']['name'] ?? '') : $post['author']; - } - - $comments = $this->extractComments($post); - - $posts[] = [ - 'id' => $post['id'] ?? '', - 'title' => $title, - 'slug' => $slug, - 'content' => $content, - 'excerpt' => $excerpt, - 'type' => ($post['type'] ?? 'post') === 'page' ? 'page' : 'blog', - 'status' => $status, - 'date' => $publishedAt, - 'created_at' => $createdAt, - 'modified' => $updatedAt, - 'author' => $author, - 'feature_image' => $featureImage, - 'comment_status' => $commentStatus, - 'categories' => $categories, - 'tags' => $tags, - 'url' => $post['url'] ?? '', - 'comments' => $comments - ]; + + return $posts; } - - return $posts; - } - - /** - * Extract comments from post - * - * @param array $post - * @return array - */ - private function extractComments($post) - { - $comments = []; - - if (isset($post['comments']) && is_array($post['comments'])) { - foreach ($post['comments'] as $comment) { - $commentData = [ - 'author_name' => $comment['author']['name'] ?? $comment['author_name'] ?? 'Anonymous', - 'author_email' => $comment['author']['email'] ?? $comment['author_email'] ?? '', - 'author_url' => $comment['author']['url'] ?? $comment['author_url'] ?? '', - 'author_ip' => $comment['ip'] ?? '127.0.0.1', - 'date' => $this->formatDate($comment['created_at'] ?? date('Y-m-d H:i:s')), - 'content' => $comment['html'] ?? $comment['content'] ?? '', - 'status' => $this->mapCommentStatus($comment['status'] ?? 'published'), - 'parent' => $comment['parent_id'] ?? '0' - ]; - - if (!empty($commentData['content'])) { - $comments[] = $commentData; + + /** + * Extract comments from post + * + * @param array $post + * @return array + */ + private function extractComments($post) + { + $comments = []; + + if (isset($post['comments']) && is_array($post['comments'])) { + foreach ($post['comments'] as $comment) { + $commentData = [ + 'author_name' => $comment['author']['name'] ?? $comment['author_name'] ?? 'Anonymous', + 'author_email' => $comment['author']['email'] ?? $comment['author_email'] ?? '', + 'author_url' => $comment['author']['url'] ?? $comment['author_url'] ?? '', + 'author_ip' => $comment['ip'] ?? '127.0.0.1', + 'date' => $this->formatDate($comment['created_at'] ?? date('Y-m-d H:i:s')), + 'content' => $comment['html'] ?? $comment['content'] ?? '', + 'status' => $this->mapCommentStatus($comment['status'] ?? 'published'), + 'parent' => $comment['parent_id'] ?? '0' + ]; + + if (!empty($commentData['content'])) { + $comments[] = $commentData; + } + } } - } + + return $comments; } - - return $comments; - } - - /** - * Extract tags from Ghost export - * - * @return array - */ - public function getTags() - { - $tags = []; - - $tagsData = []; - - if ($this->schema === 'v3') { - $tagsData = $this->data['tags'] ?? []; - } elseif ($this->schema === 'v2') { - $tagsData = $this->data['db']['tags'] ?? []; - } - - if (empty($tagsData)) { - return $tags; - } - - foreach ($tagsData as $tag) { - $tags[] = [ - 'name' => $tag['name'] ?? '', - 'slug' => $tag['slug'] ?? make_slug($tag['name'] ?? ''), - 'description' => $tag['description'] ?? '', - 'visibility' => $tag['visibility'] ?? 'public' - ]; + + /** + * Extract tags from Ghost export + * + * @return array + */ + public function getTags() + { + $tags = []; + + $tagsData = []; + + if ($this->schema === 'v3') { + $tagsData = $this->data['tags'] ?? []; + } elseif ($this->schema === 'v2') { + $tagsData = $this->data['db']['tags'] ?? []; + } + + if (empty($tagsData)) { + return $tags; + } + + foreach ($tagsData as $tag) { + $tags[] = [ + 'name' => $tag['name'] ?? '', + 'slug' => $tag['slug'] ?? make_slug($tag['name'] ?? ''), + 'description' => $tag['description'] ?? '', + 'visibility' => $tag['visibility'] ?? 'public' + ]; + } + + return $tags; } - - return $tags; - } - - /** - * Extract categories from Ghost export - * - * @return array - */ - public function getCategories() - { - $categories = []; - - $tagsData = []; - - if ($this->schema === 'v3') { - $tagsData = $this->data['tags'] ?? []; - } elseif ($this->schema === 'v2') { - $tagsData = $this->data['db']['tags'] ?? []; + + /** + * Extract categories from Ghost export + * + * @return array + */ + public function getCategories() + { + $categories = []; + + $tagsData = []; + + if ($this->schema === 'v3') { + $tagsData = $this->data['tags'] ?? []; + } elseif ($this->schema === 'v2') { + $tagsData = $this->data['db']['tags'] ?? []; + } + + if (empty($tagsData)) { + return $categories; + } + + foreach ($tagsData as $tag) { + $visibility = $tag['visibility'] ?? 'public'; + + if ($visibility === 'internal') { + $categories[] = [ + 'name' => $tag['name'] ?? '', + 'slug' => $tag['slug'] ?? make_slug($tag['name'] ?? ''), + 'description' => $tag['description'] ?? '' + ]; + } + } + + return $categories; } - - if (empty($tagsData)) { - return $categories; + + /** + * Map Ghost post status to Blogware status + * + * @param string $status + * @return string + */ + private function mapPostStatus($status) + { + $statusMap = [ + 'published' => 'publish', + 'draft' => 'draft', + 'scheduled' => 'pending', + 'private' => 'private' + ]; + + return $statusMap[$status] ?? 'draft'; } - - foreach ($tagsData as $tag) { - $visibility = $tag['visibility'] ?? 'public'; - - if ($visibility === 'internal') { - $categories[] = [ - 'name' => $tag['name'] ?? '', - 'slug' => $tag['slug'] ?? make_slug($tag['name'] ?? ''), - 'description' => $tag['description'] ?? '' + + /** + * Map Ghost comment status to Blogware status + * + * @param string $status + * @return string + */ + private function mapCommentStatus($status) + { + $statusMap = [ + 'published' => 'approved', + 'draft' => 'pending', + 'spam' => 'spam' ]; - } + + return $statusMap[$status] ?? 'pending'; } - - return $categories; - } - - /** - * Map Ghost post status to Blogware status - * - * @param string $status - * @return string - */ - private function mapPostStatus($status) - { - $statusMap = [ - 'published' => 'publish', - 'draft' => 'draft', - 'scheduled' => 'pending', - 'private' => 'private' - ]; - - return $statusMap[$status] ?? 'draft'; - } - - /** - * Map Ghost comment status to Blogware status - * - * @param string $status - * @return string - */ - private function mapCommentStatus($status) - { - $statusMap = [ - 'published' => 'approved', - 'draft' => 'pending', - 'spam' => 'spam' - ]; - - return $statusMap[$status] ?? 'pending'; - } - - /** - * Format date string - * - * @param string $date - * @return string - */ - private function formatDate($date) - { - if (empty($date)) { - return date('Y-m-d H:i:s'); + + /** + * Format date string + * + * @param string $date + * @return string + */ + private function formatDate($date) + { + if (empty($date)) { + return date('Y-m-d H:i:s'); + } + + $timestamp = strtotime($date); + return $timestamp ? date('Y-m-d H:i:s', $timestamp) : date('Y-m-d H:i:s'); } - - $timestamp = strtotime($date); - return $timestamp ? date('Y-m-d H:i:s', $timestamp) : date('Y-m-d H:i:s'); - } } diff --git a/src/lib/utility/import-scriptlog.php b/src/lib/utility/import-scriptlog.php new file mode 100644 index 000000000..b5364c156 --- /dev/null +++ b/src/lib/utility/import-scriptlog.php @@ -0,0 +1,187 @@ +version = ''; + $this->siteUrl = ''; + $this->siteTitle = ''; + } + + /** + * Parse JSON file from string + * + * @param string $content + * @return bool + * @throws ImportException + */ + public function parse($content) + { + $this->data = json_decode($content, true); + + if (json_last_error() !== JSON_ERROR_NONE) { + throw new ImportException('Failed to parse JSON: ' . json_last_error_msg()); + } + + if (!isset($this->data['_meta'])) { + throw new ImportException('Invalid Scriptlog export file: missing metadata'); + } + + if (!isset($this->data['_meta']['format']) || $this->data['_meta']['format'] !== 'scriptlog-native') { + throw new ImportException('Invalid Scriptlog export file: not a native export'); + } + + $this->version = $this->data['_meta']['version'] ?? ''; + $this->siteUrl = $this->data['_meta']['exported_from'] ?? ''; + + if (isset($this->data['site'])) { + $this->siteTitle = $this->data['site']['title'] ?? ''; + } + + return true; + } + + /** + * Get site information + * + * @return array + */ + public function getSiteInfo() + { + return [ + 'version' => $this->version, + 'site_url' => $this->siteUrl, + 'title' => $this->siteTitle, + 'format' => 'scriptlog-native' + ]; + } + + /** + * Get all users + * + * @return array + */ + public function getUsers() + { + return $this->data['users'] ?? []; + } + + /** + * Get all topics/categories + * + * @return array + */ + public function getTopics() + { + return $this->data['topics'] ?? []; + } + + /** + * Get all posts + * + * @return array + */ + public function getPosts() + { + return $this->data['posts'] ?? []; + } + + /** + * Get all pages + * + * @return array + */ + public function getPages() + { + return $this->data['pages'] ?? []; + } + + /** + * Get all comments + * + * @return array + */ + public function getComments() + { + return $this->data['comments'] ?? []; + } + + /** + * Get all menus + * + * @return array + */ + public function getMenus() + { + return $this->data['menus'] ?? []; + } + + /** + * Get all settings + * + * @return array + */ + public function getSettings() + { + return $this->data['settings'] ?? []; + } + + /** + * Get post-topic relationships + * + * @return array + */ + public function getPostTopics() + { + return $this->data['_post_topic'] ?? []; + } + + /** + * Get tags (extracted from posts) + * + * @return array + */ + public function getTags() + { + $tags = []; + $posts = $this->getPosts(); + $pages = $this->getPages(); + + foreach (array_merge($posts, $pages) as $content) { + if (!empty($content['post_tags'])) { + $tagList = explode(',', $content['post_tags']); + foreach ($tagList as $tag) { + $tag = trim($tag); + if (!empty($tag)) { + $slug = make_slug($tag); + $tags[$slug] = [ + 'name' => $tag, + 'slug' => $slug + ]; + } + } + } + } + + return array_values($tags); + } +} diff --git a/src/lib/utility/import-wordpress.php b/src/lib/utility/import-wordpress.php old mode 100644 new mode 100755 index e3ccdebbf..de8b27e9b --- a/src/lib/utility/import-wordpress.php +++ b/src/lib/utility/import-wordpress.php @@ -1,9 +1,11 @@ -wxrVersion = ''; - $this->siteUrl = ''; - $this->title = ''; - } - - /** - * Parse WXR file from string - * - * @param string $content - * @return bool - * @throws ImportException - */ - public function parse($content) - { - $content = $this->cleanXmlContent($content); - - libxml_use_internal_errors(true); - $this->xml = simplexml_load_string($content, 'SimpleXMLElement', LIBXML_NOCDATA); - - if ($this->xml === false) { - $errors = libxml_get_errors(); - libxml_clear_errors(); - $errorMsg = !empty($errors) ? $errors[0]->message : 'Invalid XML format'; - throw new ImportException('Failed to parse WXR file: ' . $errorMsg); + private $xml; + private $wxrVersion; + private $siteUrl; + private $title; + + public function __construct() + { + $this->wxrVersion = ''; + $this->siteUrl = ''; + $this->title = ''; } - - $this->wxrVersion = (string) $this->xml->xpath('//wp:wxr_version')[0] ?? '1.0'; - $this->siteUrl = (string) $this->xml->xpath('//channel/link')[0] ?? ''; - $this->title = (string) $this->xml->xpath('//channel/title')[0] ?? ''; - - return true; - } - - /** - * Get site information - * - * @return array - */ - public function getSiteInfo() - { - return [ - 'wxr_version' => $this->wxrVersion, - 'site_url' => $this->siteUrl, - 'title' => $this->title - ]; - } - - /** - * Extract all categories from WXR - * - * @return array - */ - public function getCategories() - { - $categories = []; - - $xmlCategories = $this->xml->xpath('//wp:category'); - - if (empty($xmlCategories)) { - return $categories; + + /** + * Parse WXR file from string + * + * @param string $content + * @return bool + * @throws ImportException + */ + public function parse($content) + { + $content = $this->cleanXmlContent($content); + + libxml_use_internal_errors(true); + libxml_disable_entity_loader(true); + $this->xml = simplexml_load_string($content, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_DTDLOAD); + + if ($this->xml === false) { + $errors = libxml_get_errors(); + libxml_clear_errors(); + $errorMsg = !empty($errors) ? $errors[0]->message : 'Invalid XML format'; + throw new ImportException('Failed to parse WXR file: ' . $errorMsg); + } + + $wxrVersionResults = $this->xml->xpath('//wp:wxr_version'); + $this->wxrVersion = !empty($wxrVersionResults) ? (string) $wxrVersionResults[0] : '1.0'; + + $linkResults = $this->xml->xpath('//channel/link'); + $this->siteUrl = !empty($linkResults) ? (string) $linkResults[0] : ''; + + $titleResults = $this->xml->xpath('//channel/title'); + $this->title = !empty($titleResults) ? (string) $titleResults[0] : ''; + + return true; } - - foreach ($xmlCategories as $cat) { - $catName = (string) $cat->xpath('.//wp:cat_name')[0] ?? ''; - $catSlug = (string) $cat->xpath('.//wp:category_nicename')[0] ?? ''; - $catParent = (string) $cat->xpath('.//wp:category_parent')[0] ?? ''; - - if (!empty($catName)) { - $categories[] = [ - 'name' => $catName, - 'slug' => !empty($catSlug) ? $catSlug : make_slug($catName), - 'parent' => $catParent + + /** + * Get site information + * + * @return array + */ + public function getSiteInfo() + { + return [ + 'wxr_version' => $this->wxrVersion, + 'site_url' => $this->siteUrl, + 'title' => $this->title ]; - } - } - - return $categories; - } - - /** - * Extract all tags from WXR - * - * @return array - */ - public function getTags() - { - $tags = []; - - $xmlTags = $this->xml->xpath('//wp:tag'); - - if (empty($xmlTags)) { - return $tags; } - - foreach ($xmlTags as $tag) { - $tagName = (string) $tag->xpath('.//wp:tag_name')[0] ?? ''; - $tagSlug = (string) $tag->xpath('.//wp:tag_slug')[0] ?? ''; - - if (!empty($tagName)) { - $tags[] = [ - 'name' => $tagName, - 'slug' => !empty($tagSlug) ? $tagSlug : make_slug($tagName) - ]; - } + + /** + * Extract all categories from WXR + * + * @return array + */ + public function getCategories() + { + $categories = []; + + $xmlCategories = $this->xml->xpath('//wp:category'); + + if (empty($xmlCategories)) { + return $categories; + } + + foreach ($xmlCategories as $cat) { + $catNameResults = $cat->xpath('.//wp:cat_name'); + $catName = !empty($catNameResults) ? (string) $catNameResults[0] : ''; + + $catSlugResults = $cat->xpath('.//wp:category_nicename'); + $catSlug = !empty($catSlugResults) ? (string) $catSlugResults[0] : ''; + + $catParentResults = $cat->xpath('.//wp:category_parent'); + $catParent = !empty($catParentResults) ? (string) $catParentResults[0] : ''; + + if (!empty($catName)) { + $categories[] = [ + 'name' => $catName, + 'slug' => !empty($catSlug) ? $catSlug : make_slug($catName), + 'parent' => $catParent + ]; + } + } + + return $categories; } - - return $tags; - } - - /** - * Extract all posts/pages from WXR - * - * @return array - */ - public function getPosts() - { - $posts = []; - - $xmlItems = $this->xml->channel->item; - - if (empty($xmlItems)) { - return $posts; + + /** + * Extract all tags from WXR + * + * @return array + */ + public function getTags() + { + $tags = []; + + $xmlTags = $this->xml->xpath('//wp:tag'); + + if (empty($xmlTags)) { + return $tags; + } + + foreach ($xmlTags as $tag) { + $tagNameResults = $tag->xpath('.//wp:tag_name'); + $tagName = !empty($tagNameResults) ? (string) $tagNameResults[0] : ''; + + $tagSlugResults = $tag->xpath('.//wp:tag_slug'); + $tagSlug = !empty($tagSlugResults) ? (string) $tagSlugResults[0] : ''; + + if (!empty($tagName)) { + $tags[] = [ + 'name' => $tagName, + 'slug' => !empty($tagSlug) ? $tagSlug : make_slug($tagName) + ]; + } + } + + return $tags; } - - foreach ($xmlItems as $item) { - $children = $item->children(); - $namespaces = $item->getNamespaces(true); - - $postType = (string) $children->xpath('.//wp:post_type')[0] ?? 'post'; - - if (!in_array($postType, ['post', 'page'])) { - continue; - } - - $title = (string) $item->title ?? ''; - $link = (string) $item->link ?? ''; - $pubDate = (string) $item->pubDate ?? date('Y-m-d H:i:s'); - $creator = (string) $children->xpath('.//dc:creator')[0] ?? ''; - $content = (string) $children->xpath('.//content:encoded')[0] ?? ''; - $excerpt = (string) $children->xpath('.//excerpt:encoded')[0] ?? ''; - $postId = (string) $children->xpath('.//wp:post_id')[0] ?? ''; - $postName = (string) $children->xpath('.//wp:post_name')[0] ?? ''; - $status = (string) $children->xpath('.//wp:status')[0] ?? 'publish'; - $parent = (string) $children->xpath('.//wp:post_parent')[0] ?? '0'; - $menuOrder = (string) $children->xpath('.//wp:menu_order')[0] ?? '0'; - $commentStatus = (string) $children->xpath('.//wp:comment_status')[0] ?? 'open'; - - $categories = []; - foreach ($item->category as $cat) { - $catDomain = (string) $cat['domain'] ?? ''; - $catNicename = (string) $cat['nicename'] ?? ''; - $catName = (string) $cat ?? ''; - - if ($catDomain === 'category' && !empty($catNicename)) { - $categories[] = [ - 'slug' => $catNicename, - 'name' => $catName - ]; + + /** + * Extract all posts/pages from WXR + * + * @return array + */ + public function getPosts() + { + $posts = []; + + $xmlItems = $this->xml->channel->item; + + if (empty($xmlItems)) { + return $posts; + } + + foreach ($xmlItems as $item) { + $children = $item->children(); + $namespaces = $item->getNamespaces(true); + + $postTypeResults = $children->xpath('.//wp:post_type'); + $postType = !empty($postTypeResults) ? (string) $postTypeResults[0] : 'post'; + + if (!in_array($postType, ['post', 'page'])) { + continue; + } + + $title = (string) $item->title ?? ''; + $link = (string) $item->link ?? ''; + $pubDate = (string) $item->pubDate ?? date('Y-m-d H:i:s'); + + $creatorResults = $children->xpath('.//dc:creator'); + $creator = !empty($creatorResults) ? (string) $creatorResults[0] : ''; + + $contentResults = $children->xpath('.//content:encoded'); + $content = !empty($contentResults) ? (string) $contentResults[0] : ''; + + $excerptResults = $children->xpath('.//excerpt:encoded'); + $excerpt = !empty($excerptResults) ? (string) $excerptResults[0] : ''; + + $postIdResults = $children->xpath('.//wp:post_id'); + $postId = !empty($postIdResults) ? (string) $postIdResults[0] : ''; + + $postNameResults = $children->xpath('.//wp:post_name'); + $postName = !empty($postNameResults) ? (string) $postNameResults[0] : ''; + + $statusResults = $children->xpath('.//wp:status'); + $status = !empty($statusResults) ? (string) $statusResults[0] : 'publish'; + + $parentResults = $children->xpath('.//wp:post_parent'); + $parent = !empty($parentResults) ? (string) $parentResults[0] : '0'; + + $menuOrderResults = $children->xpath('.//wp:menu_order'); + $menuOrder = !empty($menuOrderResults) ? (string) $menuOrderResults[0] : '0'; + + $commentStatusResults = $children->xpath('.//wp:comment_status'); + $commentStatus = !empty($commentStatusResults) ? (string) $commentStatusResults[0] : 'open'; + + $categories = []; + foreach ($item->category as $cat) { + $catDomain = (string) $cat['domain'] ?? ''; + $catNicename = (string) $cat['nicename'] ?? ''; + $catName = (string) $cat ?? ''; + + if ($catDomain === 'category' && !empty($catNicename)) { + $categories[] = [ + 'slug' => $catNicename, + 'name' => $catName + ]; + } + } + + $tags = []; + foreach ($item->category as $cat) { + $catDomain = (string) $cat['domain'] ?? ''; + $catNicename = (string) $cat['nicename'] ?? ''; + + if ($catDomain === 'post_tag' && !empty($catNicename)) { + $tags[] = $catNicename; + } + } + + $postCategories = []; + $postTags = []; + + foreach ($item->category as $cat) { + $catDomain = (string) $cat['domain'] ?? ''; + $catNicename = (string) $cat['nicename'] ?? ''; + $catName = (string) $cat ?? ''; + + if ($catDomain === 'category' && !empty($catNicename)) { + $postCategories[] = [ + 'slug' => $catNicename, + 'name' => $catName + ]; + } elseif ($catDomain === 'post_tag' && !empty($catNicename)) { + $postTags[] = $catNicename; + } + } + + $comments = $this->getCommentsFromItem($item, $namespaces); + + $posts[] = [ + 'id' => $postId, + 'title' => $title, + 'slug' => !empty($postName) ? $postName : make_slug($title), + 'content' => $content, + 'excerpt' => $excerpt, + 'type' => $postType, + 'status' => $this->mapPostStatus($status), + 'date' => $this->formatDate($pubDate), + 'author' => $creator, + 'link' => $link, + 'parent' => $parent, + 'menu_order' => $menuOrder, + 'comment_status' => $commentStatus === 'open' ? 'open' : 'closed', + 'categories' => $postCategories, + 'tags' => $postTags, + 'comments' => $comments + ]; } - } - - $tags = []; - foreach ($item->category as $cat) { - $catDomain = (string) $cat['domain'] ?? ''; - $catNicename = (string) $cat['nicename'] ?? ''; - - if ($catDomain === 'post_tag' && !empty($catNicename)) { - $tags[] = $catNicename; + + return $posts; + } + + /** + * Extract comments from post item + * + * @param SimpleXMLElement $item + * @param array $namespaces + * @return array + */ + private function getCommentsFromItem($item, $namespaces) + { + $comments = []; + + $wp = $item->children('wp', true); + + if (!isset($wp->comment)) { + return $comments; } - } - - $postCategories = []; - $postTags = []; - - foreach ($item->category as $cat) { - $catDomain = (string) $cat['domain'] ?? ''; - $catNicename = (string) $cat['nicename'] ?? ''; - $catName = (string) $cat ?? ''; - - if ($catDomain === 'category' && !empty($catNicename)) { - $postCategories[] = [ - 'slug' => $catNicename, - 'name' => $catName - ]; - } elseif ($catDomain === 'post_tag' && !empty($catNicename)) { - $postTags[] = $catNicename; + + foreach ($wp->comment as $comment) { + $commentData = [ + 'author_name' => (string) $comment->comment_author ?? '', + 'author_email' => (string) $comment->comment_author_email ?? '', + 'author_url' => (string) $comment->comment_author_url ?? '', + 'author_ip' => (string) $comment->comment_author_ip ?? '', + 'date' => $this->formatDate((string) $comment->comment_date ?? ''), + 'content' => (string) $comment->comment_content ?? '', + 'status' => $this->mapCommentStatus((string) $comment->comment_approved ?? '1'), + 'parent' => (string) $comment->comment_parent ?? '0' + ]; + + if (!empty($commentData['content'])) { + $comments[] = $commentData; + } } - } - - $comments = $this->getCommentsFromItem($item, $namespaces); - - $posts[] = [ - 'id' => $postId, - 'title' => $title, - 'slug' => !empty($postName) ? $postName : make_slug($title), - 'content' => $content, - 'excerpt' => $excerpt, - 'type' => $postType, - 'status' => $this->mapPostStatus($status), - 'date' => $this->formatDate($pubDate), - 'author' => $creator, - 'link' => $link, - 'parent' => $parent, - 'menu_order' => $menuOrder, - 'comment_status' => $commentStatus === 'open' ? 'open' : 'closed', - 'categories' => $postCategories, - 'tags' => $postTags, - 'comments' => $comments - ]; + + return $comments; } - - return $posts; - } - - /** - * Extract comments from post item - * - * @param SimpleXMLElement $item - * @param array $namespaces - * @return array - */ - private function getCommentsFromItem($item, $namespaces) - { - $comments = []; - - $wp = $item->children('wp', true); - - if (!isset($wp->comment)) { - return $comments; + + /** + * Map WordPress post status to Blogware status + * + * @param string $status + * @return string + */ + private function mapPostStatus($status) + { + $statusMap = [ + 'publish' => 'publish', + 'future' => 'publish', + 'draft' => 'draft', + 'pending' => 'pending', + 'private' => 'private', + 'trash' => 'draft' + ]; + + return $statusMap[$status] ?? 'draft'; } - - foreach ($wp->comment as $comment) { - $commentData = [ - 'author_name' => (string) $comment->comment_author ?? '', - 'author_email' => (string) $comment->comment_author_email ?? '', - 'author_url' => (string) $comment->comment_author_url ?? '', - 'author_ip' => (string) $comment->comment_author_ip ?? '', - 'date' => $this->formatDate((string) $comment->comment_date ?? ''), - 'content' => (string) $comment->comment_content ?? '', - 'status' => $this->mapCommentStatus((string) $comment->comment_approved ?? '1'), - 'parent' => (string) $comment->comment_parent ?? '0' - ]; - - if (!empty($commentData['content'])) { - $comments[] = $commentData; - } + + /** + * Map WordPress comment status to Blogware status + * + * @param string $status + * @return string + */ + private function mapCommentStatus($status) + { + $statusMap = [ + '1' => 'approved', + '0' => 'pending', + 'spam' => 'spam', + 'trash' => 'spam' + ]; + + return $statusMap[$status] ?? 'pending'; } - - return $comments; - } - - /** - * Map WordPress post status to Blogware status - * - * @param string $status - * @return string - */ - private function mapPostStatus($status) - { - $statusMap = [ - 'publish' => 'publish', - 'future' => 'publish', - 'draft' => 'draft', - 'pending' => 'pending', - 'private' => 'private', - 'trash' => 'draft' - ]; - - return $statusMap[$status] ?? 'draft'; - } - - /** - * Map WordPress comment status to Blogware status - * - * @param string $status - * @return string - */ - private function mapCommentStatus($status) - { - $statusMap = [ - '1' => 'approved', - '0' => 'pending', - 'spam' => 'spam', - 'trash' => 'spam' - ]; - - return $statusMap[$status] ?? 'pending'; - } - - /** - * Format date string - * - * @param string $date - * @return string - */ - private function formatDate($date) - { - if (empty($date)) { - return date('Y-m-d H:i:s'); + + /** + * Format date string + * + * @param string $date + * @return string + */ + private function formatDate($date) + { + if (empty($date)) { + return date('Y-m-d H:i:s'); + } + + $timestamp = strtotime($date); + return $timestamp ? date('Y-m-d H:i:s', $timestamp) : date('Y-m-d H:i:s'); } - - $timestamp = strtotime($date); - return $timestamp ? date('Y-m-d H:i:s', $timestamp) : date('Y-m-d H:i:s'); - } - - /** - * Clean XML content - * - * @param string $content - * @return string - */ - private function cleanXmlContent($content) - { - $content = preg_replace('/<\?xml[^>]*encoding="[^"]*"[^>]*\?>/i', '', $content); - $content = preg_replace('/<\?xml[^>]*version="[^"]*"[^>]*\?>/i', '', $content); - - if (stripos($content, ''); - if ($firstTagEnd !== false) { - $content = substr($content, $firstTagEnd + 2); - } + + /** + * Clean XML content + * + * @param string $content + * @return string + */ + private function cleanXmlContent($content) + { + $content = preg_replace('/<\?xml[^>]*encoding="[^"]*"[^>]*\?>/i', '', $content); + $content = preg_replace('/<\?xml[^>]*version="[^"]*"[^>]*\?>/i', '', $content); + + if (stripos($content, ''); + if ($firstTagEnd !== false) { + $content = substr($content, $firstTagEnd + 2); + } + } + + return $content; } - - return $content; - } } diff --git a/src/lib/utility/index.html b/src/lib/utility/index.html old mode 100644 new mode 100755 diff --git a/src/lib/utility/invoke-audio-uploaded.php b/src/lib/utility/invoke-audio-uploaded.php index 44cb33e0f..2ccab0c16 100755 --- a/src/lib/utility/invoke-audio-uploaded.php +++ b/src/lib/utility/invoke-audio-uploaded.php @@ -1,25 +1,21 @@ -'; - - break; - - case "application/vnd.ms-excel": - case "application/vnd.oasis.opendocument.spreadsheet": - - return ''; - - break; - - case "application/msword": - case "application/vnd.oasis.opendocument.text": - - return ''; - - break; - - case "application/vnd.ms-powerpoint": - - return ''; - - break; - - case "application/zip": - case "application/x-rar-compressed": - - return ''; - - break; - - case "audio/mpeg": - case "audio/wav": - case "audio/ogg": - - return ''; - - break; - - case "video/mp4": - case "video/webm": - case "video/ogg": - - return ''; - - break; - - case "image/jpg": - case "image/jpeg": - case "image/png": - case "image/gif": - case "image/webp": - - return ''; - - break; - - default: - - return ''; - - break; - - } - -} \ No newline at end of file + + switch ($media_type) { + case "application/pdf": + return ''; + + break; + + case "application/vnd.ms-excel": + case "application/vnd.oasis.opendocument.spreadsheet": + return ''; + + break; + + case "application/msword": + case "application/vnd.oasis.opendocument.text": + return ''; + + break; + + case "application/vnd.ms-powerpoint": + return ''; + + break; + + case "application/zip": + case "application/x-rar-compressed": + return ''; + + break; + + case "audio/mpeg": + case "audio/wav": + case "audio/ogg": + return ''; + + break; + + case "video/mp4": + case "video/webm": + case "video/ogg": + return ''; + + break; + + case "image/jpg": + case "image/jpeg": + case "image/png": + case "image/gif": + case "image/webp": + return ''; + + break; + + default: + return ''; + + break; + } +} diff --git a/src/lib/utility/invoke-frontimg.php b/src/lib/utility/invoke-frontimg.php index 894f7fbe5..d78badab5 100755 --- a/src/lib/utility/invoke-frontimg.php +++ b/src/lib/utility/invoke-frontimg.php @@ -1,26 +1,23 @@ -setMenuPlugin($plugin_name, plugin_authorizer()); - + + $plugin = new PluginDao(); + + return $plugin->setMenuPlugin($plugin_name, plugin_authorizer()); } /** * plugin_authorizer * * checking user_level and return it - * + * * @return string - * + * */ function plugin_authorizer() { -Authorization::setAuthInstance(new Authentication(new UserDao, new UserTokenDao, new FormValidator())); - -return Authorization::authorizeLevel(); + Authorization::setAuthInstance(new Authentication(new UserDao(), new UserTokenDao(), new FormValidator())); + return Authorization::authorizeLevel(); } /** @@ -42,40 +41,37 @@ function plugin_authorizer() * @param string $plugin_name * @param string $args * @return string|bool -- return false if plugin does not exists - * + * */ function invoke_plugin($plugin_name, $args) { - if ((is_plugin_exist($plugin_name) == true) && (is_plugin_enabled($plugin_name) == true)) { - - $plugin_dir = get_plugin_directory($plugin_name); - - if ($plugin_dir) { - $plugin_path = APP_ROOT . APP_PLUGIN . $plugin_dir; - enable_plugin($plugin_path); - - // Also ensure the plugin class is instantiated to register hooks - $plugin_ini = read_plugin_ini($plugin_path); - if (isset($plugin_ini['plugin_loader'])) { - $plugin_class = $plugin_ini['plugin_loader']; - if (class_exists($plugin_class)) { - new $plugin_class(); - } - } - } - - // Ensure the hook exists to return at least the original args - clip('clip_'.$plugin_name, null, function($val) { return $val; }); - - return clip('clip_'.$plugin_name, $args); - - } else { - - return false; - - } - + if ((is_plugin_exist($plugin_name) == true) && (is_plugin_enabled($plugin_name) == true)) { + $plugin_dir = get_plugin_directory($plugin_name); + + if ($plugin_dir) { + $plugin_path = APP_ROOT . APP_PLUGIN . $plugin_dir; + enable_plugin($plugin_path); + + // Also ensure the plugin class is instantiated to register hooks + $plugin_ini = read_plugin_ini($plugin_path); + if (isset($plugin_ini['plugin_loader'])) { + $plugin_class = $plugin_ini['plugin_loader']; + if (class_exists($plugin_class)) { + new $plugin_class(); + } + } + } + + // Ensure the hook exists to return at least the original args + clip('clip_' . $plugin_name, null, function ($val) { + return $val; + }); + + return clip('clip_' . $plugin_name, $args); + } else { + return false; + } } /** @@ -83,46 +79,44 @@ function invoke_plugin($plugin_name, $args) * * @param string $plugin_name * @return boolean - * + * */ function is_plugin_exist($plugin_name) { - $plugin = new PluginDao(); - - $is_plugin_exists = $plugin->pluginExists($plugin_name); + $plugin = new PluginDao(); - return ($is_plugin_exists) ? true : false; + $is_plugin_exists = $plugin->pluginExists($plugin_name); + return ($is_plugin_exists) ? true : false; } /** * is_plugin_enabled * * checking whether plugin enabled - * + * * @param string $plugin_name * @return boolean - * + * */ function is_plugin_enabled($plugin_name) { - $plugin = new PluginDao(); - - $is_plugin_actived = $plugin->isPluginActived($plugin_name); + $plugin = new PluginDao(); - return ($is_plugin_actived == 'Y') ? true : false; + $is_plugin_actived = $plugin->isPluginActived($plugin_name); + return ($is_plugin_actived == 'Y') ? true : false; } /** * get_plugin_directory - * + * * @param string $plugin_name * @return string|bool */ function get_plugin_directory($plugin_name) { - $plugin = new PluginDao(); - return $plugin->getPluginDirectory($plugin_name); -} \ No newline at end of file + $plugin = new PluginDao(); + return $plugin->getPluginDirectory($plugin_name); +} diff --git a/src/lib/utility/invoke-responsive-image.php b/src/lib/utility/invoke-responsive-image.php new file mode 100644 index 000000000..a3927074a --- /dev/null +++ b/src/lib/utility/invoke-responsive-image.php @@ -0,0 +1,173 @@ +'; + } + + $file_basename = substr($media_filename, 0, strripos($media_filename, '.')); + + // Define sizes + $sizes = [ + 'thumbnail' => ['width' => 640, 'height' => 450, 'prefix' => 'small_', 'folder' => 'small'], + 'medium' => ['width' => 730, 'height' => 486, 'prefix' => 'medium_', 'folder' => 'medium'], + 'large' => ['width' => 1200, 'height' => 630, 'prefix' => 'large_', 'folder' => 'large'], + ]; + + $size_info = $sizes[$size] ?? $sizes['thumbnail']; + $width = $size_info['width']; + $height = $size_info['height']; + $prefix = $size_info['prefix']; + $folder = $size_info['folder']; + + // Paths to check - using APP_IMAGE constants + $base_path = __DIR__ . '/../../' . APP_IMAGE; + $webp_path = $base_path . $file_basename . '.webp'; + $sized_jpg = $base_path . $folder . DS . $prefix . basename($media_filename); + $original_jpg = $base_path . basename($media_filename); + + // Check for WebP + $has_webp = is_readable($webp_path); + + // Build image URL - prefer sized version + if (is_readable($sized_jpg)) { + $image_src = app_url() . DS . APP_IMAGE . $folder . DS . $prefix . rawurlencode(basename($media_filename)); + } elseif (is_readable($original_jpg)) { + $image_src = app_url() . DS . APP_IMAGE . rawurlencode(basename($media_filename)); + } else { + // No image found, return placeholder + return '' . htmlout($alt) . ''; + } + + // Build WebP URL + $webp_src = $has_webp ? app_url() . DS . APP_IMAGE . rawurlencode($file_basename . '.webp') : $image_src; + + $fetchpriority_attr = $fetchpriority ? ' fetchpriority="high"' : ''; + + if ($has_webp) { + return ' + + ' . htmlout($alt) . ' + '; + } else { + return '' . htmlout($alt) . ''; + } +} + +/** + * invoke_hero_image() + * + * Specialized function for hero/LCP images with fetchpriority="high" + * + * @param string $media_filename + * @param string $fallback_url + * @param string $alt + * @return string + */ +function invoke_hero_image($media_filename, $fallback_url = '', $alt = '') +{ + if (empty($media_filename) || $media_filename === 'nophoto') { + $url = !empty($fallback_url) ? $fallback_url : theme_dir() . 'assets/img/hero.jpg'; + return '' . htmlout($alt) . ''; + } + + $file_basename = substr($media_filename, 0, strripos($media_filename, '.')); + + // Paths using APP_IMAGE constants + $base_path = __DIR__ . '/../../' . APP_IMAGE; + $webp_path = $base_path . $file_basename . '.webp'; + $large_jpg = $base_path . 'large' . DS . 'large_' . basename($media_filename); + $original_jpg = $base_path . basename($media_filename); + + $has_webp = is_readable($webp_path); + + if (is_readable($large_jpg)) { + $image_src = app_url() . DS . APP_IMAGE_LARGE . 'large_' . rawurlencode(basename($media_filename)); + } elseif (is_readable($original_jpg)) { + $image_src = app_url() . DS . APP_IMAGE . rawurlencode(basename($media_filename)); + } else { + return '' . htmlout($alt) . ''; + } + + $webp_src = $has_webp ? app_url() . DS . APP_IMAGE . rawurlencode($file_basename . '.webp') : $image_src; + + if ($has_webp) { + return ' + + ' . htmlout($alt) . ' + '; + } else { + return '' . htmlout($alt) . ''; + } +} + +/** + * invoke_gallery_image() + * + * Specialized function for gallery images with lazy loading + * + * @param string $media_filename + * @param string $alt + * @return string + */ +function invoke_gallery_image($media_filename, $alt = '') +{ + if (empty($media_filename) || $media_filename === 'nophoto') { + return '' . htmlout($alt) . ''; + } + + $file_basename = substr($media_filename, 0, strripos($media_filename, '.')); + + // Paths using APP_IMAGE constants + $base_path = __DIR__ . '/../../' . APP_IMAGE; + $webp_path = $base_path . $file_basename . '.webp'; + $medium_jpg = $base_path . 'medium' . DS . 'medium_' . basename($media_filename); + $original_jpg = $base_path . basename($media_filename); + + $has_webp = is_readable($webp_path); + + if (is_readable($medium_jpg)) { + $image_src = app_url() . DS . APP_IMAGE_MEDIUM . 'medium_' . rawurlencode(basename($media_filename)); + } elseif (is_readable($original_jpg)) { + $image_src = app_url() . DS . APP_IMAGE . rawurlencode(basename($media_filename)); + } else { + return '' . htmlout($alt) . ''; + } + + $webp_src = $has_webp ? app_url() . DS . APP_IMAGE . rawurlencode($file_basename . '.webp') : $image_src; + + if ($has_webp) { + return ' + + ' . htmlout($alt) . ' + '; + } else { + return '' . htmlout($alt) . ''; + } +} diff --git a/src/lib/utility/invoke-video-uploaded.php b/src/lib/utility/invoke-video-uploaded.php index 8832ba30b..8f6e2684d 100755 --- a/src/lib/utility/invoke-video-uploaded.php +++ b/src/lib/utility/invoke-video-uploaded.php @@ -1,29 +1,25 @@ =')) { - - return str_starts_with($haystack, $needle); - - } else { - - return substr_compare($haystack, $needle, 0, strlen($needle)) === 0; - - } - + if (version_compare(PHP_VERSION, '7.4', '>=')) { + return str_starts_with($haystack, $needle); + } else { + return substr_compare($haystack, $needle, 0, strlen($needle)) === 0; + } } /** * ends_with * * @category function - * @see https://stackoverflow.com/questions/834303/startswith-and-endswith-functions-in-php + * @see https://stackoverflow.com/questions/834303/startswith-and-endswith-functions-in-php * @param string $haystack * @param string $needle * @return void - * + * */ function ends_with($haystack, $needle) { - if (version_compare(PHP_VERSION, '7.4', '>=')) { - - return str_ends_with($haystack, $needle); - - } else { - - return substr_compare($haystack, $needle, -strlen($needle)) === 0; - - } - -} \ No newline at end of file + if (version_compare(PHP_VERSION, '7.4', '>=')) { + return str_ends_with($haystack, $needle); + } else { + return substr_compare($haystack, $needle, -strlen($needle)) === 0; + } +} diff --git a/src/lib/utility/is-json-valid.php b/src/lib/utility/is-json-valid.php old mode 100644 new mode 100755 index e8d56499f..50708a38c --- a/src/lib/utility/is-json-valid.php +++ b/src/lib/utility/is-json-valid.php @@ -1,17 +1,18 @@ -accessLevel(); - - if ($accessLevel !== 'administrator') { - - $user_level = true; - - } else { + $user_level = false; - $user_level = false; + $userDao = class_exists('UserDao') ? new UserDao() : ""; + $userToken = class_exists('UserTokenDao') ? new UserTokenDao() : ""; + $validator = class_exists('FormValidator') ? new FormValidator() : ""; + $authenticator = class_exists('Authentication') ? new Authentication($userDao, $userToken, $validator) : ""; - } + $accessLevel = $authenticator->accessLevel(); - return $user_level; + if ($accessLevel !== 'administrator') { + $user_level = true; + } else { + $user_level = false; + } -} \ No newline at end of file + return $user_level; +} diff --git a/src/lib/utility/is-ssl.php b/src/lib/utility/is-ssl.php index 117b5814a..1e1e2aa7c 100755 --- a/src/lib/utility/is-ssl.php +++ b/src/lib/utility/is-ssl.php @@ -1,7 +1,8 @@ $limit) { - $words = str_word_count($text, 2); - $pos = array_keys($words); - $text = substr($text, 0, $pos[$limit]).'...'; - } + if (str_word_count($text, 0) > $limit) { + $words = str_word_count($text, 2); + $pos = array_keys($words); + $text = substr($text, 0, $pos[$limit]) . '...'; + } - return $text; + return $text; } /** @@ -32,5 +33,5 @@ function limit_word($args, $limit) */ function str_word_count_utf8($str) { - return count(preg_split('~[^\p{L}\p{N}\']+~u',$str)); -} \ No newline at end of file + return count(preg_split('~[^\p{L}\p{N}\']+~u', $str)); +} diff --git a/src/lib/utility/login-attempt.php b/src/lib/utility/login-attempt.php index 99d84a0df..76c07a1c5 100755 --- a/src/lib/utility/login-attempt.php +++ b/src/lib/utility/login-attempt.php @@ -1,4 +1,5 @@ get_result()->fetch_assoc(); - + $result = db_prepared_query($sql, [$ip], "s"); + return fetch_assoc($result); } /** @@ -27,15 +27,12 @@ function get_login_attempt($ip) * * @param string $ip * @return void - * + * */ function create_login_attempt($ip) { - - $sql = "INSERT INTO tbl_login_attempt (ip_address, login_date) VALUES (?, NOW())"; - - return db_prepared_query($sql, [$ip], "s"); - + $sql = "INSERT INTO tbl_login_attempt (ip_address, login_date) VALUES (?, NOW())"; + return db_prepared_query($sql, [$ip], "s"); } /** @@ -43,15 +40,12 @@ function create_login_attempt($ip) * * @param string $ip * @return void - * + * */ function delete_login_attempt($ip) { - - $sql = "DELETE FROM tbl_login_attempt WHERE ip_address = ?"; - - return db_prepared_query($sql, [$ip], "s"); - + $sql = "DELETE FROM tbl_login_attempt WHERE ip_address = ?"; + return db_prepared_query($sql, [$ip], "s"); } /** @@ -59,27 +53,22 @@ function delete_login_attempt($ip) * * @param string $user_login * @return array - * + * */ function get_user_signin($user_login) { - -if (filter_var($user_login, FILTER_VALIDATE_EMAIL)) { - - $sql = "SELECT ID, user_login, user_email, user_pass, user_level, user_fullname, user_url, user_registered, + if (filter_var($user_login, FILTER_VALIDATE_EMAIL)) { + $sql = "SELECT ID, user_login, user_email, user_pass, user_level, user_fullname, user_url, user_registered, user_session, user_banned, user_signin_count, user_locked_until, login_time FROM tbl_users WHERE user_email = ? LIMIT 1"; - -} else { - - $sql = "SELECT ID, user_login, user_email, user_pass, user_level, user_fullname, user_url, user_registered, + } else { + $sql = "SELECT ID, user_login, user_email, user_pass, user_level, user_fullname, user_url, user_registered, user_session, user_banned, user_signin_count, user_locked_until, login_time FROM tbl_users WHERE user_login = ? LIMIT 1"; + } -} - -return db_prepared_query($sql, [$user_login], "s")->get_result()->fetch_assoc(); - + $result = db_prepared_query($sql, [$user_login], "s"); + return fetch_assoc($result); } /** @@ -88,24 +77,17 @@ function get_user_signin($user_login) * @param int|numeric $sign_in_count * @param string $login * @return void - * + * */ function sign_in_count($sign_in_count, $login) { + if (filter_var($login, FILTER_VALIDATE_EMAIL)) { + $sql = "UPDATE tbl_users SET user_signin_count = ? WHERE user_email = ?"; + } else { + $sql = "UPDATE tbl_users SET user_signin_count = ? WHERE user_login = ?"; + } -if (filter_var($login, FILTER_VALIDATE_EMAIL)) { - - $sql = "UPDATE tbl_users SET user_signin_count = ? WHERE user_email = ?"; - - -} else { - - $sql = "UPDATE tbl_users SET user_signin_count = ? WHERE user_login = ?"; - -} - -return db_prepared_query($sql, [$sign_in_count, $login], "is"); - + return db_prepared_query($sql, [$sign_in_count, $login], "is"); } /** @@ -115,23 +97,17 @@ function sign_in_count($sign_in_count, $login) * @param string $locked_until * @param string $login * @return void - * + * */ function locked_down_until($sign_in_count, $locked_until, $login) { + if (filter_var($login, FILTER_VALIDATE_EMAIL)) { + $sql = "UPDATE tbl_users SET user_signin_count = ?, user_locked_until = ? WHERE user_email = ?"; + } else { + $sql = "UPDATE tbl_users SET user_signin_count = ?, user_locked_until = ? WHERE user_login = ?"; + } -if (filter_var($login, FILTER_VALIDATE_EMAIL)) { - - $sql = "UPDATE tbl_users SET user_signin_count = ?, user_locked_until = ? WHERE user_email = ?"; - -} else { - - $sql = "UPDATE tbl_users SET user_signin_count = ?, user_locked_until = ? WHERE user_login = ?"; - -} - -return db_prepared_query($sql, [$sign_in_count, $locked_until, $login], "iss"); - + return db_prepared_query($sql, [$sign_in_count, $locked_until, $login], "iss"); } /** @@ -139,23 +115,17 @@ function locked_down_until($sign_in_count, $locked_until, $login) * * @param string $login * @return void - * + * */ function signin_count_to_zero($login) { + if (filter_var($login, FILTER_VALIDATE_EMAIL)) { + $sql = "UPDATE tbl_users SET user_signin_count = 0 WHERE user_email = ?"; + } else { + $sql = "UPDATE tbl_users SET user_signin_count = 0 WHERE user_login = ?"; + } -if (filter_var($login, FILTER_VALIDATE_EMAIL)) { - - $sql = "UPDATE tbl_users SET user_signin_count = 0 WHERE user_email = ?"; - -} else { - - $sql = "UPDATE tbl_users SET user_signin_count = 0 WHERE user_login = ?"; - -} - -return db_prepared_query($sql, [$login], 's'); - + return db_prepared_query($sql, [$login], 's'); } /** @@ -163,23 +133,17 @@ function signin_count_to_zero($login) * * @param string $login * @return void - * + * */ function locked_down_to_null($login) { + if (filter_var($login, FILTER_VALIDATE_EMAIL)) { + $sql = "UPDATE tbl_users SET user_locked_until = null WHERE user_email = ?"; + } else { + $sql = "UPDATE tbl_users SET user_locked_until = null WHERE user_login = ?"; + } -if (filter_var($login, FILTER_VALIDATE_EMAIL)) { - -$sql = "UPDATE tbl_users SET user_locked_until = null WHERE user_email = ?"; - -} else { - -$sql = "UPDATE tbl_users SET user_locked_until = null WHERE user_login = ?"; - -} - -return db_prepared_query($sql, [$login], 's'); - + return db_prepared_query($sql, [$login], 's'); } /** @@ -189,20 +153,32 @@ function locked_down_to_null($login) * @author M.Noermoehammad * @param string $ip * @return array - * + * */ function alert_login_attempt($ip) { + if (filter_var($ip, FILTER_VALIDATE_IP)) { + $sql = "SELECT count(ip_address) AS alert_login_attempt + FROM tbl_login_attempt + WHERE ip_address = ? + AND login_date >= DATE_SUB(NOW(), INTERVAL 1 DAY)"; + + $result = db_prepared_query($sql, [$ip], "s"); + return fetch_assoc($result); + } +} - if (filter_var($ip, FILTER_VALIDATE_IP)) { - - $sql = "SELECT count(ip_address) AS alert_login_attempt - FROM tbl_login_attempt - WHERE ip_address = ? - AND login_date = NOW()"; - - return db_prepared_query($sql, [$ip], "s")->get_result()->fetch_assoc(); - - } - +/** + * fetch_assoc - Helper to get associative array from result (PDO/mysqli compatible) + */ +function fetch_assoc($result) +{ + if ($result instanceof PDOStatement) { + return $result->fetch(PDO::FETCH_ASSOC) ?: []; + } elseif (method_exists($result, 'get_result')) { + return $result->get_result()->fetch_assoc() ?: []; + } elseif (method_exists($result, 'fetch_assoc')) { + return $result->fetch_assoc() ?: []; + } + return []; } \ No newline at end of file diff --git a/src/lib/utility/make-date.php b/src/lib/utility/make-date.php index 78918a870..21df9868c 100755 --- a/src/lib/utility/make-date.php +++ b/src/lib/utility/make-date.php @@ -1,7 +1,8 @@ 'mysql', + 'host' => isset($read_config['db']['host']) ? $read_config['db']['host'] : "", + 'database' => isset($read_config['db']['name']) ? $read_config['db']['name'] : "", + 'username' => isset($read_config['db']['user']) ? $read_config['db']['user'] : "", + 'password' => isset($read_config['db']['pass']) ? $read_config['db']['pass'] : "", + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_general_ci', + 'port' => isset($read_config['db']['port']) ? $read_config['db']['port'] : "" + ]; + + return (class_exists('MedooInit')) ? MedooInit::connect($configuration) : ""; +} + +/** + * is_medoo_database + * Check if database object is Db (has Db methods) + * Returns true for both Db class and Medoo class + */ +function is_medoo_database($database) +{ + if (!is_object($database)) { + return false; + } + // Check for Db class (PDO wrapper with table prefix support) + if (method_exists($database, 'dbSelect')) { + return true; + } + // Check for Medoo class (has Medoo methods) + return method_exists($database, 'select'); +} + +/** + * is_db_database + * Check if database object is Db class + */ +function is_db_database($database) +{ + return is_object($database) && method_exists($database, 'dbSelect'); +} + +/** + * Build WHERE clause from Medoo-style where array + * + * @param array $where Medoo-style where conditions + * @return array ['sql' => string, 'params' => array] + */ +function db_build_where($where) +{ + if (empty($where)) { + return ['sql' => '', 'params' => []]; + } - $configuration = [ - 'type' => 'mysql', - 'host' => isset($read_config['db']['host']) ? $read_config['db']['host'] : "", - 'database' => isset($read_config['db']['name']) ? $read_config['db']['name'] : "", - 'username' => isset($read_config['db']['user']) ? $read_config['db']['user'] : "", - 'password' => isset($read_config['db']['pass']) ? $read_config['db']['pass'] : "", - 'charset' => 'utf8mb4', - 'collation'=> 'utf8mb4_general_ci', - 'port' => isset($read_config['db']['port']) ? $read_config['db']['port'] : "" - ]; + $conditions = []; + $params = []; - return (class_exists('MedooInit')) ? MedooInit::connect($configuration) : ""; + foreach ($where as $key => $value) { + if (is_array($value)) { + // Handle IN clause: ['column' => ['value1', 'value2']] + $placeholders = implode(', ', array_fill(0, count($value), '?')); + $conditions[] = "`{$key}` IN ({$placeholders})"; + $params = array_merge($params, array_values($value)); + } elseif (strpos($key, '>') !== false || strpos($key, '<') !== false || strpos($key, '!') !== false) { + // Handle operators: 'column>' => value, 'column<' => value, 'column!' => value + $op = ''; + if (strpos($key, '>=') !== false) { + $col = str_replace('>=', '', $key); + $op = '>='; + } elseif (strpos($key, '<=') !== false) { + $col = str_replace('<=', '', $key); + $op = '<='; + } elseif (strpos($key, '!=') !== false) { + $col = str_replace('!=', '', $key); + $op = '!='; + } elseif (strpos($key, '>') !== false) { + $col = str_replace('>', '', $key); + $op = '>'; + } elseif (strpos($key, '<') !== false) { + $col = str_replace('<', '', $key); + $op = '<'; + } + $conditions[] = "`" . trim($col) . "` {$op} ?"; + $params[] = $value; + } elseif ($key === 'OR') { + // Handle OR conditions + $orConditions = []; + foreach ($value as $orKey => $orValue) { + $orConditions[] = "`{$orKey}` = ?"; + $params[] = $orValue; + } + $conditions[] = '(' . implode(' OR ', $orConditions) . ')'; + } else { + $conditions[] = "`{$key}` = ?"; + $params[] = $value; + } + } + $sql = !empty($conditions) ? ' WHERE ' . implode(' AND ', $conditions) : ''; + return ['sql' => $sql, 'params' => $params]; } /** * medoo_column() - * + * * select data from the table * * @category function - * @param string $select + * @param string $table * @param string|array $columns * @return array|mixed - * + * */ function medoo_column($table, $columns) { - $database = medoo_init(); - return $database->select($table, $columns); + $database = medoo_init(); + if (is_medoo_database($database)) { + // If it's Db class (has dbSelect), build SQL query + if (is_db_database($database)) { + $cols = is_array($columns) ? implode(', ', $columns) : $columns; + $sql = "SELECT {$cols} FROM {$table}"; + // Use FETCH_ASSOC to return associative array (matches Medoo behavior) + return $database->dbSelect($sql, [], PDO::FETCH_ASSOC); + } + // Medoo class + return $database->select($table, $columns); + } + return []; } /** @@ -50,15 +157,27 @@ function medoo_column($table, $columns) * * @category function * @param string $table - * @param string|array $column - * @param array|option $where + * @param string|array $columns + * @param array $where * @return mixed|array - * + * */ function medoo_column_where($table, $columns, $where) { - $database = medoo_init(); - return $database->select($table, $columns, $where); + $database = medoo_init(); + if (is_medoo_database($database)) { + // If it's Db class (has dbSelect), build SQL query + if (is_db_database($database)) { + $cols = is_array($columns) ? implode(', ', $columns) : $columns; + $whereClause = db_build_where($where); + $sql = "SELECT {$cols} FROM {$table}" . $whereClause['sql']; + // Use FETCH_ASSOC to return associative array (matches Medoo behavior) + return $database->dbSelect($sql, $whereClause['params'], PDO::FETCH_ASSOC); + } + // Medoo class + return $database->select($table, $columns, $where); + } + return []; } /** @@ -68,34 +187,77 @@ function medoo_column_where($table, $columns, $where) * @param array $join * @param array|string $columns * @param array $where - * + * */ function medoo_join($table, $join, $columns, $where) { - $database = medoo_init(); - return $database->select($table, $join, $columns, $where); + $database = medoo_init(); + if (is_medoo_database($database)) { + // If it's Db class, we need to build SQL manually for JOINs + if (is_db_database($database)) { + // Build JOIN clause from join array + // Format: ['>' => 'table2.table_id:tbl_posts.post_id'] or ['JOIN_TYPE' => 'table2 ON table2.id = table1.id'] + $joinClauses = []; + foreach ($join as $type => $condition) { + $joinType = trim($type); + if (strtoupper($joinType) === '>' || strtoupper($joinType) === '[>]') { + $joinType = 'LEFT JOIN'; + } elseif (strtoupper($joinType) === '<' || strtoupper($joinType) === '[<]') { + $joinType = 'RIGHT JOIN'; + } elseif (strtoupper($joinType) === '<>' || strtoupper($joinType) === '[<>]') { + $joinType = 'INNER JOIN'; + } + + if (is_string($condition) && strpos($condition, ':') !== false) { + // Medoo shorthand: 'table.column:other_table.other_column' + list($left, $right) = explode(':', $condition); + $joinClauses[] = "{$joinType} {$left} ON {$left} = {$right}"; + } elseif (is_string($condition)) { + $joinClauses[] = "{$joinType} {$condition}"; + } + } + + $cols = is_array($columns) ? implode(', ', $columns) : $columns; + $whereClause = db_build_where($where); + $sql = "SELECT {$cols} FROM {$table} " . implode(' ', $joinClauses) . $whereClause['sql']; + // Use FETCH_ASSOC to return associative array (matches Medoo behavior) + return $database->dbSelect($sql, $whereClause['params'], PDO::FETCH_ASSOC); + } + // Medoo class + return $database->select($table, $join, $columns, $where); + } + return []; } /** * medoo_fetch_callback * * @param string $table - * @param array $column + * @param array $columns * @param array $where - * + * */ function medoo_fetch_callback($table, $columns, $where) { - $database = medoo_init(); - - if (method_exists($database, 'select')) { + $database = medoo_init(); - return $database->select($table, $columns, $where, function ($data) { - return $data; - }); - - } - + if (is_medoo_database($database)) { + // If it's Db class, process callback manually + if (is_db_database($database)) { + $cols = is_array($columns) ? implode(', ', $columns) : $columns; + $whereClause = db_build_where($where); + $sql = "SELECT {$cols} FROM {$table}" . $whereClause['sql']; + $result = $database->dbSelect($sql, $whereClause['params'], PDO::FETCH_ASSOC); + return array_map(function ($data) { + return $data; + }, $result); + } + // Medoo class + return $database->select($table, $columns, $where, function ($data) { + return $data; + }); + } + return []; } /** @@ -103,14 +265,27 @@ function medoo_fetch_callback($table, $columns, $where) * * @param string $table * @param string|array $columns - * @param optional|array $where + * @param array $where * @see https://medoo.in/api/get - * + * */ function medoo_get_where($table, $columns, $where) { - $database = medoo_init(); - return (method_exists($database, 'get')) ? $database->get($table, $columns, $where) : ""; + $database = medoo_init(); + if (is_medoo_database($database)) { + // If it's Db class, build SQL query and return first result + if (is_db_database($database)) { + $cols = is_array($columns) ? implode(', ', $columns) : $columns; + $whereClause = db_build_where($where); + $sql = "SELECT {$cols} FROM {$table}" . $whereClause['sql']; + // Use FETCH_ASSOC to return associative array (matches Medoo behavior) + $result = $database->dbSelect($sql, $whereClause['params'], PDO::FETCH_ASSOC); + return !empty($result) ? $result[0] : null; + } + // Medoo class + return $database->get($table, $columns, $where); + } + return ""; } /** @@ -124,8 +299,38 @@ function medoo_get_where($table, $columns, $where) */ function medoo_get_join($table, $join, $columns, $where) { - $database = medoo_init(); - return $database->get($table, $join, $columns, $where); + $database = medoo_init(); + if (is_medoo_database($database)) { + // If it's Db class, build SQL manually + if (is_db_database($database)) { + $joinClauses = []; + foreach ($join as $type => $condition) { + $joinType = trim($type); + if (strtoupper($joinType) === '>' || strtoupper($joinType) === '[>]') { + $joinType = 'LEFT JOIN'; + } elseif (strtoupper($joinType) === '<') { + $joinType = 'RIGHT JOIN'; + } + + if (is_string($condition) && strpos($condition, ':') !== false) { + list($left, $right) = explode(':', $condition); + $joinClauses[] = "{$joinType} {$left} ON {$left} = {$right}"; + } elseif (is_string($condition)) { + $joinClauses[] = "{$joinType} {$condition}"; + } + } + + $cols = is_array($columns) ? implode(', ', $columns) : $columns; + $whereClause = db_build_where($where); + $sql = "SELECT {$cols} FROM {$table} " . implode(' ', $joinClauses) . $whereClause['sql']; + // Use FETCH_ASSOC to return associative array (matches Medoo behavior) + $result = $database->dbSelect($sql, $whereClause['params'], PDO::FETCH_ASSOC); + return !empty($result) ? $result[0] : null; + } + // Medoo class + return $database->get($table, $join, $columns, $where); + } + return null; } /** @@ -133,12 +338,20 @@ function medoo_get_join($table, $join, $columns, $where) * * @param string $table * @param array $values - * + * */ function medoo_insert($table, $values) { - $database = medoo_init(); - return $database->insert($table, $values); + $database = medoo_init(); + if (is_medoo_database($database)) { + // If it's Db class, use dbInsert + if (is_db_database($database)) { + return $database->dbInsert($table, $values); + } + // Medoo class + return $database->insert($table, $values); + } + return false; } /** @@ -147,27 +360,48 @@ function medoo_insert($table, $values) * @param string $table * @param array $data * @param array $where - * @return object PDOStatement + * @return int|bool */ -function medoo_update($table, $column, $where) +function medoo_update($table, $data, $where) { - $database = medoo_init(); - return (method_exists($database, 'update')) ? $database->update($table, $column, $where) : ""; + $database = medoo_init(); + if (is_medoo_database($database)) { + // If it's Db class, use dbUpdate + if (is_db_database($database)) { + return $database->dbUpdate($table, $data, $where); + } + // Medoo class + return $database->update($table, $data, $where); + } + return false; } /** * medoo_replace * * @param string $table - * @param array $column + * @param array $data * @param array $where - * @return object PDOStatement - * + * @return bool + * */ -function medoo_replace($table, $column, $where) +function medoo_replace($table, $data, $where) { - $database = medoo_init(); - return (method_exists($database, 'replace')) ? $database->replace($table, $column, $where) : ""; + $database = medoo_init(); + if (is_medoo_database($database)) { + // If it's Db class, use dbReplace + if (is_db_database($database)) { + // Medoo's replace is INSERT ... ON DUPLICATE KEY UPDATE + // Db class has dbReplace which does the same + // We need to separate insert values and update values + // For simplicity, assume $data contains both insert and update values + // This is a simplified version - full implementation would need separate params + return $database->dbReplace($table, $data, $data); + } + // Medoo class + return $database->replace($table, $data, $where); + } + return false; } /** @@ -175,10 +409,18 @@ function medoo_replace($table, $column, $where) * * @param string $table * @param array $where - * @return object PDOStatement + * @return int|bool */ function medoo_delete($table, $where) { - $database = medoo_init(); - return (method_exists($database, 'delete')) ? $database->delete($table, $where) : ""; -} \ No newline at end of file + $database = medoo_init(); + if (is_medoo_database($database)) { + // If it's Db class, use dbDelete + if (is_db_database($database)) { + return $database->dbDelete($table, $where); + } + // Medoo class + return $database->delete($table, $where); + } + return false; +} diff --git a/src/lib/utility/membership.php b/src/lib/utility/membership.php old mode 100644 new mode 100755 index 729d269f4..2c13dee59 --- a/src/lib/utility/membership.php +++ b/src/lib/utility/membership.php @@ -1,4 +1,5 @@ * @param int|num $id * @return bool|true|false - * + * */ function is_registration_unable() { - $membership_data = is_array(is_membership_setting_available()) ? is_membership_setting_available() : ""; + $membership_data = is_array(is_membership_setting_available()) ? is_membership_setting_available() : ""; + + $id_setting = isset($membership_data['ID']) ? $membership_data['ID'] : ""; - $id_setting = isset($membership_data['ID']) ? $membership_data['ID'] : ""; - - if (function_exists('sanitizer')) { + if (function_exists('sanitizer') && !empty($id_setting)) { + $idsanitized = sanitizer($id_setting, 'sql'); - $idsanitized = sanitizer($id_setting, 'sql'); + $is_registration_unabled = medoo_get_where("tbl_settings", ["setting_value"], ["ID" => $idsanitized]); - $is_registration_unabled = medoo_get_where("tbl_settings", "setting_value", ["ID" => $idsanitized]); + if (empty($is_registration_unabled)) { + return false; + } - $can_register = json_decode($is_registration_unabled, true); + $can_register = json_decode($is_registration_unabled['setting_value'], true); - return ($can_register['user_can_register'] == '1') ? true : false; - } + return (isset($can_register['user_can_register']) && $can_register['user_can_register'] == '1') ? true : false; + } + + return false; } /** @@ -33,24 +39,29 @@ function is_registration_unable() * @category function * @author Nirmala Khanza * @return mixed - * + * */ function membership_default_role() { - $membership_data = is_array(is_membership_setting_available()) ? is_membership_setting_available() : ""; + $membership_data = is_array(is_membership_setting_available()) ? is_membership_setting_available() : ""; - $id_setting = isset($membership_data['ID']) ? $membership_data['ID'] : ""; + $id_setting = isset($membership_data['ID']) ? $membership_data['ID'] : ""; - if (function_exists('sanitizer')) { + if (function_exists('sanitizer') && !empty($id_setting)) { + $idsanitized = sanitizer($id_setting, 'sql'); - $idsanitized = sanitizer($id_setting, 'sql'); + $retrieve_default_role = medoo_get_where("tbl_settings", ["setting_value"], ["ID" => $idsanitized]); - $retrieve_default_role = medoo_get_where("tbl_settings", "setting_value", ["ID" => $idsanitized]); + if (empty($retrieve_default_role)) { + return ""; + } - $default_role = json_decode($retrieve_default_role, true); + $default_role = json_decode($retrieve_default_role['setting_value'], true); - return $default_role['default_role']; - } + return isset($default_role['default_role']) ? $default_role['default_role'] : ""; + } + + return ""; } /** @@ -59,14 +70,13 @@ function membership_default_role() * @category function * @author Nirmala Khanza * @return mixed - * + * */ function is_membership_setting_available() { - if (function_exists('medoo_get_where')) { + if (function_exists('medoo_get_where')) { + $grab_setting = medoo_get_where("tbl_settings", ["ID", "setting_name", "setting_value"], ["setting_name" => "membership_setting"]); - $grab_setting = medoo_get_where("tbl_settings", ["ID", "setting_name", "setting_value"], ["setting_name" => "membership_setting"]); - - return is_iterable($grab_setting) ? $grab_setting : array(); - } -} \ No newline at end of file + return is_iterable($grab_setting) ? $grab_setting : array(); + } +} diff --git a/src/lib/utility/mime-type-dictionary.php b/src/lib/utility/mime-type-dictionary.php index 4fa3f02fd..58a9fcfcc 100755 --- a/src/lib/utility/mime-type-dictionary.php +++ b/src/lib/utility/mime-type-dictionary.php @@ -1,54 +1,54 @@ 'image/png', - 'jpe' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'gif' => 'image/gif', - 'bmp' => 'image/bmp', - 'webp' => 'image/webp', - - // archives - 'zip' => 'application/zip', - - // audio/video - 'mp3' => 'audio/mpeg', - 'wav' => 'audio/wav', - 'ogg' => 'audio/ogg', - 'mp4' => 'video/mp4', - 'ogv' => 'video/ogg', - 'webm' => 'video/webm', - - // adobe - 'pdf' => 'application/pdf', - - // ms office - 'doc' => 'application/msword', - 'docx' => 'application/msword', - 'rtf' => 'application/rtf', - 'xls' => 'application/vnd.ms-excel', - 'xlsx' => 'application/vnd.ms-excel', - 'ppt' => 'application/vnd.ms-powerpoint', - 'pptx' => 'application/vnd.ms-powerpoint', - - // open office - 'odt' => 'application/vnd.oasis.opendocument.text', - 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', - - ]; - - return $mime_types; - -} \ No newline at end of file + $mime_types = [ + + // images + 'png' => 'image/png', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'gif' => 'image/gif', + 'bmp' => 'image/bmp', + 'webp' => 'image/webp', + + // archives + 'zip' => 'application/zip', + + // audio/video + 'mp3' => 'audio/mpeg', + 'wav' => 'audio/wav', + 'ogg' => 'audio/ogg', + 'mp4' => 'video/mp4', + 'ogv' => 'video/ogg', + 'webm' => 'video/webm', + + // adobe + 'pdf' => 'application/pdf', + + // ms office + 'doc' => 'application/msword', + 'docx' => 'application/msword', + 'rtf' => 'application/rtf', + 'xls' => 'application/vnd.ms-excel', + 'xlsx' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptx' => 'application/vnd.ms-powerpoint', + + // open office + 'odt' => 'application/vnd.oasis.opendocument.text', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + + ]; + + return $mime_types; +} diff --git a/src/lib/utility/navigation-helper.php b/src/lib/utility/navigation-helper.php index cdc0f51d2..1833a9037 100755 --- a/src/lib/utility/navigation-helper.php +++ b/src/lib/utility/navigation-helper.php @@ -1,21 +1,21 @@ fetch_array(MYSQLI_ASSOC) : ""; - - return (is_iterable($row)) ? $row : []; + $row = (is_object($parent)) ? $parent->fetch_array(MYSQLI_ASSOC) : ""; -} \ No newline at end of file + return (is_iterable($row)) ? $row : []; +} diff --git a/src/lib/utility/notfound-id.php b/src/lib/utility/notfound-id.php index 7bea55f87..dcdd9f227 100755 --- a/src/lib/utility/notfound-id.php +++ b/src/lib/utility/notfound-id.php @@ -1,17 +1,18 @@ + $site_info = function_exists('app_info') ? app_info() : ""; + $app_url = isset($site_info['app_url']) ? $site_info['app_url'] : ""; + $site_name = isset($site_info['site_name']) ? $site_info['site_name'] : ""; + $activation_key = function_exists('') ? user_activation_key($recipient . get_ip_address()) : ""; + $sender = isset($site_info['email_address']) ? $site_info['email_address'] : ""; + $sanitize_sender = function_exists('sanitize_email') ? sanitize_email($sender) : ""; + + $mailer = class_exists('Mailer') ? new Mailer() : ""; + + $subject = "Join for The Best Team in Town!"; + $content = " If you never ask to be a user at {$site_name}. please feel free to ignore this email. But if you are asking for this information, @@ -30,29 +31,24 @@ function notify_new_user($recipient, $user_pass) Email address:{$recipient}
Password:{$user_pass}
Activate your account by clicking the link below:
- Activate My Account

+ Activate My Account

Thank you,
{$site_name} "; - - // Define Headers - $email_headers = 'From '. $sanitize_sender . "\r\n" . - 'Reply-To: '. $sanitize_sender . "\r\n" . - 'Return-Path: '. $sanitize_sender . "\r\n". - 'MIME-Version: 1.0'. "\r\n". - 'Content-Type: text/html; charset=utf-8'."\r\n". - 'X-Mailer: PHP/' . phpversion(). "\r\n" . - 'X-Priority: 1'. "\r\n". - 'X-Sender:'.$sanitize_sender."\r\n"; - + + // Define Headers + $email_headers = 'From ' . $sanitize_sender . "\r\n" . + 'Reply-To: ' . $sanitize_sender . "\r\n" . + 'Return-Path: ' . $sanitize_sender . "\r\n" . + 'MIME-Version: 1.0' . "\r\n" . + 'Content-Type: text/html; charset=utf-8' . "\r\n" . + 'X-Mailer: PHP/' . phpversion() . "\r\n" . + 'X-Priority: 1' . "\r\n" . + 'X-Sender:' . $sanitize_sender . "\r\n"; + if (filter_var($recipient, FILTER_SANITIZE_EMAIL)) { - if ((filter_var($recipient, FILTER_VALIDATE_EMAIL)) && (false === $mailer->send($recipient, $subject, $content, $email_headers))) { - scriptlog_error("E-mail notification fail to sent", E_USER_ERROR); - } - } - -} \ No newline at end of file +} diff --git a/src/lib/utility/number-cpus.php b/src/lib/utility/number-cpus.php index 17cdf0718..cb38ea8fa 100755 --- a/src/lib/utility/number-cpus.php +++ b/src/lib/utility/number-cpus.php @@ -1,4 +1,5 @@ title($title) ->description($description) ->meta('author', $author) @@ -84,22 +82,21 @@ function generate_meta_tags($title = "", $description = "", $author = "", $image ->meta('robots', "index, follow") ->canonical($canonical); } else { - - $metatags->title($title) + $metatags->title($title) ->description($description) ->meta('author', $author) ->meta('keywords', app_info()['site_keywords']) ->meta('robots', "index, nofollow") ->canonical($canonical); } - + // Open graph (og) Facebook $metatags->og('type', 'website') ->og('url', $canonical) ->og('image', $image) ->og('site_name', app_info()['site_name']); - // Twitter card Tags - X.com + // Twitter card Tags - X.com $metatags->twitter('card', 'summary_large_image') ->twitter('site', '@getscriptlog') ->twitter('creator', $author) diff --git a/src/lib/utility/page-cache.php b/src/lib/utility/page-cache.php new file mode 100644 index 000000000..848fe4d25 --- /dev/null +++ b/src/lib/utility/page-cache.php @@ -0,0 +1,136 @@ +"); + } + } +} + +/** + * Clear all cached pages. + * + * @return void + */ +function page_cache_clear() +{ + if (is_dir(APP_CACHE_DIR)) { + $files = glob(APP_CACHE_DIR . '*.html'); + foreach ($files as $file) { + if (is_file($file)) { + unlink($file); + } + } + } +} diff --git a/src/lib/utility/paragraph-trim.php b/src/lib/utility/paragraph-trim.php index 5095d7e61..3f254bcf8 100755 --- a/src/lib/utility/paragraph-trim.php +++ b/src/lib/utility/paragraph-trim.php @@ -2,28 +2,25 @@ /** * paragraph_l2br() - * + * * handle text on paragraph as a post content * Example: paragraph_l2br(htmlspecialchars(paragraph_trim($post_content))) - * + * * @category Function * @param string $content * @param integer|number $limit * @param string $schr * @param string $scnt - * + * */ function paragraph_l2br($content) { - if (version_compare(phpversion(), '7.4', '<=')) { - - return str_replace(paragraph_newline_checker(), '
', $content); - - } + if (version_compare(phpversion(), '7.4', '<=')) { + return str_replace(paragraph_newline_checker(), '
', $content); + } - return nl2br($content, false); - + return nl2br($content, false); } /** @@ -33,46 +30,42 @@ function paragraph_l2br($content) * @param integer $limit * @param string $schr * @param integer $scnt - * + * */ function paragraph_trim($content, $limit = 200, $schr = PHP_EOL, $scnt = 2) { - $post = 0; - $entry = null; - $trimmed = false; - - for ($i = 1; $i <= $scnt; $i++) { - - if ($tmp = strpos($content, $schr, $post + 1)) { - $post = $tmp; - $trimmed = true; - } else { - $post = strlen($content) - 1; - $trimmed = false; - break; + $post = 0; + $entry = null; + $trimmed = false; + + for ($i = 1; $i <= $scnt; $i++) { + if ($tmp = strpos($content, $schr, $post + 1)) { + $post = $tmp; + $trimmed = true; + } else { + $post = strlen($content) - 1; + $trimmed = false; + break; + } } - } - $entry = html_entity_decode($content); - $entry = strip_tags($entry); - $entry = purify_dirty_html($entry); - $content = substr($entry, 0, $post); + $entry = html_entity_decode($content); + $entry = strip_tags($entry); + $entry = purify_dirty_html($entry); + $content = substr($entry, 0, $post); - if (strlen($content) >= $limit) { - - - $content = substr($entry, 0, $limit); - $content = substr($entry, 0, strrpos($content, " ")); - $trimmed = true; - - } + if (strlen($content) >= $limit) { + $content = substr($entry, 0, $limit); + $content = substr($entry, 0, strrpos($content, " ")); + $trimmed = true; + } - if ($trimmed) { - $content .= "..."; - } + if ($trimmed) { + $content .= "..."; + } - return $content; + return $content; } /** @@ -82,26 +75,17 @@ function paragraph_trim($content, $limit = 200, $schr = PHP_EOL, $scnt = 2) function paragraph_newline_checker() { - if (defined('PHP_EOL')) { - - return PHP_EOL; - - } else { - - if (isset($_SERVER["HTTP_USER_AGENT"]) && strstr(strtolower($_SERVER["HTTP_USER_AGENT"]), 'win')) { - - $new_line = "\r\n"; - - } elseif (isset($_SERVER["HTTP_USER_AGENT"]) && strstr(strtolower($_SERVER["HTTP_USER_AGENT"]), 'mac')) { - - $new_line = "\r"; + if (defined('PHP_EOL')) { + return PHP_EOL; } else { - - $new_line = "\n"; + if (isset($_SERVER["HTTP_USER_AGENT"]) && strstr(strtolower($_SERVER["HTTP_USER_AGENT"]), 'win')) { + $new_line = "\r\n"; + } elseif (isset($_SERVER["HTTP_USER_AGENT"]) && strstr(strtolower($_SERVER["HTTP_USER_AGENT"]), 'mac')) { + $new_line = "\r"; + } else { + $new_line = "\n"; + } + + return $new_line; } - - return $new_line; - - } - } diff --git a/src/lib/utility/parse-post-id.php b/src/lib/utility/parse-post-id.php old mode 100644 new mode 100755 index 0583a102e..53545bab6 --- a/src/lib/utility/parse-post-id.php +++ b/src/lib/utility/parse-post-id.php @@ -1,31 +1,31 @@ - $post_id, 'page' => $page_id, 'cat' => $cat_id, 'archive' => $archive]; + default: + return ['post' => $post_id, 'page' => $page_id, 'cat' => $cat_id, 'archive' => $archive]; - break; - } + break; + } - return ['post' => $post_id, 'page' => $page_id, 'cat' => $cat_id, 'archive' => $archive]; + return ['post' => $post_id, 'page' => $page_id, 'cat' => $cat_id, 'archive' => $archive]; } /** * listen_request_path * - * @category Function + * @category Function * @author M.Noermoehammad * @param num|int $id * @param string $app_url @@ -144,55 +132,45 @@ function listen_query_string($id, $app_url) function listen_request_path($id, $app_url) { - $request_path = class_exists('RequestPath') ? new RequestPath() : ""; - $rewrite = array(); - - if (($request_path->matched == 'post') && ($id === $request_path->param1)) { - - $getPost = FrontHelper::grabPreparedFrontPostById($request_path->param1); - $post_id = isset($getPost['ID']) ? (int)$getPost['ID'] : 0; - $post_slug = isset($getPost['post_slug']) ? escape_html($getPost['post_slug']) : ""; - - $rewrite['post'] = $app_url . DS . 'post' . DS . $post_id . DS . $post_slug; - - } elseif (($request_path->matched == 'page') && ($id === $request_path->param1)) { - - $getPage = FrontHelper::grabPreparedFrontPageBySlug($request_path->param1); - $page_slug = isset($getPage['post_slug']) ? escape_html($getPage['post_slug']) : ""; - $rewrite['page'] = $app_url . DS . 'page' . DS . $page_slug; - - } elseif (($request_path->matched == 'category') && ($id === $request_path->param1)) { - - $getCategory = FrontHelper::grabPreparedFrontTopicBySlug($request_path->param1); - $category_slug = isset($getCategory['topic_slug']) ? escape_html($getCategory['topic_slug']) : ""; - $rewrite['cat'] = $app_url . DS . 'category' . DS . $category_slug; - - } elseif (($request_path->matched == 'archive') && ($id === $request_path->param1 . $request_path->param2)) { - - $month = isset($request_path->param1) ? escape_html($request_path->param1) : null; - $year = isset($request_path->param2) ? escape_html($request_path->param2) : null; - - $rewrite['archive'] = $app_url . DS . 'archive' . DS . $month . DS . $year; - - } else { - - $getPost = FrontHelper::grabPreparedFrontPostById($id); - $post_id = isset($getPost['ID']) ? abs((int)$getPost['ID']) : 0; - $post_slug = isset($getPost['post_slug']) ? escape_html($getPost['post_slug']) : ""; - - $rewrite['post'] = $app_url . DS . 'post' . DS . $post_id . DS . $post_slug; - - $getPage = FrontHelper::grabPreparedFrontPageBySlug($id); - $page_slug = isset($getPage['post_slug']) ? escape_html($getPage['post_slug']) : ""; - $rewrite['page'] = $app_url . DS . 'page' . DS . $page_slug; - - $getCategory = FrontHelper::grabPreparedFrontTopicByID($id); - $category_slug = isset($getCategory['topic_slug']) ? escape_html($getCategory['topic_slug']) : $id; - $rewrite['cat'] = $app_url . DS . 'category' . DS . $category_slug; - - $rewrite['archive'] = $app_url . DS . 'archive' . DS .$id; - - } - - return $rewrite; -} \ No newline at end of file + $request_path = class_exists('RequestPath') ? new RequestPath() : ""; + $rewrite = array(); + + if (($request_path->matched == 'post') && ($id === $request_path->param1)) { + $getPost = FrontHelper::grabPreparedFrontPostById($request_path->param1); + $post_id = isset($getPost['ID']) ? (int)$getPost['ID'] : 0; + $post_slug = isset($getPost['post_slug']) ? escape_html($getPost['post_slug']) : ""; + + $rewrite['post'] = $app_url . DS . 'post' . DS . $post_id . DS . $post_slug; + } elseif (($request_path->matched == 'page') && ($id === $request_path->param1)) { + $getPage = FrontHelper::grabPreparedFrontPageBySlug($request_path->param1); + $page_slug = isset($getPage['post_slug']) ? escape_html($getPage['post_slug']) : ""; + $rewrite['page'] = $app_url . DS . 'page' . DS . $page_slug; + } elseif (($request_path->matched == 'category') && ($id === $request_path->param1)) { + $getCategory = FrontHelper::grabPreparedFrontTopicBySlug($request_path->param1); + $category_slug = isset($getCategory['topic_slug']) ? escape_html($getCategory['topic_slug']) : ""; + $rewrite['cat'] = $app_url . DS . 'category' . DS . $category_slug; + } elseif (($request_path->matched == 'archive') && ($id === $request_path->param1 . $request_path->param2)) { + $month = isset($request_path->param1) ? escape_html($request_path->param1) : null; + $year = isset($request_path->param2) ? escape_html($request_path->param2) : null; + + $rewrite['archive'] = $app_url . DS . 'archive' . DS . $month . DS . $year; + } else { + $getPost = FrontHelper::grabPreparedFrontPostById($id); + $post_id = isset($getPost['ID']) ? abs((int)$getPost['ID']) : 0; + $post_slug = isset($getPost['post_slug']) ? escape_html($getPost['post_slug']) : ""; + + $rewrite['post'] = $app_url . DS . 'post' . DS . $post_id . DS . $post_slug; + + $getPage = FrontHelper::grabPreparedFrontPageBySlug($id); + $page_slug = isset($getPage['post_slug']) ? escape_html($getPage['post_slug']) : ""; + $rewrite['page'] = $app_url . DS . 'page' . DS . $page_slug; + + $getCategory = FrontHelper::grabPreparedFrontTopicByID($id); + $category_slug = isset($getCategory['topic_slug']) ? escape_html($getCategory['topic_slug']) : $id; + $rewrite['cat'] = $app_url . DS . 'category' . DS . $category_slug; + + $rewrite['archive'] = $app_url . DS . 'archive' . DS . $id; + } + + return $rewrite; +} diff --git a/src/lib/utility/plugin-helper.php b/src/lib/utility/plugin-helper.php index 41ac4be8c..6701632e6 100755 --- a/src/lib/utility/plugin-helper.php +++ b/src/lib/utility/plugin-helper.php @@ -1,4 +1,6 @@ - bool, 'errors' => array, 'info' => array] */ @@ -34,9 +36,9 @@ function validate_plugin_structure($pluginDir) { $errors = []; $info = []; - + $pluginDir = rtrim($pluginDir, '/\\'); - + if (!is_dir($pluginDir)) { return [ 'valid' => false, @@ -44,37 +46,37 @@ function validate_plugin_structure($pluginDir) 'info' => [] ]; } - + $iniFile = $pluginDir . DIRECTORY_SEPARATOR . 'plugin.ini'; - + if (!file_exists($iniFile)) { $errors[] = 'Missing required file: plugin.ini'; - + return [ 'valid' => false, 'errors' => $errors, 'info' => [] ]; } - + $iniContent = parse_ini_file($iniFile); - + if ($iniContent === false) { $errors[] = 'Invalid plugin.ini format'; - + return [ 'valid' => false, 'errors' => $errors, 'info' => [] ]; } - + foreach (PLUGIN_REQUIRED_FIELDS as $field) { if (!isset($iniContent[$field]) || empty(trim($iniContent[$field]))) { $errors[] = "Missing required field in plugin.ini: {$field}"; } } - + if (!empty($errors)) { return [ 'valid' => false, @@ -82,7 +84,7 @@ function validate_plugin_structure($pluginDir) 'info' => [] ]; } - + $info = [ 'plugin_name' => $iniContent['plugin_name'] ?? '', 'plugin_description' => $iniContent['plugin_description'] ?? '', @@ -92,13 +94,13 @@ function validate_plugin_structure($pluginDir) 'plugin_loader' => $iniContent['plugin_loader'] ?? '', 'plugin_action' => $iniContent['plugin_action'] ?? '' ]; - + $phpFiles = glob($pluginDir . DIRECTORY_SEPARATOR . '*.php'); - + if (empty($phpFiles)) { $errors[] = 'No PHP files found in plugin directory'; } - + return [ 'valid' => empty($errors), 'errors' => $errors, @@ -108,7 +110,7 @@ function validate_plugin_structure($pluginDir) /** * Validate plugin ZIP before installation - * + * * @param string $zipPath Path to uploaded ZIP file * @return array ['valid' => bool, 'errors' => array, 'plugin_name' => string] */ @@ -116,9 +118,9 @@ function validate_plugin_zip($zipPath) { $errors = []; $pluginName = ''; - + $zip = new ZipArchive(); - + if ($zip->open($zipPath) !== true) { return [ 'valid' => false, @@ -126,50 +128,50 @@ function validate_plugin_zip($zipPath) 'plugin_name' => '' ]; } - + $hasIniFile = false; $hasPhpFile = false; $iniContent = []; - + for ($i = 0; $i < $zip->numFiles; $i++) { $fileName = $zip->getNameIndex($i); - + if (strtolower(basename($fileName)) === 'plugin.ini') { $hasIniFile = true; - + $iniData = $zip->getFromName($fileName); - + if ($iniData !== false) { $tempIni = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'plugin_temp.ini'; file_put_contents($tempIni, $iniData); $iniContent = parse_ini_file($tempIni); unlink($tempIni); - + foreach (PLUGIN_REQUIRED_FIELDS as $field) { if (!isset($iniContent[$field]) || empty(trim($iniContent[$field]))) { $errors[] = "Missing required field in plugin.ini: {$field}"; } } - + $pluginName = $iniContent['plugin_name'] ?? ''; } } - + if (pathinfo($fileName, PATHINFO_EXTENSION) === 'php') { $hasPhpFile = true; } } - + $zip->close(); - + if (!$hasIniFile) { $errors[] = 'Missing required file: plugin.ini'; } - + if (!$hasPhpFile) { $errors[] = 'No PHP files found in plugin package'; } - + return [ 'valid' => empty($errors), 'errors' => $errors, @@ -179,7 +181,7 @@ function validate_plugin_zip($zipPath) /** * Get plugin info from directory - * + * * @param string $pluginDir Path to plugin directory * @return array|false */ @@ -187,32 +189,32 @@ function get_plugin_info($pluginDir) { $pluginDir = rtrim($pluginDir, '/\\'); $iniFile = $pluginDir . DIRECTORY_SEPARATOR . 'plugin.ini'; - + if (!file_exists($iniFile)) { return false; } - + return parse_ini_file($iniFile); } /** * Check if plugin has SQL file - * + * * @param string $pluginDir Path to plugin directory * @return string|false */ function get_plugin_sql_file($pluginDir) { $pluginDir = rtrim($pluginDir, '/\\'); - + $sqlFiles = glob($pluginDir . DIRECTORY_SEPARATOR . '*.sql'); - + return !empty($sqlFiles) ? $sqlFiles[0] : false; } /** * Check if plugin has functions file - * + * * @param string $pluginDir Path to plugin directory * @return string|false */ @@ -220,6 +222,6 @@ function get_plugin_functions_file($pluginDir) { $pluginDir = rtrim($pluginDir, '/\\'); $functionsFile = $pluginDir . DIRECTORY_SEPARATOR . 'functions.php'; - + return file_exists($functionsFile) ? $functionsFile : false; } diff --git a/src/lib/utility/prevent-injection.php b/src/lib/utility/prevent-injection.php index 74f755279..d1704b2f5 100755 --- a/src/lib/utility/prevent-injection.php +++ b/src/lib/utility/prevent-injection.php @@ -1,22 +1,23 @@ $protected, "post_password" => $password_shield); + $protected = encrypt_post($sanitize_content, $visibility, $password_shield); + return array("post_content" => $protected, "post_password" => $password_shield); } /** @@ -32,24 +32,21 @@ function protect_post($post_content, $visibility, $password) function grab_post_protected($post_id) { - $grab_post = null; + $grab_post = null; - $idsanitized = sanitizer($post_id, 'sql'); + $idsanitized = sanitizer($post_id, 'sql'); - $grab_post = medoo_column_where("tbl_posts", ["ID", "post_content", "post_visibility"], ["ID" => $idsanitized]); - - $postId = isset($grab_post['ID']) ? abs((int)$grab_post['ID']) : 0; - $content = isset($grab_post['post_content']) ? safe_html($grab_post['post_content']) : ""; - $visibility = isset($grab_post['post_visibility']) ? safe_html($grab_post['post_visibility']) : ""; + $grab_post = medoo_column_where("tbl_posts", ["ID", "post_content", "post_visibility"], ["ID" => $idsanitized]); - if (! $grab_post) { + $postId = isset($grab_post['ID']) ? abs((int)$grab_post['ID']) : 0; + $content = isset($grab_post['post_content']) ? safe_html($grab_post['post_content']) : ""; + $visibility = isset($grab_post['post_visibility']) ? safe_html($grab_post['post_visibility']) : ""; - scriptlog_error("Post protected not found"); - - } - - return array('post_id' => $postId, "post_content" => $content, "visibility" => $visibility); + if (! $grab_post) { + scriptlog_error("Post protected not found"); + } + return array('post_id' => $postId, "post_content" => $content, "visibility" => $visibility); } /** @@ -57,19 +54,18 @@ function grab_post_protected($post_id) * * @param int|num $post_id * @param string $post_password - * + * */ function checking_post_password($post_id, $post_password) { - -$idsanitized = sanitizer($post_id, 'sql'); -$grab_post = medoo_column_where("tbl_posts", ["ID", "post_password"], ["ID" => $idsanitized]); + $idsanitized = sanitizer($post_id, 'sql'); -$valid_post_protected = password_verify($post_password, $grab_post['post_password']); + $grab_post = medoo_column_where("tbl_posts", ["ID", "post_password"], ["ID" => $idsanitized]); -return ($valid_post_protected) ? true : false; - + $valid_post_protected = password_verify($post_password, $grab_post['post_password']); + + return ($valid_post_protected) ? true : false; } /** @@ -78,11 +74,11 @@ function checking_post_password($post_id, $post_password) * @param string $post_content * @param string $visibility * @param string $post_password - * + * */ function encrypt_post($post_content, $visibility, $post_password) { - return ($visibility == 'protected') ? encrypt($post_content, $post_password) : ""; + return ($visibility == 'protected') ? encrypt($post_content, $post_password) : ""; } /** @@ -92,56 +88,46 @@ function encrypt_post($post_content, $visibility, $post_password) * @param int|num $post_id * @param string $visibility * @param string $post_password - * + * */ function decrypt_post($post_id, $post_password) { - - $grab_post = grab_post_protected($post_id); // grab post protected based on post ID - $id_post = isset($grab_post['post_id']) ? (int)$grab_post['post_id'] : 0; - $content = isset($grab_post['post_content']) ? escape_html($grab_post['post_content']) : ""; - $visibility = isset($grab_post['visibility']) ? escape_html($grab_post['visibility']) : ""; - - if (($visibility == 'protected') && (true === checking_post_password($id_post, $post_password))) { - - $grab_password = medoo_column_where("tbl_posts", "post_password", ["ID" => $id_post]); - return ['post_content' => decrypt($content, $grab_password['post_password'])]; + $grab_post = grab_post_protected($post_id); // grab post protected based on post ID + $id_post = isset($grab_post['post_id']) ? (int)$grab_post['post_id'] : 0; + $content = isset($grab_post['post_content']) ? escape_html($grab_post['post_content']) : ""; + $visibility = isset($grab_post['visibility']) ? escape_html($grab_post['visibility']) : ""; - } + if (($visibility == 'protected') && (true === checking_post_password($id_post, $post_password))) { + $grab_password = medoo_column_where("tbl_posts", "post_password", ["ID" => $id_post]); + return ['post_content' => decrypt($content, $grab_password['post_password'])]; + } } /** * save_post_protected * * @param array $credentials - * + * */ function save_post_protected(array $credentials) { -$path = __DIR__ . '/../../admin/ui/posts/.credential' . DIRECTORY_SEPARATOR; - -$action_allowed = ['administrator', 'manager', 'editor', 'author', 'contributor']; - -if (! in_array(user_privilege(), $action_allowed)) { - - scriptlog_error("Your are not allowed undertaking this action"); - -} else { - - if (is_dir($path) === false) { - - create_directory($path); + $path = __DIR__ . '/../../admin/ui/posts/.credential' . DIRECTORY_SEPARATOR; - } + $action_allowed = ['administrator', 'manager', 'editor', 'author', 'contributor']; - // create file for post protected to keep its credentials detail - return generate_post_credentials($path, $credentials); - -} + if (! in_array(user_privilege(), $action_allowed)) { + scriptlog_error("Your are not allowed undertaking this action"); + } else { + if (is_dir($path) === false) { + create_directory($path); + } + // create file for post protected to keep its credentials detail + return generate_post_credentials($path, $credentials); + } } /** @@ -150,17 +136,17 @@ function save_post_protected(array $credentials) * @param string $path * @param array $data * @return bool - * + * */ function generate_post_credentials($path, $data) { - $created_at = isset($data['post_date']) ? $data['post_date'] : null; - $modified_at = isset($data['post_modified']) ?? $data['post_modified']; - $passphrase = isset($data['passphrase']) ? md5(app_key().$data['passphrase']) : null; - $credential_path = $path . DIRECTORY_SEPARATOR . $passphrase . '.php'; + $created_at = isset($data['post_date']) ? $data['post_date'] : null; + $modified_at = isset($data['post_modified']) ?? $data['post_modified']; + $passphrase = isset($data['passphrase']) ? md5(app_key() . $data['passphrase']) : null; + $credential_path = $path . DIRECTORY_SEPARATOR . $passphrase . '.php'; - $file = 'purify($dirty_html); + $config = class_exists('HTMLPurifier_Config') ? HTMLPurifier_Config::createDefault() : ""; -} + $purifier = class_exists('HTMLPurifier') ? new HTMLPurifier($config) : ""; + return $purifier->purify($dirty_html); +} diff --git a/src/lib/utility/random-generator.php b/src/lib/utility/random-generator.php index 2e56564d8..d1fdcb488 100755 --- a/src/lib/utility/random-generator.php +++ b/src/lib/utility/random-generator.php @@ -2,13 +2,13 @@ /** * random_generator() - * + * * A funtion for generating random strings and numbers - * + * * @category function * @param int $digits * @return string - * + * */ function random_generator($digits) { @@ -27,7 +27,6 @@ function random_generator($digits) $rand_index = array_rand($input); $randomGenerator .= $input[$rand_index]; // One char is added } else { - // Add one numeric digit between 1 and 10 $randomGenerator .= rand(1, 10); // one number is added } // end of if else @@ -38,10 +37,10 @@ function random_generator($digits) /** * make_seed - * + * * @category function * @see http://url.comhttps://www.php.net/manual/en/function.srand - * + * */ function make_seed() { @@ -51,25 +50,23 @@ function make_seed() /** * ircmaxel_generator_string() - * + * * A function for generating random string of various strength - * + * * @category function * @see https://github.com/ircmaxell/RandomLib * @param string $strength * @param integer $length * @param string $character_list - * + * */ function ircmaxell_generator_string($strength, $length = 32, $character_list = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/') { - $factory = new RandomLib\Factory; + $factory = new RandomLib\Factory(); switch ($strength) { - case 'low': - $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::LOW)); return $generator->generateString($length, $character_list) . "\n"; @@ -77,7 +74,6 @@ function ircmaxell_generator_string($strength, $length = 32, $character_list = ' break; case 'high': - $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::HIGH)); return $generator->generateString($length, $character_list) . "\n"; @@ -85,15 +81,13 @@ function ircmaxell_generator_string($strength, $length = 32, $character_list = ' break; case 'medium': - $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM)); return $generator->generateString($length, $character_list) . "\n"; break; - - default: + default: scriptlog_error("Unknown strength, generator string failed"); break; } @@ -101,9 +95,9 @@ function ircmaxell_generator_string($strength, $length = 32, $character_list = ' /** * ircmaxell_generator_numbers() - * - * A function for generating random numbers - * + * + * A function for generating random numbers + * * @category function * @param number|integer $min * @param number|integer $max @@ -112,7 +106,7 @@ function ircmaxell_generator_string($strength, $length = 32, $character_list = ' function ircmaxell_generator_numbers($min, $max) { - $factory = new RandomLib\Factory; + $factory = new RandomLib\Factory(); $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM)); @@ -121,19 +115,19 @@ function ircmaxell_generator_numbers($min, $max) /** * ircmaxell_random_generator() - * + * * generating simple random bytes string - * + * * @category function * @param int $length * @see https://github.com/ircmaxell/RandomLib * @return string - * + * */ function ircmaxell_random_generator($length) { - $factory = new RandomLib\Factory; + $factory = new RandomLib\Factory(); $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM)); @@ -146,7 +140,7 @@ function ircmaxell_random_generator($length) * @category function * https://github.com/ircmaxell/random_compat * @return string - * + * */ function ircmaxell_random_compat($length = 64) { @@ -160,12 +154,12 @@ function ircmaxell_random_compat($length = 64) * random_password function * generates random characters that can be used as insecure password * never use this function for storing your password - * + * * @see https://thisinterestsme.com/php-random-password/ * @see https://stackoverflow.com/questions/4356289/php-random-string-generator * @param integer $length * @return string - * + * */ function random_password($length) { @@ -189,10 +183,10 @@ function random_password($length) * @param integer $length * @see https://www.php.net/manual/en/function.random-bytes.php * @return string - * + * */ function str_rand($length = 64) { $length = ($length < 4) ? 4 : $length; - return bin2hex(random_bytes(($length-($length%2))/2)); -} \ No newline at end of file + return bin2hex(random_bytes(($length - ($length % 2)) / 2)); +} diff --git a/src/lib/utility/read-datetime.php b/src/lib/utility/read-datetime.php index 19269dbd7..95d91423c 100755 --- a/src/lib/utility/read-datetime.php +++ b/src/lib/utility/read-datetime.php @@ -1,15 +1,16 @@ getExternalDate($datetime) : ""; -} \ No newline at end of file + $dateGenerator = class_exists('DateGenerator') ? new DateGenerator() : ""; + return (method_exists($dateGenerator, 'getExternalDate')) ? $dateGenerator->getExternalDate($datetime) : ""; +} diff --git a/src/lib/utility/regenerate-session.php b/src/lib/utility/regenerate-session.php index 5d9ec3a7b..b1df1354f 100755 --- a/src/lib/utility/regenerate-session.php +++ b/src/lib/utility/regenerate-session.php @@ -1,81 +1,68 @@ transliterate($string); - } else { + if (class_exists('Transliterator')) { + $transliterator = Transliterator::createFromRules(':: Any-Latin; :: Latin-ASCII; :: NFD; :: [:Nonspacing Mark:] Remove; :: Lower(); :: NFC;', Transliterator::FORWARD); - return class_exists('Util') ? Util::remove_accents($string) : ""; - } -} \ No newline at end of file + return $transliterator->transliterate($string); + } else { + return class_exists('Util') ? Util::remove_accents($string) : ""; + } +} diff --git a/src/lib/utility/remove-dir-recursive.php b/src/lib/utility/remove-dir-recursive.php index cc6acee02..e8f785666 100755 --- a/src/lib/utility/remove-dir-recursive.php +++ b/src/lib/utility/remove-dir-recursive.php @@ -1,4 +1,5 @@ xss_clean($dirty_string); + $antiXss = new AntiXSS(); + return $antiXss->xss_clean($dirty_string); } /** @@ -28,21 +29,16 @@ function remove_xss($dirty_string) * @version 1.0 * @param string $dirty_string * @return void - * + * */ function simple_remove_xss($dirty_string) { - -if (is_array($dirty_string)) { - - $filter = Clean::cleanArray($dirty_string, true); -} else { - - $filter = Clean::cleanInput($dirty_string, true); + if (is_array($dirty_string)) { + $filter = Clean::cleanArray($dirty_string, true); + } else { + $filter = Clean::cleanInput($dirty_string, true); + } + return $filter; } - -return $filter; - -} \ No newline at end of file diff --git a/src/lib/utility/rename-file.php b/src/lib/utility/rename-file.php index 92f9bba9d..232f5cc85 100755 --- a/src/lib/utility/rename-file.php +++ b/src/lib/utility/rename-file.php @@ -1,15 +1,16 @@ :"/\\|?*]|[\x00-\x1F]|[\x7F\xA0\xAD]|[#\[\]@!$&\'()+,;=]|[{}^\~`] ~x', '-', $filename); -// avoids ".", ".." or ".hiddenFiles" -$filename = ltrim($filename, '.-'); -// optional beautification -if ($beautify) { - $filename = beautify_filename($filename); -} + $filename = preg_replace('~[<>:"/\\|?*]|[\x00-\x1F]|[\x7F\xA0\xAD]|[#\[\]@!$&\'()+,;=]|[{}^\~`] ~x', '-', $filename); + // avoids ".", ".." or ".hiddenFiles" + $filename = ltrim($filename, '.-'); + // optional beautification + if ($beautify) { + $filename = beautify_filename($filename); + } -// maximize filename length to 255 bytes http://serverfault.com/a/9548/44086 + // maximize filename length to 255 bytes http://serverfault.com/a/9548/44086 -$ext = pathinfo($filename, PATHINFO_EXTENSION); + $ext = pathinfo($filename, PATHINFO_EXTENSION); -$filename = mb_strcut(pathinfo($filename, PATHINFO_FILENAME), 0, 255 - ($ext ? strlen($ext) + 1 : 0), mb_detect_encoding($filename)) . ($ext ? '.' . $ext : ''); - -return $filename; + $filename = mb_strcut(pathinfo($filename, PATHINFO_FILENAME), 0, 255 - ($ext ? strlen($ext) + 1 : 0), mb_detect_encoding($filename)) . ($ext ? '.' . $ext : ''); + return $filename; } /** @@ -56,31 +56,30 @@ function filter_filename($filename, $beautify = true) * @see https://stackoverflow.com/questions/2021624/string-sanitizer-for-filename * @category Function * @return string - * + * */ function beautify_filename($filename) { - $filename = preg_replace(array( - // "file name.zip" becomes "file-name.zip" - '/ +/', - // "file___name.zip" becomes "file-name.zip" - '/_+/', - // "file---name.zip" becomes "file-name.zip" - '/-+/' -), '-', $filename); + $filename = preg_replace(array( + // "file name.zip" becomes "file-name.zip" + '/ +/', + // "file___name.zip" becomes "file-name.zip" + '/_+/', + // "file---name.zip" becomes "file-name.zip" + '/-+/' + ), '-', $filename); -$filename = preg_replace(array( - // "file--.--.-.--name.zip" becomes "file.name.zip" - '/-*\.-*/', - // "file...name..zip" becomes "file.name.zip" - '/\.{2,}/' -), '.', $filename); -// lowercase for windows/unix interoperability http://support.microsoft.com/kb/100625 -$filename = mb_strtolower($filename, mb_detect_encoding($filename)); -// ".file-name.-" becomes "file-name" -$filename = trim($filename, '.-'); + $filename = preg_replace(array( + // "file--.--.-.--name.zip" becomes "file.name.zip" + '/-*\.-*/', + // "file...name..zip" becomes "file.name.zip" + '/\.{2,}/' + ), '.', $filename); + // lowercase for windows/unix interoperability http://support.microsoft.com/kb/100625 + $filename = mb_strtolower($filename, mb_detect_encoding($filename)); + // ".file-name.-" becomes "file-name" + $filename = trim($filename, '.-'); -return $filename; - -} \ No newline at end of file + return $filename; +} diff --git a/src/lib/utility/reset-account.php b/src/lib/utility/reset-account.php index 3e48b7f9f..c0d0186fc 100755 --- a/src/lib/utility/reset-account.php +++ b/src/lib/utility/reset-account.php @@ -1,64 +1,60 @@ + + $site_info = function_exists('app_info') ? app_info() : ""; + $app_url = isset($site_info['app_url']) ? $site_info['app_url'] : ""; + $site_name = isset($site_info['site_name']) ? $site_info['site_name'] : ""; + $sender = isset($site_info['email_address']) ? $site_info['email_address'] : ""; + $sanitize_sender = function_exists('sanitize_email') ? sanitize_email($sender) : ""; + $subject = "Password Reset"; + $content = " If you have never requested an information message about forgotten passwords, please feel free to ignore this email.
But If you are indeed asking for this information, then please click on the link below:

- Recover Password

+ Recover Password

Thank You,
{$site_name} "; - // Define Headers - $email_headers = 'From '. $sanitize_sender . "\r\n" . - 'Reply-To: '. $sanitize_sender . "\r\n" . - 'Return-Path: '. $sanitize_sender . "\r\n". - 'MIME-Version: 1.0'. "\r\n". - 'Content-Type: text/html; charset=utf-8'."\r\n". - 'X-Mailer: PHP/' . PHP_VERSION . "\r\n" . - 'X-Priority: 1'. "\r\n". - 'X-Sender:'.$sanitize_sender."\r\n"; + // Define Headers + $email_headers = 'From ' . $sanitize_sender . "\r\n" . + 'Reply-To: ' . $sanitize_sender . "\r\n" . + 'Return-Path: ' . $sanitize_sender . "\r\n" . + 'MIME-Version: 1.0' . "\r\n" . + 'Content-Type: text/html; charset=utf-8' . "\r\n" . + 'X-Mailer: PHP/' . PHP_VERSION . "\r\n" . + 'X-Priority: 1' . "\r\n" . + 'X-Sender:' . $sanitize_sender . "\r\n"; if ((filter_var($recipient, FILTER_SANITIZE_EMAIL)) && (filter_var($recipient, FILTER_VALIDATE_EMAIL))) { - if (! mail($recipient, $subject, $content, $email_headers)) { - scriptlog_error("E-mail notification fail to sent"); - - } - + } } - } /** * recover_password - * + * * sending an email notification to the user's email. - * + * * @param string $user_pass - * + * */ function recover_password($user_pass, $user_email) { $site_info = function_exists('app_info') ? app_info() : ""; - $app_url = isset($site_info['app_url']) ? $site_info['app_url'] : ""; + $app_url = isset($site_info['app_url']) ? $site_info['app_url'] : ""; $site_name = isset($site_info['site_name']) ? $site_info['site_name'] : ""; $sender = isset($site_info['email_address']) ? $site_info['email_address'] : ""; $sanitize_sender = function_exists('sanitize_email') ? sanitize_email($sender) : ""; @@ -69,29 +65,24 @@ function recover_password($user_pass, $user_email) Here is your new password:

Password:{$user_pass}
You can now login with your new password, by clicking the link below:
- Login

+ Login

Thank You,
{$site_name} "; // Define Headers - $email_headers = 'From '. $sanitize_sender . "\r\n" . - 'Reply-To: '. $sanitize_sender . "\r\n" . - 'Return-Path: '. $sanitize_sender . "\r\n". - 'MIME-Version: 1.0'. "\r\n". - 'Content-Type: text/html; charset=utf-8'."\r\n". - 'X-Mailer: PHP/' . phpversion(). "\r\n" . - 'X-Priority: 1'. "\r\n". - 'X-Sender:'.$sanitize_sender."\r\n"; - - if ((filter_var($user_email, FILTER_SANITIZE_EMAIL)) && (filter_var($user_email, FILTER_VALIDATE_EMAIL))) { - - if (! mail($user_email, $subject, $content, $email_headers)) { - - scriptlog_error( "E-mail notification fail to sent" ); + $email_headers = 'From ' . $sanitize_sender . "\r\n" . + 'Reply-To: ' . $sanitize_sender . "\r\n" . + 'Return-Path: ' . $sanitize_sender . "\r\n" . + 'MIME-Version: 1.0' . "\r\n" . + 'Content-Type: text/html; charset=utf-8' . "\r\n" . + 'X-Mailer: PHP/' . phpversion() . "\r\n" . + 'X-Priority: 1' . "\r\n" . + 'X-Sender:' . $sanitize_sender . "\r\n"; - } - } - - -} \ No newline at end of file + if ((filter_var($user_email, FILTER_SANITIZE_EMAIL)) && (filter_var($user_email, FILTER_VALIDATE_EMAIL))) { + if (! mail($user_email, $subject, $content, $email_headers)) { + scriptlog_error("E-mail notification fail to sent"); + } + } +} diff --git a/src/lib/utility/rewrite-status.php b/src/lib/utility/rewrite-status.php index c116c846e..5e041d24c 100755 --- a/src/lib/utility/rewrite-status.php +++ b/src/lib/utility/rewrite-status.php @@ -1,19 +1,19 @@ dispatch() : trigger_error("Scriptlog's internal server not working"); -} \ No newline at end of file + is_object($dispatcher) ? $dispatcher->dispatch() : trigger_error("Scriptlog's internal server not working"); +} diff --git a/src/lib/utility/safe-html.php b/src/lib/utility/safe-html.php index 3cb05f97c..6b64301bf 100755 --- a/src/lib/utility/safe-html.php +++ b/src/lib/utility/safe-html.php @@ -1,17 +1,18 @@ filter($data); -} \ No newline at end of file + $html_filter = new Html(); + return $html_filter->filter($data); +} diff --git a/src/lib/utility/sanitize-email.php b/src/lib/utility/sanitize-email.php index 9523b629b..a4a82cfd3 100755 --- a/src/lib/utility/sanitize-email.php +++ b/src/lib/utility/sanitize-email.php @@ -1,14 +1,15 @@ 'English', + 'es' => 'Spanish', + 'fr' => 'French', + 'de' => 'German', + 'it' => 'Italian', + 'pt' => 'Portuguese', + 'ru' => 'Russian', + 'zh' => 'Chinese', + 'ja' => 'Japanese', + 'ko' => 'Korean', + 'ar' => 'Arabic', + 'hi' => 'Hindi', + 'id' => 'Indonesian', + 'ms' => 'Malay', + 'tr' => 'Turkish', + 'nl' => 'Dutch', + 'pl' => 'Polish', + 'vi' => 'Vietnamese', + 'th' => 'Thai', + 'he' => 'Hebrew', + 'bg' => 'Bulgarian', + 'cs' => 'Czech', + 'da' => 'Danish', + 'el' => 'Greek', + 'et' => 'Estonian', + 'fi' => 'Finnish', + 'hu' => 'Hungarian', + 'lt' => 'Lithuanian', + 'lv' => 'Latvian', + 'ro' => 'Romanian', + 'sk' => 'Slovak', + 'sl' => 'Slovenian', + 'sv' => 'Swedish', + 'uk' => 'Ukrainian', + 'fa' => 'Persian', + 'bn' => 'Bengali', + 'ta' => 'Tamil', + 'te' => 'Telugu', + 'mr' => 'Marathi', + 'gu' => 'Gujarati' + ]; +} + +function locale_dropdown($name, $selected = '') +{ + $locales = get_available_locales(); + return dropdown($name, $locales, $selected); +} diff --git a/src/lib/utility/sanitize-selection-box.php b/src/lib/utility/sanitize-selection-box.php index 41cd52d4e..f840beebd 100755 --- a/src/lib/utility/sanitize-selection-box.php +++ b/src/lib/utility/sanitize-selection-box.php @@ -1,4 +1,5 @@ -", "/", "?"); if (!is_array($string)) { - - $clean = trim(str_replace($strip, "", htmlspecialchars($string, ENT_QUOTES|ENT_HTML5, 'UTF-8', false))); - + $clean = trim(str_replace($strip, "", htmlspecialchars($string, ENT_QUOTES | ENT_HTML5, 'UTF-8', false))); } else { - - $clean = implode($string); - $clean = trim(str_replace($strip, "", htmlspecialchars($clean, ENT_QUOTES|ENT_HTML5, 'UTF-8', false))); - + $clean = implode($string); + $clean = trim(str_replace($strip, "", htmlspecialchars($clean, ENT_QUOTES | ENT_HTML5, 'UTF-8', false))); } - + $clean = preg_replace('/\s+/', "-", $clean); $clean = ($anal ? preg_replace("/[^a-zA-Z0-9]/", "", $clean) : $clean); - if ( $force_lowercase ) { - - if ( version_compare(PHP_VERSION, '7.4', '<=') && function_exists('mb_strtolower') ) { - - return mb_strtolower($clean, 'UTF-8'); - - } else { - - return strtolower($clean); - - } - + if ($force_lowercase) { + if (version_compare(PHP_VERSION, '7.4', '<=') && function_exists('mb_strtolower')) { + return mb_strtolower($clean, 'UTF-8'); + } else { + return strtolower($clean); + } } else { - - return $clean; - + return $clean; } - -} \ No newline at end of file +} diff --git a/src/lib/utility/sanitizer.php b/src/lib/utility/sanitizer.php index 73e0da93e..51acd3ed7 100755 --- a/src/lib/utility/sanitizer.php +++ b/src/lib/utility/sanitizer.php @@ -1,4 +1,5 @@ sanitasi(sanitize_string($str), $type); + $sanitizer = class_exists('Sanitize') ? new Sanitize() : ""; + return $sanitizer->sanitasi(sanitize_string($str), $type); } /** @@ -19,14 +20,13 @@ function sanitizer($str, $type) * * @category Function * @param string $str - * + * */ function sanitize_string($str) { - $str = class_exists('Sanitize') ? Sanitize::mildSanitizer($str) : ""; + $str = class_exists('Sanitize') ? Sanitize::mildSanitizer($str) : ""; - $mysqli = class_exists('DbMySQLi') ? new DbMySQLi() : ""; - - return $mysqli->filterData($str); - -} \ No newline at end of file + $mysqli = class_exists('DbMySQLi') ? new DbMySQLi() : ""; + + return $mysqli->filterData($str); +} diff --git a/src/lib/utility/scriptlog-error.php b/src/lib/utility/scriptlog-error.php index 0218153d8..552d83dac 100755 --- a/src/lib/utility/scriptlog-error.php +++ b/src/lib/utility/scriptlog-error.php @@ -1,63 +1,55 @@ "; + $error_message .= " in: " . $frame['function'] . '() function called from: ' . $frame['file'] . ' on line ' . $frame['line'] . ' ' . "\n "; + $error_message .= '

'; - if ((false === ($frame = next($stack))) || isset($frame['function']) || isset($frame['file']) || isset($frame['line'])) { - - $error_message .= "

"; - $error_message .= " in: " . $frame['function'] . '() function called from: ' . $frame['file'] . ' on line ' . $frame['line'] .' '."\n "; - $error_message .= '

'; - - break; - - } + break; + } + } + return trigger_error($error_message, $error_type); + } else { + throw new InvalidArgumentException($error_message); } - - return trigger_error($error_message, $error_type); - - } else { - - throw new InvalidArgumentException($error_message); - - } - } /** * Function scriptlog_shutdown_fatal - * + * * @category function - * + * */ function scriptlog_shutdown_fatal() { - - $site_info = app_info(); - $app_url = $site_info['app_url']; - $site_name = $site_info['site_name']; - $sender = $site_info['email_address']; - $sanitize_sender = sanitize_email($sender); - $date_error = date("Y-m-d H:i:s (T)"); + + $site_info = app_info(); + $app_url = $site_info['app_url']; + $site_name = $site_info['site_name']; + $sender = $site_info['email_address']; + $sanitize_sender = sanitize_email($sender); + $date_error = date("Y-m-d H:i:s (T)"); $errorType = [ E_ERROR => 'Error', @@ -74,50 +66,44 @@ function scriptlog_shutdown_fatal() E_STRICT => 'Runtime Notice', E_RECOVERABLE_ERROR => 'Catchable Fatal Error' ]; - + $scriptlogError = [E_ERROR, E_USER_ERROR, E_COMPILE_ERROR, E_CORE_ERROR]; - + $lastError = error_get_last(); - - if ($lastError !== NULL) { - - if (in_array($lastError['type'], $scriptlogError, true)) { - - $errno = $lastError['type']; - $errfile = $lastError['file']; - $errline = $lastError['line']; - $errstr = $lastError['message']; - - $headers = 'From '. $sanitize_sender . "\r\n" . - 'Reply-To: '. $sanitize_sender . "\r\n" . - 'Return-Path: '. $sanitize_sender . "\r\n". - 'MIME-Version: 1.0'. "\r\n". - 'Content-Type: text/html; charset=utf-8'."\r\n". - 'X-Mailer: PHP/' . phpversion(). "\r\n" . - 'X-Priority: 1'. "\r\n". - 'X-Sender:'.$sanitize_sender."\r\n"; - - scriptlog_error_mail(scriptlog_format_error($date_error, $errno, $errstr, $errfile, $errline), 1, "scriptlog@yandex.com", $headers); - - } - - } - + if ($lastError !== null) { + if (in_array($lastError['type'], $scriptlogError, true)) { + $errno = $lastError['type']; + $errfile = $lastError['file']; + $errline = $lastError['line']; + $errstr = $lastError['message']; + + $headers = 'From ' . $sanitize_sender . "\r\n" . + 'Reply-To: ' . $sanitize_sender . "\r\n" . + 'Return-Path: ' . $sanitize_sender . "\r\n" . + 'MIME-Version: 1.0' . "\r\n" . + 'Content-Type: text/html; charset=utf-8' . "\r\n" . + 'X-Mailer: PHP/' . phpversion() . "\r\n" . + 'X-Priority: 1' . "\r\n" . + 'X-Sender:' . $sanitize_sender . "\r\n"; + + scriptlog_error_mail(scriptlog_format_error($date_error, $errno, $errstr, $errfile, $errline), 1, "scriptlog@yandex.com", $headers); + } + } } /** * Function scriptlog_format_error - * + * * @category function * @return string - * + * */ function scriptlog_format_error($datetime, $errno, $errstr, $errfile, $errline) { - $trace = print_r(debug_backtrace(false), true); + $trace = print_r(debug_backtrace(false), true); - $content = " + $content = "
@@ -148,25 +134,20 @@ function scriptlog_format_error($datetime, $errno, $errstr, $errfile, $errline)
ItemDescription
"; return $content; - } /** * Function scriptlog_error_mail - * + * * @category function * @return bool - * + * */ function scriptlog_error_mail($errorMsg, $MsgType, $destination, $headers) { - if ($MsgType === 1) { - - return error_log($errorMsg, $MsgType, $destination, $headers); - - } - - return false; + if ($MsgType === 1) { + return error_log($errorMsg, $MsgType, $destination, $headers); + } + return false; } - diff --git a/src/lib/utility/scriptlog-password.php b/src/lib/utility/scriptlog-password.php index 713121116..8b95c9240 100755 --- a/src/lib/utility/scriptlog-password.php +++ b/src/lib/utility/scriptlog-password.php @@ -1,21 +1,21 @@ $cost]; + $cost = finding_pwd_cost(0.05, 10); + + $options = ['cost' => $cost]; - return password_hash(base64_encode(hash('sha384', $password, true)), PASSWORD_DEFAULT, $options); - -} \ No newline at end of file + return password_hash(base64_encode(hash('sha384', $password, true)), PASSWORD_DEFAULT, $options); +} diff --git a/src/lib/utility/scriptlog-upload-filesize.php b/src/lib/utility/scriptlog-upload-filesize.php index 25a7730b6..961f5d7b0 100755 --- a/src/lib/utility/scriptlog-upload-filesize.php +++ b/src/lib/utility/scriptlog-upload-filesize.php @@ -1,32 +1,28 @@ -- enables the XSS Filter. If a cross-site scripting attack is detected, the browser will sanitize the page and report the violation. - * + * * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection * @return void - * + * */ function x_xss_protection() { - header("X-XSS-Protection: 1; mode=block"); + header("X-XSS-Protection: 1; mode=block"); } /** * x_content_type_protection * * @return void - * + * */ function x_content_type_options($options = "nosniff") { - header("X-Content-Type-Options: $options"); + header("X-Content-Type-Options: $options"); } /** * strict_transport_security - * + * * @return void - * + * */ function strict_transport_security() { - header("Strict-Transport-Security: max-age=31536000; includeSubDomains"); + header("Strict-Transport-Security: max-age=31536000; includeSubDomains"); } /** @@ -73,14 +74,14 @@ function strict_transport_security() */ function remove_x_powered_by() { - header_remove("X-Powered-By"); + header_remove("X-Powered-By"); } /** * content_security_policy() - * + * * set content_securiy_policy header - * + * * @category function * @author M.Noermoehammad * @see https://scotthelme.co.uk/content-security-policy-an-introduction/ @@ -88,48 +89,43 @@ function remove_x_powered_by() * @license MIT * @version 1.0 * @return void - * + * */ function content_security_policy($app_url) { -if (is_ssl() === false) { + if (is_ssl() === false) { + $csp_non_ssl = "Content-Security-Policy: " . + "connect-src 'self' http:; " . + "default-src 'self' http:; " . + "font-src 'unsafe-inline' data: http:; " . + "form-action 'self' " . $app_url . "; " . + "img-src data: http:; " . + "frame-ancestors 'none' ; " . + "frame-src 'none'; " . + "child-src http:; " . + "media-src 'self' http:; " . + "object-src 'self' www.google-analytics.com ajax.googleapis.com platform-api.sharethis.com yourusername.disqus.com;" . + "script-src 'self' 'unsafe-inline' http:; " . + "style-src 'self' 'unsafe-inline' http:;"; -$csp_non_ssl = "Content-Security-Policy: ". - "connect-src 'self' http:; ". - "default-src 'self' http:; ". - "font-src 'unsafe-inline' data: http:; ". - "form-action 'self' ".$app_url."; ". - "img-src data: http:; ". - "frame-ancestors 'none' ; ". - "frame-src 'none'; ". - "child-src http:; ". - "media-src 'self' http:; ". - "object-src 'self' www.google-analytics.com ajax.googleapis.com platform-api.sharethis.com yourusername.disqus.com;". - "script-src 'self' 'unsafe-inline' http:; ". - "style-src 'self' 'unsafe-inline' http:;"; - -header($csp_non_ssl); - -} else { - -$csp_ssl = "Content-Security-Policy:". - "frame-ancestors 'none'; ". - "connect-src 'self' https:; ". - "default-src 'self' https:; ". - "font-src 'unsafe-inline' data: https:; ". - "form-action 'self' ".$app_url."; ". - "img-src data: https:; ". - "frame-ancestors 'none'; ". - "frame-src 'none; ". - "child-src https:; ". - "media-src 'self' https:; ". - "object-src 'self' www.google-analytics.com ajax.googleapis.com platform-api.sharethis.com yourusername.disqus.com;". - "script-src 'self' 'unsafe-inline' https:; ". - "style-src 'self' 'unsafe-inline' https:;"; - -header($csp_ssl); - -} + header($csp_non_ssl); + } else { + $csp_ssl = "Content-Security-Policy:" . + "frame-ancestors 'none'; " . + "connect-src 'self' https:; " . + "default-src 'self' https:; " . + "font-src 'unsafe-inline' data: https:; " . + "form-action 'self' " . $app_url . "; " . + "img-src data: https:; " . + "frame-ancestors 'none'; " . + "frame-src 'none; " . + "child-src https:; " . + "media-src 'self' https:; " . + "object-src 'self' www.google-analytics.com ajax.googleapis.com platform-api.sharethis.com yourusername.disqus.com;" . + "script-src 'self' 'unsafe-inline' https:; " . + "style-src 'self' 'unsafe-inline' https:;"; + header($csp_ssl); + } } diff --git a/src/lib/utility/simple-salt.php b/src/lib/utility/simple-salt.php index a97d5d504..6d6047010 100755 --- a/src/lib/utility/simple-salt.php +++ b/src/lib/utility/simple-salt.php @@ -1,39 +1,36 @@ 0) && (!is_null($num_chars))) { - - $accepted_chars = (version_compare(PHP_VERSION, '7.0', '<=')) ? ircmaxell_generator_string('low', $num_chars) : random_bytes($num_chars); - srand(((int)((double)microtime()*1000003))); + $salt = null; - for ($i=0; $i<=$num_chars; $i++) { + if ((is_int($num_chars)) && ($num_chars > 0) && (!is_null($num_chars))) { + $accepted_chars = (version_compare(PHP_VERSION, '7.0', '<=')) ? ircmaxell_generator_string('low', $num_chars) : random_bytes($num_chars); - $random_number = rand(0, (strlen($accepted_chars)-1)); + srand(((int)((float)microtime() * 1000003))); - $salt .= $accepted_chars[$random_number]; + for ($i = 0; $i <= $num_chars; $i++) { + $random_number = rand(0, (strlen($accepted_chars) - 1)); - } - - } + $salt .= $accepted_chars[$random_number]; + } + } - return $salt; - -} \ No newline at end of file + return $salt; +} diff --git a/src/lib/utility/sitemap-generator.php b/src/lib/utility/sitemap-generator.php old mode 100644 new mode 100755 index 6d0aaa0fa..1fe8b745d --- a/src/lib/utility/sitemap-generator.php +++ b/src/lib/utility/sitemap-generator.php @@ -1,9 +1,10 @@ -generateSitemap($items); - return (!empty($sitemapItems)) ? true : false; - } - + $items = function_exists('medoo_column') ? medoo_column('tbl_posts', 'post_slug') : ""; + $sitemap = class_exists('SitemapService') ? new SiteMapService() : ""; + if (is_array($items)) { + $sitemapItems = $sitemap->generateSitemap($items); + return (!empty($sitemapItems)) ? true : false; + } } - diff --git a/src/lib/utility/start-session-on-site.php b/src/lib/utility/start-session-on-site.php index 355cbfdaa..961068054 100755 --- a/src/lib/utility/start-session-on-site.php +++ b/src/lib/utility/start-session-on-site.php @@ -1,4 +1,5 @@ getMessage()); return false; @@ -90,7 +90,7 @@ function session_valid_id($session_id) try { if (PHP_VERSION_ID >= 70100) { $sidLength = ini_get('session.sid_length'); - + switch (ini_get('session.sid_bits_per_character')) { case 6: $characterClass = '0-9a-zA-z,-'; @@ -105,16 +105,14 @@ function session_valid_id($session_id) error_log('Unknown value in session.sid_bits_per_character: ' . ini_get('session.sid_bits_per_character')); return false; } - + $pattern = '/^[' . $characterClass . ']{' . $sidLength . '}$/'; return preg_match($pattern, $session_id) === 1; - } else { return preg_match('/^[-,a-zA-Z0-9]{1,128}$/', $session_id) === 1; } - } catch (Exception $e) { error_log("Error validating session ID: " . $e->getMessage()); return false; } -} \ No newline at end of file +} diff --git a/src/lib/utility/strip-tags-content.php b/src/lib/utility/strip-tags-content.php index ffac083e8..fb9f7cf62 100755 --- a/src/lib/utility/strip-tags-content.php +++ b/src/lib/utility/strip-tags-content.php @@ -1,29 +1,29 @@ /si', trim($tags), $tags); $tags = array_unique($tags[1]); - + if (is_array($tags) && (!empty($tags))) { if ($invert === false) { - return preg_replace('@<(?!(?:'. implode('|', $tags) .')\b)(\w+)\b.*?>.*?@si', '', $text); + return preg_replace('@<(?!(?:' . implode('|', $tags) . ')\b)(\w+)\b.*?>.*?@si', '', $text); } else { - return preg_replace('@<('. implode('|', $tags) .')\b.*?>.*?@si', '', $text); + return preg_replace('@<(' . implode('|', $tags) . ')\b.*?>.*?@si', '', $text); } } elseif ($invert === false) { return preg_replace('@<(\w+)\b.*?>.*?@si', '', $text); } return $text; - -} \ No newline at end of file +} diff --git a/src/lib/utility/system-software.php b/src/lib/utility/system-software.php index cd34a6754..f0a7fd811 100755 --- a/src/lib/utility/system-software.php +++ b/src/lib/utility/system-software.php @@ -1,17 +1,18 @@ 1 ORDER BY totalTag DESC"; - $stmt = function_exists('db_simple_query') ? db_simple_query($sql) : ""; + $stmt = function_exists('db_simple_query') ? db_simple_query($sql) : ""; - return ($stmt) ? false : true; + return ($stmt) ? false : true; } /** @@ -84,15 +80,15 @@ function checking_duplicate_tags() * @see https://www.decodingweb.dev/php-replace-space-with-dash * @see https://stackoverflow.com/questions/8425521/put-dash-between-every-third-character * @return string - * + * */ function tag_slug($tag) { - $tag = preg_replace('![\s]+!u', '-', strtolower($tag)); - $tag = preg_replace('![^-\pL\pN\s]+!u', '', $tag); - $tag = preg_replace('![-\s]+!u', '-', $tag); + $tag = preg_replace('![\s]+!u', '-', strtolower($tag)); + $tag = preg_replace('![^-\pL\pN\s]+!u', '', $tag); + $tag = preg_replace('![-\s]+!u', '-', $tag); - return trim($tag, '-'); + return trim($tag, '-'); } /** @@ -107,95 +103,81 @@ function tag_slug($tag) */ function truncate_tags($tags, $limit = 1) { - - if (preg_match('/\s/', $tags)) { - - $truncated = purify_dirty_html($tags); - $truncated = preg_replace('/((\w+\W*){' . ($limit - 1) . '}(\w+))(.*)/', '${1}', $truncated); - $truncated = implode(", ", preg_split("/[\s]+/", $truncated)); - - } else { - $truncated = purify_dirty_html($tags); - } - - return $truncated; + + if (preg_match('/\s/', $tags)) { + $truncated = purify_dirty_html($tags); + $truncated = preg_replace('/((\w+\W*){' . ($limit - 1) . '}(\w+))(.*)/', '${1}', $truncated); + $truncated = implode(", ", preg_split("/[\s]+/", $truncated)); + } else { + $truncated = purify_dirty_html($tags); + } + + return $truncated; } /** * tag_query() * * @return mixed - * + * */ function tag_query() { - $taglink = []; + $taglink = []; - $get_tags = function_exists('db_simple_query') ? db_simple_query("SELECT DISTINCT LOWER(post_tags) AS postTags FROM tbl_posts") : ""; + $get_tags = function_exists('db_simple_query') ? db_simple_query("SELECT DISTINCT LOWER(post_tags) AS postTags FROM tbl_posts") : ""; - $tags = []; + $tags = []; - if ($get_tags->num_rows > 0) { + if ($get_tags->num_rows > 0) { + while ($rows = $get_tags->fetch_array(MYSQLI_ASSOC)) { + if (isset($rows['postTags'])) { + $tags = array_merge($tags, explode(",", strtolower(trim($rows['postTags'])))); + } + } - while ($rows = $get_tags->fetch_array(MYSQLI_ASSOC)) { + if (checking_duplicate_tags() === false) { + $tags = array_unique_compact($tags); + } - if (isset($rows['postTags'])) { + for ($t = 0; $t < count($tags); $t++) { + $taglink[] = '
  • #' . $tags[$t] . '
  • '; + } - $tags = array_merge($tags, explode(",", strtolower(trim($rows['postTags'])))); - - } - - } - - if (checking_duplicate_tags() === false) { - - $tags = array_unique_compact($tags); - - } - - for ($t = 0; $t < count($tags); $t++) { - - $taglink[] = '
  • #' . $tags[$t] . '
  • '; + return is_iterable($taglink) ? implode(" ", $taglink) : array(); } - - return is_iterable($taglink) ? implode(" ", $taglink) : array(); - } } /** * tag_path - * + * * @return mixed - * + * */ function tag_path() { - $taglink = array(); - $tagArrays = array(); + $taglink = array(); + $tagArrays = array(); - $get_tags = function_exists('db_simple_query') ? db_simple_query('SELECT DISTINCT LOWER(post_tags) AS postTags FROM tbl_posts WHERE post_tags != "" GROUP BY postTags') : ""; + $get_tags = function_exists('db_simple_query') ? db_simple_query('SELECT DISTINCT LOWER(post_tags) AS postTags FROM tbl_posts WHERE post_tags != "" GROUP BY postTags') : ""; - if ($get_tags->num_rows > 0) { + if ($get_tags->num_rows > 0) { + while ($row = $get_tags->fetch_array(MYSQLI_ASSOC)) { + if (isset($row['postTags'])) { + $parts = explode(',', $row['postTags']); + } - while ($row = $get_tags->fetch_array(MYSQLI_ASSOC)) { + foreach ($parts as $part) { + $tagArrays[] = $part; + } + } - if (isset($row['postTags'])) { - $parts = explode(',', $row['postTags']); - } - - foreach ($parts as $part) { - $tagArrays[] = $part; - } - - } - - $finalTags = array_unique($tagArrays); - foreach ($finalTags as $tag) { + $finalTags = array_unique($tagArrays); + foreach ($finalTags as $tag) { + $taglink[] = '
  • #' . trim($tag) . '
  • '; + } - $taglink[] = '
  • #' .trim($tag). '
  • '; + return is_iterable($taglink) ? implode(" ", $taglink) : array(); } - - return is_iterable($taglink) ? implode(" ", $taglink) : array(); - } -} \ No newline at end of file +} diff --git a/src/lib/utility/terminator.php b/src/lib/utility/terminator.php index 98f26af86..0380c153e 100755 --- a/src/lib/utility/terminator.php +++ b/src/lib/utility/terminator.php @@ -4,12 +4,12 @@ * terminator() * * terminating user's related content (ex: post, comment) - * + * * @category function * @author Nirmala Adiba Khanza * @param int|numeric $userID * @return bool - * + * */ function terminator($userID) { @@ -19,18 +19,15 @@ function terminator($userID) $privilege = ['administrator', 'manager', 'editor', 'author', 'contributor', 'subscriber']; if (!in_array(user_privilege(), $privilege)) { - header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400); header("Status: 400 Bad Request"); exit("Sorry, user termination failed"); } else { - // grabbing post ID $grab_post_id = function_exists('medoo_get_where') ? medoo_get_where('tbl_posts', 'ID', ['post_author' => $userID]) : ""; $post_id = isset($grab_post_id['ID']) ? abs((int)$grab_post_id['ID']) : 0; if (function_exists('medoo_delete')) { - // removing comment $remove_comments = medoo_delete('tbl_comments', ['comment_post_id' => $post_id]); diff --git a/src/lib/utility/theme-caller.php b/src/lib/utility/theme-caller.php index 9863a8001..d09c64ad5 100755 --- a/src/lib/utility/theme-caller.php +++ b/src/lib/utility/theme-caller.php @@ -1,64 +1,59 @@ loadTheme('Y')) ?: $theme_init->loadTheme('Y'); + $theme_init = class_exists('ThemeDao') ? new ThemeDao() : ""; + + return empty($theme_init->loadTheme('Y')) ?: $theme_init->loadTheme('Y'); } /** * call_theme_header - * + * * @category functions * @author M.Noermoehammad * @license MIT * @version 1.0 - * + * */ function call_theme_header() { -if (file_exists(APP_ROOT.APP_THEME.theme_identifier()['theme_directory'].DIRECTORY_SEPARATOR.'header.php')) { - - include_once APP_ROOT.APP_THEME.theme_identifier()['theme_directory'].DIRECTORY_SEPARATOR.'header.php'; - -} else { - - scriptlog_error("File header not found"); - -} - + if (file_exists(APP_ROOT . APP_THEME . theme_identifier()['theme_directory'] . DIRECTORY_SEPARATOR . 'header.php')) { + include_once APP_ROOT . APP_THEME . theme_identifier()['theme_directory'] . DIRECTORY_SEPARATOR . 'header.php'; + } else { + scriptlog_error("File header not found"); + } } /** @@ -69,21 +64,16 @@ function call_theme_header() * @license MIT * @version 1.0 * @param string $content - * + * */ function call_theme_content($content = null) { - if (file_exists(APP_ROOT.APP_THEME.theme_identifier()['theme_directory'].DIRECTORY_SEPARATOR.basename($content.'.php'))) { - - include_once APP_ROOT.APP_THEME.theme_identifier()['theme_directory'].DIRECTORY_SEPARATOR.basename($content.'.php'); - - } else { - - scriptlog_error("File content not found"); - - } - + if (file_exists(APP_ROOT . APP_THEME . theme_identifier()['theme_directory'] . DIRECTORY_SEPARATOR . basename($content . '.php'))) { + include_once APP_ROOT . APP_THEME . theme_identifier()['theme_directory'] . DIRECTORY_SEPARATOR . basename($content . '.php'); + } else { + scriptlog_error("File content not found"); + } } /** @@ -93,19 +83,14 @@ function call_theme_content($content = null) * @author M.Noermoehammad * @license MIT * @version 1.0 - * + * */ function call_theme_footer() { - if (file_exists(APP_ROOT.APP_THEME.theme_identifier()['theme_directory'].DIRECTORY_SEPARATOR.'footer.php')) { - - include_once APP_ROOT.APP_THEME.theme_identifier()['theme_directory'].DIRECTORY_SEPARATOR.'footer.php'; - - } else { - - scriptlog_error("File footer not found"); - - } - -} \ No newline at end of file + if (file_exists(APP_ROOT . APP_THEME . theme_identifier()['theme_directory'] . DIRECTORY_SEPARATOR . 'footer.php')) { + include_once APP_ROOT . APP_THEME . theme_identifier()['theme_directory'] . DIRECTORY_SEPARATOR . 'footer.php'; + } else { + scriptlog_error("File footer not found"); + } +} diff --git a/src/lib/utility/theme-helpers.php b/src/lib/utility/theme-helpers.php index a0ef23302..8287f4770 100755 --- a/src/lib/utility/theme-helpers.php +++ b/src/lib/utility/theme-helpers.php @@ -1,70 +1,70 @@ $1', $text); - $text = preg_replace('/\*\*(.+?)\*\*/s', '$1', $text); + // strong emphasis + $text = preg_replace('/__(.+?)__/s', '$1', $text); + $text = preg_replace('/\*\*(.+?)\*\*/s', '$1', $text); - // emphasis - $text = preg_replace('/_([^_]+)_/', '$1', $text); - $text = preg_replace('/\*([^\*]+)\*/', '$1', $text); + // emphasis + $text = preg_replace('/_([^_]+)_/', '$1', $text); + $text = preg_replace('/\*([^\*]+)\*/', '$1', $text); - // convert windows (\r\n) to unix(\n) - $text = str_replace("\r\n", "\n", $text); - // convert macintosh(\r) to unix(\n) - $text = str_replace("\r", "\n", $text); + // convert windows (\r\n) to unix(\n) + $text = str_replace("\r\n", "\n", $text); + // convert macintosh(\r) to unix(\n) + $text = str_replace("\r", "\n", $text); - // paragraph - $text = '

    '. str_replace("\n\n", '

    ', $text) .'

    '; - //Line breaks - $text = str_replace("\n", '
    ', $text); + // paragraph + $text = '

    ' . str_replace("\n\n", '

    ', $text) . '

    '; + //Line breaks + $text = str_replace("\n", '
    ', $text); - // [linked text](link URL) - $text = preg_replace('/\[([^\]]+)]\(([-a-z0-9._~:\/?#@!$&\'()*+,;=%]+)\)/i', '$1', $text); + // [linked text](link URL) + $text = preg_replace('/\[([^\]]+)]\(([-a-z0-9._~:\/?#@!$&\'()*+,;=%]+)\)/i', '$1', $text); - return $text; - + return $text; } /** * markdown_html_out * * @param string $text - * + * */ function markdown_html_out($text) { - echo markdown_html($text); + echo markdown_html($text); } /** @@ -74,28 +74,23 @@ function markdown_html_out($text) */ function copyright() { - - return '©'; + return '©'; } /** * year_on_footer * * @param string $start_year - * + * */ function year_on_footer($start_year) { - $this_year = date("Y"); - - if ($start_year == $this_year) { - - echo $start_year; - - } else { - - echo " {$start_year} – {$this_year} "; + $this_year = date("Y"); - } -} \ No newline at end of file + if ($start_year == $this_year) { + echo $start_year; + } else { + echo " {$start_year} – {$this_year} "; + } +} diff --git a/src/lib/utility/theme-meta.php b/src/lib/utility/theme-meta.php index d9d1b459a..e7c98d2ce 100755 --- a/src/lib/utility/theme-meta.php +++ b/src/lib/utility/theme-meta.php @@ -1,31 +1,36 @@ -matched) { - - case 'post': - - if (!empty($uri->param1)) { - - $read_post = class_exists('FrontHelper') ? FrontHelper::grabPreparedFrontPostById($uri->param1) : ""; - $post_id = (!empty($read_post['ID'])) ? abs((int)$read_post['ID']) : null; - $post_title = (!empty($read_post['post_title'])) ? escape_html($read_post['post_title']) : ""; - $description = (!empty($read_post['post_summary'])) ? escape_html($read_post['post_summary']) : escape_html($read_post['post_title']); - $author = (!empty($read_post['user_login'])) ? escape_html($read_post['user_login']) : escape_html(app_info()['site_name']); - $image = (!empty($read_post['media_filename'])) ? invoke_webp_image(escape_html($read_post['media_filename'])) : $scriptlog_imgthumb; - $canonical = (!empty($read_post['post_slug'])) ? app_url() . DS . 'post' . DS . $post_id . DS . escape_html($read_post['post_slug']) : app_url(); - $created_at = (!empty($read_post['post_date'])) ? convert_to_timestamp(escape_html($read_post['post_date'])) : ""; - $modified_at = (!empty($read_post['post_modified'])) ? convert_to_timestamp(escape_html($read_post['post_modified'])) : ""; - $date_published = (!empty($created_at)) ? convert_to_atom($created_at) : date(DATE_ATOM); - $date_modified = (!empty($modified_at)) ? convert_to_atom($modified_at) : date(DATE_ATOM); - } - - $theme_meta['site_schema'] = is_null($post_id) ? generate_schema_org(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : BlogSchema::generateBlogPostSchema($post_id); - $theme_meta['site_meta_tags'] = is_null($post_id) ? generate_meta_tags(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_meta_tags(ucfirst(trim($post_title)), $description, $author, $image, $canonical, true); - - break; - - case 'page': - - if (!empty($uri->param1)) { - - $read_page = FrontHelper::grabPreparedFrontPageBySlug($uri->param1); - $page_id = (!empty($read_page['ID'])) ? abs((int)$read_page['ID']) : null; - $page_title = (!empty($read_page['post_title'])) ? escape_html($read_page['post_title']) : ""; - $description = (!empty($read_page['post_summary'])) ? escape_html($read_page['post_summary']) : escape_html($read_page['post_title']); - $author = (!empty($read_page['user_login'])) ? escape_html($read_page['user_login']) : escape_html(app_info()['site_name']); - $image = (!empty($read_page['media_filename'])) ? invoke_webp_image(escape_html($read_page['media_filename'])) : $scriptlog_imgthumb; - $canonical = (!empty($read_page['post_slug'])) ? app_url() . DS . 'page' . DS . escape_html($read_page['post_slug']) : app_url(); - $created_at = (!empty($read_page['post_date'])) ? convert_to_timestamp(escape_html($read_page['post_date'])) : ""; - $modified_at = (!empty($read_page['post_modified'])) ? convert_to_timestamp(escape_html($read_page['post_modified'])) : ""; - $date_published = (!empty($created_at)) ? convert_to_atom($created_at) : date(DATE_ATOM); - $date_modified = (!empty($modified_at)) ? convert_to_atom($modified_at) : date(DATE_ATOM); - } - - $theme_meta['site_schema'] = is_null($page_id) ? generate_schema_org(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_schema_org(ucfirst(trim($page_title)) . ' | ' . escape_html(app_info()['site_name']), $canonical, $image, escape_html(app_info()['site_keywords']), $description, $image, $date_published, $date_modified); - $theme_meta['site_meta_tags'] = is_null($page_id) ? generate_meta_tags(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_ame'])) : generate_meta_tags($page_title, $description, $author, $image, $canonical); - - break; - - case 'blog': - - $date_published = date(DATE_ATOM); - $date_modified = date(DATE_ATOM); - $theme_meta['site_schema'] = generate_schema_org(app_info()['site_name'] . ' | ' . app_info()['site_tagline'], app_url(), $scriptlog_image, escape_html(app_info()['site_description']), escape_html(app_info()['site_keywords']), $scriptlog_imgthumb, $date_published, $date_modified); - $theme_meta['site_meta_tags'] = generate_meta_tags('Blog: ' . ucfirst(trim(app_info()['site_description'])), escape_html(app_info()['site_keywords']), escape_html(app_info()['site_name']), $scriptlog_image, app_url() . DS . 'blog'); - - break; - - case 'category': - - if (!empty($uri->param1)) { - - $read_topic = FrontHelper::grabPreparedFrontTopicBySlug($uri->param1); - $topic_id = (!empty($read_topic['ID'])) ? abs((int)$read_topic['ID']) : null; - $topic_title = (!empty($read_topic['topic_title'])) ? escape_html($read_topic['topic_title']) : app_info()['site_name']; - $description = 'Category: ' . $topic_title . ' | ' . escape_html(app_info()['site_description']); - $canonical = app_url() . DS . 'category' . DS . $uri->param1; - $date_published = date(DATE_ATOM); - $date_modified = date(DATE_ATOM); - } - - $theme_meta['site_schema'] = (is_null($topic_id)) ? generate_schema_org(ucfirst(trim('page not fiund')) . ' | ' . escape_html(app_info()['site_name'])) : generate_schema_org(ucfirst(trim($topic_title)), $canonical, $scriptlog_image, $description, escape_html(app_info()['site_keywords']), $scriptlog_imgthumb, $date_published, $date_modified); - $theme_meta['site_meta_tags'] = (is_null($topic_id)) ? generate_meta_tags(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_meta_tags( 'Category: ' . ucfirst(trim($topic_title)), $description, escape_html(app_info()['site_name']), $scriptlog_image, $canonical); - - break; - - case 'archive': - - $month = (isset($uri->param1)) ? $uri->param1 : null; - $year = (isset($uri->param2)) ? $uri->param2 : null; - - $canonical = ((isset($month)) || (isset($year)) ? app_url() . DS . 'archive ' . DS . $month . DS . $year : app_url()); - $month_name = date("F Y", mktime(0, 0, 0, intval($month), 7, intval($year))); - $description = 'Archive: ' . $month_name . ' | ' . escape_html(app_info()['site_description']); - $keyword = escape_html(app_info()['site_keywords']); - $date_published = date(DATE_ATOM); - - $theme_meta['site_schema'] = (is_null($month)) ? generate_schema_org(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_schema_org(ucfirst(trim(escape_html($month_name))) . ' | ' . escape_html(app_info()['site_name']), $canonical, $scriptlog_image, $description, $keyword, $scriptlog_imgthumb, $date_published); - $theme_meta['site_meta_tags'] = (is_null($month)) ? generate_meta_tags(ucfirst(trim('page not found')).' | ' . escape_html(app_info()['site_name'])) : generate_meta_tags( 'Archive: '. ucfirst(trim($month_name)), $description, escape_html(app_info()['site_name']), $scriptlog_image, $canonical); - - break; - - case 'tag': - - $tag_item = isset($uri->param1) ? $uri->param1 : null; - - $canonical = ((isset($tag)) || (isset($tag_item)) ? app_url() . DS . 'tag' . DS . $tag_item : app_url()); - $description = 'Tag:' . ' - ' . $tag_item; - $keyword = escape_html(app_info()['site_keywords']); - $date_published = date(DATE_ATOM); - - $theme_meta['site_schema'] = (is_null($tag_item)) ? generate_schema_org(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_schema_org(ucfirst(trim(escape_html($tag_item))) . ' | ' . escape_html(app_info()['site_name']), $canonical, $scriptlog_image, $description, $keyword, $scriptlog_imgthumb, $date_published); - $theme_meta['site_meta_tags'] = (is_null($tag_item)) ? generate_meta_tags(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_meta_tags('Tag: '.ucfirst(trim($tag_item)), $description, app_info()['site_name'], $scriptlog_image, $canonical); - - break; - - default: - - $theme_meta['site_schema'] = generate_schema_org(app_info()['site_name'], app_url(), $scriptlog_image, app_info()['site_description'], escape_html(app_info()['site_keywords']), $scriptlog_imgthumb, date(DATE_ATOM)); - $theme_meta['site_meta_tags'] = generate_meta_tags(escape_html(app_info()['site_description']), escape_html(app_info()['site_keywords']), escape_html(app_info()['site_name']), $scriptlog_image, app_url()); - - break; - } - - return array('site_schema' => $theme_meta['site_schema'], 'site_meta_tags' => $theme_meta['site_meta_tags']); + $uri = is_a($uri, 'RequestPath') ? $uri : null; + + $theme_meta = array(); + $post_id = null; + $created_at = null; + $modified_at = null; + $page_id = null; + $post_title = null; + $page_title = null; + $author = null; + $description = null; + $topic_id = null; + $topic_title = null; + $canonical = null; + $image = null; + $date_published = null; + $date_modified = null; + + switch ($uri->matched) { + case 'post': + if (!empty($uri->param1)) { + $read_post = class_exists('FrontHelper') ? FrontHelper::grabPreparedFrontPostById($uri->param1) : null; + if (!empty($read_post) && is_array($read_post)) { + $post_id = (!empty($read_post['ID'])) ? abs((int)$read_post['ID']) : null; + $post_title = (!empty($read_post['post_title'])) ? escape_html($read_post['post_title']) : ""; + $description = (!empty($read_post['post_summary'])) ? escape_html($read_post['post_summary']) : (isset($read_post['post_title']) ? escape_html($read_post['post_title']) : ""); + $author = (!empty($read_post['user_login'])) ? escape_html($read_post['user_login']) : escape_html(app_info()['site_name']); + $image = (!empty($read_post['media_filename'])) ? invoke_webp_image(escape_html($read_post['media_filename'])) : $scriptlog_imgthumb; + $canonical = (!empty($read_post['post_slug'])) ? app_url() . DS . 'post' . DS . $post_id . DS . escape_html($read_post['post_slug']) : app_url(); + $created_at = (!empty($read_post['post_date'])) ? convert_to_timestamp(escape_html($read_post['post_date'])) : ""; + $modified_at = (!empty($read_post['post_modified'])) ? convert_to_timestamp(escape_html($read_post['post_modified'])) : ""; + $date_published = (!empty($created_at)) ? convert_to_atom($created_at) : date(DATE_ATOM); + $date_modified = (!empty($modified_at)) ? convert_to_atom($modified_at) : date(DATE_ATOM); + } + } + + $theme_meta['site_schema'] = is_null($post_id) ? generate_schema_org(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : BlogSchema::generateBlogPostSchema($post_id); + $theme_meta['site_meta_tags'] = is_null($post_id) ? generate_meta_tags(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_meta_tags(ucfirst(trim($post_title)), $description, $author, $image, $canonical, true); + + break; + + case 'page': + if (!empty($uri->param1)) { + $read_page = FrontHelper::grabPreparedFrontPageBySlug($uri->param1); + if (!empty($read_page) && is_array($read_page)) { + $page_id = (!empty($read_page['ID'])) ? abs((int)$read_page['ID']) : null; + $page_title = (!empty($read_page['post_title'])) ? escape_html($read_page['post_title']) : ""; + $description = (!empty($read_page['post_summary'])) ? escape_html($read_page['post_summary']) : (isset($read_page['post_title']) ? escape_html($read_page['post_title']) : ""); + $author = (!empty($read_page['user_login'])) ? escape_html($read_page['user_login']) : escape_html(app_info()['site_name']); + $image = (!empty($read_page['media_filename'])) ? invoke_webp_image(escape_html($read_page['media_filename'])) : $scriptlog_imgthumb; + $canonical = (!empty($read_page['post_slug'])) ? app_url() . DS . 'page' . DS . escape_html($read_page['post_slug']) : app_url(); + $created_at = (!empty($read_page['post_date'])) ? convert_to_timestamp(escape_html($read_page['post_date'])) : ""; + $modified_at = (!empty($read_page['post_modified'])) ? convert_to_timestamp(escape_html($read_page['post_modified'])) : ""; + $date_published = (!empty($created_at)) ? convert_to_atom($created_at) : date(DATE_ATOM); + $date_modified = (!empty($modified_at)) ? convert_to_atom($modified_at) : date(DATE_ATOM); + } + } + + $theme_meta['site_schema'] = is_null($page_id) ? generate_schema_org(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_schema_org(ucfirst(trim($page_title)) . ' | ' . escape_html(app_info()['site_name']), $canonical, $image, escape_html(app_info()['site_keywords']), $description, $image, $date_published, $date_modified); + $theme_meta['site_meta_tags'] = is_null($page_id) ? generate_meta_tags(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_meta_tags($page_title, $description, $author, $image, $canonical); + + break; + + case 'blog': + $date_published = date(DATE_ATOM); + $date_modified = date(DATE_ATOM); + $theme_meta['site_schema'] = generate_schema_org(app_info()['site_name'] . ' | ' . app_info()['site_tagline'], app_url(), $scriptlog_image, escape_html(app_info()['site_description']), escape_html(app_info()['site_keywords']), $scriptlog_imgthumb, $date_published, $date_modified); + $theme_meta['site_meta_tags'] = generate_meta_tags('Blog: ' . ucfirst(trim(app_info()['site_description'])), escape_html(app_info()['site_keywords']), escape_html(app_info()['site_name']), $scriptlog_image, app_url() . DS . 'blog'); + + break; + + case 'category': + if (!empty($uri->param1)) { + $read_topic = FrontHelper::grabPreparedFrontTopicBySlug($uri->param1); + if (!empty($read_topic) && is_array($read_topic)) { + $topic_id = (!empty($read_topic['ID'])) ? abs((int)$read_topic['ID']) : null; + $topic_title = (!empty($read_topic['topic_title'])) ? escape_html($read_topic['topic_title']) : app_info()['site_name']; + $description = 'Category: ' . $topic_title . ' | ' . escape_html(app_info()['site_description']); + $canonical = app_url() . DS . 'category' . DS . $uri->param1; + $date_published = date(DATE_ATOM); + $date_modified = date(DATE_ATOM); + } + } + + $theme_meta['site_schema'] = (is_null($topic_id)) ? generate_schema_org(ucfirst(trim('page not fiund')) . ' | ' . escape_html(app_info()['site_name'])) : generate_schema_org(ucfirst(trim($topic_title)), $canonical, $scriptlog_image, $description, escape_html(app_info()['site_keywords']), $scriptlog_imgthumb, $date_published, $date_modified); + $theme_meta['site_meta_tags'] = (is_null($topic_id)) ? generate_meta_tags(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_meta_tags('Category: ' . ucfirst(trim($topic_title)), $description, escape_html(app_info()['site_name']), $scriptlog_image, $canonical); + + break; + + case 'archive': + $month = (isset($uri->param1)) ? $uri->param1 : null; + $year = (isset($uri->param2)) ? $uri->param2 : null; + + $canonical = ((isset($month)) || (isset($year)) ? app_url() . DS . 'archive ' . DS . $month . DS . $year : app_url()); + $month_name = date("F Y", mktime(0, 0, 0, intval($month), 7, intval($year))); + $description = 'Archive: ' . $month_name . ' | ' . escape_html(app_info()['site_description']); + $keyword = escape_html(app_info()['site_keywords']); + $date_published = date(DATE_ATOM); + + $theme_meta['site_schema'] = (is_null($month)) ? generate_schema_org(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_schema_org(ucfirst(trim(escape_html($month_name))) . ' | ' . escape_html(app_info()['site_name']), $canonical, $scriptlog_image, $description, $keyword, $scriptlog_imgthumb, $date_published); + $theme_meta['site_meta_tags'] = (is_null($month)) ? generate_meta_tags(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_meta_tags('Archive: ' . ucfirst(trim($month_name)), $description, escape_html(app_info()['site_name']), $scriptlog_image, $canonical); + + break; + + case 'tag': + $tag_item = isset($uri->param1) ? $uri->param1 : null; + + $canonical = ((isset($tag)) || (isset($tag_item)) ? app_url() . DS . 'tag' . DS . $tag_item : app_url()); + $description = 'Tag:' . ' - ' . $tag_item; + $keyword = escape_html(app_info()['site_keywords']); + $date_published = date(DATE_ATOM); + + $theme_meta['site_schema'] = (is_null($tag_item)) ? generate_schema_org(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_schema_org(ucfirst(trim(escape_html($tag_item))) . ' | ' . escape_html(app_info()['site_name']), $canonical, $scriptlog_image, $description, $keyword, $scriptlog_imgthumb, $date_published); + $theme_meta['site_meta_tags'] = (is_null($tag_item)) ? generate_meta_tags(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_meta_tags('Tag: ' . ucfirst(trim($tag_item)), $description, app_info()['site_name'], $scriptlog_image, $canonical); + + break; + + default: + $theme_meta['site_schema'] = generate_schema_org(app_info()['site_name'], app_url(), $scriptlog_image, app_info()['site_description'], escape_html(app_info()['site_keywords']), $scriptlog_imgthumb, date(DATE_ATOM)); + $theme_meta['site_meta_tags'] = generate_meta_tags(escape_html(app_info()['site_description']), escape_html(app_info()['site_keywords']), escape_html(app_info()['site_name']), $scriptlog_image, app_url()); + + break; + } + + return array('site_schema' => $theme_meta['site_schema'], 'site_meta_tags' => $theme_meta['site_meta_tags']); } /** @@ -179,181 +179,176 @@ function metatag_by_path($scriptlog_image, $scriptlog_imgthumb, $uri) * @param string $value * @param string $scriptlog_image * @param string $scriptlog_imgthumb - * + * */ function metatag_by_query($key, $value, $scriptlog_image, $scriptlog_imgthumb) { - $theme_meta = array(); - $post_id = null; - $page_id = null; - $category_id = null; - $post_title = null; - $page_title = null; - $category_title = null; - $tag_id = null; - $tag_title = null; - $author = null; - $keyword = null; - $description = null; - $category_title = null; - $canonical = null; - $image = null; - $created_at = null; - $modified_at = null; - $date_published = null; - $date_modified = null; - - switch ($key) { - - case 'p': - - if ((empty($value)) || ($value === '')) { - - http_response_code(404); - throw new InvalidArgumentException("Argument passed must be of the type string, numeric or integer, null given"); - - } else { - - $read_post = class_exists('FrontHelper') ? FrontHelper::grabSimpleFrontPost($value) : ""; - - $post_id = (!empty($read_post['ID'])) ? abs((int)$read_post['ID']) : null; - $post_title = (!empty($read_post['post_title'])) ? escape_html($read_post['post_title']) : ""; - $description = (!empty($read_post['post_summary'])) ? escape_html($read_post['post_summary']) : escape_html($read_post['post_title']); - $author = (!empty($read_post['user_login'])) ? escape_html($read_post['user_login']) : escape_html(app_info()['site_name']); - $image = (!empty($read_post['media_filename'])) ? invoke_webp_image(escape_html($read_post['media_filename'])) : app_url() . DS . APP_IMAGE . 'scriptlog-612x221.jpg'; - $canonical = (!empty($read_post['post_slug'])) ? app_url() . DS . '?p=' . $post_id : app_url(); - $created_at = (!empty($read_post['post_date'])) ? convert_to_timestamp(escape_html($read_post['post_date'])) : ""; - $modified_at = (!empty($read_post['post_modified'])) ? convert_to_timestamp(escape_html($read_post['post_modified'])) : ""; - $date_published = (!empty($created_at))? convert_to_atom($created_at) : date(DATE_ATOM); - $date_modified = (!empty($modified_at)) ? convert_to_atom($modified_at) : date(DATE_ATOM); - - } - - $theme_meta['site_schema'] = (is_null($post_id)) ? generate_schema_org(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : BlogSchema::generateBlogPostSchema($post_id); - $theme_meta['site_meta_tags'] = (is_null($post_id)) ? generate_meta_tags(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_meta_tags($post_title, $description, $author, $image, $canonical); - - break; - - case 'pg': - - if ((empty($value)) || ($value === '')) { - - http_response_code(404); - throw new InvalidArgumentException("Argument passed must be of the type string, numeric or integer, null given"); - - } else { - - $read_page = class_exists('FrontHelper') ? FrontHelper::grabSimpleFrontPage($value) : ""; - - $page_id = (!empty($read_page['ID'])) ? $read_page['ID'] : null; - $page_title = (!empty($read_page['post_title'])) ? escape_html($read_page['post_title']) : ""; - $description = (!empty($read_page['post_summary'])) ? escape_html($read_page['post_summary']) : escape_html($read_page['post_title']); - $author = (!empty($read_page['user_login'])) ? escape_html($read_page['user_login']) : escape_html(app_info()['site_name']); - $image = (!empty($read_page['media_filename'])) ? invoke_webp_image(escape_html($read_page['media_filename'])) : app_url() . DS . APP_IMAGE . 'scriptlog-612x221.jpg'; - $canonical = (!empty($read_page['post_slug'])) ? app_url() . DS . '?pg=' . $page_id : app_url(); - $created_at = (!empty($read_page['post_date'])) ? convert_to_timestamp(escape_html($read_page['post_date'])) : ""; - $modified_at = (!empty($read_page['post_modified'])) ? convert_to_timestamp(escape_html($read_page['post_modified'])) : ""; - $date_published = (!empty($created_at)) ? convert_to_atom($created_at) : date(DATE_ATOM); - $date_modified = (!empty($modified_at)) ? convert_to_atom($modified_at) : date(DATE_ATOM); - - } - - $theme_meta['site_schema'] = (is_null($page_id)) ? generate_schema_org(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_schema_org(ucfirst(trim($page_title)) . ' | ' . app_info()['site_name'], $canonical, $image, $description, escape_html(app_info()['site_keywords']), $scriptlog_imgthumb, $date_published, $date_modified); - $theme_meta['site_meta_tags'] = (is_null($page_id)) ? generate_meta_tags(ucfirst(trim('page not found')) . ' | ' . app_info()['site_name']) : generate_meta_tags($page_title, $description, $author, $image, $canonical); - - break; - - case 'cat': - - if ((empty($value)) || ($value === '')) { - - http_response_code(404); - throw new InvalidArgumentException("Argument passed must be of the type string, numeric or integer, null given"); - - } else { - - $read_category = class_exists('FrontHelper') ? FrontHelper::grabSimpleFrontTopic($value) : ""; - - $category_id = (!empty($read_category['ID'])) ? $read_category['ID'] : null; - $category_title = (!empty($read_category['topic_title'])) ? escape_html($read_category['topic_title']) : app_info()['site_name']; - $description = isset($read_category['topic_title']) ? escape_html($read_category['topic_title']) : app_info()['site_description']; - $canonical = (!empty($read_category['topic_slug'])) ? app_url() . DS . '?cat=' . $category_id : app_url(); - $date_published = date(DATE_ATOM); - $date_modified = date(DATE_ATOM); - - } - - $theme_meta['site_schema'] = (is_null($category_id)) ? generate_schema_org(ucfirst(trim('page not found')) . '|' . escape_html(app_info()['site_name'])) : generate_schema_org(ucfirst(trim($category_title)) . '|' . app_info()['site_name'], $canonical, $image, $category_title, $description, $scriptlog_imgthumb, $date_published, $date_modified); - $theme_meta['site_meta_tags'] = (is_null($category_id)) ? generate_meta_tags(ucfirst(trim('page not found')) . '|' . app_info()['site_name'], app_info()['site_description'], app_info()['site_keywords'], APP_TITLE, $scriptlog_image, app_url()) : generate_meta_tags($category_title, $description, app_info()['site_name'], $scriptlog_image, $canonical); - - break; - - case 'a': - - if (!empty($value)) { - - $archive_requested = class_exists('HandleRequest') ? preg_split("//", HandleRequest::isQueryStringRequested()['value'], -1, PREG_SPLIT_NO_EMPTY) : preg_split("//", $value, -1, PREG_SPLIT_NO_EMPTY); - - $year = (isset($archive_requested[0]) && isset($archive_requested[1]) && isset($archive_requested[2]) && isset($archive_requested[3])) ? $archive_requested[0] . $archive_requested[1] . $archive_requested[2] . $archive_requested[3] : null; - $month = (isset($archive_requested[4]) && isset($archive_requested[5])) ? $archive_requested[4] . $archive_requested[5] : $archive_requested[4] . ""; - - $canonical = (!empty($month)) ? app_url() . DS . '?a=' .$year.$month : app_url(); - $month_num = isset($month) ? safe_html($month) : ""; - $monthObj = class_exists('DateTime') ? DateTime::createFromFormat('!m', $month_num) : ""; - $month_name = method_exists($monthObj, 'format') ? $monthObj->format('F') : ""; - $month_name = isset($month_name) ? $month_name : date("F", mktime(0, 0, 0, $month, 10)); - - } else { - - http_response_code(404); - throw new InvalidArgumentException("Argument passed must be of the type string, numeric or integer, null given"); - } - - $theme_meta['site_schema'] = (is_null($month)) ? generate_schema_org(ucfirst(trim('page not found')) . '|' . app_info()['site_name']) : generate_schema_org(ucfirst(trim(app_info()['site_name'] . '|' . $month . $year)), $canonical, $scriptlog_image, app_info()['site_description'], app_info()['site_keywords'], $scriptlog_imgthumb, date(DATE_ATOM)); - $theme_meta['site_meta_tags'] = (is_null($month)) ? generate_meta_tags(ucfirst(trim('page not found')), app_info()['site_description'], app_info()['site_keywords'], APP_TITLE, $scriptlog_image, app_url()) : generate_meta_tags($month_name, app_info()['site_description'], app_info()['site_name'], $scriptlog_image, $canonical); - - break; - - case 'tag': - - if ((empty($value)) || (empty($value) === '')) { - - http_response_code(404); - throw new InvalidArgumentException("Argument passed must be of the type string, numeric or integer, null given"); - - } else { - - $tag_requested = class_exists('HandleRequest') ? HandleRequest::isQueryStringRequested()['value'] : escape_html($value); - $tag = class_exists('FrontHelper') ? FrontHelper::simpleSearchingTag($tag_requested) : ""; - - $canonical = app_url() . DS . '?tag=' . $tag_requested; - $tag_id = isset($tag['ID']) ? intval($tag['ID']) : null; - $tag_title = isset($tag_requested) ? $tag_requested : null; - $description = isset($tag['post_content']) ? html_entity_decode(paragraph_l2br(htmlout($tag['post_content']))) : null; - $keyword = isset($tag['post_summary']) ? htmlout($tag['post_summary']) : null; - - } - - $theme_meta['site_schema'] = (is_null($tag_id)) ? generate_schema_org(ucfirst(trim('page not found')) . '' . app_info()['site_name']) : generate_schema_org(strtolower(trim(app_info()['site_name'])), $canonical, $scriptlog_image, $description, $tag_title, $scriptlog_imgthumb, date(DATE_ATOM)); - $theme_meta['site_meta_tags'] = (is_null($tag_title)) ? generate_meta_tags(ucfirst(trim('page not found')), app_info()['site_description'], app_info()['site_keywords'], APP_TITLE, $scriptlog_image, app_url()) . '' . app_info()['site_name'] : generate_meta_tags(strtolower(trim(str_replace('-', ' ', $value))), $description, $keyword, app_info()['site_name'], $scriptlog_image, $canonical); - - break; - - case 'blog': - - $theme_meta['site_schema'] = generate_schema_org(ucfirst(trim('blog')) . ' | ' . app_info()['site_name'], app_url(), $scriptlog_image, app_info()['site_description'], app_info()['site_tagline'], $scriptlog_imgthumb, date(DATE_ATOM)); - $theme_meta['site_meta_tags'] = generate_meta_tags('Blog: ' . ucfirst(trim(app_info()['site_name'] . ' | ' . app_info()['site_tagline'])), app_info()['site_description'], app_info()['site_keywords'], $scriptlog_image, app_url() . DS . 'blog'); - - break; - - default: - - $theme_meta['site_schema'] = generate_schema_org(app_info()['site_name'], app_url(), $scriptlog_image, app_info()['site_description'], app_info()['site_keywords'], $scriptlog_imgthumb, date(DATE_ATOM)); - $theme_meta['site_meta_tags'] = generate_meta_tags(app_info()['site_description'], app_info()['site_keywords'], app_info()['site_name'], $scriptlog_image, app_url()) ?? ""; - - break; - } - - return array('site_schema' => $theme_meta['site_schema'], 'site_meta_tags' => $theme_meta['site_meta_tags']); + $theme_meta = array(); + $post_id = null; + $page_id = null; + $category_id = null; + $post_title = null; + $page_title = null; + $category_title = null; + $tag_id = null; + $tag_title = null; + $author = null; + $keyword = null; + $description = null; + $category_title = null; + $canonical = null; + $image = null; + $created_at = null; + $modified_at = null; + $date_published = null; + $date_modified = null; + + switch ($key) { + case 'p': + if ((empty($value)) || ($value === '')) { + http_response_code(404); + throw new InvalidArgumentException("Argument passed must be of the type string, numeric or integer, null given"); + } else { + $read_post = class_exists('FrontHelper') ? FrontHelper::grabSimpleFrontPost($value) : null; + + // Handle case when post is not found (null returned) + if (empty($read_post) || !is_array($read_post)) { + $post_id = null; + $post_title = ""; + $description = ""; + $author = escape_html(app_info()['site_name']); + $image = app_url() . DS . APP_IMAGE . 'scriptlog-612x221.jpg'; + $canonical = app_url(); + $created_at = ""; + $modified_at = ""; + } else { + $post_id = (!empty($read_post['ID'])) ? abs((int)$read_post['ID']) : null; + $post_title = (!empty($read_post['post_title'])) ? escape_html($read_post['post_title']) : ""; + $description = (!empty($read_post['post_summary'])) ? escape_html($read_post['post_summary']) : escape_html($read_post['post_title']); + $author = (!empty($read_post['user_login'])) ? escape_html($read_post['user_login']) : escape_html(app_info()['site_name']); + $image = (!empty($read_post['media_filename'])) ? invoke_webp_image(escape_html($read_post['media_filename'])) : app_url() . DS . APP_IMAGE . 'scriptlog-612x221.jpg'; + $canonical = (!empty($read_post['post_slug'])) ? app_url() . DS . '?p=' . $post_id : app_url(); + $created_at = (!empty($read_post['post_date'])) ? convert_to_timestamp(escape_html($read_post['post_date'])) : ""; + $modified_at = (!empty($read_post['post_modified'])) ? convert_to_timestamp(escape_html($read_post['post_modified'])) : ""; + $date_published = (!empty($created_at)) ? convert_to_atom($created_at) : date(DATE_ATOM); + $date_modified = (!empty($modified_at)) ? convert_to_atom($modified_at) : date(DATE_ATOM); + } + } + + $theme_meta['site_schema'] = (is_null($post_id)) ? generate_schema_org(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : BlogSchema::generateBlogPostSchema($post_id); + $theme_meta['site_meta_tags'] = (is_null($post_id)) ? generate_meta_tags(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_meta_tags($post_title, $description, $author, $image, $canonical); + + break; + + case 'pg': + if ((empty($value)) || ($value === '')) { + http_response_code(404); + throw new InvalidArgumentException("Argument passed must be of the type string, numeric or integer, null given"); + } else { + $read_page = class_exists('FrontHelper') ? FrontHelper::grabSimpleFrontPage($value) : ""; + + $page_id = (!empty($read_page['ID'])) ? $read_page['ID'] : null; + $page_title = (!empty($read_page['post_title'])) ? escape_html($read_page['post_title']) : ""; + $description = (!empty($read_page['post_summary'])) ? escape_html($read_page['post_summary']) : escape_html($read_page['post_title']); + $author = (!empty($read_page['user_login'])) ? escape_html($read_page['user_login']) : escape_html(app_info()['site_name']); + $image = (!empty($read_page['media_filename'])) ? invoke_webp_image(escape_html($read_page['media_filename'])) : app_url() . DS . APP_IMAGE . 'scriptlog-612x221.jpg'; + $canonical = (!empty($read_page['post_slug'])) ? app_url() . DS . '?pg=' . $page_id : app_url(); + $created_at = (!empty($read_page['post_date'])) ? convert_to_timestamp(escape_html($read_page['post_date'])) : ""; + $modified_at = (!empty($read_page['post_modified'])) ? convert_to_timestamp(escape_html($read_page['post_modified'])) : ""; + $date_published = (!empty($created_at)) ? convert_to_atom($created_at) : date(DATE_ATOM); + $date_modified = (!empty($modified_at)) ? convert_to_atom($modified_at) : date(DATE_ATOM); + } + + $theme_meta['site_schema'] = (is_null($page_id)) ? generate_schema_org(ucfirst(trim('page not found')) . ' | ' . escape_html(app_info()['site_name'])) : generate_schema_org(ucfirst(trim($page_title)) . ' | ' . app_info()['site_name'], $canonical, $image, $description, escape_html(app_info()['site_keywords']), $scriptlog_imgthumb, $date_published, $date_modified); + $theme_meta['site_meta_tags'] = (is_null($page_id)) ? generate_meta_tags(ucfirst(trim('page not found')) . ' | ' . app_info()['site_name']) : generate_meta_tags($page_title, $description, $author, $image, $canonical); + + break; + + case 'cat': + if ((empty($value)) || ($value === '')) { + http_response_code(404); + throw new InvalidArgumentException("Argument passed must be of the type string, numeric or integer, null given"); + } else { + $read_category = class_exists('FrontHelper') ? FrontHelper::grabSimpleFrontTopic($value) : ""; + + $category_id = (!empty($read_category['ID'])) ? $read_category['ID'] : null; + $category_title = (!empty($read_category['topic_title'])) ? escape_html($read_category['topic_title']) : app_info()['site_name']; + $description = isset($read_category['topic_title']) ? escape_html($read_category['topic_title']) : app_info()['site_description']; + $canonical = (!empty($read_category['topic_slug'])) ? app_url() . DS . '?cat=' . $category_id : app_url(); + $date_published = date(DATE_ATOM); + $date_modified = date(DATE_ATOM); + } + + $theme_meta['site_schema'] = (is_null($category_id)) ? generate_schema_org(ucfirst(trim('page not found')) . '|' . escape_html(app_info()['site_name'])) : generate_schema_org(ucfirst(trim($category_title)) . '|' . app_info()['site_name'], $canonical, $image, $category_title, $description, $scriptlog_imgthumb, $date_published, $date_modified); + $theme_meta['site_meta_tags'] = (is_null($category_id)) ? generate_meta_tags(ucfirst(trim('page not found')) . '|' . app_info()['site_name'], app_info()['site_description'], app_info()['site_keywords'], APP_TITLE, $scriptlog_image, app_url()) : generate_meta_tags($category_title, $description, app_info()['site_name'], $scriptlog_image, $canonical); + + break; + + case 'a': + if (!empty($value)) { + $archive_requested = class_exists('HandleRequest') ? preg_split("//", HandleRequest::isQueryStringRequested()['value'], -1, PREG_SPLIT_NO_EMPTY) : preg_split("//", $value, -1, PREG_SPLIT_NO_EMPTY); + + $year = (isset($archive_requested[0]) && isset($archive_requested[1]) && isset($archive_requested[2]) && isset($archive_requested[3])) ? $archive_requested[0] . $archive_requested[1] . $archive_requested[2] . $archive_requested[3] : null; + $month = (isset($archive_requested[4]) && isset($archive_requested[5])) ? $archive_requested[4] . $archive_requested[5] : $archive_requested[4] . ""; + + $canonical = (!empty($month)) ? app_url() . DS . '?a=' . $year . $month : app_url(); + $month_num = isset($month) ? safe_html($month) : ""; + $monthObj = class_exists('DateTime') ? DateTime::createFromFormat('!m', $month_num) : ""; + $month_name = method_exists($monthObj, 'format') ? $monthObj->format('F') : ""; + $month_name = isset($month_name) ? $month_name : date("F", mktime(0, 0, 0, $month, 10)); + } else { + http_response_code(404); + throw new InvalidArgumentException("Argument passed must be of the type string, numeric or integer, null given"); + } + + $theme_meta['site_schema'] = (is_null($month)) ? generate_schema_org(ucfirst(trim('page not found')) . '|' . app_info()['site_name']) : generate_schema_org(ucfirst(trim(app_info()['site_name'] . '|' . $month . $year)), $canonical, $scriptlog_image, app_info()['site_description'], app_info()['site_keywords'], $scriptlog_imgthumb, date(DATE_ATOM)); + $theme_meta['site_meta_tags'] = (is_null($month)) ? generate_meta_tags(ucfirst(trim('page not found')), app_info()['site_description'], app_info()['site_keywords'], APP_TITLE, $scriptlog_image, app_url()) : generate_meta_tags($month_name, app_info()['site_description'], app_info()['site_name'], $scriptlog_image, $canonical); + + break; + + case 'tag': + if ((empty($value)) || (empty($value) === '')) { + http_response_code(404); + throw new InvalidArgumentException("Argument passed must be of the type string, numeric or integer, null given"); + } else { + $tag_requested = class_exists('HandleRequest') ? HandleRequest::isQueryStringRequested()['value'] : escape_html($value); + + // Get tag data - can be empty array if no results or error + $tag = class_exists('FrontHelper') ? FrontHelper::simpleSearchingTag($tag_requested) : ""; + + // Handle both empty array and proper result + $tag_id = (!empty($tag) && is_array($tag) && isset($tag['ID'])) ? intval($tag['ID']) : null; + $tag_title = !empty($tag_requested) ? $tag_requested : null; + + // Ensure description and keyword are never null - use fallback values + $description = (!empty($tag) && is_array($tag) && isset($tag['post_content'])) + ? html_entity_decode(paragraph_l2br(htmlout($tag['post_content']))) + : app_info()['site_description']; + $keyword = (!empty($tag) && is_array($tag) && isset($tag['post_summary'])) + ? htmlout($tag['post_summary']) + : app_info()['site_keywords']; + + $canonical = app_url() . DS . '?tag=' . $tag_requested; + } + + $theme_meta['site_schema'] = (is_null($tag_id)) ? generate_schema_org(ucfirst(trim('page not found')) . '' . app_info()['site_name']) : generate_schema_org(strtolower(trim(app_info()['site_name'])), $canonical, $scriptlog_image, $description, $tag_title, $scriptlog_imgthumb, date(DATE_ATOM)); + $theme_meta['site_meta_tags'] = (is_null($tag_title)) ? generate_meta_tags(ucfirst(trim('page not found')), app_info()['site_description'], app_info()['site_keywords'], APP_TITLE, $scriptlog_image, app_url()) . '' . app_info()['site_name'] : generate_meta_tags(strtolower(trim(str_replace('-', ' ', $value))), $description, $keyword, app_info()['site_name'], $scriptlog_image, $canonical); + + break; + + case 'blog': + $theme_meta['site_schema'] = generate_schema_org(ucfirst(trim('blog')) . ' | ' . app_info()['site_name'], app_url(), $scriptlog_image, app_info()['site_description'], app_info()['site_tagline'], $scriptlog_imgthumb, date(DATE_ATOM)); + $theme_meta['site_meta_tags'] = generate_meta_tags('Blog: ' . ucfirst(trim(app_info()['site_name'] . ' | ' . app_info()['site_tagline'])), app_info()['site_description'], app_info()['site_keywords'], $scriptlog_image, app_url() . DS . 'blog'); + + break; + + default: + $theme_meta['site_schema'] = generate_schema_org(app_info()['site_name'], app_url(), $scriptlog_image, app_info()['site_description'], app_info()['site_keywords'], $scriptlog_imgthumb, date(DATE_ATOM)); + $theme_meta['site_meta_tags'] = generate_meta_tags(app_info()['site_description'], app_info()['site_keywords'], app_info()['site_name'], $scriptlog_image, app_url()) ?? ""; + + break; + } + + return array('site_schema' => $theme_meta['site_schema'], 'site_meta_tags' => $theme_meta['site_meta_tags']); } diff --git a/src/lib/utility/theme-navigation.php b/src/lib/utility/theme-navigation.php index 87e550b71..cd88990dc 100755 --- a/src/lib/utility/theme-navigation.php +++ b/src/lib/utility/theme-navigation.php @@ -4,32 +4,45 @@ * retrieves_navigation * * @param string $visibility - * + * */ function theme_navigation($visibility) { - $sql = "SELECT ID, menu_label, menu_link, menu_status, menu_visibility, parent_id, menu_sort - FROM tbl_menu WHERE menu_status = 'Y' AND menu_visibility = '$visibility' + $sql = "SELECT ID, menu_label, menu_link, menu_status, menu_visibility, parent_id, menu_sort + FROM tbl_menu WHERE menu_status = 'Y' AND menu_visibility = ? ORDER BY menu_sort ASC, menu_label"; -$menus = array( - 'items' => array(), - 'parents' => array() -); - - $stmt = db_simple_query($sql); - - if ($stmt->num_rows > 0) { - - while ($items = $stmt->fetch_array(MYSQLI_ASSOC)) { - - $menus['items'][$items['ID']] = $items; // Create current menus item id into array - - $menus['parents'][$items['parent_id']][] = $items['ID']; // Create list of all items with child - + $menus = array( + 'items' => array(), + 'parents' => array() + ); + + $db = db_instance(); + + // Handle both Db (PDO) and mysqli + if (method_exists($db, 'dbQuery')) { + // PDO style - use dbQuery + $stmt = $db->dbQuery($sql, [$visibility]); + + if ($stmt && $stmt->rowCount() > 0) { + while ($items = $stmt->fetch(PDO::FETCH_ASSOC)) { + $menus['items'][$items['ID']] = $items; + $menus['parents'][$items['parent_id']][] = $items['ID']; + } + } + } else { + // mysqli style - use simpleQuery + $sql = str_replace('?', "'" . db_instance()->real_escape_string($visibility) . "'", $sql); + $stmt = $db->simpleQuery($sql); + + if ($stmt->num_rows > 0) { + while ($items = $stmt->fetch_array(MYSQLI_ASSOC)) { + $menus['items'][$items['ID']] = $items; + $menus['parents'][$items['parent_id']][] = $items['ID']; + } + } } - } - return $menus; -} \ No newline at end of file + return $menus; +} diff --git a/src/lib/utility/time-elapsed-string.php b/src/lib/utility/time-elapsed-string.php old mode 100644 new mode 100755 index 7a20b6da4..69c04e1b6 --- a/src/lib/utility/time-elapsed-string.php +++ b/src/lib/utility/time-elapsed-string.php @@ -1,16 +1,18 @@ diff($ago); $w = floor($diff->d / 7); @@ -19,12 +21,14 @@ function time_elapsed_string($datetime, $full = false) { foreach ($string as $k => &$v) { if ($k == 'w' && $w) { $v = $w . ' week' . ($w > 1 ? 's' : ''); - } else if (isset($diff->$k) && $diff->$k) { + } elseif (isset($diff->$k) && $diff->$k) { $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : ''); } else { unset($string[$k]); } } - if (!$full) $string = array_slice($string, 0, 1); + if (!$full) { + $string = array_slice($string, 0, 1); + } return $string ? implode(', ', $string) . ' ago' : 'just now'; -} \ No newline at end of file +} diff --git a/src/lib/utility/time-keeper.php b/src/lib/utility/time-keeper.php index d4bb8a0a0..dc42b49d5 100755 --- a/src/lib/utility/time-keeper.php +++ b/src/lib/utility/time-keeper.php @@ -1,11 +1,12 @@ (int)$currentTimezone->getOffset($utcTime), 'identifier' => $timezoneIdentifier); + $timezoneIdentifiers = DateTimeZone::listIdentifiers(); + $utcTime = new DateTime('now', new DateTimeZone('UTC')); + $tempTimezones = array(); + + foreach ($timezoneIdentifiers as $timezoneIdentifier) { + $currentTimezone = new DateTimeZone($timezoneIdentifier); + $tempTimezones[] = array('offset' => (int)$currentTimezone->getOffset($utcTime), 'identifier' => $timezoneIdentifier); + } - } + usort($tempTimezones, function ($a, $b) { + return ($a['offset'] == $b['offset']) ? strcmp($a['identifier'], $b['identifier']) : $a['offset'] - $b['offset']; + }); - usort($tempTimezones, function ($a, $b){ - return ($a['offset'] == $b['offset']) ? strcmp($a['identifier'], $b['identifier']) : $a['offset'] - $b['offset']; - }); - - $timezoneList = array(); - - foreach ($tempTimezones as $tz) { - - $sign = ($tz['offset'] > 0) ? '+' : '-'; - $offset = gmdate('H:i', abs($tz['offset'])); - $timezoneList[$tz['identifier']] = '(UTC ' . $sign . $offset . ') ' . $tz['identifier']; - - } + $timezoneList = array(); - return $timezoneList; + foreach ($tempTimezones as $tz) { + $sign = ($tz['offset'] > 0) ? '+' : '-'; + $offset = gmdate('H:i', abs($tz['offset'])); + $timezoneList[$tz['identifier']] = '(UTC ' . $sign . $offset . ') ' . $tz['identifier']; + } + return $timezoneList; } /** @@ -62,36 +58,35 @@ function timezone_list() * @see https://stackoverflow.com/questions/44216857/php-filters-list-of-timezone-as-array * @see https://stackoverflow.com/questions/4755704/php-timezone-list * @see https://stackoverflow.com/questions/851574/how-do-i-get-greenwich-mean-time-in-php/9328760#9328760 - * + * */ -function timezone_picker() +function timezone_picker() { - static $timezones = null; - if ($timezones === null) { - $timezones = []; - $offsets = []; - $now = new \DateTime('now', new \DateTimeZone('UTC')); - foreach (\DateTimeZone::listIdentifiers(\DateTimeZone::ALL) as $timezone) { - - // Calculate offset - $now->setTimezone(new \DateTimeZone($timezone)); - $offsets[] = $offset = $now->getOffset(); + static $timezones = null; + if ($timezones === null) { + $timezones = []; + $offsets = []; + $now = new \DateTime('now', new \DateTimeZone('UTC')); + foreach (\DateTimeZone::listIdentifiers(\DateTimeZone::ALL) as $timezone) { + // Calculate offset + $now->setTimezone(new \DateTimeZone($timezone)); + $offsets[] = $offset = $now->getOffset(); - // Display text for UTC offset - $hours = intval($offset / 3600); - $minutes = abs(intval($offset % 3600 / 60)); - $utcDiff = 'UTC' . ($offset ? sprintf('%+03d:%02d', $hours, $minutes) : ''); + // Display text for UTC offset + $hours = intval($offset / 3600); + $minutes = abs(intval($offset % 3600 / 60)); + $utcDiff = 'UTC' . ($offset ? sprintf('%+03d:%02d', $hours, $minutes) : ''); - // Display text for name - $name = str_replace('/', ', ', $timezone); - $name = str_replace('_', ' ', $name); - $name = str_replace('St ', 'St. ', $name); + // Display text for name + $name = str_replace('/', ', ', $timezone); + $name = str_replace('_', ' ', $name); + $name = str_replace('St ', 'St. ', $name); - $timezones[$timezone] = "$name ($utcDiff)"; - } - } + $timezones[$timezone] = "$name ($utcDiff)"; + } + } - return $timezones; + return $timezones; } /** @@ -101,19 +96,19 @@ function timezone_picker() */ function print_timezone_list() { - $timezone = DateTimeZone::listIdentifiers(DateTimeZone::ALL); - return print_r($timezone); + $timezone = DateTimeZone::listIdentifiers(DateTimeZone::ALL); + return print_r($timezone); } /** * timezone_identifier * * retrieve timezone_identifier info and return it record - * + * * @category function */ function timezone_identifier() { - $timezone_identifier = json_decode(app_info()['timezone_setting'], true); - return $timezone_identifier['timezone_identifier']; -} \ No newline at end of file + $timezone_identifier = json_decode(app_info()['timezone_setting'], true); + return $timezone_identifier['timezone_identifier']; +} diff --git a/src/lib/utility/timing-safe-equals.php b/src/lib/utility/timing-safe-equals.php index 582e5bca6..e40b4fd78 100755 --- a/src/lib/utility/timing-safe-equals.php +++ b/src/lib/utility/timing-safe-equals.php @@ -1,7 +1,8 @@ 0) { - - $string = substr($string, 0, $length); - - } - - return $string; - -} \ No newline at end of file + $string = trim($string); + + $string = function_exists('mb_convert_encoding') ? mb_convert_encoding($string, ' ISO-8859-1', 'UTF-8') : ""; + + $string = htmlentities($string, ENT_QUOTES, 'UTF-8'); + + $string = str_replace("#", "#", $string); + + $string = str_replace("%", "%", $string); + + $length = intval($length); + + if ($length > 0) { + $string = substr($string, 0, $length); + } + + return $string; +} diff --git a/src/lib/utility/turn-on-session.php b/src/lib/utility/turn-on-session.php index 8fcd15553..6e4009115 100755 --- a/src/lib/utility/turn-on-session.php +++ b/src/lib/utility/turn-on-session.php @@ -1,4 +1,5 @@ start(); - + // Check if session is valid (not expired, genuine IP/user-agent) if (!$session_handler->isValid()) { $session_handler->forget(); $session_handler->start(); // Start fresh session } - + // Do not allow to use too old session ID if (!empty($_SESSION['deleted_time']) && $_SESSION['deleted_time'] < time() - $life_time) { $session_handler->forget(); @@ -44,13 +45,12 @@ function turn_on_session($session_handler, $life_time, $cookies_name, $path, $do set_cookies_scl($cookies_name, session_id(), $life_time, $path, $domain, $secure, $httponly); $session_handler->refresh(); } - + return true; - } catch (ScriptlogCryptonizeException $e) { // Session decryption failed error_log("Session decryption error in turn_on_session: " . $e->getMessage()); - + // Attempt to recover by destroying and starting fresh try { $session_handler->forget(); @@ -60,9 +60,8 @@ function turn_on_session($session_handler, $life_time, $cookies_name, $path, $do error_log("Failed to recover session: " . $retryError->getMessage()); return false; } - } catch (Exception $e) { error_log("Unexpected error in turn_on_session: " . $e->getMessage()); return false; } -} \ No newline at end of file +} diff --git a/src/lib/utility/uniqid-real.php b/src/lib/utility/uniqid-real.php index 34806dce3..e1ebda225 100755 --- a/src/lib/utility/uniqid-real.php +++ b/src/lib/utility/uniqid-real.php @@ -1,30 +1,24 @@ $v) { + // variable that should not be unset + $no_unset = array('GLOBALS', '_GET', '_POST', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES'); - if (!in_array($k, $no_unset) && isset($GLOBALS[$k])) { - - unset($GLOBALS[$k]); - - } + $input = array_merge($_GET, $_POST, $_COOKIE, $_SERVER, $_ENV, $_FILES, isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array()); + foreach ($input as $k => $v) { + if (!in_array($k, $no_unset) && isset($GLOBALS[$k])) { + unset($GLOBALS[$k]); + } + } } - -} \ No newline at end of file diff --git a/src/lib/utility/upload-audio.php b/src/lib/utility/upload-audio.php index b3aa7831a..18a7ba967 100755 --- a/src/lib/utility/upload-audio.php +++ b/src/lib/utility/upload-audio.php @@ -1,4 +1,5 @@ open($doc_uploaded); - - if ($opened === true) { - - $file_count = (version_compare(phpversion(), "7.4.30", ">=")) ? $zip->count() : $zip->numFiles; + $zip = new ZipArchive(); - for ($i = 0; $i < $file_count; $i++) { + $opened = $zip->open($doc_uploaded); - $file_index = $zip->getNameIndex($i); + if ($opened === true) { + $file_count = (version_compare(phpversion(), "7.4.30", ">=")) ? $zip->count() : $zip->numFiles; - preg_match('/(.*)(phpinfo|system|php_uname|chmod|fopen|eval|flclose|readfile|base64_decode|passthru)(.*)/Us', $file_index, $matches); + for ($i = 0; $i < $file_count; $i++) { + $file_index = $zip->getNameIndex($i); - if (count($matches) > 0) { - - $zip->deleteName($file_index); + preg_match('/(.*)(phpinfo|system|php_uname|chmod|fopen|eval|flclose|readfile|base64_decode|passthru)(.*)/Us', $file_index, $matches); + if (count($matches) > 0) { + $zip->deleteName($file_index); + } } - - } - - $zip->close(); - - } -} \ No newline at end of file + $zip->close(); + } +} diff --git a/src/lib/utility/upload-media.php b/src/lib/utility/upload-media.php index 32ad3b9d7..65b88a57e 100755 --- a/src/lib/utility/upload-media.php +++ b/src/lib/utility/upload-media.php @@ -1,7 +1,8 @@ 'gd']); + // Currently you can choose between gd and imagick + return new ImageManager(['driver' => 'gd']); } /** * upload_photo() - * + * * uploading picture * if fileinfo enabled then Intervention Image works properly else will implement non-secure approach - * + * * @category function * @author M.Noermoehammad * @license MIT @@ -35,168 +37,133 @@ function photo_instance() * @param string $file_type * @param string $file_name * @return void - * + * */ function upload_photo($file_location, $file_size, $file_type, $file_name) { -$small_size = 320; -$medium_size = 640; -$large_size = 770; -$temp_src = $file_location; -$img_ext = get_file_extension($file_name); -$img_name = pathinfo($file_name, PATHINFO_BASENAME); -$img_source = null; - -switch (strtolower($file_type)) { - - case 'image/png': - - $img_source = imagecreatefrompng($file_location); - imagepalettetotruecolor($img_source); - imagealphablending($img_source, true); - imagesavealpha($img_source, true); + $small_size = 320; + $medium_size = 640; + $large_size = 770; + $temp_src = $file_location; + $img_ext = get_file_extension($file_name); + $img_name = pathinfo($file_name, PATHINFO_BASENAME); + $img_source = null; - break; - - case 'image/gif': + switch (strtolower($file_type)) { + case 'image/png': + $img_source = imagecreatefrompng($file_location); + imagepalettetotruecolor($img_source); + imagealphablending($img_source, true); + imagesavealpha($img_source, true); - $img_source = imagecreatefromgif($file_location); + break; - break; - - case 'image/jpeg': - case 'image/pjpeg': - case 'image/jpg': - - $img_source = imagecreatefromjpeg($file_location); - - break; - - case 'image/webp': - - $img_source = imagecreatefromwebp($file_location); - - break; - - case 'image/bmp': - - $img_source = imagecreatefrombmp($file_location); - - break; - - default: - - scriptlog_error("Unsupported File!"); - - break; - -} + case 'image/gif': + $img_source = imagecreatefromgif($file_location); -list($current_width, $current_height) = isset($temp_src) ? getimagesize($temp_src) : ""; + break; -// construct new name -$large_thumb_name = 'large_'.$img_name; -$medium_thumb_name = 'medium_'.$img_name; -$small_thumb_name = 'small_'.$img_name; + case 'image/jpeg': + case 'image/pjpeg': + case 'image/jpg': + $img_source = imagecreatefromjpeg($file_location); -// picture directory -$origin_path = __DIR__ . '/../../'.APP_IMAGE; -$origin_path_uploaded = $origin_path . $file_name; + break; -$small_path = __DIR__ . '/../../'.APP_IMAGE_SMALL; -create_directory($small_path); -$small_path_uploaded = $small_path . $small_thumb_name; + case 'image/webp': + $img_source = imagecreatefromwebp($file_location); -$medium_path = __DIR__ . '/../../'.APP_IMAGE_MEDIUM; -create_directory($medium_path); -$medium_path_uploaded = $medium_path. $medium_thumb_name; + break; -$large_path = __DIR__ . '/../../'.APP_IMAGE_LARGE; -create_directory($large_path); -$large_path_uploaded = $large_path . $large_thumb_name; + case 'image/bmp': + $img_source = imagecreatefrombmp($file_location); -if (!(extension_loaded('fileinfo') || function_exists('finfo_open') || class_exists('finfo'))) { + break; - if (resize_image($current_width, $current_height, $medium_size, $medium_path_uploaded, $img_source, 80, $file_type)) { - - if (!crop_image($current_width, $current_height, $small_size, $small_path_uploaded, $img_source, 80, $file_type)) { - - scriptlog_error("Error Creating small size of thumbnail!"); + default: + scriptlog_error("Unsupported File!"); + break; } - - if (!move_uploaded_file($temp_src, $origin_path_uploaded) ) { - - scriptlog_error("Error uploading picture"); - - } - - // creating large size thumbnail - $large_size_thumb = new Resize($origin_path_uploaded); - $large_size_thumb->resizeImage($large_size, 400, "crop"); - $large_size_thumb->saveImage($large_path_uploaded, 80); - - } -} else { - - if ($img_ext == "jpeg" || $img_ext == "jpg" || $img_ext == "png" || $img_ext == "gif" || $img_ext == "bmp") { - - if (false === set_webp_origin($current_width, $current_height, $file_location, $file_size, $origin_path_uploaded, $origin_path, $file_name)) { - - scriptlog_error("Error creating origin size of webp image format", E_USER_WARNING); - + list($current_width, $current_height) = isset($temp_src) ? getimagesize($temp_src) : ""; + + // construct new name + $large_thumb_name = 'large_' . $img_name; + $medium_thumb_name = 'medium_' . $img_name; + $small_thumb_name = 'small_' . $img_name; + + // picture directory + $origin_path = __DIR__ . '/../../' . APP_IMAGE; + $origin_path_uploaded = $origin_path . $file_name; + + $small_path = __DIR__ . '/../../' . APP_IMAGE_SMALL; + create_directory($small_path); + $small_path_uploaded = $small_path . $small_thumb_name; + + $medium_path = __DIR__ . '/../../' . APP_IMAGE_MEDIUM; + create_directory($medium_path); + $medium_path_uploaded = $medium_path . $medium_thumb_name; + + $large_path = __DIR__ . '/../../' . APP_IMAGE_LARGE; + create_directory($large_path); + $large_path_uploaded = $large_path . $large_thumb_name; + + if (!(extension_loaded('fileinfo') || function_exists('finfo_open') || class_exists('finfo'))) { + if (resize_image($current_width, $current_height, $medium_size, $medium_path_uploaded, $img_source, 80, $file_type)) { + if (!crop_image($current_width, $current_height, $small_size, $small_path_uploaded, $img_source, 80, $file_type)) { + scriptlog_error("Error Creating small size of thumbnail!"); + } + + if (!move_uploaded_file($temp_src, $origin_path_uploaded)) { + scriptlog_error("Error uploading picture"); + } + + // creating large size thumbnail + $large_size_thumb = new Resize($origin_path_uploaded); + $large_size_thumb->resizeImage($large_size, 400, "crop"); + $large_size_thumb->saveImage($large_path_uploaded, 80); + } + } else { + if ($img_ext == "jpeg" || $img_ext == "jpg" || $img_ext == "png" || $img_ext == "gif" || $img_ext == "bmp") { + if (false === set_webp_origin($current_width, $current_height, $file_location, $file_size, $origin_path_uploaded, $origin_path, $file_name)) { + scriptlog_error("Error creating origin size of webp image format", E_USER_WARNING); + } + + if (false === set_webp_regular($current_width, $current_height, $origin_path_uploaded, $large_path, $file_name)) { + scriptlog_error("Error creating regular size of webp image format", E_USER_WARNING); + } + + if (false === set_webp_medium($current_width, $current_height, $origin_path_uploaded, $medium_path, $file_name)) { + scriptlog_error("Error creating medium size of webp image format", E_USER_WARNING); + } + + if (false === set_webp_small($current_width, $current_height, $origin_path_uploaded, $small_path, $file_name)) { + scriptlog_error("Error creating small of webp image format", E_USER_WARNING); + } + } } - if (false === set_webp_regular($current_width, $current_height, $origin_path_uploaded, $large_path, $file_name)) { - - scriptlog_error("Error creating regular size of webp image format", E_USER_WARNING); - - } - - if (false === set_webp_medium($current_width, $current_height, $origin_path_uploaded, $medium_path, $file_name)) { - - scriptlog_error("Error creating medium size of webp image format", E_USER_WARNING); - + // save origin picture + if (false === set_origin_photo($current_width, $current_height, $file_location, $file_size, $origin_path_uploaded)) { + scriptlog_error("Error uploading picture", E_USER_WARNING); } - - if (false === set_webp_small($current_width, $current_height, $origin_path_uploaded, $small_path, $file_name)) { - - scriptlog_error("Error creating small of webp image format", E_USER_WARNING); - - } - - } - -} - - // save origin picture - if (false === set_origin_photo($current_width, $current_height, $file_location, $file_size, $origin_path_uploaded)) { - scriptlog_error("Error uploading picture", E_USER_WARNING); - - } - - // crop to regular size -if (false === set_regular_photo($current_width, $current_height, $origin_path_uploaded, $large_path, $file_name, $file_type)) { - - scriptlog_error("Error creating regular size of picture", E_USER_WARNING); - -} - -// crop to medium size -if (false === set_medium_photo($current_width, $current_height, $origin_path_uploaded, $medium_path, $file_name, $file_type) ) { - -scriptlog_error("Error creating medium size of picture", E_USER_WARNING); - -} + // crop to regular size + if (false === set_regular_photo($current_width, $current_height, $origin_path_uploaded, $large_path, $file_name, $file_type)) { + scriptlog_error("Error creating regular size of picture", E_USER_WARNING); + } -// crop to smaller size -if (false === set_small_photo($current_width, $current_height, $origin_path_uploaded, $small_path, $file_name, $file_type ) ) { - scriptlog_error("Error creating smaller size of picture", E_USER_WARNING); -} + // crop to medium size + if (false === set_medium_photo($current_width, $current_height, $origin_path_uploaded, $medium_path, $file_name, $file_type)) { + scriptlog_error("Error creating medium size of picture", E_USER_WARNING); + } + // crop to smaller size + if (false === set_small_photo($current_width, $current_height, $origin_path_uploaded, $small_path, $file_name, $file_type)) { + scriptlog_error("Error creating smaller size of picture", E_USER_WARNING); + } } /** @@ -210,24 +177,23 @@ function upload_photo($file_location, $file_size, $file_type, $file_name) * @param string $file_name * @param string $file_path_uploaded * @param string $file_type - * + * */ -function set_origin_photo($current_width, $current_height, $file_location, $file_size, $file_path_uploaded) +function set_origin_photo($current_width, $current_height, $file_location, $file_size, $file_path_uploaded) { -if ($current_width <= 0 || $current_height <= 0) { - return false; -} + if ($current_width <= 0 || $current_height <= 0) { + return false; + } -if (move_uploaded_file($file_location, $file_path_uploaded) && filesize($file_path_uploaded) !== $file_size) { - unlink($file_path_uploaded); -} - + if (move_uploaded_file($file_location, $file_path_uploaded) && filesize($file_path_uploaded) !== $file_size) { + unlink($file_path_uploaded); + } } /** * set_webp_origin - * + * * @category Function * @param int|numeric $current_width * @param int|numeric $current_height @@ -237,41 +203,32 @@ function set_origin_photo($current_width, $current_height, $file_location, $file * @param string $origin_path * @param string $file_name * @return false|true - * + * */ function set_webp_origin($current_width, $current_height, $file_location, $file_size, $origin_path_uploaded, $origin_path, $file_name) { -if ($current_width <= 0 || $current_height <= 0) { - - return false; - -} - -if (!move_uploaded_file($file_location, $origin_path_uploaded)) { - - return false; - -} - -if (filesize($origin_path_uploaded) !== $file_size) { - - unlink($origin_path_uploaded); - return false; - -} + if ($current_width <= 0 || $current_height <= 0) { + return false; + } -// get filename -$file_basename = substr($file_name, 0, strripos($file_name, '.')); - -$origin_webp = photo_instance()->make($origin_path_uploaded); -if ($origin_webp->save($origin_path.$file_basename.'.webp', 80, 'webp')) { + if (!move_uploaded_file($file_location, $origin_path_uploaded)) { + return false; + } - $origin_webp->destroy(); - return true; + if (filesize($origin_path_uploaded) !== $file_size) { + unlink($origin_path_uploaded); + return false; + } -} + // get filename + $file_basename = substr($file_name, 0, strripos($file_name, '.')); + $origin_webp = photo_instance()->make($origin_path_uploaded); + if ($origin_webp->save($origin_path . $file_basename . '.webp', 80, 'webp')) { + $origin_webp->destroy(); + return true; + } } /** @@ -283,92 +240,71 @@ function set_webp_origin($current_width, $current_height, $file_location, $file_ * @param string $file_path_thumb * @param string $file_name * @param string $file_type - * + * */ function set_regular_photo($current_width, $current_height, $file_path_uploaded, $file_path_thumb, $file_name, $file_type) { - $regular_size = 770; - - if ($current_width <= 0 || $current_height <= 0) { - - return false; - - } - - $regular_scaled = min($regular_size/$current_width, $regular_size/$current_height); - $new_width = ceil($regular_scaled*$current_width); - $new_height = ceil($regular_scaled*$current_height); - - $regular_photo = photo_instance()->make($file_path_uploaded); - $regular_photo->fit($new_width, $new_height); - - switch ($file_type) { - - case "image/jpeg": - case "image/jpg": - - if ($regular_photo->save($file_path_thumb .'large_'.$file_name, 80, 'jpg')) { - - $regular_photo->destroy(); - return true; - - } - - break; - - case "image/png": - - if ($regular_photo->save($file_path_thumb .'large_'.$file_name, 80, 'png')) { - - $regular_photo->destroy(); - return true; - - } - - break; - - case "image/gif": - - if ($regular_photo->save($file_path_thumb .'large_'.$file_name, 80, 'gif')) { - - $regular_photo->destroy(); - return true; - - } + $regular_size = 770; - break; + if ($current_width <= 0 || $current_height <= 0) { + return false; + } - case "image/bmp": + $regular_scaled = min($regular_size / $current_width, $regular_size / $current_height); + $new_width = ceil($regular_scaled * $current_width); + $new_height = ceil($regular_scaled * $current_height); - if ($regular_photo->save($file_path_thumb.'large_'.$file_name, 80, 'bmp')) { + $regular_photo = photo_instance()->make($file_path_uploaded); + $regular_photo->fit($new_width, $new_height); - $regular_photo->destroy(); - return true; + switch ($file_type) { + case "image/jpeg": + case "image/jpg": + if ($regular_photo->save($file_path_thumb . 'large_' . $file_name, 80, 'jpg')) { + $regular_photo->destroy(); + return true; + } + + break; + + case "image/png": + if ($regular_photo->save($file_path_thumb . 'large_' . $file_name, 80, 'png')) { + $regular_photo->destroy(); + return true; + } + + break; + + case "image/gif": + if ($regular_photo->save($file_path_thumb . 'large_' . $file_name, 80, 'gif')) { + $regular_photo->destroy(); + return true; + } + + break; - } + case "image/bmp": + if ($regular_photo->save($file_path_thumb . 'large_' . $file_name, 80, 'bmp')) { + $regular_photo->destroy(); + return true; + } - break; - - case "image/webp": + break; - if ($regular_photo->save($file_path_thumb.'large_'.$file_name, 80, 'webp')) { + case "image/webp": + if ($regular_photo->save($file_path_thumb . 'large_' . $file_name, 80, 'webp')) { + $regular_photo->destroy(); + return true; + } - $regular_photo->destroy(); - return true; + break; - } + default: + return false; - break; - - default: - - return false; - - break; - - } - + break; + } } /** @@ -380,267 +316,210 @@ function set_regular_photo($current_width, $current_height, $file_path_uploaded, * @param string $file_path_uploaded * @param string $file_path_thumb * @param string $file_name - * + * */ -function set_webp_regular($current_width, $current_height, $file_path_uploaded, $file_path_thumb, $file_name ) -{ - $regular_size = 770; - - if ($current_width <= 0 || $current_height <= 0) { - - return false; - - } - - // get filename - $file_basename = substr($file_name, 0, strripos($file_name, '.')); - - $regular_scaled = min($regular_size/$current_width, $regular_size/$current_height); - $new_width = ceil($regular_scaled*$current_width); - $new_height = ceil($regular_scaled*$current_height); - - $regular_webp = photo_instance()->make($file_path_uploaded); - $regular_webp->fit($new_width, $new_height); - if ($regular_webp->save($file_path_thumb.'large_'.$file_basename.'.webp', 80, 'webp')) { - - $regular_webp->destroy(); - return true; - - } - -} - -// setting medium size of picture -function set_medium_photo($current_width, $current_height, $file_path_uploaded, $file_path_thumb, $file_name, $file_type ) +function set_webp_regular($current_width, $current_height, $file_path_uploaded, $file_path_thumb, $file_name) { + $regular_size = 770; -$medium_size = 640; + if ($current_width <= 0 || $current_height <= 0) { + return false; + } -if ($current_width <= 0 || $current_height <= 0) { + // get filename + $file_basename = substr($file_name, 0, strripos($file_name, '.')); - return false; + $regular_scaled = min($regular_size / $current_width, $regular_size / $current_height); + $new_width = ceil($regular_scaled * $current_width); + $new_height = ceil($regular_scaled * $current_height); + $regular_webp = photo_instance()->make($file_path_uploaded); + $regular_webp->fit($new_width, $new_height); + if ($regular_webp->save($file_path_thumb . 'large_' . $file_basename . '.webp', 80, 'webp')) { + $regular_webp->destroy(); + return true; + } } -$medium_scaled = min($medium_size/$current_width, $medium_size/$current_height); -$new_width = ceil($medium_scaled*$current_width); -$new_height = ceil($medium_scaled*$current_height); - -$medium_photo = photo_instance()->make($file_path_uploaded); -$medium_photo->fit($new_width, $new_height); - -switch ($file_type) { - - case "image/jpeg": - case "image/jpg": +// setting medium size of picture +function set_medium_photo($current_width, $current_height, $file_path_uploaded, $file_path_thumb, $file_name, $file_type) +{ - if ($medium_photo->save($file_path_thumb .'medium_'.$file_name, 80, 'jpg') ) { + $medium_size = 640; - $medium_photo->destroy(); - return true; - + if ($current_width <= 0 || $current_height <= 0) { + return false; } - - break; - - case "image/png": - - if ($medium_photo->save($file_path_thumb .'medium_'.$file_name, 80, 'png') ) { - $medium_photo->destroy(); - return true; - - } + $medium_scaled = min($medium_size / $current_width, $medium_size / $current_height); + $new_width = ceil($medium_scaled * $current_width); + $new_height = ceil($medium_scaled * $current_height); - break; + $medium_photo = photo_instance()->make($file_path_uploaded); + $medium_photo->fit($new_width, $new_height); - case "image/gif": + switch ($file_type) { + case "image/jpeg": + case "image/jpg": + if ($medium_photo->save($file_path_thumb . 'medium_' . $file_name, 80, 'jpg')) { + $medium_photo->destroy(); + return true; + } - if ($medium_photo->save($file_path_thumb .'medium_'.$file_name, 80, 'gif') ) { + break; - $medium_photo->destroy(); - return true; - - } - - break; + case "image/png": + if ($medium_photo->save($file_path_thumb . 'medium_' . $file_name, 80, 'png')) { + $medium_photo->destroy(); + return true; + } - case "image/bmp": + break; - if ($medium_photo->save($file_path_thumb . 'medium_'.$file_name, 80, 'bmp') ) { + case "image/gif": + if ($medium_photo->save($file_path_thumb . 'medium_' . $file_name, 80, 'gif')) { + $medium_photo->destroy(); + return true; + } - $medium_photo->destroy(); - return true; + break; - } + case "image/bmp": + if ($medium_photo->save($file_path_thumb . 'medium_' . $file_name, 80, 'bmp')) { + $medium_photo->destroy(); + return true; + } - break; + break; - case "image/webp": + case "image/webp": + if ($medium_photo->save($file_path_thumb . 'medium_' . $file_name, 80, 'webp')) { + $medium_photo->destroy(); + return true; + } - if ($medium_photo->save($file_path_thumb.'medium_'.$file_name, 80, 'webp')) { + break; - $medium_photo->destroy(); - return true; + default: + return false; + break; } - - break; - - default: - - return false; - - break; - -} - } // setting medium size of webp image format -function set_webp_medium( $current_width, $current_height, $file_path_uploaded, $file_path_thumb, $file_name ) +function set_webp_medium($current_width, $current_height, $file_path_uploaded, $file_path_thumb, $file_name) { -$medium_size = 640; - -if ($current_width <= 0 || $current_height <= 0) { - - return false; + $medium_size = 640; -} - -// get filename -$file_basename = substr($file_name, 0, strripos($file_name, '.')); - -$medium_scaled = min($medium_size/$current_width, $medium_size/$current_height); -$new_width = ceil($medium_scaled*$current_width); -$new_height = ceil($medium_scaled*$current_height); - -$medium_webp = photo_instance()->make($file_path_uploaded); -$medium_webp->fit($new_width, $new_height); -if ($medium_webp->save($file_path_thumb.'medium_'.$file_basename.'.webp', 80, 'webp')) { + if ($current_width <= 0 || $current_height <= 0) { + return false; + } - $medium_webp->destroy(); - return true; + // get filename + $file_basename = substr($file_name, 0, strripos($file_name, '.')); -} + $medium_scaled = min($medium_size / $current_width, $medium_size / $current_height); + $new_width = ceil($medium_scaled * $current_width); + $new_height = ceil($medium_scaled * $current_height); + $medium_webp = photo_instance()->make($file_path_uploaded); + $medium_webp->fit($new_width, $new_height); + if ($medium_webp->save($file_path_thumb . 'medium_' . $file_basename . '.webp', 80, 'webp')) { + $medium_webp->destroy(); + return true; + } } // setting smaller size of picture -function set_small_photo( $current_width, $current_height, $file_path_uploaded, $file_path_thumb, $file_name, $file_type) +function set_small_photo($current_width, $current_height, $file_path_uploaded, $file_path_thumb, $file_name, $file_type) { -$small_size = 320; - -if ($current_width <= 0 || $current_height <= 0) { - - return false; + $small_size = 320; -} - -$small_scaled = min($small_size/$current_width, $small_size/$current_height); -$new_width = ceil($small_scaled*$current_width); -$new_height = ceil($small_scaled*$current_height); - -$small_photo = photo_instance()->make($file_path_uploaded); -$small_photo->fit($new_width, $new_height); - -switch ($file_type) { - - case "image/jpeg": - case "image/jpg": - - if ($small_photo->save($file_path_thumb.'small_'.$file_name, 80, 'jpg' ) ) { - - $small_photo->destroy(); - return true; - + if ($current_width <= 0 || $current_height <= 0) { + return false; } - - break; - - case "image/png": - - if ($small_photo->save($file_path_thumb.'small_'.$file_name, 80, 'png' ) ) { - $small_photo->destroy(); - return true; - - } + $small_scaled = min($small_size / $current_width, $small_size / $current_height); + $new_width = ceil($small_scaled * $current_width); + $new_height = ceil($small_scaled * $current_height); - break; - - case "image/gif": + $small_photo = photo_instance()->make($file_path_uploaded); + $small_photo->fit($new_width, $new_height); - if ($small_photo->save($file_path_thumb.'small_'.$file_name, 80, 'gif' ) ) { + switch ($file_type) { + case "image/jpeg": + case "image/jpg": + if ($small_photo->save($file_path_thumb . 'small_' . $file_name, 80, 'jpg')) { + $small_photo->destroy(); + return true; + } - $small_photo->destroy(); - return true; - - } + break; + case "image/png": + if ($small_photo->save($file_path_thumb . 'small_' . $file_name, 80, 'png')) { + $small_photo->destroy(); + return true; + } - break; + break; - case "image/bmp": + case "image/gif": + if ($small_photo->save($file_path_thumb . 'small_' . $file_name, 80, 'gif')) { + $small_photo->destroy(); + return true; + } - if ($small_photo->save($file_path_thumb.'small_'.$file_name, 80, 'bmp') ) { - $small_photo->destroy(); - return true; + break; - } + case "image/bmp": + if ($small_photo->save($file_path_thumb . 'small_' . $file_name, 80, 'bmp')) { + $small_photo->destroy(); + return true; + } - break; + break; - case "image/webp": + case "image/webp": + if ($small_photo->save($file_path_thumb . 'small_' . $file_name, 80, 'webp')) { + $small_photo->destroy(); + return true; + } - if ($small_photo->save($file_path_thumb.'small_'.$file_name, 80, 'webp') ) { + break; - $small_photo->destroy(); - return true; + default: + return false; + break; } - - break; - - default: - - return false; - - break; - -} - } // setting smaller size of webp image format -function set_webp_small( $current_width, $current_height, $file_path_uploaded, $file_path_thumb, $file_name ) +function set_webp_small($current_width, $current_height, $file_path_uploaded, $file_path_thumb, $file_name) { -$small_size = 320; + $small_size = 320; -if ($current_width <= 0 || $current_height <= 0) { - - return false; - -} - -// get filename -$file_basename = substr($file_name, 0, strripos($file_name, '.')); - -$small_scaled = min($small_size/$current_width, $small_size/$current_height); -$new_width = ceil($small_scaled*$current_width); -$new_height = ceil($small_scaled*$current_height); + if ($current_width <= 0 || $current_height <= 0) { + return false; + } -$small_webp = photo_instance()->make($file_path_uploaded); -$small_webp->fit($new_width, $new_height); -if ($small_webp->save($file_path_thumb.'small_'.$file_basename.'.webp', 80, 'webp')) { + // get filename + $file_basename = substr($file_name, 0, strripos($file_name, '.')); - $small_webp->destroy(); - return true; + $small_scaled = min($small_size / $current_width, $small_size / $current_height); + $new_width = ceil($small_scaled * $current_width); + $new_height = ceil($small_scaled * $current_height); + $small_webp = photo_instance()->make($file_path_uploaded); + $small_webp->fit($new_width, $new_height); + if ($small_webp->save($file_path_thumb . 'small_' . $file_basename . '.webp', 80, 'webp')) { + $small_webp->destroy(); + return true; + } } - -} \ No newline at end of file diff --git a/src/lib/utility/upload-plugin.php b/src/lib/utility/upload-plugin.php index 7ae9c71c1..2fe165466 100755 --- a/src/lib/utility/upload-plugin.php +++ b/src/lib/utility/upload-plugin.php @@ -1,9 +1,11 @@ -open($zip_path_uploaded) === true) { - - $file_count = (version_compare(phpversion(), "7.4.30", ">=")) ? $zip->count() : $zip->numFiles; + $file_count = 0; + $total_size = 0; + $zip = new ZipArchive(); - for ($i = 0; $i < $file_count; $i++) { + if ($zip->open($zip_path_uploaded) === true) { + $file_count = (version_compare(phpversion(), "7.4.30", ">=")) ? $zip->count() : $zip->numFiles; - $file_index = $zip->getNameIndex($i); - $stats = $zip->statIndex($i); + for ($i = 0; $i < $file_count; $i++) { + $file_index = $zip->getNameIndex($i); + $stats = $zip->statIndex($i); - // Preventing zip slip path traversal - if (strpos($file_index, '../') !== false || substr($file_index, 0, 1) === '/') { - throw new InvalidArgumentException(); - } + // Preventing zip slip path traversal + if (strpos($file_index, '../') !== false || substr($file_index, 0, 1) === '/') { + throw new InvalidArgumentException(); + } - if (substr($file_index, -1) !== '/') { + if (substr($file_index, -1) !== '/') { + $file_count++; + if ($file_count > MAX_FILES) { + throw new InvalidArgumentException(); + } - $file_count++; - if ($file_count > MAX_FILES) { - throw new InvalidArgumentException(); - } + $fp = $zip->getStream($file_index); + $current_size = 0; + while (!feof($fp)) { + $current_size += READ_LENGTH; + $total_size += READ_LENGTH; - $fp = $zip->getStream($file_index); - $current_size = 0; - while (!feof($fp)) { - $current_size += READ_LENGTH; - $total_size += READ_LENGTH; + if ($total_size > MAX_SIZE) { + throw new InvalidArgumentException(); + } - if ($total_size > MAX_SIZE) { - throw new InvalidArgumentException(); - } + // Additional protection: checking compression ration + if ($stats['comp_size'] > 0) { + $ratio = $current_size / $stats['com_size']; + if ($ratio > MAX_RATIO) { + throw new InvalidArgumentException(); + } + } - // Additional protection: checking compression ration - if ($stats['comp_size'] > 0) { - $ratio = $current_size / $stats['com_size']; - if ($ratio > MAX_RATIO) { - throw new InvalidArgumentException(); - } - } + $extractPath = $plugin_path . DIRECTORY_SEPARATOR . $file_index; + $extractDir = dirname($extractPath); - $extractPath = $plugin_path . DIRECTORY_SEPARATOR . $file_index; - $extractDir = dirname($extractPath); - - if (!is_dir($extractDir)) { - mkdir($extractDir, 0755, true); - } - - file_put_contents($extractPath, fread($fp, READ_LENGTH), FILE_APPEND); + if (!is_dir($extractDir)) { + mkdir($extractDir, 0755, true); + } - } + file_put_contents($extractPath, fread($fp, READ_LENGTH), FILE_APPEND); + } - fclose($fp); + fclose($fp); + } else { + mkdir($plugin_path . DIRECTORY_SEPARATOR . $file_index, 0755, true); + } - } else { + preg_match('/(.*)(phpinfo|system|php_uname|chmod|fopen|eval|flclose|readfile|base64_decode|passthru)(.*)/Us', $file_index, $matches); - mkdir($plugin_path . DIRECTORY_SEPARATOR . $file_index, 0755, true); - } + if (count($matches) > 0) { + $zip->deleteName($file_index); + } + } - preg_match('/(.*)(phpinfo|system|php_uname|chmod|fopen|eval|flclose|readfile|base64_decode|passthru)(.*)/Us', $file_index, $matches); + $zip->extractTo($plugin_path); - if (count($matches) > 0) { + $zip->close(); - $zip->deleteName($file_index); + unlink($zip_path_uploaded); - } - - } - - $zip->extractTo($plugin_path); - - $zip->close(); - - unlink($zip_path_uploaded); - - return true; - - } else { - - return false; - - } - -} \ No newline at end of file + return true; + } else { + return false; + } +} diff --git a/src/lib/utility/upload-theme.php b/src/lib/utility/upload-theme.php index 6cde4dfc6..5d8647ada 100755 --- a/src/lib/utility/upload-theme.php +++ b/src/lib/utility/upload-theme.php @@ -1,52 +1,46 @@ open($pathFile); + if (move_uploaded_file($file_location, $pathFile)) { + $zip = new ZipArchive(); + $x = $zip->open($pathFile); - if ($x === true) { - - $zip->extractTo(APP_ROOT.'public/themes/'); - $zip->close(); + if ($x === true) { + $zip->extractTo(APP_ROOT . 'public/themes/'); + $zip->close(); - unlink($pathFile); + unlink($pathFile); + } + return true; + } else { + scriptlog_error("There was problem with the upload. Please try again"); } - - return true; - - } else { - - scriptlog_error("There was problem with the upload. Please try again"); - - } - -} \ No newline at end of file +} diff --git a/src/lib/utility/upload-video.php b/src/lib/utility/upload-video.php index b9affb671..3853d3327 100755 --- a/src/lib/utility/upload-video.php +++ b/src/lib/utility/upload-video.php @@ -1,9 +1,10 @@ findUserByLogin($user_login); - - } + $user_info = array(); - return $user_info; + if (is_object($authenticator)) { + $user_info = $authenticator->findUserByLogin($user_login); + } -} \ No newline at end of file + return $user_info; +} diff --git a/src/lib/utility/user-privilege.php b/src/lib/utility/user-privilege.php index 58a633ff0..2571d9e77 100755 --- a/src/lib/utility/user-privilege.php +++ b/src/lib/utility/user-privilege.php @@ -1,4 +1,5 @@ scriptlog_session_level)) { - - return Session::getInstance()->scriptlog_session_level; - - } + if (isset(Session::getInstance()->scriptlog_session_level)) { + return Session::getInstance()->scriptlog_session_level; + } - return false; - -} \ No newline at end of file + return false; +} diff --git a/src/lib/utility/user-registration.php b/src/lib/utility/user-registration.php old mode 100644 new mode 100755 index dbd5a546e..c2dc428a2 --- a/src/lib/utility/user-registration.php +++ b/src/lib/utility/user-registration.php @@ -5,12 +5,12 @@ /** * user_init_dao * - * @return object|bool Returns true if class is a defined class, false otherwise. - * + * @return object|bool Returns true if class is a defined class, false otherwise. + * */ function user_init_dao() { - return (class_exists('UserDao')) ? new UserDao() : ""; + return (class_exists('UserDao')) ? new UserDao() : ""; } /** @@ -18,24 +18,24 @@ function user_init_dao() * * @param string $userLogin * @return bool - * + * */ function is_username_available($userLogin) { - $userDao = user_init_dao(); - return $userDao->isUserLoginExists($userLogin); + $userDao = user_init_dao(); + return $userDao->isUserLoginExists($userLogin); } /** * is_email_exists - * + * * @param string $userEmail * @return boolean */ function is_email_exists($userEmail) { - $userDao = user_init_dao(); - return $userDao->checkUserEmail($userEmail); + $userDao = user_init_dao(); + return $userDao->checkUserEmail($userEmail); } /** @@ -46,11 +46,11 @@ function is_email_exists($userEmail) * @license MIT * @version 1.0 * @return int|num - * + * */ function signup_id() { - return form_id("signup"); + return form_id("signup"); } /** @@ -61,12 +61,11 @@ function signup_id() */ function verify_signup_id($signupId) { - if ((!isset($_SESSION['human_signup_id'], $signupId)) || ($_SESSION['human_signup_id'] !== $signupId)) { - - return false; - } + if ((!isset($_SESSION['human_signup_id'], $signupId)) || ($_SESSION['human_signup_id'] !== $signupId)) { + return false; + } - return true; + return true; } /** @@ -77,27 +76,26 @@ function verify_signup_id($signupId) * @param string $uniqueKey * @param array $values * @return void - * + * */ function checking_signup_request($ip, $signupId, $uniqueKey, array $values) { - if (function_exists('check_form_request') && check_form_request($values, ['user_login', 'user_email', 'user_pass', 'user_pass2', 'scriptpot_name', 'scriptpot_email', 'iagree', 'csrf', 'SignUp']) === false) { - header(APP_PROTOCOL . ' 413 Payload Too Large', true, 413); - header('Status: 413 Payload Too Large'); - header('Retry-After: 3600'); - exit("413 Payload Too Large"); - } - - if (false === verify_signup_id($signupId)) { - http_response_code(400); - exit("400 Bad Request"); - } - - if (!isset($uniqueKey) || ($uniqueKey !== md5(app_key() . $ip))) { - - http_response_code(400); - exit("400 Bad Request "); - } + if (function_exists('check_form_request') && check_form_request($values, ['user_login', 'user_email', 'user_pass', 'user_pass2', 'scriptpot_name', 'scriptpot_email', 'iagree', 'csrf', 'SignUp']) === false) { + header(APP_PROTOCOL . ' 413 Payload Too Large', true, 413); + header('Status: 413 Payload Too Large'); + header('Retry-After: 3600'); + exit("413 Payload Too Large"); + } + + if (false === verify_signup_id($signupId)) { + http_response_code(400); + exit("400 Bad Request"); + } + + if (!isset($uniqueKey) || ($uniqueKey !== md5(app_key() . $ip))) { + http_response_code(400); + exit("400 Bad Request "); + } } /** @@ -109,103 +107,91 @@ function checking_signup_request($ip, $signupId, $uniqueKey, array $values) * @param mixed $errors * @param array $values * @return mixed - * + * */ function processing_signup($ip, $signupId, $uniqueKey, $errors, array $values) { - $checkError = true; - $signup_success = array(); - - $user_login = (!empty($values['user_login']) && $values['user_login'] == $_POST['user_login']) ? prevent_injection($values['user_login']) : ''; - $user_email = (!empty($values['user_email']) && $values['user_email'] == $_POST['user_email']) ? prevent_injection($values['user_email']) : ''; - $user_pass = (!empty($values['user_pass']) && $values['user_pass'] == $_POST['user_pass']) ? prevent_injection($values['user_pass']) : ''; - $confirm_pass = (!empty($values['user_pass2']) && $values['user_pass2'] == $_POST['user_pass2']) ? prevent_injection($values['user_pass2']) : ''; - $iagree = (isset($values['iagree']) && $values['iagree'] == $_POST['iagree']) ? $values['iagree'] : ''; - $csrf = (isset($values['csrf']) && $values['csrf'] == $_POST['csrf']) ? $values['csrf'] : ''; - - $user_session = function_exists('openssl_random_pseudo_bytes') ? substr(hash('sha256', bin2hex(openssl_random_pseudo_bytes(ceil(32 / 2)))), 0, 32) : ''; - $hash_password = function_exists('scriptlog_password') ? scriptlog_password($user_pass) : ''; - $user_level = function_exists('membership_default_role') ? membership_default_role() : ''; - - // validate registration request - checking_signup_request($ip, $signupId, $uniqueKey, $values); - $valid = !empty($csrf) && verify_form_token('signup_form', $csrf); + $checkError = true; + $signup_success = array(); - if (!$valid) { + $user_login = (!empty($values['user_login']) && $values['user_login'] == $_POST['user_login']) ? prevent_injection($values['user_login']) : ''; + $user_email = (!empty($values['user_email']) && $values['user_email'] == $_POST['user_email']) ? prevent_injection($values['user_email']) : ''; + $user_pass = (!empty($values['user_pass']) && $values['user_pass'] == $_POST['user_pass']) ? prevent_injection($values['user_pass']) : ''; + $confirm_pass = (!empty($values['user_pass2']) && $values['user_pass2'] == $_POST['user_pass2']) ? prevent_injection($values['user_pass2']) : ''; + $iagree = (isset($values['iagree']) && $values['iagree'] == $_POST['iagree']) ? $values['iagree'] : ''; + $csrf = (isset($values['csrf']) && $values['csrf'] == $_POST['csrf']) ? $values['csrf'] : ''; - $checkError = false; - $errors['errorMessage'] = "Sorry, attack detected!"; - } + $user_session = function_exists('openssl_random_pseudo_bytes') ? substr(hash('sha256', bin2hex(openssl_random_pseudo_bytes(ceil(32 / 2)))), 0, 32) : ''; + $hash_password = function_exists('scriptlog_password') ? scriptlog_password($user_pass) : ''; + $user_level = function_exists('membership_default_role') ? membership_default_role() : ''; - if (empty($user_login) || empty($user_email) || empty($user_pass) || empty($confirm_pass)) { + // validate registration request + checking_signup_request($ip, $signupId, $uniqueKey, $values); + $valid = !empty($csrf) && verify_form_token('signup_form', $csrf); - $checkError = false; - $errors['errorMessage'] = "All columns required must be filled"; - } - - if (!preg_match('/^(?=.{8,20}$)(?![_.])(?!.*[_.]{2})[a-zA-Z0-9._]+(? $user_login, - "user_email" => $user_email, - "user_pass" => $hash_password, - "user_level" => $user_level, - "user_url" => "#", - "user_registered" => date("Y-m-d H:i:s"), - "user_session" => $user_session - ]); + if (false === check_pwd_strength($user_pass)) { + $checkError = false; + $errors['errorMessage'] = MESSAGE_WEAK_PASSWORD; + } + } - $signup_success['successMessage'] = "Register Successful"; - } else { + if (scriptpot_validate($values) === false) { + http_response_code(403); + $errors['errorMessage'] = "anomaly behaviour detected!"; + } - $checkError = false; - $errors['errorMessage'] = "Please checked terms of use!"; - } + if ((!empty($iagree)) && ($checkError === true)) { + medoo_insert("tbl_users", [ + "user_login" => $user_login, + "user_email" => $user_email, + "user_pass" => $hash_password, + "user_level" => $user_level, + "user_url" => "#", + "user_registered" => date("Y-m-d H:i:s"), + "user_session" => $user_session + ]); + + $signup_success['successMessage'] = "Register Successful"; + } else { + $checkError = false; + $errors['errorMessage'] = "Please checked terms of use!"; + } - return array($errors, $signup_success); + return array($errors, $signup_success); } diff --git a/src/lib/utility/validate-date.php b/src/lib/utility/validate-date.php index f14bafe22..ee11327ec 100755 --- a/src/lib/utility/validate-date.php +++ b/src/lib/utility/validate-date.php @@ -1,22 +1,22 @@ format($format) === $date; + $d = DateTime::createFromFormat($format, $date); -} \ No newline at end of file + return $d && $d->format($format) === $date; +} diff --git a/src/lib/utility/whoops-error.php b/src/lib/utility/whoops-error.php index c45f0922d..b44176a3d 100755 --- a/src/lib/utility/whoops-error.php +++ b/src/lib/utility/whoops-error.php @@ -1,7 +1,8 @@ setPageTitle(APP_TITLE . " broken!"); -$errorPage->addDataTable(APP_TITLE, array( - "version" => APP_VERSION, - "codename" => APP_CODENAME, - "hostname" => app_url() -)); - -$whoops->pushHandler($errorPage); -$whoops->register(); - -} else { - -set_exception_handler('LogError::exceptionHandler'); - -set_error_handler('LogError::errorHandler'); - -register_shutdown_function(function () { - $error = error_get_last(); - if ($error !== null) { - $e = new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']); - - if (class_exists('LogError')) { - LogError::exceptionHandler($e); - } + if (APP_DEVELOPMENT === true) { + $whoops = new \Whoops\Run(); + + $errorPage = new \Whoops\Handler\PrettyPageHandler(); + $errorPage->setPageTitle(APP_TITLE . " broken!"); + $errorPage->addDataTable(APP_TITLE, array( + "version" => APP_VERSION, + "codename" => APP_CODENAME, + "hostname" => app_url() + )); + + $whoops->pushHandler($errorPage); + $whoops->register(); + } else { + set_exception_handler('LogError::exceptionHandler'); + + set_error_handler('LogError::errorHandler'); + + register_shutdown_function(function () { + $error = error_get_last(); + if ($error !== null) { + $e = new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']); + + if (class_exists('LogError')) { + LogError::exceptionHandler($e); + } + } + }); } -}); - } - -} \ No newline at end of file diff --git a/src/lib/utility/worst-passwords.php b/src/lib/utility/worst-passwords.php index e5305d097..4dea77802 100755 --- a/src/lib/utility/worst-passwords.php +++ b/src/lib/utility/worst-passwords.php @@ -1,9 +1,10 @@ =')) ? clearstatcache() : clearstatcache(true); - -$privilege = (isset($user_level)) ? user_privilege() : ""; + (version_compare(PHP_VERSION, '7.4', '>=')) ? clearstatcache() : clearstatcache(true); -if ($privilege === 'administrator' || $privilege === 'manager') { + $privilege = (isset($user_level)) ? user_privilege() : ""; - $fp = fopen(__DIR__ . '/../../.htaccess', 'w'); + if ($privilege === 'administrator' || $privilege === 'manager') { + $fp = fopen(__DIR__ . '/../../.htaccess', 'w'); - $sleep_timer = ($permalink_status === 'yes') ? 10 : 5; + $sleep_timer = ($permalink_status === 'yes') ? 10 : 5; - (function_exists('sleep')) ? sleep($sleep_timer) : ""; - - fwrite($fp, $data); - fclose($fp); - -} else { - - scriptlog_error("Privilege is not compatible to perform this action"); - -} + (function_exists('sleep')) ? sleep($sleep_timer) : ""; + fwrite($fp, $data); + fclose($fp); + } else { + scriptlog_error("Privilege is not compatible to perform this action"); + } } /** @@ -47,49 +43,48 @@ function write_htaccess($permalink_status, $user_level, $data) * @version 1.0 * @param string $permalink_status * @return string - * + * */ function read_htaccess_config($permalink_status) { -$content = '# START ScriptLog'. PHP_EOL; -$content .= '# The directives (lines) between "START ScriptLog" and "FINISH ScriptLog" are' . PHP_EOL; -$content .= '# dynamically generated, and should only be modified if you know what you are doing.' . PHP_EOL; -$content .= '# Any changes to these lines will be overwritten by scriptlog herself on setting permalink.' . PHP_EOL; - -if ($permalink_status === 'yes') { - - $content .= '' . PHP_EOL; - $content .= 'RewriteEngine On'. PHP_EOL; - $content .= '#RewriteCond %{HTTP_USER_AGENT} libwww-perl.* ' . PHP_EOL; - $content .= '#RewriteRule .* – [F,L]'. PHP_EOL; - $content .= '# The RewriteBase of the system (change if you are using this system in a sub-folder)' . PHP_EOL; - $content .= '#RewriteBase /'. PHP_EOL; - $content .= '# Force HTTPS and remove www (canonical: https://yourdomain.TLD) ' . PHP_EOL; - $content .= '#RewriteCond %{HTTPS} off [OR]' . PHP_EOL; - $content .= '#RewriteCond %{HTTP_HOST} ^www\.yourdomain\.TLD$'. PHP_EOL; - $content .= '#RewriteRule ^/?$ "https\:\/\/yourdomain\.TLD\/" [R=301, L]' . PHP_EOL; - $content .= '# Ensure all front-end UI-UX files readable'. PHP_EOL; - $content .= 'RewriteCond %{REQUEST_FILENAME} !\.(ico|css|png|jpg|jpeg|webp|gif|js|txt|htm|html|eot|svg|ttf|woff|woff2|webm|ogg|mp4|wav|mp3|pdf)$ [NC]' . PHP_EOL; - $content .= 'RewriteRule ^public/.*$ index.php'. PHP_EOL; - $content .= '# API routes' . PHP_EOL; - $content .= 'RewriteCond %{REQUEST_URI} ^/api [NC]' . PHP_EOL; - $content .= 'RewriteRule ^api/(.*)$ api/index.php [QSA,L]' . PHP_EOL; - $content .= 'RewriteCond %{REQUEST_FILENAME} !-d ' . PHP_EOL; - $content .= 'RewriteCond %{REQUEST_FILENAME} !-f ' . PHP_EOL; - $content .= 'RewriteCond %{REQUEST_FILENAME} !-l ' . PHP_EOL; - $content .= 'RewriteRule ^(.*)$ index.php [QSA,L]' . PHP_EOL; - $content .= ''. PHP_EOL; - -} else { - - $content .= ''.PHP_EOL; - $content .= ''.PHP_EOL; - + $content = '# START ScriptLog' . PHP_EOL; + $content .= '# The directives (lines) between "START ScriptLog" and "FINISH ScriptLog" are' . PHP_EOL; + $content .= '# dynamically generated, and should only be modified if you know what you are doing.' . PHP_EOL; + $content .= '# Any changes to these lines will be overwritten by scriptlog herself on setting permalink.' . PHP_EOL; + + if ($permalink_status === 'yes') { + $content .= '' . PHP_EOL; + $content .= 'RewriteEngine On' . PHP_EOL; + $content .= '#RewriteCond %{HTTP_USER_AGENT} libwww-perl.* ' . PHP_EOL; + $content .= '#RewriteRule .* – [F,L]' . PHP_EOL; + $content .= '# The RewriteBase of the system (change if you are using this system in a sub-folder)' . PHP_EOL; + $content .= '#RewriteBase /' . PHP_EOL; + $content .= '# Force HTTPS and remove www (canonical: https://yourdomain.TLD) ' . PHP_EOL; + $content .= '#RewriteCond %{HTTPS} off [OR]' . PHP_EOL; + $content .= '#RewriteCond %{HTTP_HOST} ^www\.yourdomain\.TLD$' . PHP_EOL; + $content .= '#RewriteRule ^/?$ "https\:\/\/yourdomain\.TLD\/" [R=301, L]' . PHP_EOL; + $content .= '# Ensure all front-end UI-UX files readable' . PHP_EOL; + $content .= 'RewriteCond %{REQUEST_FILENAME} !\.(ico|css|png|jpg|jpeg|webp|gif|js|txt|htm|html|eot|svg|ttf|woff|woff2|webm|ogg|mp4|wav|mp3|pdf)$ [NC]' . PHP_EOL; + $content .= 'RewriteRule ^public/.*$ index.php' . PHP_EOL; + $content .= '# API routes' . PHP_EOL; + $content .= 'RewriteCond %{REQUEST_URI} ^/api [NC]' . PHP_EOL; + $content .= 'RewriteRule ^api/(.*)$ api/index.php [QSA,L]' . PHP_EOL; + $content .= 'RewriteCond %{REQUEST_FILENAME} !-d ' . PHP_EOL; + $content .= 'RewriteCond %{REQUEST_FILENAME} !-f ' . PHP_EOL; + $content .= 'RewriteCond %{REQUEST_FILENAME} !-l ' . PHP_EOL; + $content .= '# Only route known application prefixes to index.php' . PHP_EOL; + $content .= 'RewriteRule ^(post|page|blog|category|archive|archives|tag|privacy|download|download_file)(/.*)?$ index.php [QSA,L]' . PHP_EOL; + $content .= 'RewriteRule ^$ index.php [QSA,L]' . PHP_EOL; + $content .= 'RewriteRule ^[a-z]{2}/(post|page|blog|category|archive|archives|tag|privacy|download|download_file)(/.*)?$ index.php [QSA,L]' . PHP_EOL; + $content .= 'RewriteRule ^[a-z]{2}/?$ index.php [QSA,L]' . PHP_EOL; + $content .= '' . PHP_EOL; + } else { + $content .= '' . PHP_EOL; + $content .= '' . PHP_EOL; + } + + $content .= '# FINISH ScriptLog' . PHP_EOL; + + return $content; } - -$content .= '# FINISH ScriptLog' . PHP_EOL; - -return $content; - -} \ No newline at end of file diff --git a/src/lib/utility/write-ini.php b/src/lib/utility/write-ini.php index 451c22f9e..3c1b8fba8 100755 --- a/src/lib/utility/write-ini.php +++ b/src/lib/utility/write-ini.php @@ -1,7 +1,8 @@ - $val) { - if (is_array($val)) { - $data[] = "[$key]"; - foreach ($val as $skey => $sval) { - if (is_array($sval)) { - foreach ($sval as $_skey => $_sval) { - if (is_numeric($_skey)) { - $data[] = $skey.'[] = '.(is_numeric($_sval) ? $_sval : (ctype_upper($_sval) ? $_sval : '"'.$_sval.'"')); - } else { - $data[] = $skey.'['.$_skey.'] = '.(is_numeric($_sval) ? $_sval : (ctype_upper($_sval) ? $_sval : '"'.$_sval.'"')); - } - } - } else { - $data[] = $skey.' = '.(is_numeric($sval) ? $sval : (ctype_upper($sval) ? $sval : '"'.$sval.'"')); - } - } - } else { - $data[] = $key.' = '.(is_numeric($val) ? $val : (ctype_upper($val) ? $val : '"'.$val.'"')); - } - // empty line - $data[] = null; - } + if (!is_array($array)) { + scriptlog_error("Function argument 2 must be an array"); + } - // open file pointer, init flock options - $fp = fopen($file, 'w'); - $retries = 0; - $max_retries = 100; + // process array + $data = array(); + foreach ($array as $key => $val) { + if (is_array($val)) { + $data[] = "[$key]"; + foreach ($val as $skey => $sval) { + if (is_array($sval)) { + foreach ($sval as $_skey => $_sval) { + if (is_numeric($_skey)) { + $data[] = $skey . '[] = ' . (is_numeric($_sval) ? $_sval : (ctype_upper($_sval) ? $_sval : '"' . $_sval . '"')); + } else { + $data[] = $skey . '[' . $_skey . '] = ' . (is_numeric($_sval) ? $_sval : (ctype_upper($_sval) ? $_sval : '"' . $_sval . '"')); + } + } + } else { + $data[] = $skey . ' = ' . (is_numeric($sval) ? $sval : (ctype_upper($sval) ? $sval : '"' . $sval . '"')); + } + } + } else { + $data[] = $key . ' = ' . (is_numeric($val) ? $val : (ctype_upper($val) ? $val : '"' . $val . '"')); + } + // empty line + $data[] = null; + } - if (!$fp) { - return false; - } + // open file pointer, init flock options + $fp = fopen($file, 'w'); + $retries = 0; + $max_retries = 100; - // loop until get lock, or reach max retries - do { - if ($retries > 0) { - usleep(rand(1, 5000)); - } - $retries += 1; - } while (!flock($fp, LOCK_EX) && $retries <= $max_retries); + if (!$fp) { + return false; + } - // couldn't get the lock - if ($retries == $max_retries) { - return false; - } + // loop until get lock, or reach max retries + do { + if ($retries > 0) { + usleep(rand(1, 5000)); + } + $retries += 1; + } while (!flock($fp, LOCK_EX) && $retries <= $max_retries); - // got lock, write data - fwrite($fp, implode(PHP_EOL, $data).PHP_EOL); + // couldn't get the lock + if ($retries == $max_retries) { + return false; + } - // release lock - flock($fp, LOCK_UN); - fclose($fp); + // got lock, write data + fwrite($fp, implode(PHP_EOL, $data) . PHP_EOL); - return true; + // release lock + flock($fp, LOCK_UN); + fclose($fp); -} \ No newline at end of file + return true; +} diff --git a/src/lib/utility/write-log.php b/src/lib/utility/write-log.php index 2a66346ac..f5348778e 100755 --- a/src/lib/utility/write-log.php +++ b/src/lib/utility/write-log.php @@ -1,24 +1,25 @@ >\n There was a hacking attempt on your login form: Date of Attack: {$date_attacked} @@ -30,33 +31,22 @@ function write_log($ip, $where) << End of Message >>\n LOG; - $logfile = __DIR__ . '/../../public/log/hacklog.log'; - - if (is_readable($logfile)) { - - if ($handle = fopen($logfile, 'a')) { - - fputs($handle, $logging); - fclose($handle); - - } else { - - $to = 'mnoermoehammad@outlook.com'; - $subject = 'Hack Attempt'; - $header = 'From:'. sanitize_email(app_info()['site_email']); - - if (mail($to, $subject, $logging, $header)) { + $logfile = __DIR__ . '/../../public/log/hacklog.log'; - echo "Email sent to author of scriptlog"; + if (is_readable($logfile)) { + if ($handle = fopen($logfile, 'a')) { + fputs($handle, $logging); + fclose($handle); + } else { + $to = 'mnoermoehammad@outlook.com'; + $subject = 'Hack Attempt'; + $header = 'From:' . sanitize_email(app_info()['site_email']); + if (mail($to, $subject, $logging, $header)) { + echo "Email sent to author of scriptlog"; + } } - + } else { + scriptlog_error("Permission denied. Check your permission for writing on {$logfile} "); } - - } else { - - scriptlog_error("Permission denied. Check your permission for writing on {$logfile} "); - - } - -} \ No newline at end of file +} diff --git a/src/lib/utility/write-nginx-config.php b/src/lib/utility/write-nginx-config.php new file mode 100644 index 000000000..57a7eb4ef --- /dev/null +++ b/src/lib/utility/write-nginx-config.php @@ -0,0 +1,128 @@ + + + + + + + Privacy Policy - Scriptlog + + + + + + + + +
    +
    +

    Privacy Policy

    +

    Last updated: [Date]

    + +

    This Privacy Policy describes how Scriptlog ("we," "us," or "our") collects, uses, and discloses your information when you use our software and services. We are committed to protecting your privacy and handling your data in an open and transparent manner.

    + +

    Information We Collect

    +

    We may collect the following types of information:

    +
      +
    • Account Information: When you create an account, we may collect your username, email address, and a hashed version of your password.
    • +
    • User-Generated Content: Any content you create, such as blog posts, comments, and uploaded media, is stored on our servers.
    • +
    • Technical Information: We may automatically collect information about your device and how you interact with our software, including your IP address, browser type, and operating system. This data is used for security and analytics purposes.
    • +
    + +

    How We Use Your Information

    +

    We use the information we collect for the following purposes:

    +
      +
    • To provide, operate, and maintain our services.
    • +
    • To manage your account and provide you with customer support.
    • +
    • To improve the security and performance of our software.
    • +
    • To monitor usage and analyze trends to enhance user experience.
    • +
    • To communicate with you about updates, security alerts, and support messages.
    • +
    + +

    Data Security

    +

    We take the security of your data seriously and implement a variety of measures to protect it. These include:

    +
      +
    • Password Hashing: User passwords are not stored in plaintext; they are securely hashed.
    • +
    • Data Encryption: Sensitive information is protected using industry-standard encryption.
    • +
    • XSS and CSRF Protection: We employ multi-layered defenses to protect against cross-site scripting and cross-site request forgery attacks.
    • +
    • Prepared Statements: All database queries are executed using prepared statements to prevent SQL injection.
    • +
    +

    While we strive to use commercially acceptable means to protect your personal information, no method of transmission over the Internet or method of electronic storage is 100% secure.

    + +

    Data Retention

    +

    We will retain your personal information only for as long as is necessary for the purposes set out in this Privacy Policy. We will retain and use your information to the extent necessary to comply with our legal obligations, resolve disputes, and enforce our policies.

    + +

    Cookies

    +

    We use cookies to maintain your session and provide essential functionality. Cookies are small files stored on your device that help our software remember your preferences and login status. You can instruct your browser to refuse all cookies or to indicate when a cookie is being sent. However, if you do not accept cookies, you may not be able to use some portions of our service.

    + +

    Your Rights

    +

    You have the right to access, update, or delete the information we have on you. If you are unable to perform these actions yourself, please contact us to assist you.

    + +

    Changes to This Privacy Policy

    +

    We may update our Privacy Policy from time to time. We will notify you of any changes by posting the new Privacy Policy on this page. You are advised to review this Privacy Policy periodically for any changes.

    + +

    Contact Us

    +

    If you have any questions about this Privacy Policy, please contact us at: scriptlog@yandex.com.

    + +
    + + +
    +
    + + + diff --git a/src/public/files/cache/index.html b/src/public/files/cache/index.html new file mode 100755 index 000000000..e69de29bb diff --git a/src/public/files/cache/translations/en.json b/src/public/files/cache/translations/en.json new file mode 100644 index 000000000..5a9a796c6 --- /dev/null +++ b/src/public/files/cache/translations/en.json @@ -0,0 +1,133 @@ +{ + "404.back_home": "Back to Home Page", + "404.message": "Sorry, the page you are looking for does not exist.", + "404.title": "404", + "admin.add_language": "Add Language", + "admin.all_languages": "All Languages", + "admin.delete_language": "Delete Language", + "admin.edit_language": "Edit Language", + "admin.translations": "Translations", + "button.add": "Add", + "button.approve": "Approve", + "button.delete": "Delete", + "button.draft": "Draft", + "button.edit": "Edit", + "button.preview": "Preview", + "button.publish": "Publish", + "button.read_more": "Read More", + "button.restore": "Restore", + "button.spam": "Spam", + "button.subscribe": "Subscribe", + "button.trash": "Trash", + "button.update": "Update", + "cookie_consent.banner.description": "We use cookies to enhance your experience. By continuing to visit this site you agree to our use of cookies.", + "cookie_consent.banner.title": "Cookie Consent", + "cookie_consent.buttons.accept": "Accept", + "cookie_consent.buttons.learn_more": "Learn More", + "cookie_consent.buttons.reject": "Reject", + "cookie_consent.privacy.link": "Privacy Policy", + "error.forbidden": "Forbidden", + "error.invalid_input": "Invalid Input", + "error.not_found": "Not Found", + "error.required": "Required", + "error.server_error": "Server Error", + "footer.copyright": "All Rights Reserved", + "form.cancel": "Cancel", + "form.email": "Email", + "form.message": "Message", + "form.name": "Name", + "form.save": "Save", + "form.search": "Search", + "form.subject": "Subject", + "form.website": "Website", + "header.nav.about": "About", + "header.nav.blog": "Blog", + "header.nav.contact": "Contact", + "header.nav.home": "Home", + "header.nav.search": "Search", + "home.divider.view_more": "View More", + "home.hero.admin_panel": "Admin Panel", + "home.hero.discover_more": "Discover More", + "home.hero.scroll_down": "Scroll Down", + "home.intro.description": "A powerful PHP blog CMS built with modern architecture", + "home.intro.welcome": "Welcome to ScriptLog", + "home.latest_posts.title": "Latest Posts", + "nav.add_media": "Add New", + "nav.add_new": "Add New", + "nav.add_user": "Add User", + "nav.all_pages": "All Pages", + "nav.all_posts": "All Posts", + "nav.all_users": "All Users", + "nav.appearance": "Appearance", + "nav.approved_comments": "Approved Comments", + "nav.audit_logs": "Audit Logs", + "nav.backup": "Backup", + "nav.categories": "Categories", + "nav.comments": "Comments", + "nav.dashboard": "Dashboard", + "nav.data_requests": "Data Requests", + "nav.downloads": "Downloads", + "nav.download_settings": "Download Settings", + "nav.edit_page": "Edit Page", + "nav.edit_post": "Edit Post", + "nav.export": "Export", + "nav.general": "General", + "nav.import": "Import", + "nav.languages": "Languages", + "nav.language_config": "Language Config", + "nav.language_settings": "Language Settings", + "nav.library": "Library", + "nav.mail_settings": "Mail Settings", + "nav.media": "Media", + "nav.membership": "Membership", + "nav.menus": "Menus", + "nav.navigation": "Navigation", + "nav.new_page": "New Page", + "nav.new_post": "New Post", + "nav.no_languages": "No languages found", + "nav.pages": "Pages", + "nav.pending_comments": "Pending Comments", + "nav.permalink": "Permalink", + "nav.plugins": "Plugins", + "nav.posts": "Posts", + "nav.privacy": "Privacy", + "nav.privacy_settings": "Privacy Settings", + "nav.reading": "Reading", + "nav.restore": "Restore", + "nav.settings": "Settings", + "nav.set_default": "Set as Default", + "nav.spam_comments": "Spam", + "nav.themes": "Themes", + "nav.timezone": "Timezone", + "nav.tools": "Tools", + "nav.translations": "Translations", + "nav.trash_comments": "Trash", + "nav.users": "Users", + "nav.widgets": "Widgets", + "page.static_page": "Static Page", + "privacy.contact_us": "Contact Us", + "privacy.data_security": "Data Security", + "privacy.how_we_use": "How We Use Your Information", + "privacy.information_we_collect": "Information We Collect", + "privacy.last_updated": "Last Updated", + "privacy.page_title": "Privacy Policy", + "privacy.your_rights": "Your Rights", + "sidebar.archives.title": "Archives", + "sidebar.categories.title": "Categories", + "sidebar.latest_posts.title": "Latest Posts", + "sidebar.search.placeholder": "What are you looking for?", + "sidebar.search.title": "Search", + "sidebar.tags.title": "Tags", + "single.comment.label": "Comments", + "single.comment.leave_reply": "Leave a Reply", + "single.comment.placeholder": "Comment", + "single.comment.submit": "Submit Comment", + "status.draft": "Draft", + "status.pending": "Pending", + "status.private": "Private", + "status.publish": "Published", + "status.trash": "Trash", + "visibility.password": "Password Protected", + "visibility.private": "Private", + "visibility.public": "Public" +} \ No newline at end of file diff --git a/src/public/files/docs/.htaccess b/src/public/files/docs/.htaccess new file mode 100755 index 000000000..1ec8dacff --- /dev/null +++ b/src/public/files/docs/.htaccess @@ -0,0 +1,28 @@ +# Protect files directory from direct web access +# Allow only through PHP scripts (download handler) + +# Deny access to all files + + Order deny,allow + Deny from all + + +# Allow index.php for directory listing (optional) + + Order allow,deny + Allow from all + + +# Prevent directory browsing +Options -Indexes + +# Disable script execution in this directory + + php_flag engine off + + +# Additional security headers + + Header set X-Content-Type-Options "nosniff" + Header set X-Frame-Options "SAMEORIGIN" + \ No newline at end of file diff --git a/src/public/files/pictures/68244d2b45b557d128aecebdf055646c.jpg b/src/public/files/pictures/68244d2b45b557d128aecebdf055646c.jpg deleted file mode 100644 index e46e40fd8..000000000 Binary files a/src/public/files/pictures/68244d2b45b557d128aecebdf055646c.jpg and /dev/null differ diff --git a/src/public/files/pictures/68244d2b45b557d128aecebdf055646c.webp b/src/public/files/pictures/68244d2b45b557d128aecebdf055646c.webp deleted file mode 100644 index 786de60ae..000000000 Binary files a/src/public/files/pictures/68244d2b45b557d128aecebdf055646c.webp and /dev/null differ diff --git a/src/public/files/pictures/b8c233c1e809e66f97f8915d1741e1e3.jpg b/src/public/files/pictures/b8c233c1e809e66f97f8915d1741e1e3.jpg deleted file mode 100644 index b07e1f8d8..000000000 Binary files a/src/public/files/pictures/b8c233c1e809e66f97f8915d1741e1e3.jpg and /dev/null differ diff --git a/src/public/files/pictures/b8c233c1e809e66f97f8915d1741e1e3.webp b/src/public/files/pictures/b8c233c1e809e66f97f8915d1741e1e3.webp deleted file mode 100644 index 4b918932c..000000000 Binary files a/src/public/files/pictures/b8c233c1e809e66f97f8915d1741e1e3.webp and /dev/null differ diff --git a/src/public/files/pictures/large/large_68244d2b45b557d128aecebdf055646c.jpg b/src/public/files/pictures/large/large_68244d2b45b557d128aecebdf055646c.jpg deleted file mode 100644 index 54a49a541..000000000 Binary files a/src/public/files/pictures/large/large_68244d2b45b557d128aecebdf055646c.jpg and /dev/null differ diff --git a/src/public/files/pictures/large/large_68244d2b45b557d128aecebdf055646c.webp b/src/public/files/pictures/large/large_68244d2b45b557d128aecebdf055646c.webp deleted file mode 100644 index 9433086cb..000000000 Binary files a/src/public/files/pictures/large/large_68244d2b45b557d128aecebdf055646c.webp and /dev/null differ diff --git a/src/public/files/pictures/large/large_b8c233c1e809e66f97f8915d1741e1e3.jpg b/src/public/files/pictures/large/large_b8c233c1e809e66f97f8915d1741e1e3.jpg deleted file mode 100644 index 04adcd854..000000000 Binary files a/src/public/files/pictures/large/large_b8c233c1e809e66f97f8915d1741e1e3.jpg and /dev/null differ diff --git a/src/public/files/pictures/large/large_b8c233c1e809e66f97f8915d1741e1e3.webp b/src/public/files/pictures/large/large_b8c233c1e809e66f97f8915d1741e1e3.webp deleted file mode 100644 index 9b053b234..000000000 Binary files a/src/public/files/pictures/large/large_b8c233c1e809e66f97f8915d1741e1e3.webp and /dev/null differ diff --git a/src/public/files/pictures/medium/medium_68244d2b45b557d128aecebdf055646c.jpg b/src/public/files/pictures/medium/medium_68244d2b45b557d128aecebdf055646c.jpg deleted file mode 100644 index 426db0836..000000000 Binary files a/src/public/files/pictures/medium/medium_68244d2b45b557d128aecebdf055646c.jpg and /dev/null differ diff --git a/src/public/files/pictures/medium/medium_68244d2b45b557d128aecebdf055646c.webp b/src/public/files/pictures/medium/medium_68244d2b45b557d128aecebdf055646c.webp deleted file mode 100644 index b7053129b..000000000 Binary files a/src/public/files/pictures/medium/medium_68244d2b45b557d128aecebdf055646c.webp and /dev/null differ diff --git a/src/public/files/pictures/medium/medium_b8c233c1e809e66f97f8915d1741e1e3.jpg b/src/public/files/pictures/medium/medium_b8c233c1e809e66f97f8915d1741e1e3.jpg deleted file mode 100644 index ddd32ebf0..000000000 Binary files a/src/public/files/pictures/medium/medium_b8c233c1e809e66f97f8915d1741e1e3.jpg and /dev/null differ diff --git a/src/public/files/pictures/medium/medium_b8c233c1e809e66f97f8915d1741e1e3.webp b/src/public/files/pictures/medium/medium_b8c233c1e809e66f97f8915d1741e1e3.webp deleted file mode 100644 index a100ebe0d..000000000 Binary files a/src/public/files/pictures/medium/medium_b8c233c1e809e66f97f8915d1741e1e3.webp and /dev/null differ diff --git a/src/public/files/pictures/small/small_68244d2b45b557d128aecebdf055646c.jpg b/src/public/files/pictures/small/small_68244d2b45b557d128aecebdf055646c.jpg deleted file mode 100644 index ba9a78829..000000000 Binary files a/src/public/files/pictures/small/small_68244d2b45b557d128aecebdf055646c.jpg and /dev/null differ diff --git a/src/public/files/pictures/small/small_68244d2b45b557d128aecebdf055646c.webp b/src/public/files/pictures/small/small_68244d2b45b557d128aecebdf055646c.webp deleted file mode 100644 index 38c11cc99..000000000 Binary files a/src/public/files/pictures/small/small_68244d2b45b557d128aecebdf055646c.webp and /dev/null differ diff --git a/src/public/files/pictures/small/small_b8c233c1e809e66f97f8915d1741e1e3.jpg b/src/public/files/pictures/small/small_b8c233c1e809e66f97f8915d1741e1e3.jpg deleted file mode 100644 index 1296cb0a9..000000000 Binary files a/src/public/files/pictures/small/small_b8c233c1e809e66f97f8915d1741e1e3.jpg and /dev/null differ diff --git a/src/public/files/pictures/small/small_b8c233c1e809e66f97f8915d1741e1e3.webp b/src/public/files/pictures/small/small_b8c233c1e809e66f97f8915d1741e1e3.webp deleted file mode 100644 index 28d36d012..000000000 Binary files a/src/public/files/pictures/small/small_b8c233c1e809e66f97f8915d1741e1e3.webp and /dev/null differ diff --git a/src/public/log/session.log b/src/public/log/session.log old mode 100644 new mode 100755 diff --git a/src/public/themes/blog/404.php b/src/public/themes/blog/404.php index 531edf5ed..ab0bc9a86 100755 --- a/src/public/themes/blog/404.php +++ b/src/public/themes/blog/404.php @@ -2,9 +2,9 @@
    - 404 -
    The page you are looking for was not found.
    - " class="btn btn-link">Back to Home + +
    + " class="btn btn-link">
    diff --git a/src/public/themes/blog/archive.php b/src/public/themes/blog/archive.php old mode 100644 new mode 100755 index 7f1cca992..77e721196 --- a/src/public/themes/blog/archive.php +++ b/src/public/themes/blog/archive.php @@ -1,25 +1,47 @@ param1 : ""; - $grab_year = function_exists('request_path') ? request_path()->param2 : ""; - - $values = ['month_archive' => $grab_month, 'year_archive' => $grab_year]; - - $archives = function_exists('posts_by_archive') ? posts_by_archive($values) : ""; - $entries = (!empty($archives)) ? $archives['archivesPublished'] : ""; - +$grab_month = ""; +$grab_year = ""; + +if (function_exists('is_permalink_enabled') && is_permalink_enabled() === 'yes') { + if (function_exists('request_path')) { + $requestPath = request_path(); + if (isset($requestPath->param1) && isset($requestPath->param2)) { + $grab_month = $requestPath->param1; + $grab_year = $requestPath->param2; + } + } } else { + $query_param = class_exists('HandleRequest') ? HandleRequest::isQueryStringRequested()['value'] : ""; + + if (!empty($query_param)) { + $archive_requested = preg_split("//", $query_param, -1, PREG_SPLIT_NO_EMPTY); + + // Extract year (first 4 digits) - indices 0-3 + $yearPart = ""; + for ($i = 0; $i < 4; $i++) { + if (isset($archive_requested[$i])) { + $yearPart .= $archive_requested[$i]; + } + } + $grab_year = $yearPart; + + // Extract month (next 2 digits) - indices 4-5, pad with leading zero if needed + $monthPart = ""; + for ($i = 4; $i < 6; $i++) { + if (isset($archive_requested[$i])) { + $monthPart .= $archive_requested[$i]; + } + } + $grab_month = str_pad($monthPart, 2, '0', STR_PAD_LEFT); + } +} - $archive_requested = class_exists('HandleRequest') ? preg_split("//", HandleRequest::isQueryStringRequested()['value'], -1, PREG_SPLIT_NO_EMPTY) : ""; - $grab_year = (isset($archive_requested[0]) && isset($archive_requested[1]) && isset($archive_requested[2]) && isset($archive_requested[3])) ? $archive_requested[0] . $archive_requested[1] . $archive_requested[2] . $archive_requested[3] : $_SESSION['year_archive']; - $grab_month = (isset($archive_requested[4]) && isset($archive_requested[5])) ? $archive_requested[4].$archive_requested[5] : $archive_requested[4] . ""; - $values = ['month_archive' => $grab_month, 'year_archive' => $grab_year]; +$values = ['month_archive' => $grab_month, 'year_archive' => $grab_year]; - $archives = function_exists('posts_by_archive') ? posts_by_archive($values) : ""; - $entries = (isset($archives)) ? $archives['archivesPublished'] : ""; -} +$archives = function_exists('posts_by_archive') ? posts_by_archive($values) : []; +$entries = !empty($archives) && isset($archives['archivesPublished']) ? $archives['archivesPublished'] : []; +$pagination = !empty($archives) && isset($archives['paginationLink']) ? $archives['paginationLink'] : ""; ?> @@ -33,25 +55,25 @@ 0) ? total_comment($entry_id)['total'] : 0; + if (!empty($entries)) : + foreach ($entries as $entry) : + $entry_id = isset($entry['ID']) ? (int)$entry['ID'] : ""; + $entry_title = isset($entry['post_title']) ? htmlout($entry['post_title']) : ""; + $entry_content = isset($entry['post_content']) ? paragraph_l2br(htmlout(paragraph_trim($entry['post_content']))) : ""; + $entry_img = ((isset($entry['media_filename'])) && ($entry['media_filename'] !== '') ? htmlout($entry['media_filename']) : ""); + $entry_img_caption = isset($entry['media_caption']) ? htmlout($entry['media_caption']) : ""; + $entry_created = isset($entry['modified_at']) ? htmlout(make_date($entry['modified_at'])) : htmlout(make_date($entry['created_at'])); + $entry_author = (isset($entry['user_login']) || isset($entry['user_fullname']) ? htmlout($entry['user_login']) : htmlout($entry['user_fullname'])); + $total_comment = isset($entry['total_comments']) ? (int)$entry['total_comments'] : 0; - ?> + ?>
    -
    ">" alt="" class="img-fluid">
    +
    ">' ?>
    " title="">

    @@ -66,18 +88,21 @@
    -
    + +
    diff --git a/src/public/themes/blog/archives.php b/src/public/themes/blog/archives.php new file mode 100755 index 000000000..77142da26 --- /dev/null +++ b/src/public/themes/blog/archives.php @@ -0,0 +1,70 @@ + 'January', '02' => 'February', '03' => 'March', + '04' => 'April', '05' => 'May', '06' => 'June', + '07' => 'July', '08' => 'August', '09' => 'September', + '10' => 'October', '11' => 'November', '12' => 'December' +]; + +// Group archives by year +$archivesByYear = []; +if (!empty($archives)) { + foreach ($archives as $archive) { + $year = $archive['year_archive']; + if (!isset($archivesByYear[$year])) { + $archivesByYear[$year] = []; + } + $archivesByYear[$year][] = $archive; + } +} + +?> + +
    +
    +
    +
    +
    +
    +

    Archives

    +
    + + + $yearArchives) : ?> +
    +

    +
    + + + +
    +
    + + +
    +

    No archives found.

    +
    + + +
    +
    +
    + + + +
    +
    diff --git a/src/public/themes/blog/assets/css/comment.min.css b/src/public/themes/blog/assets/css/comment.min.css new file mode 100755 index 000000000..9c8b31f6f --- /dev/null +++ b/src/public/themes/blog/assets/css/comment.min.css @@ -0,0 +1 @@ +.comment-form-wrap{clear:both}.comment-list{padding:0;margin:0}.comment-list .children{padding:50px 0 0 40px;margin:0;float:left;width:100%}.comment-list li{padding:0;margin:0 0 30px 0;float:left;width:100%;clear:both;list-style:none}.comment-list li .vcard{width:80px;float:left}.comment-list li .vcard img{width:50px;border-radius:50%}.comment-list li .comment-body{float:right;width:calc(100% - 80px)}.comment-list li .comment-body h3{font-size:20px;color:#000}.comment-list li .comment-body .meta{text-transform:uppercase;font-size:13px;letter-spacing:.1em;color:#ccc}.comment-list li .comment-body .reply{padding:5px 10px;background:#e6e6e6;color:#000;text-transform:uppercase;font-size:14px}.comment-list li .comment-body .reply:hover{color:#000;background:#e3e3e3}#error_message{background:#ec6c6c;display:none}#success_message{background:#acfaa2;display:none}.ajax_response{padding:10px 20px;border:0;display:inline-block;margin-top:20px;cursor:pointer;color:#555}.is-invalid{border:1px solid #dc3545;background-color:#f5f2f2}.invalid-feedback{color:#dc3545;font-size:12px;margin-top:5px} \ No newline at end of file diff --git a/src/public/themes/blog/assets/css/cookie-consent.css b/src/public/themes/blog/assets/css/cookie-consent.css new file mode 100755 index 000000000..b099d3e5c --- /dev/null +++ b/src/public/themes/blog/assets/css/cookie-consent.css @@ -0,0 +1,211 @@ +/** + * Cookie Consent Banner Styles + * + * @category Theme Assets + * @author Scriptlog + * @license MIT + * @version 1.0 + */ + +/* Cookie Consent Banner Container */ +.cookie-consent-banner { + position: fixed; + bottom: 0; + left: 0; + right: 0; + background-color: #1a1a1a; + color: #ffffff; + padding: 20px; + z-index: 9999; + box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + transform: translateY(100%); + transition: transform 0.3s ease-in-out; +} + +.cookie-consent-banner.show { + transform: translateY(0); +} + +.cookie-consent-banner.hidden { + display: none; +} + +/* Container */ +.cookie-consent-container { + max-width: 1200px; + margin: 0 auto; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 15px; +} + +/* Content Section */ +.cookie-consent-content { + flex: 1; + min-width: 280px; +} + +.cookie-consent-title { + font-size: 16px; + font-weight: 600; + margin-bottom: 8px; + display: flex; + align-items: center; + gap: 8px; +} + +.cookie-consent-text { + font-size: 14px; + line-height: 1.5; + color: #cccccc; + margin: 0; +} + +.cookie-consent-text a { + color: #4dabf7; + text-decoration: underline; +} + +.cookie-consent-text a:hover { + color: #74c0fc; +} + +/* Button Group */ +.cookie-consent-buttons { + display: flex; + gap: 10px; + flex-shrink: 0; +} + +/* Buttons */ +.cookie-btn { + padding: 10px 20px; + border: none; + border-radius: 4px; + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.cookie-btn:focus { + outline: 2px solid #4dabf7; + outline-offset: 2px; +} + +.cookie-btn-accept { + background-color: #28a745; + color: #ffffff; +} + +.cookie-btn-accept:hover { + background-color: #218838; +} + +.cookie-btn-accept:active { + background-color: #1e7e34; +} + +.cookie-btn-reject { + background-color: #6c757d; + color: #ffffff; +} + +.cookie-btn-reject:hover { + background-color: #5a6268; +} + +.cookie-btn-reject:active { + background-color: #545b62; +} + +.cookie-btn-learn-more { + background-color: transparent; + color: #4dabf7; + border: 1px solid #4dabf7; +} + +.cookie-btn-learn-more:hover { + background-color: rgba(77, 171, 247, 0.1); +} + +/* Responsive */ +@media (max-width: 768px) { + .cookie-consent-container { + flex-direction: column; + text-align: center; + } + + .cookie-consent-content { + min-width: 100%; + } + + .cookie-consent-buttons { + width: 100%; + justify-content: center; + flex-wrap: wrap; + } + + .cookie-btn { + flex: 1; + min-width: 120px; + } +} + +@media (max-width: 480px) { + .cookie-consent-banner { + padding: 15px; + } + + .cookie-consent-title { + font-size: 14px; + } + + .cookie-consent-text { + font-size: 13px; + } + + .cookie-btn { + padding: 8px 15px; + font-size: 12px; + } +} + +/* Animation */ +@keyframes slideUp { + from { + transform: translateY(100%); + } + to { + transform: translateY(0); + } +} + +.cookie-consent-banner.animate { + animation: slideUp 0.5s ease-out forwards; +} + +/* Dark mode support */ +@media (prefers-color-scheme: dark) { + .cookie-consent-banner { + background-color: #2d2d2d; + } + + .cookie-consent-text { + color: #b0b0b0; + } + + .cookie-btn-learn-more { + border-color: #74c0fc; + color: #74c0fc; + } + + .cookie-btn-learn-more:hover { + background-color: rgba(116, 192, 252, 0.1); + } +} diff --git a/src/public/themes/blog/assets/css/cookie-consent.min.css b/src/public/themes/blog/assets/css/cookie-consent.min.css new file mode 100755 index 000000000..b8b2afa4a --- /dev/null +++ b/src/public/themes/blog/assets/css/cookie-consent.min.css @@ -0,0 +1 @@ +.cookie-consent-banner{position:fixed;bottom:0;left:0;right:0;background-color:#1a1a1a;color:#ffffff;padding:20px;z-index:9999;box-shadow:0 -2px 10px rgba(0, 0, 0, 0.1);font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;transform:translateY(100%);transition:transform 0.3s ease-in-out}.cookie-consent-banner.show{transform:translateY(0)}.cookie-consent-banner.hidden{display:none}.cookie-consent-container{max-width:1200px;margin:0 auto;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:15px}.cookie-consent-content{flex:1;min-width:280px}.cookie-consent-title{font-size:16px;font-weight:600;margin-bottom:8px;display:flex;align-items:center;gap:8px}.cookie-consent-text{font-size:14px;line-height:1.5;color:#cccccc;margin:0}.cookie-consent-text a{color:#4dabf7;text-decoration:underline}.cookie-consent-text a:hover{color:#74c0fc}.cookie-consent-buttons{display:flex;gap:10px;flex-shrink:0}.cookie-btn{padding:10px 20px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:all 0.2s ease;text-transform:uppercase;letter-spacing:0.5px}.cookie-btn:focus{outline:2px solid #4dabf7;outline-offset:2px}.cookie-btn-accept{background-color:#28a745;color:#ffffff}.cookie-btn-accept:hover{background-color:#218838}.cookie-btn-accept:active{background-color:#1e7e34}.cookie-btn-reject{background-color:#6c757d;color:#ffffff}.cookie-btn-reject:hover{background-color:#5a6268}.cookie-btn-reject:active{background-color:#545b62}.cookie-btn-learn-more{background-color:transparent;color:#4dabf7;border:1px solid #4dabf7}.cookie-btn-learn-more:hover{background-color:rgba(77, 171, 247, 0.1)}@media (max-width:768px){.cookie-consent-container{flex-direction:column;text-align:center}.cookie-consent-content{min-width:100%}.cookie-consent-buttons{width:100%;justify-content:center;flex-wrap:wrap}.cookie-btn{flex:1;min-width:120px}}@media (max-width:480px){.cookie-consent-banner{padding:15px}.cookie-consent-title{font-size:14px}.cookie-consent-text{font-size:13px}.cookie-btn{padding:8px 15px;font-size:12px}}@keyframes slideUp{from{transform:translateY(100%)}to{transform:translateY(0)}}.cookie-consent-banner.animate{animation:slideUp 0.5s ease-out forwards}@media (prefers-color-scheme:dark){.cookie-consent-banner{background-color:#2d2d2d}.cookie-consent-text{color:#b0b0b0}.cookie-btn-learn-more{border-color:#74c0fc;color:#74c0fc}.cookie-btn-learn-more:hover{background-color:rgba(116, 192, 252, 0.1)}} \ No newline at end of file diff --git a/src/public/themes/blog/assets/css/custom.css b/src/public/themes/blog/assets/css/custom.css index 674c83036..afbc4d492 100755 --- a/src/public/themes/blog/assets/css/custom.css +++ b/src/public/themes/blog/assets/css/custom.css @@ -8,4 +8,131 @@ /* not found page wrap */ .page-wrap { min-height: 100vh; +} + +/* Search Widget Styles */ +.widget.search .search-form { + position: relative; +} + +.widget.search .search-results { + position: absolute; + top: 100%; + left: 0; + right: 0; + background: #fff; + border: 1px solid #ddd; + border-top: none; + max-height: 400px; + overflow-y: auto; + z-index: 1000; + box-shadow: 0 4px 6px rgba(0,0,0,0.1); + display: none; +} + +.widget.search .search-results.show { + display: block; +} + +.widget.search .search-result-item { + padding: 12px 15px; + border-bottom: 1px solid #eee; + transition: background-color 0.2s; +} + +.widget.search .search-result-item:last-child { + border-bottom: none; +} + +.widget.search .search-result-item:hover { + background-color: #f8f9fa; +} + +.widget.search .search-result-item a { + display: block; + text-decoration: none; +} + +.widget.search .search-result-title { + font-weight: 600; + color: #333; + margin-bottom: 4px; + font-size: 14px; +} + +.widget.search .search-result-excerpt { + font-size: 12px; + color: #666; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.widget.search .search-result-type { + font-size: 10px; + color: #999; + text-transform: uppercase; + margin-top: 4px; +} + +.widget.search .search-no-results { + padding: 15px; + text-align: center; + color: #666; + font-size: 14px; +} + +.widget.search .search-loading { + padding: 15px; + text-align: center; + color: #666; +} + +.widget.search .search-error { + color: #dc3545; + font-size: 12px; + margin-top: 8px; + display: none; +} + +.widget.search .search-error.show { + display: block; +} + +.widget.search .search-result-count { + padding: 8px 15px; + background-color: #f8f9fa; + font-size: 12px; + color: #666; + border-bottom: 1px solid #eee; +} + +.widget.search input[type="search"] { + width: 100%; + padding: 10px 40px 10px 15px; + border: 1px solid #ddd; + border-radius: 4px; + font-size: 14px; + transition: border-color 0.2s; +} + +.widget.search input[type="search"]:focus { + outline: none; + border-color: #007bff; +} + +.widget.search button.submit { + position: absolute; + right: 8px; + top: 50%; + transform: translateY(-50%); + background: none; + border: none; + cursor: pointer; + padding: 5px; + color: #666; +} + +.widget.search button.submit:hover { + color: #007bff; } \ No newline at end of file diff --git a/src/public/themes/blog/assets/css/custom.min.css b/src/public/themes/blog/assets/css/custom.min.css new file mode 100755 index 000000000..48ea40486 --- /dev/null +++ b/src/public/themes/blog/assets/css/custom.min.css @@ -0,0 +1 @@ +.transparent{zoom:1;filter:alpha(opacity=50);opacity:0.5}.page-wrap{min-height:100vh}.widget.search .search-form{position:relative}.widget.search .search-results{position:absolute;top:100%;left:0;right:0;background:#fff;border:1px solid #ddd;border-top:none;max-height:400px;overflow-y:auto;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.1);display:none}.widget.search .search-results.show{display:block}.widget.search .search-result-item{padding:12px 15px;border-bottom:1px solid #eee;transition:background-color 0.2s}.widget.search .search-result-item:last-child{border-bottom:none}.widget.search .search-result-item:hover{background-color:#f8f9fa}.widget.search .search-result-item a{display:block;text-decoration:none}.widget.search .search-result-title{font-weight:600;color:#333;margin-bottom:4px;font-size:14px}.widget.search .search-result-excerpt{font-size:12px;color:#666;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.widget.search .search-result-type{font-size:10px;color:#999;text-transform:uppercase;margin-top:4px}.widget.search .search-no-results{padding:15px;text-align:center;color:#666;font-size:14px}.widget.search .search-loading{padding:15px;text-align:center;color:#666}.widget.search .search-error{color:#dc3545;font-size:12px;margin-top:8px;display:none}.widget.search .search-error.show{display:block}.widget.search .search-result-count{padding:8px 15px;background-color:#f8f9fa;font-size:12px;color:#666;border-bottom:1px solid #eee}.widget.search input[type="search"]{width:100%;padding:10px 40px 10px 15px;border:1px solid #ddd;border-radius:4px;font-size:14px;transition:border-color 0.2s}.widget.search input[type="search"]:focus{outline:none;border-color:#007bff}.widget.search button.submit{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;padding:5px;color:#666}.widget.search button.submit:hover{color:#007bff} \ No newline at end of file diff --git a/src/public/themes/blog/assets/css/fontastic.css b/src/public/themes/blog/assets/css/fontastic.css deleted file mode 100755 index 25f83dbfc..000000000 --- a/src/public/themes/blog/assets/css/fontastic.css +++ /dev/null @@ -1,58 +0,0 @@ -@charset "UTF-8"; - -@font-face { - font-family: "blog"; - src:url("fonts/blog.eot"); - src:url("fonts/blog.eot?#iefix") format("embedded-opentype"), - url("fonts/blog.woff") format("woff"), - url("fonts/blog.ttf") format("truetype"), - url("fonts/blog.svg#blog") format("svg"); - font-weight: normal; - font-style: normal; - -} - -[data-icon]:before { - font-family: "blog" !important; - content: attr(data-icon); - font-style: normal !important; - font-weight: normal !important; - font-variant: normal !important; - text-transform: none !important; - speak: none; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -[class^="icon-"]:before, -[class*=" icon-"]:before { - font-family: "blog" !important; - font-style: normal !important; - font-weight: normal !important; - font-variant: normal !important; - text-transform: none !important; - speak: none; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.icon-search:before { - content: "\61"; -} -.icon-clock:before { - content: "\62"; -} -.icon-comment:before { - content: "\64"; -} -.icon-search-1:before { - content: "\67"; -} -.icon-close:before { - content: "\68"; -} -.icon-eye:before { - content: "\63"; -} diff --git a/src/public/themes/blog/assets/css/fontastic.min.css b/src/public/themes/blog/assets/css/fontastic.min.css new file mode 100755 index 000000000..9c458e8eb --- /dev/null +++ b/src/public/themes/blog/assets/css/fontastic.min.css @@ -0,0 +1 @@ +@charset "UTF-8";@font-face{font-family:"blog";src:url("fonts/blog.eot");src:url("fonts/blog.eot?#iefix") format("embedded-opentype"),url("fonts/blog.woff") format("woff"),url("fonts/blog.ttf") format("truetype"),url("fonts/blog.svg#blog") format("svg");font-weight:normal;font-style:normal}[data-icon]:before{font-family:"blog" !important;content:attr(data-icon);font-style:normal !important;font-weight:normal !important;font-variant:normal !important;text-transform:none !important;speak:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}[class^="icon-"]:before,[class*=" icon-"]:before{font-family:"blog" !important;font-style:normal !important;font-weight:normal !important;font-variant:normal !important;text-transform:none !important;speak:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-search:before{content:"\61"}.icon-clock:before{content:"\62"}.icon-comment:before{content:"\64"}.icon-search-1:before{content:"\67"}.icon-close:before{content:"\68"}.icon-eye:before{content:"\63"} \ No newline at end of file diff --git a/src/public/themes/blog/assets/css/not-found.css b/src/public/themes/blog/assets/css/not-found.css deleted file mode 100755 index ce06040cd..000000000 --- a/src/public/themes/blog/assets/css/not-found.css +++ /dev/null @@ -1,3 +0,0 @@ -.page-wrap { - min-height: 100vh; -} \ No newline at end of file diff --git a/src/public/themes/blog/assets/css/not-found.min.css b/src/public/themes/blog/assets/css/not-found.min.css new file mode 100755 index 000000000..4381f2898 --- /dev/null +++ b/src/public/themes/blog/assets/css/not-found.min.css @@ -0,0 +1 @@ +.page-wrap{min-height:100vh} \ No newline at end of file diff --git a/src/public/themes/blog/assets/css/privacy.css b/src/public/themes/blog/assets/css/privacy.css new file mode 100755 index 000000000..d563352a7 --- /dev/null +++ b/src/public/themes/blog/assets/css/privacy.css @@ -0,0 +1,145 @@ +@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;700;800&display=swap'); + +:root { + --navy-dark: #000080; + --chartreuse: #7FFF00; + --glass-bg: rgba(255, 255, 255, 0.85); +} + +.privacy-wrapper { + font-family: 'Outfit', sans-serif; + padding: 60px 0; + background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); + min-height: 100vh; +} + +.privacy-card { + background: var(--glass-bg); + backdrop-filter: blur(25px); + -webkit-backdrop-filter: blur(25px); + border: 1px solid rgba(255, 255, 255, 0.4); + border-radius: 20px; + padding: 3rem; + box-shadow: 0 15px 35px rgba(0, 0, 0, 0.05); + animation: fadeInUp 0.8s ease-out; +} + +.privacy-header h1 { + color: var(--navy-dark); + font-weight: 800; + font-size: 2.5rem; + margin: 0 0 5px 0; + line-height: 1.1; +} + +.privacy-meta { + font-weight: 300; + color: #6c757d; + margin-bottom: 15px; + border-bottom: 2px solid var(--chartreuse); + display: inline-block; + padding-bottom: 5px; +} + +.privacy-meta i { + color: var(--chartreuse); + margin-right: 6px; +} + +.privacy-body { + line-height: 1.7; + font-weight: 400; + color: #2d3436; + margin: 0; + padding: 0; +} + +.privacy-body .lead { + font-size: 1.1rem; + color: #495057; + margin: 0 0 10px 0; +} + +.privacy-body h2 { + font-weight: 700; + color: var(--navy-dark); + margin: 15px 0 10px 0; + font-size: 1.5rem; +} + +.privacy-body p { + margin-bottom: 1rem; +} + +.privacy-body ul { + padding-left: 1.2rem; + list-style-type: none; +} + +.privacy-body ul li { + margin-bottom: 0.75rem; + position: relative; + padding-left: 1.5rem; +} + +.privacy-body ul li::before { + content: "\2022"; + color: var(--chartreuse); + font-weight: bold; + font-size: 1.2em; + position: absolute; + left: 0; +} + +.privacy-body ul li strong { + color: var(--navy-dark); +} + +.privacy-body a { + color: var(--navy-dark); + text-decoration: none; + border-bottom: 1px solid transparent; + transition: border-color 0.2s ease; +} + +.privacy-body a:hover { + border-bottom-color: var(--chartreuse); +} + +.privacy-footer { + margin-top: 3rem; + padding-top: 2rem; + border-top: 1px solid #e9ecef; + text-align: center; +} + +.privacy-back-btn { + background-color: var(--navy-dark); + color: #fff !important; + border: none; + padding: 14px 32px; + border-radius: 50px; + transition: all 0.3s ease; + text-transform: uppercase; + font-weight: 600; + font-size: 0.9rem; + letter-spacing: 0.5px; + display: inline-block; + text-decoration: none !important; +} + +.privacy-back-btn:hover { + background-color: #0000a0; + transform: translateY(-2px); + color: var(--chartreuse) !important; +} + +@keyframes fadeInUp { + from { opacity: 0; transform: translateY(30px); } + to { opacity: 1; transform: translateY(0); } +} + +@media (max-width: 768px) { + .privacy-card { padding: 1.5rem; } + .privacy-header h1 { font-size: 1.8rem; } +} diff --git a/src/public/themes/blog/assets/css/privacy.min.css b/src/public/themes/blog/assets/css/privacy.min.css new file mode 100755 index 000000000..77f3b5692 --- /dev/null +++ b/src/public/themes/blog/assets/css/privacy.min.css @@ -0,0 +1 @@ +@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;700;800&display=swap');:root{--navy-dark:#000080;--chartreuse:#7FFF00;--glass-bg:rgba(255,255,255,0.85);}.privacy-wrapper{font-family:'Outfit',sans-serif;padding:60px 0;background:linear-gradient(135deg,#f8f9fa 0%,#e9ecef 100%);min-height:100vh;}.privacy-card{background:var(--glass-bg);backdrop-filter:blur(25px);-webkit-backdrop-filter:blur(25px);border:1px solid rgba(255,255,255,0.4);border-radius:20px;padding:3rem;box-shadow:0 15px 35px rgba(0,0,0,0.05);animation:fadeInUp 0.8s ease-out;}.privacy-header h1{color:var(--navy-dark);font-weight:800;font-size:2.5rem;margin:0 0 5px 0;line-height:1.1;}.privacy-meta{font-weight:300;color:#6c757d;margin-bottom:15px;border-bottom:2px solid var(--chartreuse);display:inline-block;padding-bottom:5px;}.privacy-meta i{color:var(--chartreuse);margin-right:6px;}.privacy-body{line-height:1.7;font-weight:400;color:#2d3436;margin:0;padding:0;}.privacy-body .lead{font-size:1.1rem;color:#495057;margin:0 0 10px 0;}.privacy-body h2{font-weight:700;color:var(--navy-dark);margin:15px 0 10px 0;font-size:1.5rem;}.privacy-body p{margin-bottom:1rem;}.privacy-body ul{padding-left:1.2rem;list-style-type:none;}.privacy-body ul li{margin-bottom:0.75rem;position:relative;padding-left:1.5rem;}.privacy-body ul li::before{content:"\2022";color:var(--chartreuse);font-weight:bold;font-size:1.2em;position:absolute;left:0;}.privacy-body ul li strong{color:var(--navy-dark);}.privacy-body a{color:var(--navy-dark);text-decoration:none;border-bottom:1px solid transparent;transition:border-color 0.2s ease;}.privacy-body a:hover{border-bottom-color:var(--chartreuse);}.privacy-footer{margin-top:3rem;padding-top:2rem;border-top:1px solid #e9ecef;text-align:center;}.privacy-back-btn{background-color:var(--navy-dark);color:#fff !important;border:none;padding:14px 32px;border-radius:50px;transition:all 0.3s ease;text-transform:uppercase;font-weight:600;font-size:0.9rem;letter-spacing:0.5px;display:inline-block;text-decoration:none !important;}.privacy-back-btn:hover{background-color:#0000a0;transform:translateY(-2px);color:var(--chartreuse) !important;}@keyframes fadeInUp{from{opacity:0;transform:translateY(30px);}to{opacity:1;transform:translateY(0);}}@media (max-width:768px){.privacy-card{padding:1.5rem;}.privacy-header h1{font-size:1.8rem;}} \ No newline at end of file diff --git a/src/public/themes/blog/assets/css/rtl.css b/src/public/themes/blog/assets/css/rtl.css new file mode 100755 index 000000000..05ba73411 --- /dev/null +++ b/src/public/themes/blog/assets/css/rtl.css @@ -0,0 +1,454 @@ +/** + * RTL (Right-to-Left) Styles for Blogware Theme + * + * These styles override Bootstrap defaults for RTL languages + * like Arabic, Hebrew, Farsi, and Urdu. + * + * @version 1.0 + * @since 1.0 + */ + +/* Base RTL Overrides */ +[dir="rtl"] { + direction: rtl; + text-align: right; +} + +/* Typography */ +[dir="rtl"] body { + font-family: 'Cairo', 'Tajawal', 'Noto Sans Arabic', Arial, sans-serif; +} + +/* Links */ +[dir="rtl"] a { + direction: rtl; +} + +/* Navigation */ +[dir="rtl"] .navbar { + padding-right: 0; + padding-left: 1rem; +} + +[dir="rtl"] .navbar-brand { + margin-right: 0; + margin-left: 1rem; +} + +[dir="rtl"] .navbar-nav { + padding-right: 0; + padding-left: auto; +} + +[dir="rtl"] .nav-link { + text-align: right; +} + +/* Dropdown Menus */ +[dir="rtl"] .dropdown-menu { + right: auto; + left: 0; + text-align: right; +} + +[dir="rtl"] .dropdown-menu-right { + right: auto; + left: 0; +} + +[dir="rtl"] .dropdown-toggle::after { + margin-left: 0; + margin-right: 0.255em; +} + +[dir="rtl"] .dropdown-toggle-split::after { + margin-left: 0; + margin-right: 0; +} + +/* Margin/Padding Utilities */ +[dir="rtl"] .ml-auto, +[dir="rtl"] .mx-auto { + margin-left: 0 !important; + margin-right: auto !important; +} + +[dir="rtl"] .mr-auto, +[dir="rtl"] .mx-auto { + margin-right: 0 !important; + margin-left: auto !important; +} + +[dir="rtl"] .pl-0, +[dir="rtl"] .px-0 { + padding-left: 0 !important; + padding-right: 0 !important; +} + +[dir="rtl"] .pr-0, +[dir="rtl"] .px-0 { + padding-right: 0 !important; + padding-left: 0 !important; +} + +[dir="rtl"] .ml-1, +[dir="rtl"] .ml-2, +[dir="rtl"] .ml-3, +[dir="rtl"] .ml-4, +[dir="rtl"] .ml-5 { + margin-left: 0 !important; +} + +[dir="rtl"] .mr-1, +[dir="rtl"] .mr-2, +[dir="rtl"] .mr-3, +[dir="rtl"] .mr-4, +[dir="rtl"] .mr-5 { + margin-right: 0 !important; +} + +/* Text Alignment */ +[dir="rtl"] .text-left { + text-align: right !important; +} + +[dir="rtl"] .text-right { + text-align: left !important; +} + +/* Floats */ +[dir="rtl"] .float-left { + float: right !important; +} + +[dir="rtl"] .float-right { + float: left !important; +} + +/* Borders */ +[dir="rtl"] .border-left { + border-left: 0 !important; + border-right: 1px solid #dee2e6 !important; +} + +[dir="rtl"] .border-right { + border-right: 0 !important; + border-left: 1px solid #dee2e6 !important; +} + +/* List Group */ +[dir="rtl"] .list-group { + padding-right: 0; +} + +[dir="rtl"] .list-inline-item:not(:last-child) { + margin-right: 0; + margin-left: 0.5rem; +} + +/* Cards */ +[dir="rtl"] .card-header { + border-right: 0; + border-left: 4px solid rgba(0, 0, 0, 0.125); +} + +[dir="rtl"] .card-footer { + border-right: 0; + border-left: none; +} + +/* Badges */ +[dir="rtl"] .badge { + margin-right: 0; + margin-left: 0.5rem; +} + +/* Breadcrumbs */ +[dir="rtl"] .breadcrumb-item + .breadcrumb-item::before { + padding-right: 0; + padding-left: 0.5rem; + content: "«"; +} + +[dir="rtl"] .breadcrumb-item + .breadcrumb-item::after { + display: none; +} + +/* Pagination */ +[dir="rtl"] .page-item:first-child .page-link { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; +} + +[dir="rtl"] .page-item:last-child .page-link { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +/* Alerts */ +[dir="rtl"] .alert-dismissible { + padding-right: 1.25rem; + padding-left: 4rem; +} + +[dir="rtl"] .alert-dismissible .close { + right: auto; + left: 0; +} + +/* Close Button */ +[dir="rtl"] .close { + float: left; +} + +/* Modal */ +[dir="rtl"] .modal-header .close { + margin: -1rem auto -1rem -1rem; +} + +[dir="rtl"] .modal-footer > :not(:last-child) { + margin-right: 0; + margin-left: 0.25rem; +} + +[dir="rtl"] .modal-footer > :not(:first-child) { + margin-left: 0; + margin-right: 0.25rem; +} + +/* Forms */ +[dir="rtl"] .form-check { + padding-right: 1.25rem; + padding-left: 0; +} + +[dir="rtl"] .form-check-input { + margin-right: -1.25rem; + margin-left: 0; +} + +[dir="rtl"] .form-check-label { + margin-right: 0.25rem; + margin-left: 0; +} + +[dir="rtl"] input[type="radio"].form-check-input, +[dir="rtl"] input[type="checkbox"].form-check-input { + margin-right: 0; + margin-left: 1rem; +} + +[dir="rtl"] .custom-control { + padding-right: 1.5rem; + padding-left: 0; +} + +[dir="rtl"] .custom-control-label::before, +[dir="rtl"] .custom-control-label::after { + right: 0; + left: auto; +} + +[dir="rtl"] .custom-file-label::after { + right: auto; + left: 0; + border-right: 1px solid #ced4da; + border-left: none; +} + +/* Input Groups */ +[dir="rtl"] .input-group > .form-control:not(:last-child), +[dir="rtl"] .input-group > .custom-select:not(:last-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; +} + +[dir="rtl"] .input-group > .input-group-append > .btn, +[dir="rtl"] .input-group > .input-group-append > .input-group-text, +[dir="rtl"] .input-group > .input-group-prepend:not(:first-child) > .btn, +[dir="rtl"] .input-group > .input-group-prepend:not(:first-child) > .input-group-text { + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +[dir="rtl"] .input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle), +[dir="rtl"] .input-group > .input-group-append:last-child > .input-group-text:not(:last-child), +[dir="rtl"] .input-group > .input-group-append:not(:last-child) > .btn, +[dir="rtl"] .input-group > .input-group-append:not(:last-child) > .input-group-text { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; +} + +[dir="rtl"] .input-group > .form-control:not(:first-child), +[dir="rtl"] .input-group > .custom-select:not(:first-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +/* Icons - Flip horizontal icons for RTL */ +[dir="rtl"] .fa-arrow-left:before { + content: "\f30b"; /* fa-arrow-right */ +} + +[dir="rtl"] .fa-arrow-right:before { + content: "\f30a"; /* fa-arrow-left */ +} + +[dir="rtl"] .fa-chevron-left:before { + content: "\f054"; /* fa-chevron-right */ +} + +[dir="rtl"] .fa-chevron-right:before { + content: "\f053"; /* fa-chevron-left */ +} + +[dir="rtl"] .fa-angle-left:before { + content: "\f105"; /* fa-angle-right */ +} + +[dir="rtl"] .fa-angle-right:before { + content: "\f104"; /* fa-angle-left */ +} + +[dir="rtl"] .fa-caret-left:before { + content: "\f0d7"; /* fa-caret-down */ +} + +[dir="rtl"] .fa-caret-right:before { + content: "\f0d4"; /* fa-caret-up */ +} + +[dir="rtl"] .fa-long-arrow-left:before { + content: "\f30b"; /* fa-arrow-right */ +} + +[dir="rtl"] .fa-long-arrow-right:before { + content: "\f30a"; /* fa-arrow-left */ +} + +[dir="rtl"] .fa-chevron-circle-left:before { + content: "\f138"; /* fa-chevron-circle-right */ +} + +[dir="rtl"] .fa-chevron-circle-right:before { + content: "\f137"; /* fa-chevron-circle-left */ +} + +/* Sidebar */ +[dir="rtl"] .sidebar { + border-right: 0; + border-left: 1px solid #dee2e6; +} + +[dir="rtl"] .widget { + text-align: right; +} + +[dir="rtl"] .widget ul { + padding-right: 0; +} + +/* Post Navigation */ +[dir="rtl"] .post-navigation .previous-post { + text-align: left; +} + +[dir="rtl"] .post-navigation .next-post { + text-align: right; +} + +[dir="rtl"] .previous-post .icon i { + margin-right: 0; + margin-left: 1rem; +} + +[dir="rtl"] .next-post .icon i { + margin-left: 0; + margin-right: 1rem; +} + +/* Comments */ +[dir="rtl"] .comment-avatar { + float: right; + margin-right: 0; + margin-left: 1rem; +} + +[dir="rtl"] .comment-content { + margin-right: 0; + margin-left: 0; +} + +[dir="rtl"] .comment-reply { + text-align: left; +} + +/* Language Switcher */ +[dir="rtl"] .language-switcher { + direction: ltr; +} + +[dir="rtl"] .language-switcher .dropdown-menu { + left: auto; + right: 0; +} + +/* Footer */ +[dir="rtl"] .footer .text-right { + text-align: left !important; +} + +/* Pre/Code */ +[dir="rtl"] pre { + text-align: right; + direction: ltr; +} + +/* Blockquote */ +[dir="rtl"] blockquote { + border-right: 4px solid #6c757d; + border-left: none; + padding-right: 1rem; + padding-left: 0; +} + +[dir="rtl"] blockquote.float-right { + float: left; +} + +/* Tables */ +[dir="rtl"] table.text-right, +[dir="rtl"] .table text-right { + text-align: left !important; +} + +/* Responsive RTL Adjustments */ +@media (max-width: 767.98px) { + [dir="rtl"] .navbar-collapse { + text-align: right; + } + + [dir="rtl"] .dropdown-menu { + right: 0; + left: auto; + } +} + +/* Print Styles */ +@media print { + [dir="rtl"] body { + direction: rtl; + } +} diff --git a/src/public/themes/blog/assets/css/rtl.min.css b/src/public/themes/blog/assets/css/rtl.min.css new file mode 100755 index 000000000..d5d4d216b --- /dev/null +++ b/src/public/themes/blog/assets/css/rtl.min.css @@ -0,0 +1 @@ +[dir="rtl"]{direction:rtl;text-align:right}[dir="rtl"] body{font-family:'Cairo', 'Tajawal', 'Noto Sans Arabic', Arial, sans-serif}[dir="rtl"] a{direction:rtl}[dir="rtl"] .navbar{padding-right:0;padding-left:1rem}[dir="rtl"] .navbar-brand{margin-right:0;margin-left:1rem}[dir="rtl"] .navbar-nav{padding-right:0;padding-left:auto}[dir="rtl"] .nav-link{text-align:right}[dir="rtl"] .dropdown-menu{right:auto;left:0;text-align:right}[dir="rtl"] .dropdown-menu-right{right:auto;left:0}[dir="rtl"] .dropdown-toggle::after{margin-left:0;margin-right:0.255em}[dir="rtl"] .dropdown-toggle-split::after{margin-left:0;margin-right:0}[dir="rtl"] .ml-auto,[dir="rtl"] .mx-auto{margin-left:0 !important;margin-right:auto !important}[dir="rtl"] .mr-auto,[dir="rtl"] .mx-auto{margin-right:0 !important;margin-left:auto !important}[dir="rtl"] .pl-0,[dir="rtl"] .px-0{padding-left:0 !important;padding-right:0 !important}[dir="rtl"] .pr-0,[dir="rtl"] .px-0{padding-right:0 !important;padding-left:0 !important}[dir="rtl"] .ml-1,[dir="rtl"] .ml-2,[dir="rtl"] .ml-3,[dir="rtl"] .ml-4,[dir="rtl"] .ml-5{margin-left:0 !important}[dir="rtl"] .mr-1,[dir="rtl"] .mr-2,[dir="rtl"] .mr-3,[dir="rtl"] .mr-4,[dir="rtl"] .mr-5{margin-right:0 !important}[dir="rtl"] .text-left{text-align:right !important}[dir="rtl"] .text-right{text-align:left !important}[dir="rtl"] .float-left{float:right !important}[dir="rtl"] .float-right{float:left !important}[dir="rtl"] .border-left{border-left:0 !important;border-right:1px solid #dee2e6 !important}[dir="rtl"] .border-right{border-right:0 !important;border-left:1px solid #dee2e6 !important}[dir="rtl"] .list-group{padding-right:0}[dir="rtl"] .list-inline-item:not(:last-child){margin-right:0;margin-left:0.5rem}[dir="rtl"] .card-header{border-right:0;border-left:4px solid rgba(0, 0, 0, 0.125)}[dir="rtl"] .card-footer{border-right:0;border-left:none}[dir="rtl"] .badge{margin-right:0;margin-left:0.5rem}[dir="rtl"] .breadcrumb-item+.breadcrumb-item::before{padding-right:0;padding-left:0.5rem;content:"«"}[dir="rtl"] .breadcrumb-item+.breadcrumb-item::after{display:none}[dir="rtl"] .page-item:first-child .page-link{border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:0.25rem;border-bottom-right-radius:0.25rem}[dir="rtl"] .page-item:last-child .page-link{border-top-right-radius:0;border-bottom-right-radius:0;border-top-left-radius:0.25rem;border-bottom-left-radius:0.25rem}[dir="rtl"] .alert-dismissible{padding-right:1.25rem;padding-left:4rem}[dir="rtl"] .alert-dismissible .close{right:auto;left:0}[dir="rtl"] .close{float:left}[dir="rtl"] .modal-header .close{margin:-1rem auto -1rem -1rem}[dir="rtl"] .modal-footer>:not(:last-child){margin-right:0;margin-left:0.25rem}[dir="rtl"] .modal-footer>:not(:first-child){margin-left:0;margin-right:0.25rem}[dir="rtl"] .form-check{padding-right:1.25rem;padding-left:0}[dir="rtl"] .form-check-input{margin-right:-1.25rem;margin-left:0}[dir="rtl"] .form-check-label{margin-right:0.25rem;margin-left:0}[dir="rtl"] input[type="radio"].form-check-input,[dir="rtl"] input[type="checkbox"].form-check-input{margin-right:0;margin-left:1rem}[dir="rtl"] .custom-control{padding-right:1.5rem;padding-left:0}[dir="rtl"] .custom-control-label::before,[dir="rtl"] .custom-control-label::after{right:0;left:auto}[dir="rtl"] .custom-file-label::after{right:auto;left:0;border-right:1px solid #ced4da;border-left:none}[dir="rtl"] .input-group>.form-control:not(:last-child),[dir="rtl"] .input-group>.custom-select:not(:last-child){border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:0.25rem;border-bottom-right-radius:0.25rem}[dir="rtl"] .input-group>.input-group-append>.btn,[dir="rtl"] .input-group>.input-group-append>.input-group-text,[dir="rtl"] .input-group>.input-group-prepend:not(:first-child)>.btn,[dir="rtl"] .input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0.25rem;border-bottom-left-radius:0.25rem;border-top-right-radius:0;border-bottom-right-radius:0}[dir="rtl"] .input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),[dir="rtl"] .input-group>.input-group-append:last-child>.input-group-text:not(:last-child),[dir="rtl"] .input-group>.input-group-append:not(:last-child)>.btn,[dir="rtl"] .input-group>.input-group-append:not(:last-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:0.25rem;border-bottom-right-radius:0.25rem}[dir="rtl"] .input-group>.form-control:not(:first-child),[dir="rtl"] .input-group>.custom-select:not(:first-child){border-top-right-radius:0;border-bottom-right-radius:0;border-top-left-radius:0.25rem;border-bottom-left-radius:0.25rem}[dir="rtl"] .fa-arrow-left:before{content:"\f30b"}[dir="rtl"] .fa-arrow-right:before{content:"\f30a"}[dir="rtl"] .fa-chevron-left:before{content:"\f054"}[dir="rtl"] .fa-chevron-right:before{content:"\f053"}[dir="rtl"] .fa-angle-left:before{content:"\f105"}[dir="rtl"] .fa-angle-right:before{content:"\f104"}[dir="rtl"] .fa-caret-left:before{content:"\f0d7"}[dir="rtl"] .fa-caret-right:before{content:"\f0d4"}[dir="rtl"] .fa-long-arrow-left:before{content:"\f30b"}[dir="rtl"] .fa-long-arrow-right:before{content:"\f30a"}[dir="rtl"] .fa-chevron-circle-left:before{content:"\f138"}[dir="rtl"] .fa-chevron-circle-right:before{content:"\f137"}[dir="rtl"] .sidebar{border-right:0;border-left:1px solid #dee2e6}[dir="rtl"] .widget{text-align:right}[dir="rtl"] .widget ul{padding-right:0}[dir="rtl"] .post-navigation .previous-post{text-align:left}[dir="rtl"] .post-navigation .next-post{text-align:right}[dir="rtl"] .previous-post .icon i{margin-right:0;margin-left:1rem}[dir="rtl"] .next-post .icon i{margin-left:0;margin-right:1rem}[dir="rtl"] .comment-avatar{float:right;margin-right:0;margin-left:1rem}[dir="rtl"] .comment-content{margin-right:0;margin-left:0}[dir="rtl"] .comment-reply{text-align:left}[dir="rtl"] .language-switcher{direction:ltr}[dir="rtl"] .language-switcher .dropdown-menu{left:auto;right:0}[dir="rtl"] .footer .text-right{text-align:left !important}[dir="rtl"] pre{text-align:right;direction:ltr}[dir="rtl"] blockquote{border-right:4px solid #6c757d;border-left:none;padding-right:1rem;padding-left:0}[dir="rtl"] blockquote.float-right{float:left}[dir="rtl"] table.text-right,[dir="rtl"] .table text-right{text-align:left !important}@media (max-width:767.98px){[dir="rtl"] .navbar-collapse{text-align:right}[dir="rtl"] .dropdown-menu{right:0;left:auto}}@media print{[dir="rtl"] body{direction:rtl}} \ No newline at end of file diff --git a/src/public/themes/blog/assets/css/show-more.css b/src/public/themes/blog/assets/css/show-more.css deleted file mode 100644 index afa30839b..000000000 --- a/src/public/themes/blog/assets/css/show-more.css +++ /dev/null @@ -1,49 +0,0 @@ -.show_more_main { - margin: 15px 25px; -} - -.show_more { - background-color: #f8f8f8; - background-image: linear-gradient(to bottom, #fcfcfc 0%, #f8f8f8 100%); - border: 1px solid #d3d3d3; - color: #333; - font-size: 12px; - outline: 0; - cursor: pointer; - display: block; - padding: 10px 0; - text-align: center; - font-weight: bold; - border-radius: .25rem; /* Bootstrap default border radius */ -} - -.loding { - background-color: #e9e9e9; - border: 1px solid #c6c6c6; - color: #333; - font-size: 12px; - display: block; - text-align: center; - padding: 10px 0; - outline: 0; - font-weight: bold; - border-radius: .25rem; /* Bootstrap default border radius */ -} - -.loding_txt { - background-image: url(loading.gif); - background-position: left center; - background-repeat: no-repeat; - border: 0; - display: inline-block; - height: 16px; - padding-left: 20px; -} - -/* Use Bootstrap 4 utility classes to align and style the text */ -.text-center { - text-align: center !important; -} -.font-weight-bold { - font-weight: 700 !important; -} diff --git a/src/public/themes/blog/assets/css/sina-nav.min.css b/src/public/themes/blog/assets/css/sina-nav.min.css index 9d2ff16e4..43f90b4a3 100755 --- a/src/public/themes/blog/assets/css/sina-nav.min.css +++ b/src/public/themes/blog/assets/css/sina-nav.min.css @@ -1,7 +1 @@ -/** - * Template name: Sina-nav Multi Purpose Menu - * Template URI: https://github.com/shaonsina/sina-nav-4 - * Version: 2.1 - * Author: shaonsina - */ -.search-box{padding:8px 0;display:none;border-radius:4px;overflow:hidden;background-color:#f6f6f6}.search-box input.form-control{height:44px;border:0;box-shadow:0 0 0;color:#222;background-color:transparent}.search-box .search-input{float:left;width:calc(100% - 108px)}.search-box .search-addon{padding:10px 20px;float:left;color:#222;background-color:transparent}.search-box .search-addon.close-search{cursor:pointer}.sina-nav-overlay{display:none;position:fixed;top:0;left:0;width:100%;height:100%;z-index:9998;background:rgba(0,0,0,0.5)}.sina-nav{margin-bottom:0;border-radius:0;min-height:60px;z-index:9999;left:0;right:0;background:#fff;border:1px solid #eee;transition:box-shadow,border,background .5s ease-in-out}.sina-nav ul,.sina-nav ul ul{padding:0;margin:0;list-style:none}.sina-nav ul li a{display:block;font-family:"Montserrat",sans-serif;text-transform:uppercase;line-height:20px;text-decoration:none;white-space:normal;transition:all .3s ease-in-out;background:transparent}.sina-nav .animated{animation-duration:1s;animation-fill-mode:both}.sina-nav .container,.sina-nav .container-fluid{position:relative}.sina-nav .sina-brand{height:60px;max-width:200px;padding:0;margin:0 30px 0 0;float:left;text-decoration:none}.sina-nav .sina-brand > img{height:100%;padding:6px 0}.sina-nav .sina-brand h2{color:#222;font-size:30px;line-height:36px;margin:0;padding:0}.sina-nav .sina-brand p{color:#222;font-size:14px;line-height:16px;margin:0;padding:0}.sina-nav .logo-primary,.sina-nav.navbar-transparent .logo-secondary{display:inline-block}.sina-nav .logo-secondary,.sina-nav.navbar-transparent .logo-primary{display:none}.sina-nav .dropdown-toggle::after{width:inherit;height:inherit;border:0;margin:0}.sina-nav .dropdown{position:relative}.sina-nav .dropdown-menu{position:absolute;display:none;top:100%;left:0;z-index:1000}.sina-nav .open > .dropdown-menu{display:block}.sina-nav .collapse:not(.show){display:none}.sina-nav .collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}.sina-nav .navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;-webkit-overflow-scrolling:touch}.sina-nav .navbar-collapse.show{overflow-y:auto}.sina-nav .navbar-collapse:before,.sina-nav .navbar-collapse:after{content:" ";display:table}.sina-nav .navbar-collapse:after{clear:both}.sina-nav .sina-menu li a{position:relative;display:block;font-size:14px}.sina-nav .sina-menu li .fa-icon-left{margin-right:8px}.sina-nav .sina-menu li .fa-icon-right{margin-left:8px}.sina-nav .sina-menu > li > a{padding:20px 15px;max-width:160px;color:#222;font-size:14px;font-weight:700;line-height:20px}.sina-nav .sina-menu > li.active > a,.sina-nav .sina-menu > li > a:hover,.sina-nav .sina-menu > li > a:focus{color:#1085e4;background-color:transparent}.sina-nav .sina-menu > li.sina-nav-cta-btn{padding:11px 15px;margin-left:20px}.sina-nav .sina-menu > li.sina-nav-cta-btn a{padding:8px 15px;border:1px solid #1085e4;border-radius:4px;text-align:center;color:#fff;background:#1085e4}.sina-nav .sina-menu > li.sina-nav-cta-btn a:hover,.sina-nav .sina-menu > li.sina-nav-cta-btn a:focus{border-color:#1085e4;color:#1085e4;background:transparent}.sina-nav .sina-menu li .description{font-style:italic;font-size:90%;margin:6px 0 0;font-weight:400}.sina-nav .sina-menu .dropdown-menu{background-color:#fcfcfc;margin:0}.sina-nav .sina-menu .dropdown-menu li a{color:#222;font-size:12px}.sina-nav .sina-menu .dropdown-menu li.active > a,.sina-nav .sina-menu .dropdown-menu li > a:hover,.sina-nav .sina-menu .dropdown-menu li > a:focus{color:#222;background-color:#f6f6f6}.sina-nav .sina-menu .dropdown-toggle:focus{outline:0}.sina-nav .sina-menu .mega-menu-col-title:before,.sina-nav .sina-menu .dropdown .dropdown-toggle:before,.sina-nav .sina-menu .dropdown .dropdown-toggle:after{font-family:'FontAwesome'}.sina-nav.navbar-reverse .search-box .form-control{text-align:right}.sina-nav.navbar-reverse .extension-nav > ul > li.dropdown .dropdown-menu{left:0;margin-left:0}.sina-nav.navbar-reverse.sina-nav-cta-btn{margin-right:20px;margin-left:0}.sina-nav .navbar-collapse{padding:0}.sina-nav .menu-item-has-mega-menu.dropdown{position:static}.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu.dropdown-menu{width:100%;padding:0;background-color:#fcfcfc}.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu-row{width:100%;float:left}.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu-col{list-style:none;color:#222}.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu-col a{color:#222}.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu-col .active > a,.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu-col > a:hover,.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu-col > a:focus{color:#1085e4;background:transparent}.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu-col-title{font-size:15px;line-height:20px;margin:0}.sina-nav.navbar-fixed{position:relative}.sina-nav .extension-nav{float:right;margin-left:20px}.sina-nav .extension-nav > ul{float:left}.sina-nav .extension-nav > ul > li{float:left}.sina-nav .extension-nav > ul > li > a{display:block;padding:20px 12px;position:relative;font-size:18px;color:#222}.sina-nav .extension-nav > ul > li > a:hover,.sina-nav .extension-nav > ul > li > a:focus{color:#1085e4;background-color:transparent}.sina-nav .extension-nav > ul > li > a .shop-badge{position:absolute;top:12px;right:10px;padding:4px 5px;font-size:10px;line-height:10px;border-radius:50%;background-color:#1085e4;color:#fff}.sina-nav .extension-nav > ul > li.dropdown .dropdown-menu{border-radius:0;box-shadow:0 0 0;margin-left:40px;width:232px;left:-232px;background-color:#fcfcfc;border:solid 1px #eee}.sina-nav .extension-nav > ul > li .shop-menu > li{padding:12px 15px;width:100%;overflow:hidden;border-bottom:solid 1px #eee}.sina-nav .extension-nav > ul > li .shop-menu > li:last-child{border-bottom:0}.sina-nav .extension-nav > ul > li .shop-menu > li .shop-item-photo{padding:0;float:left;width:60px;height:60px;margin-right:10px;border:solid 1px #eee}.sina-nav .extension-nav > ul > li .shop-menu > li .shop-item-link,.sina-nav .extension-nav > ul > li .shop-menu > li .shop-item-price{margin:0;padding:0;font-size:14px;line-height:20px;display:inline-block;max-width:130px;color:#222}.sina-nav .extension-nav > ul > li .shop-menu > li .shop-item-link{color:#1085e4;font-size:12px}.sina-nav .extension-nav > ul > li .shop-menu > li .shop-item-link:hover,.sina-nav .extension-nav > ul > li .shop-menu > li .shop-item-link:focus{background-color:transparent}.sina-nav .extension-nav > ul > li .shop-menu > li.shop-total-price .shop-btn{padding:8px 12px;display:inline-block;border-radius:4px;border:1px solid #1085e4;font-size:14px;color:#1085e4;background-color:#fcfcfc}.sina-nav .extension-nav > ul > li .shop-menu > li.shop-total-price .shop-btn:hover,.sina-nav .extension-nav > ul > li .shop-menu > li.shop-total-price .shop-btn:focus{background-color:#1085e4;color:#fcfcfc}.sina-nav .extension-nav > ul > li .shop-menu > li.shop-total-price > span{color:#222;float:right;font-weight:700;margin-top:5px}.sina-nav.navbar-fixed.navbar-freez.wp-topbar,.sina-nav.mobile-sidebar.wp-topbar .navbar-collapse,.sina-nav.wp-topbar .widget-bar{top:32px}.sina-nav .widget-bar{position:fixed;overflow-y:auto;top:0;right:-300px;width:300px;padding:20px;height:100%;z-index:99999;transition:all .6s ease;background-color:#333}.sina-nav .widget-bar.on{right:0}.sina-nav .widget-bar .widget{margin-bottom:30px}.sina-nav .widget-bar .widget .link li a{color:#ccc;font-size:14px}.sina-nav .widget-bar .widget .link li a:focus,.sina-nav .widget-bar .widget .link li a:hover{color:#fcfcfc}.sina-nav .widget-bar .widget .title{font-size:20px;margin-bottom:10px;color:#ccc;font-weight:700}.sina-nav .widget-bar .close-widget-bar{float:right;font-size:16px;color:#ccc}.sina-nav.navbar-reverse .widget-bar{right:inherit;left:-300px;text-align:right}.sina-nav.navbar-reverse .widget-bar.on{right:inherit;left:0}.sina-nav.navbar-reverse .widget-bar .close-widget-bar{float:left}@media (min-width: 1025px){.sina-nav .navbar-toggle{display:none}.sina-nav .navbar-collapse.collapse{display:block}.sina-nav.navbar-reverse .sina-nav-header{float:right}.sina-nav.navbar-reverse .sina-brand{margin:0 0 0 30px;text-align:right}.sina-nav.navbar-reverse .extension-nav{float:left;margin-right:20px;margin-left:0}.sina-nav.navbar-reverse .extension-nav li{float:right}.sina-nav .sina-menu{float:left}.sina-nav .sina-menu > li{float:left}.sina-nav .sina-menu > .dropdown > .dropdown-toggle{padding-right:20px}.sina-nav .sina-menu > .dropdown > .dropdown-toggle:after{content:"\f107";position:absolute;top:20px;right:5px}.sina-nav .sina-menu .dropdown .dropdown-menu{box-shadow:0 0 0;border-radius:0;width:200px;border:solid 1px #eee}.sina-nav .sina-menu .dropdown .dropdown-menu .dropdown-menu{left:100%;top:0}.sina-nav .sina-menu .dropdown .dropdown-menu .dropdown:first-child > .dropdown-menu{top:-1px}.sina-nav .sina-menu .dropdown .dropdown-menu > li > a{padding:10px 12px;border-top:solid 1px #eee}.sina-nav .sina-menu .dropdown .dropdown-menu > li:first-child > a{border-top:0}.sina-nav .sina-menu .dropdown .dropdown-menu .dropdown > .dropdown-toggle{padding:10px 20px 10px 12px}.sina-nav .sina-menu .dropdown .dropdown-menu .dropdown > .dropdown-toggle:before{float:right;content:"\f105";position:absolute;right:8px}.sina-nav .sina-menu .dropdown .mega-menu.dropdown-menu{max-height:400px;overflow-y:auto}.sina-nav .sina-menu .mega-menu-col{padding:10px 15px;float:left}.sina-nav .sina-menu .mega-menu-col .sub-menu a{padding:6px 10px;display:inline-block}.sina-nav .sina-menu .mega-menu-col .sub-menu a:hover,.sina-nav .sina-menu .mega-menu-col .sub-menu a:focus{color:#1085e4;background:transparent}.sina-nav .sina-menu .mega-menu-col-title{font-weight:700;padding:6px 10px;display:inline-block}.sina-nav .sina-menu .mega-menu-col-content{padding:4px 10px}.sina-nav .sina-menu.sina-menu-dropdown-right{float:right;left:auto;right:0}.sina-nav .sina-menu.sina-menu-dropdown-right .mega-menu.dropdown-menu .mega-menu-col{float:right}.sina-nav .sina-menu.sina-menu-dropdown-right > .dropdown > .dropdown-toggle{padding-left:20px;padding-right:15px}.sina-nav .sina-menu.sina-menu-dropdown-right > .dropdown > .dropdown-toggle:after{left:5px;right:inherit}.sina-nav .sina-menu.sina-menu-dropdown-right .dropdown-menu .dropdown-menu{left:-200px}.sina-nav .sina-menu.sina-menu-dropdown-right .dropdown .dropdown-menu{text-align:right}.sina-nav .sina-menu.sina-menu-dropdown-right .dropdown .dropdown-menu .dropdown > .dropdown-toggle{padding:10px 12px 10px 20px}.sina-nav .sina-menu.sina-menu-dropdown-right .dropdown .dropdown-menu .dropdown > .dropdown-toggle:before{float:left;content:"\f104";left:8px;right:inherit}.sina-nav .sina-menu.sina-menu-right,.sina-nav .sina-menu.sina-menu-list-right > li{float:right}.sina-nav .sina-menu.sina-menu-left{float:left}.sina-nav.navbar-fixed.navbar-freez{position:fixed!important;top:0;box-shadow:0 1px 4px #eee}.sina-nav.navbar-transparent{background-color:transparent;border-color:transparent}.sina-nav.navbar-transparent .sina-brand{color:#ddd}.sina-nav.navbar-transparent .extension-nav > ul > li > a,.sina-nav.navbar-transparent .sina-menu > li > a{color:#ddd}.sina-nav.navbar-transparent .extension-nav > ul > li.active > a,.sina-nav.navbar-transparent .extension-nav > ul > li > a:hover,.sina-nav.navbar-transparent .extension-nav > ul > li > a:focus,.sina-nav.navbar-transparent .sina-menu > li.active > a,.sina-nav.navbar-transparent .sina-menu > li > a:hover,.sina-nav.navbar-transparent .sina-menu > li > a:focus{color:#1085e4}.sina-nav.navbar-transparent .sina-menu > li.sina-nav-cta-btn a{border-color:#1085e4;color:#fff;background:#1085e4}.sina-nav.navbar-transparent .sina-menu > li.sina-nav-cta-btn a:hover,.sina-nav.navbar-transparent .sina-menu > li.sina-nav-cta-btn a:focus{border-color:#fff;color:#1085e4;background:#fff}.sina-nav.logo-center .sina-nav-header{width:100%;position:absolute;text-align:center;top:0;left:0}.sina-nav.logo-center .sina-brand{float:none;display:inline-block;margin:0}.sina-nav.logo-center .navbar-collapse{text-align:center}.sina-nav.logo-center .navbar-collapse .col-half{width:50%;float:left;display:block}.sina-nav.logo-center .navbar-collapse .col-half.left{padding-right:120px}.sina-nav.logo-center .navbar-collapse .col-half.right{padding-left:120px}.sina-nav.logo-center .sina-menu{display:inline-block;padding:0}.sina-nav.logo-center .sina-menu > li > .dropdown-menu.mega-menu{margin-top:0}.sina-nav .sina-menu.sina-menu-center{float:none;margin:0 auto;display:table}}@media (max-width: 1024px){.sina-nav{background-color:#fff;border-color:#eee}.sina-nav.navbar-fixed.navbar-freez.wp-topbar{top:inherit}.sina-nav .sina-brand{display:inline-block;float:none;text-align:center;margin:0 0 0 -35px;color:#222}.sina-nav .sina-brand h2{margin-top:0}.sina-nav.navbar-reverse .sina-brand,.sina-nav.navbar-reverse .sina-brand{margin:0 -26px 0 15px}.sina-nav .sina-nav-header{float:none;display:block;text-align:center;height:60px}.sina-nav .navbar-toggle{display:inline-block;position:relative;float:left;font-size:18px;margin:12px 0 0;padding:4px 10px;width:38px;cursor:pointer;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px;transition:all .3s ease-in-out;color:#222}.sina-nav .navbar-toggle:hover,.sina-nav .navbar-toggle:focus{outline:0;color:#222;background-color:#f6f6f6}.sina-nav.navbar-reverse .navbar-toggle{float:right}.sina-nav.navbar-reverse .extension-nav{left:15px;right:inherit;margin-left:0;margin-right:15px}.sina-nav.navbar-reverse .extension-nav li{float:right}.sina-nav.navbar-reverse .sina-menu > li.sina-nav-cta-btn{margin-right:0}.sina-nav .navbar-collapse{overflow-y:auto!important;border:1px solid #eee}.sina-nav .mega-menu-col .mega-menu-col-title,.sina-nav .dropdown .dropdown-toggle{padding:12px 24px 12px 12px}.sina-nav .mega-menu-col .mega-menu-col-title:before,.sina-nav .dropdown .dropdown-toggle:before{float:right;content:"\f105";font-size:16px;position:absolute;right:8px}.sina-nav .mega-menu-col.on .mega-menu-col-title:before,.sina-nav .dropdown.on > .dropdown-toggle:before{content:"\f107"}.sina-nav .sina-menu{float:none!important}.sina-nav .sina-menu .sina-nav-cta-btn{margin-top:20px}.sina-nav .sina-menu li{float:none}.sina-nav .sina-menu li .mega-menu-col-title,.sina-nav .sina-menu li a{max-width:inherit;padding:12px;font-weight:400;display:block;cursor:pointer;font-size:14px;line-height:20px;transition:all .3s ease-in-out;color:#222;border-top:solid 1px #eee}.sina-nav .sina-menu li a:hover,.sina-nav .sina-menu li a:focus,.sina-nav .sina-menu li.active > a,.sina-nav .sina-menu li .mega-menu-col-title:hover,.sina-nav .sina-menu li .mega-menu.dropdown-menu .mega-menu-col .active > a,.sina-nav .sina-menu li .dropdown-menu li.active > a,.sina-nav .sina-menu li .dropdown-menu li a:hover,.sina-nav .sina-menu li .dropdown-menu li a:focus,.sina-nav .sina-menu li .mega-menu .mega-menu-col ul li a:hover,.sina-nav .sina-menu li .mega-menu .mega-menu-col ul li a:focus{color:#222;background-color:#f6f6f6}.sina-nav .sina-menu > li:first-child > a{border-top:0}.sina-nav .sina-menu > li.sina-nav-cta-btn{margin-left:0}.sina-nav .sina-menu .dropdown .mega-menu.dropdown-menu,.sina-nav .sina-menu .dropdown .dropdown-menu{float:none;position:relative;left:0;box-shadow:0 0 0;border-radius:0 0 0;border:0;background-color:transparent}.sina-nav .sina-menu .dropdown .mega-menu.dropdown-menu .mega-menu-row{float:none}.sina-nav .sina-menu .dropdown .mega-menu.dropdown-menu .mega-menu-row .mega-menu-col{padding:0}.sina-nav .sina-menu .dropdown .mega-menu.dropdown-menu .mega-menu-row .mega-menu-col-title{font-size:14px}.sina-nav.navbar-transparent{border-color:transparent}.sina-nav.logo-center .sina-menu .dropdown .dropdown-toggle:before{content:"\f105";float:right}.sina-nav.logo-center .sina-menu .dropdown.on > .dropdown-toggle:before{content:"\f107"}.sina-nav.logo-center .col-half:first-child .sina-menu{padding-bottom:0}.sina-nav.logo-center .col-half:first-child .sina-menu > li:first-child > a{border-top:0}.sina-nav.logo-center .col-half:last-child .sina-menu{padding-top:0}.sina-nav.logo-center .col-half:last-child .sina-menu > li:first-child > a{border-top:solid 1px #eee}.sina-nav .extension-nav{position:absolute;right:15px;margin-right:0}.sina-nav .extension-nav > ul > .dropdown > .dropdown-toggle,.sina-nav .extension-nav > ul > li > a{padding:20px 10px;color:#222}.sina-nav .extension-nav > ul > .dropdown > .dropdown-toggle:hover,.sina-nav .extension-nav > ul > .dropdown > .dropdown-toggle:focus,.sina-nav .extension-nav > ul > li > a:hover,.sina-nav .extension-nav > ul > li > a:focus{color:#222}.sina-nav .extension-nav > ul .dropdown > .dropdown-toggle:before{display:none}.sina-nav.mobile-sidebar .navbar-collapse{position:fixed;overflow-x:hidden;display:block;z-index:99;width:300px;height:100%!important;max-height:100%;left:-300px;top:0;padding:0 0 60px;margin:0;transition:all .4s ease-in-out;background-color:#fcfcfc}.sina-nav.mobile-sidebar .navbar-collapse.show{left:0}.sina-nav.mobile-sidebar .navbar-collapse .mega-menu-col{width:100%;max-width:100%}.sina-nav.mobile-sidebar .sina-menu{padding:15px;margin:0}.sina-nav.mobile-sidebar.navbar-reverse .navbar-collapse{right:-300px;left:inherit}.sina-nav.mobile-sidebar.navbar-reverse .navbar-collapse.show{right:0;left:inherit}body.mobile-left > .wrapper{margin-left:300px;margin-right:-300px}body.mobile-right > .wrapper{margin-right:300px;margin-left:-300px}body > .wrapper{transition:all .4s ease-in-out;position:relative}}@media (max-width: 767px){.sina-nav .sina-nav-header,.sina-nav .navbar-collapse{margin:0}.sina-nav .sina-nav-header.social-on{height:120px}.sina-nav .sina-nav-header.social-on .sina-brand{margin-top:60px}}@media (max-width: 479px){.sina-nav .widget-bar{right:-250px;width:250px}body.on-side{margin-left:-250px}body.mobile-left > .wrapper{margin-left:250px;margin-right:-250px}body.mobile-right > .wrapper{margin-right:250px;margin-left:-250px}.sina-nav.mobile-sidebar .navbar-collapse{width:250px;left:-250px}}@media (max-width: 782px){.sina-nav.mobile-sidebar.wp-topbar .navbar-collapse{top:46px}.sina-nav.wp-topbar .widget-bar{top:46px}} \ No newline at end of file +.search-box{padding:8px 0;display:none;border-radius:4px;overflow:hidden;background-color:#f6f6f6}.search-box input.form-control{height:44px;border:0;box-shadow:0 0 0;color:#222;background-color:transparent}.search-box .search-input{float:left;width:calc( 100% - 108px )}.search-box .search-addon{padding:10px 20px;float:left;color:#222;background-color:transparent}.search-box .search-addon.close-search{cursor:pointer}.sina-nav-overlay{display:none;position:fixed;top:0;left:0;width:100%;height:100%;z-index:9998;background:rgba(0, 0, 0, 0.5)}.sina-nav{margin-bottom:0;border-radius:0;min-height:60px;z-index:9999;left:0;right:0;background:#fff;border:1px solid #eee;transition:box-shadow, border, background 0.5s ease-in-out}.sina-nav ul,.sina-nav ul ul{padding:0;margin:0;list-style:none}.sina-nav ul li a{display:block;font-family:"Montserrat", sans-serif;text-transform:uppercase;line-height:20px;text-decoration:none;white-space:normal;transition:all 0.3s ease-in-out;background:transparent}.sina-nav .animated{animation-duration:1s;animation-fill-mode:both}.sina-nav .container,.sina-nav .container-fluid{position:relative}.sina-nav .sina-brand{height:60px;max-width:200px;padding:0;margin:0 30px 0 0;float:left;text-decoration:none}.sina-nav .sina-brand>img{height:100%;padding:6px 0}.sina-nav .sina-brand h2{color:#222;font-size:30px;line-height:36px;margin:0;padding:0}.sina-nav .sina-brand p{color:#222;font-size:14px;line-height:16px;margin:0;padding:0}.sina-nav .logo-primary, .sina-nav.navbar-transparent .logo-secondary{display:inline-block}.sina-nav .logo-secondary, .sina-nav.navbar-transparent .logo-primary{display:none}.sina-nav .dropdown-toggle::after{width:inherit;height:inherit;border:0;margin:0}.sina-nav .dropdown{position:relative}.sina-nav .dropdown-menu{position:absolute;display:none;top:100%;left:0;z-index:1000}.sina-nav .open>.dropdown-menu{display:block}.sina-nav .collapse:not(.show){display:none}.sina-nav .collapsing{position:relative;height:0;overflow:hidden;transition:height 0.35s ease}.sina-nav .navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;-webkit-overflow-scrolling:touch}.sina-nav .navbar-collapse.show{overflow-y:auto}.sina-nav .navbar-collapse:before,.sina-nav .navbar-collapse:after{content:" ";display:table}.sina-nav .navbar-collapse:after{clear:both}.sina-nav .sina-menu li a{position:relative;display:block;font-size:14px}.sina-nav .sina-menu li .fa-icon-left{margin-right:8px}.sina-nav .sina-menu li .fa-icon-right{margin-left:8px}.sina-nav .sina-menu>li>a{padding:20px 15px;max-width:160px;color:#222;font-size:14px;font-weight:700;line-height:20px}.sina-nav .sina-menu>li.active>a,.sina-nav .sina-menu>li>a:hover,.sina-nav .sina-menu>li>a:focus{color:#1085e4;background-color:transparent}.sina-nav .sina-menu>li.sina-nav-cta-btn{padding:11px 15px;margin-left:20px}.sina-nav .sina-menu>li.sina-nav-cta-btn a{padding:8px 15px;border:1px solid #1085e4;border-radius:4px;text-align:center;color:#fff;background:#1085e4}.sina-nav .sina-menu>li.sina-nav-cta-btn a:hover, .sina-nav .sina-menu>li.sina-nav-cta-btn a:focus{border-color:#1085e4;color:#1085e4;background:transparent}.sina-nav .sina-menu li .description{font-style:italic;font-size:90%;margin:6px 0 0;font-weight:400}.sina-nav .sina-menu .dropdown-menu{background-color:#fcfcfc;margin:0}.sina-nav .sina-menu .dropdown-menu li a{color:#222;font-size:12px}.sina-nav .sina-menu .dropdown-menu li.active>a,.sina-nav .sina-menu .dropdown-menu li>a:hover,.sina-nav .sina-menu .dropdown-menu li>a:focus{color:#222;background-color:#f6f6f6}.sina-nav .sina-menu .dropdown-toggle:focus{outline:0}.sina-nav .sina-menu .mega-menu-col-title:before,.sina-nav .sina-menu .dropdown .dropdown-toggle:before,.sina-nav .sina-menu .dropdown .dropdown-toggle:after{font-family:'FontAwesome'}.sina-nav.navbar-reverse .search-box .form-control{text-align:right}.sina-nav.navbar-reverse .extension-nav>ul>li.dropdown .dropdown-menu{left:0;margin-left:0}.sina-nav.navbar-reverse.sina-nav-cta-btn{margin-right:20px;margin-left:0}.sina-nav .navbar-collapse{padding:0}.sina-nav .menu-item-has-mega-menu.dropdown{position:static}.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu.dropdown-menu{width:100%;padding:0;background-color:#fcfcfc}.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu-row{width:100%;float:left}.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu-col{list-style:none;color:#222}.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu-col a{color:#222}.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu-col .active>a,.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu-col>a:hover,.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu-col>a:focus{color:#1085e4;background:transparent}.sina-nav .menu-item-has-mega-menu.dropdown .mega-menu-col-title{font-size:15px;line-height:20px;margin:0}.sina-nav.navbar-fixed{position:relative}.sina-nav .extension-nav{float:right;margin-left:20px}.sina-nav .extension-nav>ul{float:left}.sina-nav .extension-nav>ul>li{float:left}.sina-nav .extension-nav>ul>li>a{display:block;padding:20px 12px;position:relative;font-size:18px;color:#222}.sina-nav .extension-nav>ul>li>a:hover, .sina-nav .extension-nav>ul>li>a:focus{color:#1085e4;background-color:transparent}.sina-nav .extension-nav>ul>li>a .shop-badge{position:absolute;top:12px;right:10px;padding:4px 5px;font-size:10px;line-height:10px;border-radius:50%;background-color:#1085e4;color:#fff}.sina-nav .extension-nav>ul>li.dropdown .dropdown-menu{border-radius:0;box-shadow:0 0 0;margin-left:40px;width:232px;left:-232px;background-color:#fcfcfc;border:solid 1px #eee}.sina-nav .extension-nav>ul>li .shop-menu>li{padding:12px 15px;width:100%;overflow:hidden;border-bottom:solid 1px #eee}.sina-nav .extension-nav>ul>li .shop-menu>li:last-child{border-bottom:0}.sina-nav .extension-nav>ul>li .shop-menu>li .shop-item-photo{padding:0;float:left;width:60px;height:60px;margin-right:10px;border:solid 1px #eee}.sina-nav .extension-nav>ul>li .shop-menu>li .shop-item-link,.sina-nav .extension-nav>ul>li .shop-menu>li .shop-item-price{margin:0;padding:0;font-size:14px;line-height:20px;display:inline-block;max-width:130px;color:#222}.sina-nav .extension-nav>ul>li .shop-menu>li .shop-item-link{color:#1085e4;font-size:12px}.sina-nav .extension-nav>ul>li .shop-menu>li .shop-item-link:hover, .sina-nav .extension-nav>ul>li .shop-menu>li .shop-item-link:focus{background-color:transparent}.sina-nav .extension-nav>ul>li .shop-menu>li.shop-total-price .shop-btn{padding:8px 12px;display:inline-block;border-radius:4px;border:1px solid #1085e4;font-size:14px;color:#1085e4;background-color:#fcfcfc}.sina-nav .extension-nav>ul>li .shop-menu>li.shop-total-price .shop-btn:hover, .sina-nav .extension-nav>ul>li .shop-menu>li.shop-total-price .shop-btn:focus{background-color:#1085e4;color:#fcfcfc}.sina-nav .extension-nav>ul>li .shop-menu>li.shop-total-price>span{color:#222;float:right;font-weight:700;margin-top:5px}.sina-nav.navbar-fixed.navbar-freez.wp-topbar, .sina-nav.mobile-sidebar.wp-topbar .navbar-collapse, .sina-nav.wp-topbar .widget-bar{top:32px}.sina-nav .widget-bar{position:fixed;overflow-y:auto;top:0;right:-300px;width:300px;padding:20px;height:100%;z-index:99999;transition:all 0.6s ease;background-color:#333}.sina-nav .widget-bar.on{right:0}.sina-nav .widget-bar .widget{margin-bottom:30px}.sina-nav .widget-bar .widget .link li a{color:#ccc;font-size:14px}.sina-nav .widget-bar .widget .link li a:focus, .sina-nav .widget-bar .widget .link li a:hover{color:#fcfcfc}.sina-nav .widget-bar .widget .title{font-size:20px;margin-bottom:10px;color:#ccc;font-weight:700}.sina-nav .widget-bar .close-widget-bar{float:right;font-size:16px;color:#ccc}.sina-nav.navbar-reverse .widget-bar{right:inherit;left:-300px;text-align:right}.sina-nav.navbar-reverse .widget-bar.on{right:inherit;left:0}.sina-nav.navbar-reverse .widget-bar .close-widget-bar{float:left}@media (min-width:1025px){.sina-nav .navbar-toggle{display:none}.sina-nav .navbar-collapse.collapse{display:block}.sina-nav.navbar-reverse .sina-nav-header{float:right}.sina-nav.navbar-reverse .sina-brand{margin:0 0 0 30px;text-align:right}.sina-nav.navbar-reverse .extension-nav{float:left;margin-right:20px;margin-left:0}.sina-nav.navbar-reverse .extension-nav li{float:right}.sina-nav .sina-menu{float:left}.sina-nav .sina-menu>li{float:left}.sina-nav .sina-menu>.dropdown>.dropdown-toggle{padding-right:20px}.sina-nav .sina-menu>.dropdown>.dropdown-toggle:after{content:"\f107";position:absolute;top:20px;right:5px}.sina-nav .sina-menu .dropdown .dropdown-menu{box-shadow:0 0 0;border-radius:0;width:200px;border:solid 1px #eee}.sina-nav .sina-menu .dropdown .dropdown-menu .dropdown-menu{left:100%;top:0}.sina-nav .sina-menu .dropdown .dropdown-menu .dropdown:first-child>.dropdown-menu{top:-1px}.sina-nav .sina-menu .dropdown .dropdown-menu>li>a{padding:10px 12px;border-top:solid 1px #eee}.sina-nav .sina-menu .dropdown .dropdown-menu>li:first-child>a{border-top:0}.sina-nav .sina-menu .dropdown .dropdown-menu .dropdown>.dropdown-toggle{padding:10px 20px 10px 12px}.sina-nav .sina-menu .dropdown .dropdown-menu .dropdown>.dropdown-toggle:before{float:right;content:"\f105";position:absolute;right:8px}.sina-nav .sina-menu .dropdown .mega-menu.dropdown-menu{max-height:400px;overflow-y:auto}.sina-nav .sina-menu .mega-menu-col{padding:10px 15px;float:left}.sina-nav .sina-menu .mega-menu-col .sub-menu a{padding:6px 10px;display:inline-block}.sina-nav .sina-menu .mega-menu-col .sub-menu a:hover, .sina-nav .sina-menu .mega-menu-col .sub-menu a:focus{color:#1085e4;background:transparent}.sina-nav .sina-menu .mega-menu-col-title{font-weight:700;padding:6px 10px;display:inline-block}.sina-nav .sina-menu .mega-menu-col-content{padding:4px 10px}.sina-nav .sina-menu.sina-menu-dropdown-right{float:right;left:auto;right:0}.sina-nav .sina-menu.sina-menu-dropdown-right .mega-menu.dropdown-menu .mega-menu-col{float:right}.sina-nav .sina-menu.sina-menu-dropdown-right>.dropdown>.dropdown-toggle{padding-left:20px;padding-right:15px}.sina-nav .sina-menu.sina-menu-dropdown-right>.dropdown>.dropdown-toggle:after{left:5px;right:inherit}.sina-nav .sina-menu.sina-menu-dropdown-right .dropdown-menu .dropdown-menu{left:-200px}.sina-nav .sina-menu.sina-menu-dropdown-right .dropdown .dropdown-menu{text-align:right}.sina-nav .sina-menu.sina-menu-dropdown-right .dropdown .dropdown-menu .dropdown>.dropdown-toggle{padding:10px 12px 10px 20px}.sina-nav .sina-menu.sina-menu-dropdown-right .dropdown .dropdown-menu .dropdown>.dropdown-toggle:before{float:left;content:"\f104";left:8px;right:inherit}.sina-nav .sina-menu.sina-menu-right, .sina-nav .sina-menu.sina-menu-list-right>li{float:right}.sina-nav .sina-menu.sina-menu-left{float:left}.sina-nav.navbar-fixed.navbar-freez{position:fixed !important;top:0;box-shadow:0 1px 4px #eee}.sina-nav.navbar-transparent{background-color:transparent;border-color:transparent}.sina-nav.navbar-transparent .sina-brand{color:#dddddd}.sina-nav.navbar-transparent .extension-nav>ul>li>a,.sina-nav.navbar-transparent .sina-menu>li>a{color:#dddddd}.sina-nav.navbar-transparent .extension-nav>ul>li.active>a,.sina-nav.navbar-transparent .extension-nav>ul>li>a:hover,.sina-nav.navbar-transparent .extension-nav>ul>li>a:focus,.sina-nav.navbar-transparent .sina-menu>li.active>a,.sina-nav.navbar-transparent .sina-menu>li>a:hover,.sina-nav.navbar-transparent .sina-menu>li>a:focus{color:#1085e4}.sina-nav.navbar-transparent .sina-menu>li.sina-nav-cta-btn a{border-color:#1085e4;color:#fff;background:#1085e4}.sina-nav.navbar-transparent .sina-menu>li.sina-nav-cta-btn a:hover, .sina-nav.navbar-transparent .sina-menu>li.sina-nav-cta-btn a:focus{border-color:#fff;color:#1085e4;background:#fff}.sina-nav.logo-center .sina-nav-header{width:100%;position:absolute;text-align:center;top:0;left:0}.sina-nav.logo-center .sina-brand{float:none;display:inline-block;margin:0}.sina-nav.logo-center .navbar-collapse{text-align:center}.sina-nav.logo-center .navbar-collapse .col-half{width:50%;float:left;display:block}.sina-nav.logo-center .navbar-collapse .col-half.left{padding-right:120px}.sina-nav.logo-center .navbar-collapse .col-half.right{padding-left:120px}.sina-nav.logo-center .sina-menu{display:inline-block;padding:0}.sina-nav.logo-center .sina-menu>li>.dropdown-menu.mega-menu{margin-top:0}.sina-nav .sina-menu.sina-menu-center{float:none;margin:0 auto;display:table}}@media (max-width:1024px){.sina-nav{background-color:#fff;border-color:#eee}.sina-nav.navbar-fixed.navbar-freez.wp-topbar{top:inherit}.sina-nav .sina-brand{display:inline-block;float:none;text-align:center;margin:0 0 0 -35px;color:#222}.sina-nav .sina-brand h2{margin-top:0}.sina-nav.navbar-reverse .sina-brand, .sina-nav.navbar-reverse .sina-brand{margin:0 -26px 0 15px}.sina-nav .sina-nav-header{float:none;display:block;text-align:center;height:60px}.sina-nav .navbar-toggle{display:inline-block;position:relative;float:left;font-size:18px;margin:12px 0 0 0;padding:4px 10px;width:38px;cursor:pointer;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px;transition:all 0.3s ease-in-out;color:#222}.sina-nav .navbar-toggle:hover, .sina-nav .navbar-toggle:focus{outline:0;color:#222;background-color:#f6f6f6}.sina-nav.navbar-reverse .navbar-toggle{float:right}.sina-nav.navbar-reverse .extension-nav{left:15px;right:inherit;margin-left:0;margin-right:15px}.sina-nav.navbar-reverse .extension-nav li{float:right}.sina-nav.navbar-reverse .sina-menu>li.sina-nav-cta-btn{margin-right:0}.sina-nav .navbar-collapse{overflow-y:auto !important;border:1px solid #eee}.sina-nav .mega-menu-col .mega-menu-col-title,.sina-nav .dropdown .dropdown-toggle{padding:12px 24px 12px 12px}.sina-nav .mega-menu-col .mega-menu-col-title:before,.sina-nav .dropdown .dropdown-toggle:before{float:right;content:"\f105";font-size:16px;position:absolute;right:8px}.sina-nav .mega-menu-col.on .mega-menu-col-title:before,.sina-nav .dropdown.on>.dropdown-toggle:before{content:"\f107"}.sina-nav .sina-menu{float:none !important}.sina-nav .sina-menu .sina-nav-cta-btn{margin-top:20px}.sina-nav .sina-menu li{float:none}.sina-nav .sina-menu li .mega-menu-col-title,.sina-nav .sina-menu li a{max-width:inherit;padding:12px;font-weight:400;display:block;cursor:pointer;font-size:14px;line-height:20px;transition:all 0.3s ease-in-out;color:#222;border-top:solid 1px #eee}.sina-nav .sina-menu li a:hover,.sina-nav .sina-menu li a:focus, .sina-nav .sina-menu li.active>a,.sina-nav .sina-menu li .mega-menu-col-title:hover,.sina-nav .sina-menu li .mega-menu.dropdown-menu .mega-menu-col .active>a,.sina-nav .sina-menu li .dropdown-menu li.active>a,.sina-nav .sina-menu li .dropdown-menu li a:hover,.sina-nav .sina-menu li .dropdown-menu li a:focus,.sina-nav .sina-menu li .mega-menu .mega-menu-col ul li a:hover,.sina-nav .sina-menu li .mega-menu .mega-menu-col ul li a:focus{color:#222;background-color:#f6f6f6}.sina-nav .sina-menu>li:first-child>a{border-top:0}.sina-nav .sina-menu>li.sina-nav-cta-btn{margin-left:0}.sina-nav .sina-menu .dropdown .mega-menu.dropdown-menu,.sina-nav .sina-menu .dropdown .dropdown-menu{float:none;position:relative;left:0;box-shadow:0 0 0;border-radius:0 0 0;border:0;background-color:transparent}.sina-nav .sina-menu .dropdown .mega-menu.dropdown-menu .mega-menu-row{float:none}.sina-nav .sina-menu .dropdown .mega-menu.dropdown-menu .mega-menu-row .mega-menu-col{padding:0}.sina-nav .sina-menu .dropdown .mega-menu.dropdown-menu .mega-menu-row .mega-menu-col-title{font-size:14px}.sina-nav.navbar-transparent{border-color:transparent}.sina-nav.logo-center .sina-menu .dropdown .dropdown-toggle:before{content:"\f105";float:right}.sina-nav.logo-center .sina-menu .dropdown.on>.dropdown-toggle:before{content:"\f107"}.sina-nav.logo-center .col-half:first-child .sina-menu{padding-bottom:0}.sina-nav.logo-center .col-half:first-child .sina-menu>li:first-child>a{border-top:0}.sina-nav.logo-center .col-half:last-child .sina-menu{padding-top:0}.sina-nav.logo-center .col-half:last-child .sina-menu>li:first-child>a{border-top:solid 1px #eee}.sina-nav .extension-nav{position:absolute;right:15px;margin-right:0}.sina-nav .extension-nav>ul>.dropdown>.dropdown-toggle,.sina-nav .extension-nav>ul>li>a{padding:20px 10px;color:#222}.sina-nav .extension-nav>ul>.dropdown>.dropdown-toggle:hover, .sina-nav .extension-nav>ul>.dropdown>.dropdown-toggle:focus,.sina-nav .extension-nav>ul>li>a:hover,.sina-nav .extension-nav>ul>li>a:focus{color:#222}.sina-nav .extension-nav>ul .dropdown>.dropdown-toggle:before{display:none}.sina-nav.mobile-sidebar .navbar-collapse{position:fixed;overflow-x:hidden;display:block;z-index:99;width:300px;height:100% !important;max-height:100%;left:-300px;top:0;padding:0 0 60px;margin:0;transition:all 0.4s ease-in-out;background-color:#fcfcfc}.sina-nav.mobile-sidebar .navbar-collapse.show{left:0}.sina-nav.mobile-sidebar .navbar-collapse .mega-menu-col{width:100%;max-width:100%}.sina-nav.mobile-sidebar .sina-menu{padding:15px;margin:0}.sina-nav.mobile-sidebar.navbar-reverse .navbar-collapse{right:-300px;left:inherit}.sina-nav.mobile-sidebar.navbar-reverse .navbar-collapse.show{right:0;left:inherit}body.mobile-left .sina-nav-wrapper{margin-left:300px;margin-right:-300px}body.mobile-right .sina-nav-wrapper{margin-right:300px;margin-left:-300px}body .sina-nav-wrapper{transition:all 0.4s ease-in-out;position:relative}}@media (max-width:767px){.sina-nav .sina-nav-header,.sina-nav .navbar-collapse{margin:0}.sina-nav .sina-nav-header.social-on{height:120px}.sina-nav .sina-nav-header.social-on .sina-brand{margin-top:60px}}@media (max-width:479px){.sina-nav .widget-bar{right:-250px;width:250px}body.on-side{margin-left:-250px}body.mobile-left .sina-nav-wrapper{margin-left:250px;margin-right:-250px}body.mobile-right .sina-nav-wrapper{margin-right:250px;margin-left:-250px}.sina-nav.mobile-sidebar .navbar-collapse{width:250px;left:-250px}}@media (max-width:782px){.sina-nav.mobile-sidebar.wp-topbar .navbar-collapse{top:46px}.sina-nav.wp-topbar .widget-bar{top:46px}} \ No newline at end of file diff --git a/src/public/themes/blog/assets/css/style.default.css b/src/public/themes/blog/assets/css/style.default.css deleted file mode 100755 index c4a64c641..000000000 --- a/src/public/themes/blog/assets/css/style.default.css +++ /dev/null @@ -1,2577 +0,0 @@ -/* -* ===================== -* GENERAL -* ===================== -*/ -.text-bold { - font-weight: 700; -} - -.text-small { - font-size: 0.9rem; -} - -body { - overflow-x: hidden; -} - -strong { - font-weight: 700; -} - -a, -i, -span { - display: inline-block; - text-decoration: none; - -webkit-transition: all 0.3s; - transition: all 0.3s; -} - -a:hover, a:focus, -i:hover, -i:focus, -span:hover, -span:focus { - text-decoration: none; -} - -a i { - -webkit-transition: none; - transition: none; -} - -ul { - margin: 0; - padding: 0; -} - -section { - padding: 100px 0; - overflow-x: hidden; -} - -button, -input { - outline: none !important; - font-family: "Open Sans", sans-serif; -} - -button { - cursor: pointer; -} - -main, -aside { - padding: 50px 0 100px; -} - -h1 a { - margin-left: 10px; - font-size: 0.9em; - opacity: 0; - -webkit-transition: all 0.3s; - transition: all 0.3s; - color: #555; - text-decoration: none; -} - -h1:hover a { - opacity: 1; -} - -.page-header { - padding-top: 20px; - padding-bottom: 20px; - background: #fafafa; - margin-top: 30px; -} - -.page-header h2 { - margin-bottom: 0; -} - -.animsition { - z-index: 9999; -} - -.widget { - margin-bottom: 40px; - padding: 30px; - border: 1px solid #eee; -} - -.widget header { - margin-bottom: 20px; -} - -.category a { - color: #999; - letter-spacing: 0.08em; - font-weight: 700; - text-transform: uppercase; - text-decoration: none; - font-size: 13px; -} - -.category a::after { - content: ','; - color: #ddd; - display: inline-block; - margin-right: 5px; -} - -.category a:last-of-type::after { - display: none; -} - -.category a:hover { - color: #000; -} - -i[class*="icon-"] { - -webkit-transform: translateY(3px); - transform: translateY(3px); -} - -#style-switch-button { - z-index: 9999 !important; -} - -/*=== Helpers ===*/ -.bg-red { - background: #ff7676 !important; - color: #fff; -} - -.bg-red:hover { - color: #fff; -} - -.bg-blue { - background: #85b4f2 !important; - color: #fff; -} - -.bg-blue:hover { - color: #fff; -} - -.bg-yellow { - background: #ffc107 !important; - color: #fff; -} - -.bg-yellow:hover { - color: #fff; -} - -.bg-green { - background: #54e69d !important; - color: #fff; -} - -.bg-green:hover { - color: #fff; -} - -.bg-orange { - background: #ffc36d !important; - color: #fff; -} - -.bg-orange:hover { - color: #fff; -} - -.bg-violet { - background: #796AEE !important; - color: #fff; -} - -.bg-violet:hover { - color: #fff; -} - -.bg-gray { - background: #ced4da !important; -} - -.bg-white { - background: #fff !important; -} - -.text-red { - color: #ff7676; -} - -.text-red:hover { - color: #ff7676; -} - -.text-yellow { - color: #ffc107; -} - -.text-yellow:hover { - color: #ffc107; -} - -.text-green { - color: #54e69d; -} - -.text-green:hover { - color: #54e69d; -} - -.text-orange { - color: #ffc36d; -} - -.text-orange:hover { - color: #ffc36d; -} - -.text-violet { - color: #796AEE; -} - -.text-violet:hover { - color: #796AEE; -} - -.text-blue { - color: #85b4f2; -} - -.text-blue:hover { - color: #85b4f2; -} - -.text-gray { - color: #999; -} - -.text-gray:hover { - color: #999; -} - -.text-white { - color: #fff; -} - -.no-padding { - padding: 0 !important; -} - -.no-padding-bottom { - padding-bottom: 0 !important; -} - -.no-padding-top { - padding-top: 0 !important; -} - -.no-margin { - margin: 0 !important; -} - -.no-margin-bottom { - margin-bottom: 0 !important; -} - -.no-margin-top { - margin-top: 0 !important; -} - -.padding-small { - padding: 100px 0; -} - -.btn { - border-radius: 0 !important; -} - -.badge { - font-weight: 300; -} - -.badge-rounded { - border-radius: 50px; -} - -.heading-light { - font-weight: 300 !important; -} - -.heading-medium { - font-weight: 400 !important; -} - -.pagination-template li.page-item { - margin: 0 5px; -} - -.pagination-template a.page-link { - width: 40px; - height: 40px; - line-height: 27px; - border-radius: 50% !important; - border: 1px solid #ddd; - color: #555; - text-align: center; -} - -.pagination-template a.page-link:hover, .pagination-template a.page-link.active { - background: #f5f5f5; -} - -.text-primary { - color: #999 !important; -} - -p.text-hero { - font-size: 1.2em; -} - -p.text-hero i { - font-size: 1.2em; -} - -p.small-text-hero { - font-size: 1em; -} - -h1, -h2, -h3, -h4, -h5, -h6 { - margin-bottom: 15px; -} - -.pagination-template li.page-item { - margin: 0 5px; -} - -.pagination-template a.page-link { - width: 40px; - height: 40px; - line-height: 27px; - border-radius: 50% !important; - border: none; - color: #555; - text-align: center; -} - -.pagination-template a.page-link:hover, .pagination-template a.page-link.active { - background: #eee; -} - -.container-fluid { - width: 100%; -} - -.text-big { - font-size: 1.4em; - font-weight: 300; - line-height: 1.8em; - color: #111; -} - -a.hero-link { - color: inherit !important; - text-transform: uppercase; - font-size: 1em; - text-decoration: none !important; - margin-top: 20px; - font-weight: 300; -} - -a.hero-link::after { - content: ''; - width: 100%; - height: 1px; - display: block; - background: #fff; - -webkit-transition: all 0.3s; - transition: all 0.3s; -} - -a.hero-link:hover { - color: #999 !important; -} - -a.hero-link:hover::after { - background: #999; -} - -div[class*="-btn"] { - cursor: pointer; -} - -/* General Media Query ------------------------------------- */ -@media (max-width: 767px) { - nav.navbar .search-btn { - margin-left: 0; - padding-left: 0; - border-left: none; - } -} - -@media (max-width: 575px) { - nav.navbar .container { - width: 100%; - } - .breadcrumb li { - display: block; - width: 100%; - text-align: center; - } -} - -/* -* ========================================================== -* NAVBAR -* ========================================================== -*/ -.navbar { - background: #fff; - padding-top: 20px !important; - padding-bottom: 20px !important; - z-index: 9998; - border-bottom: 1px solid #ddd; -} - -.navbar .langs a:first-of-type, -.navbar .search-btn { - margin-left: 20px; - padding-left: 20px; - border-left: 1px solid #ddd; - height: 20px; - line-height: 20px; -} - -.navbar .search-btn { - color: #333; - font-size: 0.9em; -} - -.navbar .navbar-toggler { - margin-top: 5px; -} - -.navbar .navbar-toggler span { - width: 20px; - height: 2px; - background: #222; - margin-bottom: 4px; - display: block; -} - -.navbar .navbar-toggler span:last-of-type { - margin-bottom: 0; -} - -.navbar .navbar-toggler.active span { - margin: 0; -} - -.navbar .navbar-toggler.active span:first-of-type { - -webkit-transform: rotate(45deg) translate(3px); - transform: rotate(45deg) translate(3px); -} - -.navbar .navbar-toggler.active span:nth-of-type(2) { - opacity: 0; -} - -.navbar .navbar-toggler.active span:last-of-type { - -webkit-transform: rotate(-45deg) translate(3px); - transform: rotate(-45deg) translate(3px); -} - -.navbar .langs a { - font-size: 0.8em; - color: #aaa; - font-weight: 700; -} - -.navbar .langs a.active { - color: #333; -} - -.navbar .langs span { - width: 15px; - height: 1px; - background: #ddd; - margin: 0 5px; -} - -.navbar .search-area { - display: none; - z-index: 9999; -} - -.navbar .search-area-inner { - position: fixed; - top: 0; - right: 0; - width: 100vw; - height: 100vh; - background: rgba(255, 255, 255, 0.99); - padding: 20px !important; -} - -.navbar .search-area-inner .close-btn { - position: absolute; - top: 20px; - right: 20px; -} - -.navbar .search-area-inner .row { - width: 100%; -} - -.navbar .search-area-inner .form-group { - position: relative; -} - -.navbar .search-area-inner .submit { - background: none; - border: none; - position: absolute; - right: 10px; - bottom: 15px; -} - -.navbar .search-area-inner input { - width: 100%; - border: none; - border-bottom: 1px solid #ddd; - background: none; - padding: 10px 0; - font-size: 1.6em; - font-weight: 300; - font-family: "Open Sans", sans-serif; -} - -.navbar .search-area-inner input::-moz-placeholder { - font-family: "Open Sans", sans-serif; - color: #555; - font-weight: 300; - font-size: 1.1em; -} - -.navbar .search-area-inner input::-webkit-input-placeholder { - font-family: "Open Sans", sans-serif; - color: #555; - font-weight: 300; - font-size: 1.1em; -} - -.navbar .search-area-inner input:-ms-input-placeholder { - font-family: "Open Sans", sans-serif; - color: #555; - font-weight: 300; - font-size: 1.1em; -} - -.navbar .navbar-nav a.nav-link { - color: #333; - margin: 0 5px; - font-weight: 400; - font-size: 0.95em; -} - -.navbar .navbar-nav a.nav-link:hover { - color: #999; -} - -.navbar .navbar-nav a.nav-link.active { - color: #999; - font-weight: bold; -} - -/* Navbar Media Query ------------------------------------- */ -@media (max-width: 991px) { - nav.navbar .navbar-header { - width: 100%; - } - nav.navbar::after { - width: 100%; - } - nav.navbar.active::after { - width: calc(100% - 170px); - } - nav.navbar .search-area { - font-size: 0.75em; - } -} - -/* -* ========================================================== -* HERO SECTION -* ========================================================== -*/ -section.hero { - padding: 0; - color: #fff; -} - -section.hero .container { - padding: 200px 20px; - position: relative; -} - -section.hero h1 { - line-height: 1.2em; -} - -section.hero .continue { - position: absolute; - bottom: 30px; - left: 20px; - text-decoration: none !important; - color: inherit !important; - text-transform: uppercase; - font-size: 0.75em; - opacity: 0.8; -} - -section.hero .continue i { - margin-right: 5px; -} - -/* Hero Section Media Query ------------------------------------- */ -@media (max-width: 767px) { - section.hero .container { - padding: 150px 20px; - } -} - -/* -* ========================================================== -* FEATURED POSTS SECTION -* ========================================================== -*/ -section.featured-posts .row:nth-of-type(odd) .text { - background: #fafafa; -} - -section.featured-posts .row:last-of-type { - margin-bottom: 0; -} - -section.featured-posts p { - font-weight: 400; - color: #777; - font-size: 0.95em; -} - -section.featured-posts .text-inner { - padding: 70px 30px; - height: 100%; - -webkit-transition: all 0.3s; - transition: all 0.3s; -} - -section.featured-posts a { - color: inherit; - text-decoration: none; -} - -section.featured-posts h2 { - line-height: 1.1em; - color: #333; - -webkit-transition: all 0.3s; - transition: all 0.3s; -} - -section.featured-posts h2:hover { - color: #555; -} - -section.featured-posts .avatar { - max-width: 40px; - min-width: 40px; - height: 40px; - overflow: hidden; - border-radius: 50%; - margin-right: 10px; -} - -section.featured-posts .title, -section.featured-posts .date, -section.featured-posts .comments { - font-size: 0.8em; - font-weight: 400; - color: #999; -} - -section.featured-posts .title i, -section.featured-posts .date i, -section.featured-posts .comments i { - margin-right: 5px; -} - -section.featured-posts .title::after, -section.featured-posts .date::after, -section.featured-posts .comments::after { - content: '|'; - display: inline-block; - margin: 0 7px; - font-size: 0.9em; - color: #ccc; -} - -section.featured-posts .comments::after { - display: none; -} - -section.featured-posts .image { - max-height: 200px; - width: auto; - overflow: hidden; - padding: 0; -} - -section.featured-posts .image img { - height: 100%; -} - -section.featured-posts .post-header { - margin-bottom: 10px; -} - -section.featured-posts .post-footer { - margin-top: 30px; -} - -/* Featured Posts Section Media Query ------------------------------------- */ -@media (max-width: 991px) { - section.featured-posts .image { - -webkit-box-ordinal-group: 2; - -ms-flex-order: 1; - order: 1; - max-height: 300px; - min-height: auto !important; - } - section.featured-posts .image img { - width: 100%; - height: auto !important; - } - section.featured-posts .text { - -webkit-box-ordinal-group: 3; - -ms-flex-order: 2; - order: 2; - } -} - -@media (max-width: 575px) { - section.featured-posts .post-footer { - font-size: 0.9em; - } -} - -@media (max-width: 350px) { - section.featured-posts .text-inner { - padding: 15px; - } - section.featured-posts .post-footer { - font-size: 0.75em; - } -} - -/* -* ========================================================== -* DIVIDER SECTION -* ========================================================== -*/ -section.divider { - color: #fff; -} - -/* -* ========================================================== -* LATEST SECTION -* ========================================================== -*/ -section.latest-posts header { - margin-bottom: 50px; -} - -.post-meta { - margin: 10px 0; - font-size: 0.8em; -} - -.post-meta .date { - text-transform: uppercase; - font-weight: 400; -} - -.post-meta .date::after { - display: none; -} - -.post p:not(.lead) { - font-weight: 400; - color: #777; - font-size: 0.95em; -} - -.post a { - text-decoration: none; -} - -.post a:hover, .post a:focus { - text-decoration: none; -} - -.post h3 { - line-height: 1.1em; - color: #222; - -webkit-transition: all 0.3s; - transition: all 0.3s; - margin-bottom: 1rem; -} - -.post h3:hover { - color: #555; -} - -.post .category a { - color: #999; - letter-spacing: 0.05em; - font-weight: 700; - text-transform: uppercase; - text-decoration: none; -} - -.post .date { - letter-spacing: 0.05em; - font-weight: 400; - text-transform: uppercase; - color: #aaa; -} - -.post .avatar { - max-width: 40px; - min-width: 40px; - height: 40px; - overflow: hidden; - border-radius: 50%; - margin-right: 10px; -} - -.post .title, -.post .date, -.post .comments, -.post .views { - font-weight: 400; - color: #999; - text-transform: capitalize; -} - -.post .title i, -.post .date i, -.post .comments i, -.post .views i { - margin-right: 5px; - font-size: 1.1em; -} - -.post .title::after, -.post .date::after, -.post .comments::after, -.post .views::after { - content: '|'; - display: inline-block; - margin: 0 7px; - font-size: 0.9em; - color: #ccc; -} - -.post .post-tags { - margin-top: 30px; -} - -.post .post-tags .tag { - padding: 5px 25px; - border: 1px solid #ddd; - margin: 5px; - color: #777; - font-size: 0.75em; - text-transform: uppercase; - font-weight: 600; - text-decoration: none; - border-radius: 50px; -} - -.post .post-tags .tag:hover { - background: #999; - color: #fff; - border-color: #999; -} - -.post .meta-last::after { - display: none; -} - -/* Latest Posts Section Media Query ------------------------------------- */ -@media (max-width: 767px) { - .post { - margin-bottom: 40px; - } - .post:last-of-type { - margin-bottom: 0; - } -} - -/* -* ========================================================== -* NEWSLETTER SECTION -* ========================================================== -*/ -section.newsletter .form-group { - position: relative; -} - -section.newsletter input { - width: 100%; - height: 60px; - line-height: 60px; - padding: 0 15px; - border: 1px solid #111; - font-size: 1.1em; - font-family: "Open Sans", sans-serif; - font-weight: 300; -} - -section.newsletter .submit { - height: 60px; - padding: 0 30px; - line-height: 60px; - background: #111; - border: 1px solid #111; - color: #fff; - position: absolute; - top: 0; - right: 0; - font-family: "Open Sans", sans-serif; -} - -/* Newsletter Section Media Query ------------------------------------- */ -@media (max-width: 575px) { - section.newsletter input { - font-size: 0.95em; - width: 100%; - } - section.newsletter .submit { - position: static; - width: 100%; - margin-top: 10px; - } -} - -/* -* ========================================================== -* GALLERY SECTION -* ========================================================== -*/ -section.gallery .mix { - padding: 0; - max-height: 200px; - overflow: hidden; -} - -section.gallery a { - outline: none; - width: 100%; - height: 100%; -} - -section.gallery a img { - min-height: 100%; - width: 100%; -} - -section.gallery .item { - position: relative; - width: 100%; - height: 100%; -} - -section.gallery .item:hover .overlay { - opacity: 1; -} - -section.gallery .item:hover i { - opacity: 1; - -webkit-transform: none; - transform: none; -} - -section.gallery .overlay { - position: absolute; - top: 0; - right: 0; - width: 100%; - height: 100%; - background: rgba(153, 153, 153, 0.7); - color: #fff; - opacity: 0; - -webkit-transition: all 0.5s; - transition: all 0.5s; -} - -section.gallery .overlay i { - -webkit-transform: translateY(20px); - transform: translateY(20px); - -webkit-transition: all 0.5s; - transition: all 0.5s; - opacity: 0; - font-size: 2em; -} - -/* -* ========================================================== -* FOOTER -* ========================================================== -*/ -footer.main-footer { - background: #0e0e0e; - padding: 100px 0 0; - color: #fff; -} - -footer.main-footer .contact-details p { - font-weight: 300; - color: #fff; - margin-bottom: 5px; - font-size: 0.95em; -} - -footer.main-footer .contact-details a { - text-decoration: underline; - margin-bottom: 0; -} - -footer.main-footer a { - color: inherit; - font-weight: 300; - margin-bottom: 7px; -} - -footer.main-footer a:hover, footer.main-footer a:focus { - color: #999; -} - -footer.main-footer ul { - margin-right: 30px; -} - -footer.main-footer .list-unstyled a { - font-size: 0.95em; -} - -footer.main-footer .latest-posts .image { - max-width: 50px; - padding: 4px; - border: 2px solid #333; - margin-right: 10px; -} - -footer.main-footer .latest-posts a { - font-size: 0.95em; - text-decoration: none; -} - -footer.main-footer .latest-posts a:hover { - color: #fff; -} - -footer.main-footer .latest-posts strong { - display: block; -} - -footer.main-footer .latest-posts .date { - font-size: 0.85em; - color: #aaa; -} - -footer.main-footer .copyrights { - background: #090909; - margin-top: 100px; - padding: 20px 0; - font-size: 0.9em; -} - -footer.main-footer .copyrights * { - margin-bottom: 0; -} - -footer.main-footer .social-menu { - margin-top: 20px; -} - -footer.main-footer .social-menu li { - padding: 0 5px; -} - -footer.main-footer .date::after, -footer.main-footer .title::after { - display: none !important; -} - -/* Footer Media Query ------------------------------------- */ -@media (max-width: 767px) { - footer.main-footer div[class*="col-"] { - margin-bottom: 40px; - } - footer.main-footer div[class*="col-"]:last-of-type { - margin-bottom: 0; - } - footer.main-footer .latest-posts > a { - width: 100%; - margin-bottom: 20px; - } - footer.main-footer .copyrights div[class*="col-"] { - margin-bottom: 20px; - text-align: center !important; - } - footer.main-footer .copyrights div[class*="col-"]:last-of-type { - margin-bottom: 0; - } -} - -main.posts-listing { - padding-top: 50px; - padding-left: 0; - padding-right: 0; -} - -main.posts-listing .post { - margin-bottom: 50px; -} - -main.posts-listing .post-footer { - font-size: 0.8em; -} - -.widget.search .form-group { - position: relative; -} - -.widget.search input { - width: 100%; - height: 40px; - line-height: 40px; - border: none; - border-bottom: 1px solid #ddd; - font-size: 0.95em; - font-family: "Open Sans", sans-serif; - font-weight: 400; - background: none; -} - -.widget.search input::-moz-placeholder { - color: #aaa; - font-family: "Open Sans", sans-serif; -} - -.widget.search input::-webkit-input-placeholder { - color: #aaa; - font-family: "Open Sans", sans-serif; -} - -.widget.search input:-ms-input-placeholder { - color: #aaa; - font-family: "Open Sans", sans-serif; -} - -.widget.search .submit { - height: 40px; - padding: 0; - line-height: 40px; - background: none; - border: none; - color: #555; - font-size: 0.9em; - position: absolute; - top: 0; - right: 0; -} - -.widget.latest-posts a { - display: block; - color: #555; - text-decoration: none; -} - -.widget.latest-posts a:hover { - color: #000; -} - -.widget.latest-posts .image { - min-width: 60px; - max-width: 60px; - height: 60px; - overflow: hidden; - margin-right: 20px; -} - -.widget.latest-posts .item { - margin-bottom: 20px; -} - -.widget.latest-posts strong { - font-size: 0.95em; - display: block; - line-height: 1em; -} - -.widget.latest-posts .views, -.widget.latest-posts .comments { - font-size: 0.8em; - font-weight: 400; - color: #bbb; - margin-top: 10px; -} - -.widget.latest-posts .views i, -.widget.latest-posts .comments i { - margin-right: 5px; -} - -.widget.latest-posts .views::after, -.widget.latest-posts .comments::after { - content: '|'; - display: inline-block; - margin: 0 7px; - font-size: 0.9em; - color: #ccc; -} - -.widget.latest-posts .comments::after { - display: none; -} - -.widget.categories .item { - background: #fafafa; - padding: 10px; - color: #777; - font-weight: 700; -} - -.widget.categories .item:nth-of-type(2n+2) { - background: none; -} - -.widget.categories .item a { - color: inherit; - font-size: 0.95em; -} - -.widget.categories .item a:hover { - color: #000; - text-decoration: none; -} - -.widget.categories .item span { - font-size: 0.9em; - color: #aaa; -} - -.widget.tags .tag { - padding: 5px 25px; - border: 1px solid #ddd; - margin: 5px 0; - color: #777; - font-size: 0.75em; - text-transform: uppercase; - font-weight: 600; - text-decoration: none; - border-radius: 50px; -} - -.widget.tags .tag:hover { - background: #999; - color: #fff; - border-color: #999; -} - -.blog-post { - padding-left: 0; - padding-right: 0; -} - -.blog-post .post-footer { - font-size: 0.8em; -} - -.blog-post .post-thumbnail img { - width: 100%; - margin-bottom: 10px; -} - -.blog-post h1 { - color: #444; - line-height: 1.1em; -} - -.blog-post h1:hover { - color: #444; -} - -.blog-post .post-footer { - margin-top: 20px; -} - -.blog-post .post-body { - margin-top: 40px; -} - -.blog-post .post-body h2, -.blog-post .post-body h3, -.blog-post .post-body h4, -.blog-post .post-body h5, -.blog-post .post-body h6 { - color: #333; -} - -.blog-post .post-body p { - margin-bottom: 30px; -} - -.blog-post .post-body p:not(.lead) { - font-size: 1em; - line-height: 1.7em; - color: #555; -} - -.blog-post .posts-nav { - margin-top: 50px; - color: #777; - font-size: 0.8em; -} - -.blog-post .posts-nav a { - color: inherit; - width: calc(50% - 10px); - padding: 10px 20px; - border: 1px solid #eee; - margin-bottom: 15px; -} - -.blog-post .posts-nav a:hover { - border-color: #999; -} - -.blog-post .posts-nav a:hover .icon { - background: #999; - color: #fff; - border-color: #999; -} - -.blog-post .icon { - min-width: 35px; - max-width: 35px; - height: 35px; - border-radius: 50%; - line-height: 32px; - border: 1px solid #ddd; - color: #aaa; - font-size: 1.5em; - text-align: center; - -webkit-transition: all 0.2s; - transition: all 0.2s; -} - -.blog-post .icon.prev { - margin-right: 20px; -} - -.blog-post .icon.next { - margin-left: 20px; -} - -.blog-post .post-comments { - margin-top: 50px; -} - -.blog-post .post-comments span.no-of-comments { - color: #777; - font-size: 0.8em; - margin-left: 5px; - font-weight: 400; -} - -.blog-post .post-comments header { - margin-bottom: 40px; -} - -.blog-post .post-comments .comment:last-of-type .comment-body { - border-bottom: none; -} - -.blog-post .post-comments .image { - margin-right: 15px; -} - -.blog-post .post-comments .title::after { - display: none; -} - -.blog-post .post-comments img { - max-width: 40px; - min-width: 40px; - height: 40px; -} - -.blog-post .post-comments strong { - display: block; - color: #555; -} - -.blog-post .post-comments span.date { - font-size: 0.8em; - color: #999; -} - -.blog-post .post-comments span.date::after { - display: none; -} - -.blog-post .post-comments .comment-body { - margin-left: 55px; - margin-top: 10px; - margin-bottom: 25px; - padding-bottom: 15px; - border-bottom: 1px solid #eee; -} - -.blog-post .post-comments p { - font-size: 0.95em; - color: #555; -} - -.blog-post .add-comment { - margin-top: 50px; -} - -.blog-post .add-comment header { - margin-bottom: 30px; -} - -.blog-post .add-comment input, -.blog-post .add-comment textarea { - background: none; - border: none; - border-bottom: 1px solid #ddd; - padding: 10px 0; - border-radius: 0; - font-family: "Open Sans", sans-serif; -} - -.blog-post .add-comment input::-moz-placeholder, -.blog-post .add-comment textarea::-moz-placeholder { - font-weight: 400; - font-size: 0.9em; - color: #aaa; - font-weight: 400; - font-family: "Open Sans", sans-serif; -} - -.blog-post .add-comment input::-webkit-input-placeholder, -.blog-post .add-comment textarea::-webkit-input-placeholder { - font-weight: 400; - font-size: 0.9em; - color: #aaa; - font-weight: 400; - font-family: "Open Sans", sans-serif; -} - -.blog-post .add-comment input:-ms-input-placeholder, -.blog-post .add-comment textarea:-ms-input-placeholder { - font-weight: 400; - font-size: 0.9em; - color: #aaa; - font-weight: 400; - font-family: "Open Sans", sans-serif; -} - -.blog-post .add-comment input:focus, -.blog-post .add-comment textarea:focus { - -webkit-box-shadow: none; - box-shadow: none; - border-bottom: 1px solid #999; -} - -.blog-post .add-comment textarea { - min-height: 150px; -} - -blockquote.blockquote { - font-size: 1.05em; - line-height: 1.7em; - border-color: #999; - border: 1px solid #eee; - border-left: 6px solid #eee; - padding: 20px; - border-top-right-radius: 5px; - border-bottom-right-radius: 5px; - margin-bottom: 30px; -} - -blockquote.blockquote p { - margin-bottom: 15px !important; -} - -@media (max-width: 767px) { - .posts-nav a { - width: 100% !important; - } -} - -@media (max-width: 575px) { - .blog-post .title::after { - display: none !important; - } - .blog-post .author { - margin-bottom: 10px; - } -} - -/* - -===================== -STYLE SWITCHER FOR DEMO -===================== - -*/ -#style-switch-button { - position: fixed; - top: 120px; - left: 0px; - border-radius: 0; - z-index: 100000; -} - -#style-switch { - width: 300px; - padding: 20px; - position: fixed; - top: 160px; - left: 0; - background: #fff; - border: solid 1px #ced4da; - z-index: 100000; -} - -#style-switch h4 { - color: #495057; -} - -#style-switch .text-small { - font-size: .8em; -} - -#style-switch select { - font-size: 0.85em; -} - -/* ========================================= - THEMING OF BOOTSTRAP COMPONENTS - ========================================= */ -/* - * 1. NAVBAR - */ -.navbar { - padding: 0.5rem 1rem; -} - -.navbar-brand { - display: inline-block; - padding-top: 0.5rem; - padding-bottom: 0.5rem; - margin-right: 1rem; - font-size: 1rem; - color: #333; - font-weight: bold; -} - -.navbar-toggler { - padding: 0.25rem 0.75rem; - font-size: 1.25rem; - line-height: 1; - border: 1px solid transparent; - border-radius: 0.25rem; -} - -.navbar-light .navbar-brand { - color: rgba(0, 0, 0, 0.9); -} - -.navbar-light .navbar-brand:focus, .navbar-light .navbar-brand:hover { - color: rgba(0, 0, 0, 0.9); -} - -.navbar-light .navbar-nav .nav-link { - color: rgba(0, 0, 0, 0.5); -} - -.navbar-light .navbar-nav .nav-link:focus, .navbar-light .navbar-nav .nav-link:hover { - color: rgba(0, 0, 0, 0.7); -} - -.navbar-light .navbar-nav .nav-link.disabled { - color: rgba(0, 0, 0, 0.3); -} - -.navbar-light .navbar-nav .show > .nav-link, -.navbar-light .navbar-nav .active > .nav-link, -.navbar-light .navbar-nav .nav-link.show, -.navbar-light .navbar-nav .nav-link.active { - color: rgba(0, 0, 0, 0.9); -} - -.navbar-light .navbar-toggler { - color: rgba(0, 0, 0, 0.5); - border-color: rgba(0, 0, 0, 0.1); -} - -.navbar-light .navbar-toggler-icon { - background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"); -} - -.navbar-light .navbar-text { - color: rgba(0, 0, 0, 0.5); -} - -.navbar-dark .navbar-brand { - color: white; -} - -.navbar-dark .navbar-brand:focus, .navbar-dark .navbar-brand:hover { - color: white; -} - -.navbar-dark .navbar-nav .nav-link { - color: rgba(255, 255, 255, 0.5); -} - -.navbar-dark .navbar-nav .nav-link:focus, .navbar-dark .navbar-nav .nav-link:hover { - color: rgba(255, 255, 255, 0.75); -} - -.navbar-dark .navbar-nav .nav-link.disabled { - color: rgba(255, 255, 255, 0.25); -} - -.navbar-dark .navbar-nav .show > .nav-link, -.navbar-dark .navbar-nav .active > .nav-link, -.navbar-dark .navbar-nav .nav-link.show, -.navbar-dark .navbar-nav .nav-link.active { - color: white; -} - -.navbar-dark .navbar-toggler { - color: rgba(255, 255, 255, 0.5); - border-color: rgba(255, 255, 255, 0.1); -} - -.navbar-dark .navbar-toggler-icon { - background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"); -} - -.navbar-dark .navbar-text { - color: rgba(255, 255, 255, 0.5); -} - -/* - * 2. BUTTONS - */ -.btn { - font-weight: normal; - border: 1px solid transparent; - padding: 0.5rem 1rem; - font-size: 1rem; - line-height: 1.25; - border-radius: 0.25rem; - -webkit-transition: all 0.15s ease-in-out; - transition: all 0.15s ease-in-out; -} - -.btn:focus, .btn.focus { - outline: 0; - -webkit-box-shadow: 0 0 0 3px rgba(153, 153, 153, 0.25); - box-shadow: 0 0 0 3px rgba(153, 153, 153, 0.25); -} - -.btn:active, .btn.active { - background-image: none; -} - -.btn-primary { - color: #111; - background-color: #999; - border-color: #999; -} - -.btn-primary:hover { - color: #111; - background-color: #868686; - border-color: gray; -} - -.btn-primary:focus, .btn-primary.focus { - -webkit-box-shadow: 0 0 0 3px rgba(153, 153, 153, 0.5); - box-shadow: 0 0 0 3px rgba(153, 153, 153, 0.5); -} - -.btn-primary.disabled, .btn-primary:disabled { - background-color: #999; - border-color: #999; -} - -.btn-primary:active, .btn-primary.active, -.show > .btn-primary.dropdown-toggle { - background-color: #868686; - background-image: none; - border-color: gray; -} - -.btn-secondary { - color: #fff; - background-color: #868e96; - border-color: #868e96; -} - -.btn-secondary:hover { - color: #fff; - background-color: #727b84; - border-color: #6c757d; -} - -.btn-secondary:focus, .btn-secondary.focus { - -webkit-box-shadow: 0 0 0 3px rgba(134, 142, 150, 0.5); - box-shadow: 0 0 0 3px rgba(134, 142, 150, 0.5); -} - -.btn-secondary.disabled, .btn-secondary:disabled { - background-color: #868e96; - border-color: #868e96; -} - -.btn-secondary:active, .btn-secondary.active, -.show > .btn-secondary.dropdown-toggle { - background-color: #727b84; - background-image: none; - border-color: #6c757d; -} - -.btn-success { - color: #fff; - background-color: #28a745; - border-color: #28a745; -} - -.btn-success:hover { - color: #fff; - background-color: #218838; - border-color: #1e7e34; -} - -.btn-success:focus, .btn-success.focus { - -webkit-box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.5); - box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.5); -} - -.btn-success.disabled, .btn-success:disabled { - background-color: #28a745; - border-color: #28a745; -} - -.btn-success:active, .btn-success.active, -.show > .btn-success.dropdown-toggle { - background-color: #218838; - background-image: none; - border-color: #1e7e34; -} - -.btn-info { - color: #fff; - background-color: #17a2b8; - border-color: #17a2b8; -} - -.btn-info:hover { - color: #fff; - background-color: #138496; - border-color: #117a8b; -} - -.btn-info:focus, .btn-info.focus { - -webkit-box-shadow: 0 0 0 3px rgba(23, 162, 184, 0.5); - box-shadow: 0 0 0 3px rgba(23, 162, 184, 0.5); -} - -.btn-info.disabled, .btn-info:disabled { - background-color: #17a2b8; - border-color: #17a2b8; -} - -.btn-info:active, .btn-info.active, -.show > .btn-info.dropdown-toggle { - background-color: #138496; - background-image: none; - border-color: #117a8b; -} - -.btn-warning { - color: #111; - background-color: #ffc107; - border-color: #ffc107; -} - -.btn-warning:hover { - color: #111; - background-color: #e0a800; - border-color: #d39e00; -} - -.btn-warning:focus, .btn-warning.focus { - -webkit-box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.5); - box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.5); -} - -.btn-warning.disabled, .btn-warning:disabled { - background-color: #ffc107; - border-color: #ffc107; -} - -.btn-warning:active, .btn-warning.active, -.show > .btn-warning.dropdown-toggle { - background-color: #e0a800; - background-image: none; - border-color: #d39e00; -} - -.btn-danger { - color: #fff; - background-color: #dc3545; - border-color: #dc3545; -} - -.btn-danger:hover { - color: #fff; - background-color: #c82333; - border-color: #bd2130; -} - -.btn-danger:focus, .btn-danger.focus { - -webkit-box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.5); - box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.5); -} - -.btn-danger.disabled, .btn-danger:disabled { - background-color: #dc3545; - border-color: #dc3545; -} - -.btn-danger:active, .btn-danger.active, -.show > .btn-danger.dropdown-toggle { - background-color: #c82333; - background-image: none; - border-color: #bd2130; -} - -.btn-light { - color: #111; - background-color: #f8f9fa; - border-color: #f8f9fa; -} - -.btn-light:hover { - color: #111; - background-color: #e2e6ea; - border-color: #dae0e5; -} - -.btn-light:focus, .btn-light.focus { - -webkit-box-shadow: 0 0 0 3px rgba(248, 249, 250, 0.5); - box-shadow: 0 0 0 3px rgba(248, 249, 250, 0.5); -} - -.btn-light.disabled, .btn-light:disabled { - background-color: #f8f9fa; - border-color: #f8f9fa; -} - -.btn-light:active, .btn-light.active, -.show > .btn-light.dropdown-toggle { - background-color: #e2e6ea; - background-image: none; - border-color: #dae0e5; -} - -.btn-dark { - color: #fff; - background-color: #343a40; - border-color: #343a40; -} - -.btn-dark:hover { - color: #fff; - background-color: #23272b; - border-color: #1d2124; -} - -.btn-dark:focus, .btn-dark.focus { - -webkit-box-shadow: 0 0 0 3px rgba(52, 58, 64, 0.5); - box-shadow: 0 0 0 3px rgba(52, 58, 64, 0.5); -} - -.btn-dark.disabled, .btn-dark:disabled { - background-color: #343a40; - border-color: #343a40; -} - -.btn-dark:active, .btn-dark.active, -.show > .btn-dark.dropdown-toggle { - background-color: #23272b; - background-image: none; - border-color: #1d2124; -} - -.btn-outline-primary { - color: #999; - background-color: transparent; - background-image: none; - border-color: #999; -} - -.btn-outline-primary:hover { - color: #fff; - background-color: #999; - border-color: #999; -} - -.btn-outline-primary:focus, .btn-outline-primary.focus { - -webkit-box-shadow: 0 0 0 3px rgba(153, 153, 153, 0.5); - box-shadow: 0 0 0 3px rgba(153, 153, 153, 0.5); -} - -.btn-outline-primary.disabled, .btn-outline-primary:disabled { - color: #999; - background-color: transparent; -} - -.btn-outline-primary:active, .btn-outline-primary.active, -.show > .btn-outline-primary.dropdown-toggle { - color: #fff; - background-color: #999; - border-color: #999; -} - -.btn-outline-secondary { - color: #868e96; - background-color: transparent; - background-image: none; - border-color: #868e96; -} - -.btn-outline-secondary:hover { - color: #fff; - background-color: #868e96; - border-color: #868e96; -} - -.btn-outline-secondary:focus, .btn-outline-secondary.focus { - -webkit-box-shadow: 0 0 0 3px rgba(134, 142, 150, 0.5); - box-shadow: 0 0 0 3px rgba(134, 142, 150, 0.5); -} - -.btn-outline-secondary.disabled, .btn-outline-secondary:disabled { - color: #868e96; - background-color: transparent; -} - -.btn-outline-secondary:active, .btn-outline-secondary.active, -.show > .btn-outline-secondary.dropdown-toggle { - color: #fff; - background-color: #868e96; - border-color: #868e96; -} - -.btn-outline-success { - color: #28a745; - background-color: transparent; - background-image: none; - border-color: #28a745; -} - -.btn-outline-success:hover { - color: #fff; - background-color: #28a745; - border-color: #28a745; -} - -.btn-outline-success:focus, .btn-outline-success.focus { - -webkit-box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.5); - box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.5); -} - -.btn-outline-success.disabled, .btn-outline-success:disabled { - color: #28a745; - background-color: transparent; -} - -.btn-outline-success:active, .btn-outline-success.active, -.show > .btn-outline-success.dropdown-toggle { - color: #fff; - background-color: #28a745; - border-color: #28a745; -} - -.btn-outline-info { - color: #17a2b8; - background-color: transparent; - background-image: none; - border-color: #17a2b8; -} - -.btn-outline-info:hover { - color: #fff; - background-color: #17a2b8; - border-color: #17a2b8; -} - -.btn-outline-info:focus, .btn-outline-info.focus { - -webkit-box-shadow: 0 0 0 3px rgba(23, 162, 184, 0.5); - box-shadow: 0 0 0 3px rgba(23, 162, 184, 0.5); -} - -.btn-outline-info.disabled, .btn-outline-info:disabled { - color: #17a2b8; - background-color: transparent; -} - -.btn-outline-info:active, .btn-outline-info.active, -.show > .btn-outline-info.dropdown-toggle { - color: #fff; - background-color: #17a2b8; - border-color: #17a2b8; -} - -.btn-outline-warning { - color: #ffc107; - background-color: transparent; - background-image: none; - border-color: #ffc107; -} - -.btn-outline-warning:hover { - color: #fff; - background-color: #ffc107; - border-color: #ffc107; -} - -.btn-outline-warning:focus, .btn-outline-warning.focus { - -webkit-box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.5); - box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.5); -} - -.btn-outline-warning.disabled, .btn-outline-warning:disabled { - color: #ffc107; - background-color: transparent; -} - -.btn-outline-warning:active, .btn-outline-warning.active, -.show > .btn-outline-warning.dropdown-toggle { - color: #fff; - background-color: #ffc107; - border-color: #ffc107; -} - -.btn-outline-danger { - color: #dc3545; - background-color: transparent; - background-image: none; - border-color: #dc3545; -} - -.btn-outline-danger:hover { - color: #fff; - background-color: #dc3545; - border-color: #dc3545; -} - -.btn-outline-danger:focus, .btn-outline-danger.focus { - -webkit-box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.5); - box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.5); -} - -.btn-outline-danger.disabled, .btn-outline-danger:disabled { - color: #dc3545; - background-color: transparent; -} - -.btn-outline-danger:active, .btn-outline-danger.active, -.show > .btn-outline-danger.dropdown-toggle { - color: #fff; - background-color: #dc3545; - border-color: #dc3545; -} - -.btn-outline-light { - color: #f8f9fa; - background-color: transparent; - background-image: none; - border-color: #f8f9fa; -} - -.btn-outline-light:hover { - color: #fff; - background-color: #f8f9fa; - border-color: #f8f9fa; -} - -.btn-outline-light:focus, .btn-outline-light.focus { - -webkit-box-shadow: 0 0 0 3px rgba(248, 249, 250, 0.5); - box-shadow: 0 0 0 3px rgba(248, 249, 250, 0.5); -} - -.btn-outline-light.disabled, .btn-outline-light:disabled { - color: #f8f9fa; - background-color: transparent; -} - -.btn-outline-light:active, .btn-outline-light.active, -.show > .btn-outline-light.dropdown-toggle { - color: #fff; - background-color: #f8f9fa; - border-color: #f8f9fa; -} - -.btn-outline-dark { - color: #343a40; - background-color: transparent; - background-image: none; - border-color: #343a40; -} - -.btn-outline-dark:hover { - color: #fff; - background-color: #343a40; - border-color: #343a40; -} - -.btn-outline-dark:focus, .btn-outline-dark.focus { - -webkit-box-shadow: 0 0 0 3px rgba(52, 58, 64, 0.5); - box-shadow: 0 0 0 3px rgba(52, 58, 64, 0.5); -} - -.btn-outline-dark.disabled, .btn-outline-dark:disabled { - color: #343a40; - background-color: transparent; -} - -.btn-outline-dark:active, .btn-outline-dark.active, -.show > .btn-outline-dark.dropdown-toggle { - color: #fff; - background-color: #343a40; - border-color: #343a40; -} - -.btn-lg { - padding: 0.5rem 1rem; - font-size: 1.25rem; - line-height: 1.5; - border-radius: 0.3rem; -} - -.btn-sm { - padding: 0.25rem 0.5rem; - font-size: 0.875rem; - line-height: 1.5; - border-radius: 0.2rem; -} - -/* - * 3. TYPE - */ -body { - font-family: "Open Sans", sans-serif; - font-size: 1rem; - font-weight: normal; - line-height: 1.5; - color: #212529; - background-color: #fff; -} - -a { - color: #999; - text-decoration: none; -} - -a:focus, a:hover { - color: #737373; - text-decoration: underline; -} - -h1, -h2, -h3, -h4, -h5, -h6, -.h1, -.h2, -.h3, -.h4, -.h5, -.h6 { - margin-bottom: 0.5rem; - font-family: inherit; - font-weight: 700; - line-height: 1.1; - color: inherit; -} - -h1, -.h1 { - font-size: 2.5rem; -} - -h2, -.h2 { - font-size: 2rem; -} - -h3, -.h3 { - font-size: 1.75rem; -} - -h4, -.h4 { - font-size: 1.5rem; -} - -h5, -.h5 { - font-size: 1.25rem; -} - -h6, -.h6 { - font-size: 1rem; -} - -.lead { - font-size: 1.3rem; - font-weight: 300; -} - -.display-1 { - font-size: 6rem; - font-weight: 300; - line-height: 1.1; -} - -.display-2 { - font-size: 5.5rem; - font-weight: 300; - line-height: 1.1; -} - -.display-3 { - font-size: 4.5rem; - font-weight: 300; - line-height: 1.1; -} - -.display-4 { - font-size: 3.5rem; - font-weight: 300; - line-height: 1.1; -} - -hr { - border-top: 1px solid rgba(0, 0, 0, 0.1); -} - -small, -.small { - font-size: 80%; - font-weight: normal; -} - -mark, -.mark { - padding: 0.2em; - background-color: #fcf8e3; -} - -.blockquote { - padding: 0.5rem 1rem; - margin-bottom: 1rem; - font-size: 1.25rem; - border-left: 5px solid #999; -} - -.blockquote-footer { - color: #868e96; -} - -.blockquote-footer::before { - content: "\2014 \00A0"; -} - -.text-primary { - color: #999 !important; -} - -a.text-primary:focus, a.text-primary:hover { - color: gray !important; -} - -/* - * 4. PAGINATION - */ -.page-item:first-child .page-link { - border-top-left-radius: 0.25rem; - border-bottom-left-radius: 0.25rem; -} - -.page-item:last-child .page-link { - border-top-right-radius: 0.25rem; - border-bottom-right-radius: 0.25rem; -} - -.page-item.active .page-link { - color: #fff; - background-color: #999; - border-color: #999; -} - -.page-item.disabled .page-link { - color: #868e96; - background-color: #fff; - border-color: #ddd; -} - -.page-link { - padding: 0.5rem 0.75rem; - line-height: 1.25; - color: #999; - background-color: #fff; - border: 1px solid #ddd; -} - -.page-link:focus, .page-link:hover { - color: #737373; - text-decoration: none; - background-color: #e9ecef; - border-color: #ddd; -} - -.pagination-lg .page-link { - padding: 0.75rem 1.5rem; - font-size: 1.25rem; - line-height: 1.5; -} - -.pagination-lg .page-item:first-child .page-link { - border-top-left-radius: 0.3rem; - border-bottom-left-radius: 0.3rem; -} - -.pagination-lg .page-item:last-child .page-link { - border-top-right-radius: 0.3rem; - border-bottom-right-radius: 0.3rem; -} - -.pagination-sm .page-link { - padding: 0.25rem 0.5rem; - font-size: 0.875rem; - line-height: 1.5; -} - -.pagination-sm .page-item:first-child .page-link { - border-top-left-radius: 0.2rem; - border-bottom-left-radius: 0.2rem; -} - -.pagination-sm .page-item:last-child .page-link { - border-top-right-radius: 0.2rem; - border-bottom-right-radius: 0.2rem; -} - -/* -* 5. UTILITIES -*/ -.bg-primary { - background-color: #999 !important; -} - -a.bg-primary:focus, a.bg-primary:hover { - background-color: gray !important; -} - -.bg-secondary { - background-color: #868e96 !important; -} - -a.bg-secondary:focus, a.bg-secondary:hover { - background-color: #6c757d !important; -} - -.bg-success { - background-color: #28a745 !important; -} - -a.bg-success:focus, a.bg-success:hover { - background-color: #1e7e34 !important; -} - -.bg-info { - background-color: #17a2b8 !important; -} - -a.bg-info:focus, a.bg-info:hover { - background-color: #117a8b !important; -} - -.bg-warning { - background-color: #ffc107 !important; -} - -a.bg-warning:focus, a.bg-warning:hover { - background-color: #d39e00 !important; -} - -.bg-danger { - background-color: #dc3545 !important; -} - -a.bg-danger:focus, a.bg-danger:hover { - background-color: #bd2130 !important; -} - -.bg-light { - background-color: #f8f9fa !important; -} - -a.bg-light:focus, a.bg-light:hover { - background-color: #dae0e5 !important; -} - -.bg-dark { - background-color: #343a40 !important; -} - -a.bg-dark:focus, a.bg-dark:hover { - background-color: #1d2124 !important; -} - -.border-primary { - border-color: #999 !important; -} - -.border-secondary { - border-color: #868e96 !important; -} - -.border-success { - border-color: #28a745 !important; -} - -.border-info { - border-color: #17a2b8 !important; -} - -.border-warning { - border-color: #ffc107 !important; -} - -.border-danger { - border-color: #dc3545 !important; -} - -.border-light { - border-color: #f8f9fa !important; -} - -.border-dark { - border-color: #343a40 !important; -} - -.text-primary { - color: #999 !important; -} - -a.text-primary:focus, a.text-primary:hover { - color: gray !important; -} - -.text-secondary { - color: #868e96 !important; -} - -a.text-secondary:focus, a.text-secondary:hover { - color: #6c757d !important; -} - -.text-success { - color: #28a745 !important; -} - -a.text-success:focus, a.text-success:hover { - color: #1e7e34 !important; -} - -.text-info { - color: #17a2b8 !important; -} - -a.text-info:focus, a.text-info:hover { - color: #117a8b !important; -} - -.text-warning { - color: #ffc107 !important; -} - -a.text-warning:focus, a.text-warning:hover { - color: #d39e00 !important; -} - -.text-danger { - color: #dc3545 !important; -} - -a.text-danger:focus, a.text-danger:hover { - color: #bd2130 !important; -} - -.text-light { - color: #f8f9fa !important; -} - -a.text-light:focus, a.text-light:hover { - color: #dae0e5 !important; -} - -.text-dark { - color: #343a40 !important; -} - -a.text-dark:focus, a.text-dark:hover { - color: #1d2124 !important; -} diff --git a/src/public/themes/blog/assets/css/style.sea.min.css b/src/public/themes/blog/assets/css/style.sea.min.css new file mode 100755 index 000000000..455cf3edf --- /dev/null +++ b/src/public/themes/blog/assets/css/style.sea.min.css @@ -0,0 +1 @@ +.text-bold{font-weight:700}.text-small{font-size:0.9rem}body{overflow-x:hidden}strong{font-weight:700}a,i,span{display:inline-block;text-decoration:none;-webkit-transition:all 0.3s;transition:all 0.3s}a:hover, a:focus,i:hover,i:focus,span:hover,span:focus{text-decoration:none}a i{-webkit-transition:none;transition:none}ul{margin:0;padding:0}section{padding:100px 0;overflow-x:hidden}button,input{outline:none !important;font-family:"Open Sans", sans-serif}button{cursor:pointer}main,aside{padding:50px 0 100px}h1 a{margin-left:10px;font-size:0.9em;opacity:0;-webkit-transition:all 0.3s;transition:all 0.3s;color:#555;text-decoration:none}h1:hover a{opacity:1}.page-header{padding-top:20px;padding-bottom:20px;background:#fafafa;margin-top:30px}.page-header h2{margin-bottom:0}.animsition{z-index:9999}.widget{margin-bottom:40px;padding:30px;border:1px solid #eee}.widget header{margin-bottom:20px}.category a{color:#379392;letter-spacing:0.08em;font-weight:700;text-transform:uppercase;text-decoration:none;font-size:13px}.category a::after{content:',';color:#ddd;display:inline-block;margin-right:5px}.category a:last-of-type::after{display:none}.category a:hover{color:#000}i[class*="icon-"]{-webkit-transform:translateY(3px);transform:translateY(3px)}#style-switch-button{z-index:9999 !important}.bg-red{background:#ff7676 !important;color:#fff}.bg-red:hover{color:#fff}.bg-blue{background:#85b4f2 !important;color:#fff}.bg-blue:hover{color:#fff}.bg-yellow{background:#ffc107 !important;color:#fff}.bg-yellow:hover{color:#fff}.bg-green{background:#54e69d !important;color:#fff}.bg-green:hover{color:#fff}.bg-orange{background:#ffc36d !important;color:#fff}.bg-orange:hover{color:#fff}.bg-violet{background:#796AEE !important;color:#fff}.bg-violet:hover{color:#fff}.bg-gray{background:#ced4da !important}.bg-white{background:#fff !important}.text-red{color:#ff7676}.text-red:hover{color:#ff7676}.text-yellow{color:#ffc107}.text-yellow:hover{color:#ffc107}.text-green{color:#54e69d}.text-green:hover{color:#54e69d}.text-orange{color:#ffc36d}.text-orange:hover{color:#ffc36d}.text-violet{color:#796AEE}.text-violet:hover{color:#796AEE}.text-blue{color:#85b4f2}.text-blue:hover{color:#85b4f2}.text-gray{color:#999}.text-gray:hover{color:#999}.text-white{color:#fff}.no-padding{padding:0 !important}.no-padding-bottom{padding-bottom:0 !important}.no-padding-top{padding-top:0 !important}.no-margin{margin:0 !important}.no-margin-bottom{margin-bottom:0 !important}.no-margin-top{margin-top:0 !important}.padding-small{padding:100px 0}.btn{border-radius:0 !important}.badge{font-weight:300}.badge-rounded{border-radius:50px}.heading-light{font-weight:300 !important}.heading-medium{font-weight:400 !important}.pagination-template li.page-item{margin:0 5px}.pagination-template a.page-link{width:40px;height:40px;line-height:27px;border-radius:50% !important;border:1px solid #ddd;color:#555;text-align:center}.pagination-template a.page-link:hover, .pagination-template a.page-link.active{background:#f5f5f5}.text-primary{color:#379392 !important}p.text-hero{font-size:1.2em}p.text-hero i{font-size:1.2em}p.small-text-hero{font-size:1em}h1,h2,h3,h4,h5,h6{margin-bottom:15px}.pagination-template li.page-item{margin:0 5px}.pagination-template a.page-link{width:40px;height:40px;line-height:27px;border-radius:50% !important;border:none;color:#555;text-align:center}.pagination-template a.page-link:hover, .pagination-template a.page-link.active{background:#eee}.container-fluid{width:100%}.text-big{font-size:1.4em;font-weight:300;line-height:1.8em;color:#111}a.hero-link{color:inherit !important;text-transform:uppercase;font-size:1em;text-decoration:none !important;margin-top:20px;font-weight:300}a.hero-link::after{content:'';width:100%;height:1px;display:block;background:#fff;-webkit-transition:all 0.3s;transition:all 0.3s}a.hero-link:hover{color:#379392 !important}a.hero-link:hover::after{background:#379392}div[class*="-btn"]{cursor:pointer}@media (max-width:767px){nav.navbar .search-btn{margin-left:0;padding-left:0;border-left:none}}@media (max-width:575px){nav.navbar .container{width:100%}.breadcrumb li{display:block;width:100%;text-align:center}}.navbar{background:#fff;padding-top:20px !important;padding-bottom:20px !important;z-index:9998;border-bottom:1px solid #ddd}.navbar .langs a:first-of-type,.navbar .search-btn{margin-left:20px;padding-left:20px;border-left:1px solid #ddd;height:20px;line-height:20px}.navbar .search-btn{color:#333;font-size:0.9em}.navbar .navbar-toggler{margin-top:5px}.navbar .navbar-toggler span{width:20px;height:2px;background:#222;margin-bottom:4px;display:block}.navbar .navbar-toggler span:last-of-type{margin-bottom:0}.navbar .navbar-toggler.active span{margin:0}.navbar .navbar-toggler.active span:first-of-type{-webkit-transform:rotate(45deg) translate(3px);transform:rotate(45deg) translate(3px)}.navbar .navbar-toggler.active span:nth-of-type(2){opacity:0}.navbar .navbar-toggler.active span:last-of-type{-webkit-transform:rotate(-45deg) translate(3px);transform:rotate(-45deg) translate(3px)}.navbar .langs a{font-size:0.8em;color:#aaa;font-weight:700}.navbar .langs a.active{color:#333}.navbar .langs span{width:15px;height:1px;background:#ddd;margin:0 5px}.navbar .search-area{display:none;z-index:9999}.navbar .search-area-inner{position:fixed;top:0;right:0;width:100vw;height:100vh;background:rgba(255, 255, 255, 0.99);padding:20px !important}.navbar .search-area-inner .close-btn{position:absolute;top:20px;right:20px}.navbar .search-area-inner .row{width:100%}.navbar .search-area-inner .form-group{position:relative}.navbar .search-area-inner .submit{background:none;border:none;position:absolute;right:10px;bottom:15px}.navbar .search-area-inner input{width:100%;border:none;border-bottom:1px solid #ddd;background:none;padding:10px 0;font-size:1.6em;font-weight:300;font-family:"Open Sans", sans-serif}.navbar .search-area-inner input::-moz-placeholder{font-family:"Open Sans", sans-serif;color:#555;font-weight:300;font-size:1.1em}.navbar .search-area-inner input::-webkit-input-placeholder{font-family:"Open Sans", sans-serif;color:#555;font-weight:300;font-size:1.1em}.navbar .search-area-inner input:-ms-input-placeholder{font-family:"Open Sans", sans-serif;color:#555;font-weight:300;font-size:1.1em}.navbar .navbar-nav a.nav-link{color:#333;margin:0 5px;font-weight:400;font-size:0.95em}.navbar .navbar-nav a.nav-link:hover{color:#379392}.navbar .navbar-nav a.nav-link.active{color:#379392;font-weight:bold}@media (max-width:991px){nav.navbar .navbar-header{width:100%}nav.navbar::after{width:100%}nav.navbar.active::after{width:calc(100% - 170px)}nav.navbar .search-area{font-size:0.75em}}section.hero{padding:0;color:#fff;filter:brightness(80%)}section.hero .container{padding:200px 20px;position:relative}section.hero h1{line-height:1.2em}section.hero .continue{position:absolute;bottom:30px;left:20px;text-decoration:none !important;color:inherit !important;text-transform:uppercase;font-size:0.75em;opacity:0.8}section.hero .continue i{margin-right:5px}@media (max-width:767px){section.hero .container{padding:150px 20px}}section.featured-posts .row:nth-of-type(odd) .text{background:#fafafa}section.featured-posts .row:last-of-type{margin-bottom:0}section.featured-posts p{font-weight:400;color:#777;font-size:0.95em}section.featured-posts .text-inner{padding:70px 30px;height:100%;-webkit-transition:all 0.3s;transition:all 0.3s}section.featured-posts a{color:inherit;text-decoration:none}section.featured-posts h2{line-height:1.1em;color:#333;-webkit-transition:all 0.3s;transition:all 0.3s}section.featured-posts h2:hover{color:#555}section.featured-posts .avatar{max-width:40px;min-width:40px;height:40px;overflow:hidden;border-radius:50%;margin-right:10px}section.featured-posts .title,section.featured-posts .date,section.featured-posts .comments{font-size:0.8em;font-weight:400;color:#999}section.featured-posts .title i,section.featured-posts .date i,section.featured-posts .comments i{margin-right:5px}section.featured-posts .title::after,section.featured-posts .date::after,section.featured-posts .comments::after{content:'|';display:inline-block;margin:0 7px;font-size:0.9em;color:#ccc}section.featured-posts .comments::after{display:none}section.featured-posts .image{max-height:200px;width:auto;overflow:hidden;padding:0}section.featured-posts .image img{height:100%}section.featured-posts .post-header{margin-bottom:10px}section.featured-posts .post-footer{margin-top:30px}@media (max-width:991px){section.featured-posts .image{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1;max-height:300px;min-height:auto !important}section.featured-posts .image img{width:100%;height:auto !important}section.featured-posts .text{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}}@media (max-width:575px){section.featured-posts .post-footer{font-size:0.9em}}@media (max-width:350px){section.featured-posts .text-inner{padding:15px}section.featured-posts .post-footer{font-size:0.75em}}section.divider{color:#fff}section.latest-posts header{margin-bottom:50px}.post-meta{margin:10px 0;font-size:0.8em}.post-meta .date{text-transform:uppercase;font-weight:400}.post-meta .date::after{display:none}.post p:not(.lead){font-weight:400;color:#777;font-size:0.95em}.post a{text-decoration:none}.post a:hover, .post a:focus{text-decoration:none}.post h3{line-height:1.1em;color:#222;-webkit-transition:all 0.3s;transition:all 0.3s;margin-bottom:1rem}.post h3:hover{color:#555}.post .category a{color:#379392;letter-spacing:0.05em;font-weight:700;text-transform:uppercase;text-decoration:none}.post .date{letter-spacing:0.05em;font-weight:400;text-transform:uppercase;color:#aaa}.post .avatar{max-width:40px;min-width:40px;height:40px;overflow:hidden;border-radius:50%;margin-right:10px}.post .title,.post .date,.post .comments,.post .views{font-weight:400;color:#999;text-transform:capitalize}.post .title i,.post .date i,.post .comments i,.post .views i{margin-right:5px;font-size:1.1em}.post .title::after,.post .date::after,.post .comments::after,.post .views::after{content:'|';display:inline-block;margin:0 7px;font-size:0.9em;color:#ccc}.post .post-tags{margin-top:30px}.post .post-tags .tag{padding:5px 25px;border:1px solid #ddd;margin:5px;color:#777;font-size:0.75em;text-transform:uppercase;font-weight:600;text-decoration:none;border-radius:50px}.post .post-tags .tag:hover{background:#379392;color:#fff;border-color:#379392}.post .meta-last::after{display:none}@media (max-width:767px){.post{margin-bottom:40px}.post:last-of-type{margin-bottom:0}}section.newsletter .form-group{position:relative}section.newsletter input{width:100%;height:60px;line-height:60px;padding:0 15px;border:1px solid #111;font-size:1.1em;font-family:"Open Sans", sans-serif;font-weight:300}section.newsletter .submit{height:60px;padding:0 30px;line-height:60px;background:#111;border:1px solid #111;color:#fff;position:absolute;top:0;right:0;font-family:"Open Sans", sans-serif}@media (max-width:575px){section.newsletter input{font-size:0.95em;width:100%}section.newsletter .submit{position:static;width:100%;margin-top:10px}}section.gallery .mix{padding:0;max-height:200px;overflow:hidden}section.gallery a{outline:none;width:100%;height:100%}section.gallery a img{min-height:100%;width:100%}section.gallery .item{position:relative;width:100%;height:100%}section.gallery .item:hover .overlay{opacity:1}section.gallery .item:hover i{opacity:1;-webkit-transform:none;transform:none}section.gallery .overlay{position:absolute;top:0;right:0;width:100%;height:100%;background:rgba(55, 147, 146, 0.7);color:#fff;opacity:0;-webkit-transition:all 0.5s;transition:all 0.5s}section.gallery .overlay i{-webkit-transform:translateY(20px);transform:translateY(20px);-webkit-transition:all 0.5s;transition:all 0.5s;opacity:0;font-size:2em}footer.main-footer{background:#0e0e0e;padding:100px 0 0;color:#fff}footer.main-footer .contact-details p{font-weight:300;color:#fff;margin-bottom:5px;font-size:0.95em}footer.main-footer .contact-details a{text-decoration:underline;margin-bottom:0}footer.main-footer a{color:inherit;font-weight:300;margin-bottom:7px}footer.main-footer a:hover, footer.main-footer a:focus{color:#999}footer.main-footer ul{margin-right:30px}footer.main-footer .list-unstyled a{font-size:0.95em}footer.main-footer .latest-posts .image{max-width:50px;padding:4px;border:2px solid #333;margin-right:10px}footer.main-footer .latest-posts a{font-size:0.95em;text-decoration:none}footer.main-footer .latest-posts a:hover{color:#fff}footer.main-footer .latest-posts strong{display:block}footer.main-footer .latest-posts .date{font-size:0.85em;color:#aaa}footer.main-footer .copyrights{background:#090909;margin-top:100px;padding:20px 0;font-size:0.9em}footer.main-footer .copyrights *{margin-bottom:0}footer.main-footer .social-menu{margin-top:20px}footer.main-footer .social-menu li{padding:0 5px}footer.main-footer .date::after,footer.main-footer .title::after{display:none !important}@media (max-width:767px){footer.main-footer div[class*="col-"]{margin-bottom:40px}footer.main-footer div[class*="col-"]:last-of-type{margin-bottom:0}footer.main-footer .latest-posts>a{width:100%;margin-bottom:20px}footer.main-footer .copyrights div[class*="col-"]{margin-bottom:20px;text-align:center !important}footer.main-footer .copyrights div[class*="col-"]:last-of-type{margin-bottom:0}}main.posts-listing{padding-top:50px;padding-left:0;padding-right:0}main.posts-listing .post{margin-bottom:50px}main.posts-listing .post-footer{font-size:0.8em}.widget.search .form-group{position:relative}.widget.search input{width:100%;height:40px;line-height:40px;border:none;border-bottom:1px solid #ddd;font-size:0.95em;font-family:"Open Sans", sans-serif;font-weight:400;background:none}.widget.search input::-moz-placeholder{color:#aaa;font-family:"Open Sans", sans-serif}.widget.search input::-webkit-input-placeholder{color:#aaa;font-family:"Open Sans", sans-serif}.widget.search input:-ms-input-placeholder{color:#aaa;font-family:"Open Sans", sans-serif}.widget.search .submit{height:40px;padding:0;line-height:40px;background:none;border:none;color:#555;font-size:0.9em;position:absolute;top:0;right:0}.widget.latest-posts a{display:block;color:#555;text-decoration:none}.widget.latest-posts a:hover{color:#000}.widget.latest-posts .image{min-width:60px;max-width:60px;height:60px;overflow:hidden;margin-right:20px}.widget.latest-posts .item{margin-bottom:20px}.widget.latest-posts strong{font-size:0.95em;display:block;line-height:1em}.widget.latest-posts .views,.widget.latest-posts .comments{font-size:0.8em;font-weight:400;color:#bbb;margin-top:10px}.widget.latest-posts .views i,.widget.latest-posts .comments i{margin-right:5px}.widget.latest-posts .views::after,.widget.latest-posts .comments::after{content:'|';display:inline-block;margin:0 7px;font-size:0.9em;color:#ccc}.widget.latest-posts .comments::after{display:none}.widget.categories .item{background:#fafafa;padding:10px;color:#777;font-weight:700}.widget.categories .item:nth-of-type(2n+2){background:none}.widget.categories .item a{color:inherit;font-size:0.95em}.widget.categories .item a:hover{color:#000;text-decoration:none}.widget.categories .item span{font-size:0.9em;color:#aaa}.widget.tags .tag{padding:5px 25px;border:1px solid #ddd;margin:5px 0;color:#777;font-size:0.75em;text-transform:uppercase;font-weight:600;text-decoration:none;border-radius:50px}.widget.tags .tag:hover{background:#379392;color:#fff;border-color:#379392}.blog-post{padding-left:0;padding-right:0}.blog-post .post-footer{font-size:0.8em}.blog-post .post-thumbnail img{width:100%;margin-bottom:10px}.blog-post h1{color:#444;line-height:1.1em}.blog-post h1:hover{color:#444}.blog-post .post-footer{margin-top:20px}.blog-post .post-body{margin-top:40px}.blog-post .post-body h2,.blog-post .post-body h3,.blog-post .post-body h4,.blog-post .post-body h5,.blog-post .post-body h6{color:#333}.blog-post .post-body p{margin-bottom:30px}.blog-post .post-body p:not(.lead){font-size:1em;line-height:1.7em;color:#555}.blog-post .posts-nav{margin-top:50px;color:#777;font-size:0.8em}.blog-post .posts-nav a{color:inherit;width:calc(50% - 10px);padding:10px 20px;border:1px solid #eee;margin-bottom:15px}.blog-post .posts-nav a:hover{border-color:#379392}.blog-post .posts-nav a:hover .icon{background:#379392;color:#fff;border-color:#379392}.blog-post .icon{min-width:35px;max-width:35px;height:35px;border-radius:50%;line-height:32px;border:1px solid #ddd;color:#aaa;font-size:1.5em;text-align:center;-webkit-transition:all 0.2s;transition:all 0.2s}.blog-post .icon.prev{margin-right:20px}.blog-post .icon.next{margin-left:20px}.blog-post .post-comments{margin-top:50px}.blog-post .post-comments span.no-of-comments{color:#777;font-size:0.8em;margin-left:5px;font-weight:400}.blog-post .post-comments header{margin-bottom:40px}.blog-post .post-comments .comment:last-of-type .comment-body{border-bottom:none}.blog-post .post-comments .image{margin-right:15px}.blog-post .post-comments .title::after{display:none}.blog-post .post-comments img{max-width:40px;min-width:40px;height:40px}.blog-post .post-comments strong{display:block;color:#555}.blog-post .post-comments span.date{font-size:0.8em;color:#999}.blog-post .post-comments span.date::after{display:none}.blog-post .post-comments .comment-body{margin-left:55px;margin-top:10px;margin-bottom:25px;padding-bottom:15px;border-bottom:1px solid #eee}.blog-post .post-comments p{font-size:0.95em;color:#555}.blog-post .add-comment{margin-top:50px}.blog-post .add-comment header{margin-bottom:30px}.blog-post .add-comment input,.blog-post .add-comment textarea{background:none;border:none;border-bottom:1px solid #ddd;padding:10px 0;border-radius:0;font-family:"Open Sans", sans-serif}.blog-post .add-comment input::-moz-placeholder,.blog-post .add-comment textarea::-moz-placeholder{font-weight:400;font-size:0.9em;color:#aaa;font-weight:400;font-family:"Open Sans", sans-serif}.blog-post .add-comment input::-webkit-input-placeholder,.blog-post .add-comment textarea::-webkit-input-placeholder{font-weight:400;font-size:0.9em;color:#aaa;font-weight:400;font-family:"Open Sans", sans-serif}.blog-post .add-comment input:-ms-input-placeholder,.blog-post .add-comment textarea:-ms-input-placeholder{font-weight:400;font-size:0.9em;color:#aaa;font-weight:400;font-family:"Open Sans", sans-serif}.blog-post .add-comment input:focus,.blog-post .add-comment textarea:focus{-webkit-box-shadow:none;box-shadow:none;border-bottom:1px solid #379392}.blog-post .add-comment textarea{min-height:150px}blockquote.blockquote{font-size:1.05em;line-height:1.7em;border-color:#379392;border:1px solid #eee;border-left:6px solid #eee;padding:20px;border-top-right-radius:5px;border-bottom-right-radius:5px;margin-bottom:30px}blockquote.blockquote p{margin-bottom:15px !important}@media (max-width:767px){.posts-nav a{width:100% !important}}@media (max-width:575px){.blog-post .title::after{display:none !important}.blog-post .author{margin-bottom:10px}}#style-switch-button{position:fixed;top:120px;left:0px;border-radius:0;z-index:100000}#style-switch{width:300px;padding:20px;position:fixed;top:160px;left:0;background:#fff;border:solid 1px #ced4da;z-index:100000}#style-switch h4{color:#495057}#style-switch .text-small{font-size:.8em}#style-switch select{font-size:0.85em}.navbar{padding:0.5rem 1rem}.navbar-brand{display:inline-block;padding-top:0.5rem;padding-bottom:0.5rem;margin-right:1rem;font-size:1rem;color:#333;font-weight:bold}.navbar-toggler{padding:0.25rem 0.75rem;font-size:1.25rem;line-height:1;border:1px solid transparent;border-radius:0.25rem}.navbar-light .navbar-brand{color:rgba(0, 0, 0, 0.9)}.navbar-light .navbar-brand:focus, .navbar-light .navbar-brand:hover{color:rgba(0, 0, 0, 0.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0, 0, 0, 0.5)}.navbar-light .navbar-nav .nav-link:focus, .navbar-light .navbar-nav .nav-link:hover{color:rgba(0, 0, 0, 0.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0, 0, 0, 0.3)}.navbar-light .navbar-nav .show>.nav-link,.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .nav-link.active{color:rgba(0, 0, 0, 0.9)}.navbar-light .navbar-toggler{color:rgba(0, 0, 0, 0.5);border-color:rgba(0, 0, 0, 0.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0, 0, 0, 0.5)}.navbar-dark .navbar-brand{color:white}.navbar-dark .navbar-brand:focus, .navbar-dark .navbar-brand:hover{color:white}.navbar-dark .navbar-nav .nav-link{color:rgba(255, 255, 255, 0.5)}.navbar-dark .navbar-nav .nav-link:focus, .navbar-dark .navbar-nav .nav-link:hover{color:rgba(255, 255, 255, 0.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255, 255, 255, 0.25)}.navbar-dark .navbar-nav .show>.nav-link,.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .nav-link.active{color:white}.navbar-dark .navbar-toggler{color:rgba(255, 255, 255, 0.5);border-color:rgba(255, 255, 255, 0.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255, 255, 255, 0.5)}.btn{font-weight:normal;border:1px solid transparent;padding:0.5rem 1rem;font-size:1rem;line-height:1.25;border-radius:0.25rem;-webkit-transition:all 0.15s ease-in-out;transition:all 0.15s ease-in-out}.btn:focus, .btn.focus{outline:0;-webkit-box-shadow:0 0 0 3px rgba(55, 147, 146, 0.25);box-shadow:0 0 0 3px rgba(55, 147, 146, 0.25)}.btn:active, .btn.active{background-image:none}.btn-primary{color:#fff;background-color:#379392;border-color:#379392}.btn-primary:hover{color:#fff;background-color:#2d7776;border-color:#296e6d}.btn-primary:focus, .btn-primary.focus{-webkit-box-shadow:0 0 0 3px rgba(55, 147, 146, 0.5);box-shadow:0 0 0 3px rgba(55, 147, 146, 0.5)}.btn-primary.disabled, .btn-primary:disabled{background-color:#379392;border-color:#379392}.btn-primary:active, .btn-primary.active,.show>.btn-primary.dropdown-toggle{background-color:#2d7776;background-image:none;border-color:#296e6d}.btn-secondary{color:#fff;background-color:#868e96;border-color:#868e96}.btn-secondary:hover{color:#fff;background-color:#727b84;border-color:#6c757d}.btn-secondary:focus, .btn-secondary.focus{-webkit-box-shadow:0 0 0 3px rgba(134, 142, 150, 0.5);box-shadow:0 0 0 3px rgba(134, 142, 150, 0.5)}.btn-secondary.disabled, .btn-secondary:disabled{background-color:#868e96;border-color:#868e96}.btn-secondary:active, .btn-secondary.active,.show>.btn-secondary.dropdown-toggle{background-color:#727b84;background-image:none;border-color:#6c757d}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success:focus, .btn-success.focus{-webkit-box-shadow:0 0 0 3px rgba(40, 167, 69, 0.5);box-shadow:0 0 0 3px rgba(40, 167, 69, 0.5)}.btn-success.disabled, .btn-success:disabled{background-color:#28a745;border-color:#28a745}.btn-success:active, .btn-success.active,.show>.btn-success.dropdown-toggle{background-color:#218838;background-image:none;border-color:#1e7e34}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info:focus, .btn-info.focus{-webkit-box-shadow:0 0 0 3px rgba(23, 162, 184, 0.5);box-shadow:0 0 0 3px rgba(23, 162, 184, 0.5)}.btn-info.disabled, .btn-info:disabled{background-color:#17a2b8;border-color:#17a2b8}.btn-info:active, .btn-info.active,.show>.btn-info.dropdown-toggle{background-color:#138496;background-image:none;border-color:#117a8b}.btn-warning{color:#111;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#111;background-color:#e0a800;border-color:#d39e00}.btn-warning:focus, .btn-warning.focus{-webkit-box-shadow:0 0 0 3px rgba(255, 193, 7, 0.5);box-shadow:0 0 0 3px rgba(255, 193, 7, 0.5)}.btn-warning.disabled, .btn-warning:disabled{background-color:#ffc107;border-color:#ffc107}.btn-warning:active, .btn-warning.active,.show>.btn-warning.dropdown-toggle{background-color:#e0a800;background-image:none;border-color:#d39e00}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger:focus, .btn-danger.focus{-webkit-box-shadow:0 0 0 3px rgba(220, 53, 69, 0.5);box-shadow:0 0 0 3px rgba(220, 53, 69, 0.5)}.btn-danger.disabled, .btn-danger:disabled{background-color:#dc3545;border-color:#dc3545}.btn-danger:active, .btn-danger.active,.show>.btn-danger.dropdown-toggle{background-color:#c82333;background-image:none;border-color:#bd2130}.btn-light{color:#111;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#111;background-color:#e2e6ea;border-color:#dae0e5}.btn-light:focus, .btn-light.focus{-webkit-box-shadow:0 0 0 3px rgba(248, 249, 250, 0.5);box-shadow:0 0 0 3px rgba(248, 249, 250, 0.5)}.btn-light.disabled, .btn-light:disabled{background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:active, .btn-light.active,.show>.btn-light.dropdown-toggle{background-color:#e2e6ea;background-image:none;border-color:#dae0e5}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark:focus, .btn-dark.focus{-webkit-box-shadow:0 0 0 3px rgba(52, 58, 64, 0.5);box-shadow:0 0 0 3px rgba(52, 58, 64, 0.5)}.btn-dark.disabled, .btn-dark:disabled{background-color:#343a40;border-color:#343a40}.btn-dark:active, .btn-dark.active,.show>.btn-dark.dropdown-toggle{background-color:#23272b;background-image:none;border-color:#1d2124}.btn-outline-primary{color:#379392;background-color:transparent;background-image:none;border-color:#379392}.btn-outline-primary:hover{color:#fff;background-color:#379392;border-color:#379392}.btn-outline-primary:focus, .btn-outline-primary.focus{-webkit-box-shadow:0 0 0 3px rgba(55, 147, 146, 0.5);box-shadow:0 0 0 3px rgba(55, 147, 146, 0.5)}.btn-outline-primary.disabled, .btn-outline-primary:disabled{color:#379392;background-color:transparent}.btn-outline-primary:active, .btn-outline-primary.active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#379392;border-color:#379392}.btn-outline-secondary{color:#868e96;background-color:transparent;background-image:none;border-color:#868e96}.btn-outline-secondary:hover{color:#fff;background-color:#868e96;border-color:#868e96}.btn-outline-secondary:focus, .btn-outline-secondary.focus{-webkit-box-shadow:0 0 0 3px rgba(134, 142, 150, 0.5);box-shadow:0 0 0 3px rgba(134, 142, 150, 0.5)}.btn-outline-secondary.disabled, .btn-outline-secondary:disabled{color:#868e96;background-color:transparent}.btn-outline-secondary:active, .btn-outline-secondary.active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#868e96;border-color:#868e96}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:focus, .btn-outline-success.focus{-webkit-box-shadow:0 0 0 3px rgba(40, 167, 69, 0.5);box-shadow:0 0 0 3px rgba(40, 167, 69, 0.5)}.btn-outline-success.disabled, .btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:active, .btn-outline-success.active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:focus, .btn-outline-info.focus{-webkit-box-shadow:0 0 0 3px rgba(23, 162, 184, 0.5);box-shadow:0 0 0 3px rgba(23, 162, 184, 0.5)}.btn-outline-info.disabled, .btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:active, .btn-outline-info.active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#fff;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:focus, .btn-outline-warning.focus{-webkit-box-shadow:0 0 0 3px rgba(255, 193, 7, 0.5);box-shadow:0 0 0 3px rgba(255, 193, 7, 0.5)}.btn-outline-warning.disabled, .btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:active, .btn-outline-warning.active,.show>.btn-outline-warning.dropdown-toggle{color:#fff;background-color:#ffc107;border-color:#ffc107}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:focus, .btn-outline-danger.focus{-webkit-box-shadow:0 0 0 3px rgba(220, 53, 69, 0.5);box-shadow:0 0 0 3px rgba(220, 53, 69, 0.5)}.btn-outline-danger.disabled, .btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:active, .btn-outline-danger.active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#fff;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:focus, .btn-outline-light.focus{-webkit-box-shadow:0 0 0 3px rgba(248, 249, 250, 0.5);box-shadow:0 0 0 3px rgba(248, 249, 250, 0.5)}.btn-outline-light.disabled, .btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:active, .btn-outline-light.active,.show>.btn-outline-light.dropdown-toggle{color:#fff;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:focus, .btn-outline-dark.focus{-webkit-box-shadow:0 0 0 3px rgba(52, 58, 64, 0.5);box-shadow:0 0 0 3px rgba(52, 58, 64, 0.5)}.btn-outline-dark.disabled, .btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:active, .btn-outline-dark.active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-lg{padding:0.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:0.3rem}.btn-sm{padding:0.25rem 0.5rem;font-size:0.875rem;line-height:1.5;border-radius:0.2rem}body{font-family:"Open Sans", sans-serif;font-size:1rem;font-weight:normal;line-height:1.5;color:#212529;background-color:#fff}a{color:#379392;text-decoration:none}a:focus, a:hover{color:#225b5b;text-decoration:underline}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{margin-bottom:0.5rem;font-family:inherit;font-weight:700;line-height:1.1;color:inherit}h1,.h1{font-size:2.5rem;color:#379392}h2,.h2{font-size:2rem}h3,.h3{font-size:1.75rem}h4,.h4{font-size:1.5rem}h5,.h5{font-size:1.25rem}h6,.h6{font-size:1rem}.lead{font-size:1.3rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.1}.display-2{font-size:5.5rem;font-weight:300;line-height:1.1}.display-3{font-size:4.5rem;font-weight:300;line-height:1.1}.display-4{font-size:3.5rem;font-weight:300;line-height:1.1}hr{border-top:1px solid rgba(0, 0, 0, 0.1)}small,.small{font-size:80%;font-weight:normal}mark,.mark{padding:0.2em;background-color:#fcf8e3}.blockquote{padding:0.5rem 1rem;margin-bottom:1rem;font-size:1.25rem;border-left:5px solid #379392}.blockquote-footer{color:#868e96}.blockquote-footer::before{content:"\2014 \00A0"}.text-primary{color:#379392 !important}a.text-primary:focus, a.text-primary:hover{color:#296e6d !important}.page-item:first-child .page-link{border-top-left-radius:0.25rem;border-bottom-left-radius:0.25rem}.page-item:last-child .page-link{border-top-right-radius:0.25rem;border-bottom-right-radius:0.25rem}.page-item.active .page-link{color:#fff;background-color:#379392;border-color:#379392}.page-item.disabled .page-link{color:#868e96;background-color:#fff;border-color:#ddd}.page-link{padding:0.5rem 0.75rem;line-height:1.25;color:#379392;background-color:#fff;border:1px solid #ddd}.page-link:focus, .page-link:hover{color:#225b5b;text-decoration:none;background-color:#e9ecef;border-color:#ddd}.pagination-lg .page-link{padding:0.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:0.3rem;border-bottom-left-radius:0.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:0.3rem;border-bottom-right-radius:0.3rem}.pagination-sm .page-link{padding:0.25rem 0.5rem;font-size:0.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:0.2rem;border-bottom-left-radius:0.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:0.2rem;border-bottom-right-radius:0.2rem}.bg-primary{background-color:#379392 !important}a.bg-primary:focus, a.bg-primary:hover{background-color:#296e6d !important}.bg-secondary{background-color:#868e96 !important}a.bg-secondary:focus, a.bg-secondary:hover{background-color:#6c757d !important}.bg-success{background-color:#28a745 !important}a.bg-success:focus, a.bg-success:hover{background-color:#1e7e34 !important}.bg-info{background-color:#17a2b8 !important}a.bg-info:focus, a.bg-info:hover{background-color:#117a8b !important}.bg-warning{background-color:#ffc107 !important}a.bg-warning:focus, a.bg-warning:hover{background-color:#d39e00 !important}.bg-danger{background-color:#dc3545 !important}a.bg-danger:focus, a.bg-danger:hover{background-color:#bd2130 !important}.bg-light{background-color:#f8f9fa !important}a.bg-light:focus, a.bg-light:hover{background-color:#dae0e5 !important}.bg-dark{background-color:#343a40 !important}a.bg-dark:focus, a.bg-dark:hover{background-color:#1d2124 !important}.border-primary{border-color:#379392 !important}.border-secondary{border-color:#868e96 !important}.border-success{border-color:#28a745 !important}.border-info{border-color:#17a2b8 !important}.border-warning{border-color:#ffc107 !important}.border-danger{border-color:#dc3545 !important}.border-light{border-color:#f8f9fa !important}.border-dark{border-color:#343a40 !important}.text-primary{color:#379392 !important}a.text-primary:focus, a.text-primary:hover{color:#296e6d !important}.text-secondary{color:#868e96 !important}a.text-secondary:focus, a.text-secondary:hover{color:#6c757d !important}.text-success{color:#28a745 !important}a.text-success:focus, a.text-success:hover{color:#1e7e34 !important}.text-info{color:#17a2b8 !important}a.text-info:focus, a.text-info:hover{color:#117a8b !important}.text-warning{color:#ffc107 !important}a.text-warning:focus, a.text-warning:hover{color:#d39e00 !important}.text-danger{color:#dc3545 !important}a.text-danger:focus, a.text-danger:hover{color:#bd2130 !important}.text-light{color:#f8f9fa !important}a.text-light:focus, a.text-light:hover{color:#dae0e5 !important}.text-dark{color:#343a40 !important}a.text-dark:focus, a.text-dark:hover{color:#1d2124 !important} \ No newline at end of file diff --git a/src/public/themes/blog/assets/icons-reference/fonts/blog.eot b/src/public/themes/blog/assets/icons-reference/fonts/blog.eot deleted file mode 100755 index 7604b7f29..000000000 Binary files a/src/public/themes/blog/assets/icons-reference/fonts/blog.eot and /dev/null differ diff --git a/src/public/themes/blog/assets/icons-reference/fonts/blog.svg b/src/public/themes/blog/assets/icons-reference/fonts/blog.svg deleted file mode 100755 index 9d0885ae4..000000000 --- a/src/public/themes/blog/assets/icons-reference/fonts/blog.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - -Generated by Fontastic.me - - - - - - - - - - - - diff --git a/src/public/themes/blog/assets/icons-reference/fonts/blog.ttf b/src/public/themes/blog/assets/icons-reference/fonts/blog.ttf deleted file mode 100755 index c029d98c4..000000000 Binary files a/src/public/themes/blog/assets/icons-reference/fonts/blog.ttf and /dev/null differ diff --git a/src/public/themes/blog/assets/icons-reference/fonts/blog.woff b/src/public/themes/blog/assets/icons-reference/fonts/blog.woff deleted file mode 100755 index 70d0fde61..000000000 Binary files a/src/public/themes/blog/assets/icons-reference/fonts/blog.woff and /dev/null differ diff --git a/src/public/themes/blog/assets/icons-reference/icons-reference.html b/src/public/themes/blog/assets/icons-reference/icons-reference.html deleted file mode 100755 index 0cc4fce5f..000000000 --- a/src/public/themes/blog/assets/icons-reference/icons-reference.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - Font Reference - blog - - - - - -
    -

    blog

    -

    This font was created withFontastic

    -

    CSS mapping

    -
      -
    • - - -
    • -
    • -
      - -
    • -
    • -
      - -
    • -
    • -
      - -
    • -
    • -
      - -
    • -
    • -
      - -
    • -
    -

    Character mapping

    -
      -
    • -
      - -
    • -
    • -
      - -
    • -
    • -
      - -
    • -
    • -
      - -
    • -
    • -
      - -
    • -
    • -
      - -
    • -
    -
    - - - diff --git a/src/public/themes/blog/assets/icons-reference/styles.css b/src/public/themes/blog/assets/icons-reference/styles.css deleted file mode 100755 index 6b8d850ca..000000000 --- a/src/public/themes/blog/assets/icons-reference/styles.css +++ /dev/null @@ -1,58 +0,0 @@ -@charset "UTF-8"; - -@font-face { - font-family: "blog"; - src:url("fonts/blog.eot"); - src:url("fonts/blog.eot?#iefix") format("embedded-opentype"), - url("fonts/blog.woff") format("woff"), - url("fonts/blog.ttf") format("truetype"), - url("fonts/blog.svg#blog") format("svg"); - font-weight: normal; - font-style: normal; - -} - -[data-icon]:before { - font-family: "blog" !important; - content: attr(data-icon); - font-style: normal !important; - font-weight: normal !important; - font-variant: normal !important; - text-transform: none !important; - speak: none; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -[class^="icon-"]:before, -[class*=" icon-"]:before { - font-family: "blog" !important; - font-style: normal !important; - font-weight: normal !important; - font-variant: normal !important; - text-transform: none !important; - speak: none; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.icon-search:before { - content: "\61"; -} -.icon-clock:before { - content: "\62"; -} -.icon-comment:before { - content: "\64"; -} -.icon-search-1:before { - content: "\67"; -} -.icon-close:before { - content: "\68"; -} -.icon-eye:before { - content: "\63"; -} diff --git a/src/public/themes/blog/assets/js/comment-submission.min.js b/src/public/themes/blog/assets/js/comment-submission.min.js new file mode 100755 index 000000000..8c2abbed1 --- /dev/null +++ b/src/public/themes/blog/assets/js/comment-submission.min.js @@ -0,0 +1,105 @@ +function submitComment(post_url, request_method, form_data) { + let csrfToken = $('input[name="csrf"]').val(); // Get the token value + form_data += "&csrf=" + csrfToken; // Append it to the form data + $.ajax({ + url: post_url, + type: request_method, + data: form_data + }).done(function (data) { + formSuccess(data); + }).fail(formError); // Pass the AJAX error object to formError +} +function formSuccess(response) { + let msg = $.parseJSON(response); + $("#commentForm")[0].reset(); + $("#success_message").fadeIn().html(msg.success_message); + setTimeout(function () { + $("#success_message").fadeOut("slow"); + }, 2000); + if (typeof loadComments === "function") { + offset = 0; // reset offset + $("#comments").empty(); // clear existing comments + loadComments(); // reload comments + } +} +function formError(jqXHR, textStatus, errorThrown) { + try { + let msg = $.parseJSON(jqXHR.responseText); + if (msg?.errors) { // Optional chaining to check for errors property + $.each(msg.errors, function (field, error) { + $("#" + field).addClass("is-invalid"); + $("#error_message").show().html(error); + }); + } else { + switch (textStatus) { + case "timeout": + $("#error_message").show().html("The request timed out. Please try again."); + break; + case "abort": + break; + case "parsererror": + $("#error_message").show().html("An error occurred while parsing the server response."); + break; + default: + $("#error_message").show().html("An error occurred. Please try again later."); + break; + } + console.error("AJAX error:", textStatus, errorThrown); // Log for debugging + } + } catch (e) { + console.error("Error parsing AJAX error response:", e); + $("#error_message").show().html("An unexpected error occurred. Please contact support."); + } +} +function checkingAuthorName(name) { + const regex = /^[A-Z \'.-]{2,90}$/i; + return regex.test(name); +} +$(function () { + $("#commentForm").on('submit', function (event) { + event.preventDefault(); // Prevent default form submission + let post_url = $(this).attr("action"); + let request_method = $(this).attr("method"); + let form_data = $(this).serialize(); + let comment = $("#comment").val(); + let name = $("#name").val(); + let email = $("#email").val(); + let isValid = true; + if (comment.trim() === "") { + $("#comment").addClass("is-invalid"); + $("#error_message").show().html("Please enter your comment."); + isValid = false; + } else { + $("#comment").removeClass("is-invalid"); + } + if (name.trim() === "") { + $("#name").addClass("is-invalid"); + $("#error_message").show().html("Please enter your full name."); + isValid = false; + } else if (!checkingAuthorName(name)) { + $("#name").addClass("is-invalid"); + $("#error_message").show().html("Please enter a valid name (2-90 characters, starting with an uppercase letter, spaces, apostrophes, periods, and hyphens allowed)."); + isValid = false; + } else { + $("#name").removeClass("is-invalid"); + } + if (email.trim() === "") { + $("#email").addClass("is-invalid"); + $("#error_message").show().html("Please enter your email address"); + isValid = false; + } else { + + const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; + if (!emailRegex.test(email)) { // Basic email validation + $("#email").addClass("is-invalid"); + $("#error_message").show().html("Please enter a valid email address."); + isValid = false; + } else { + $("#email").removeClass("is-invalid"); + } + } + if (isValid) { + submitComment(post_url, request_method, form_data); + } + }); +}); \ No newline at end of file diff --git a/src/public/themes/blog/assets/js/cookie-consent.js b/src/public/themes/blog/assets/js/cookie-consent.js new file mode 100755 index 000000000..93ff1f97d --- /dev/null +++ b/src/public/themes/blog/assets/js/cookie-consent.js @@ -0,0 +1,248 @@ +/** + * Cookie Consent Banner JavaScript + * + * Handles cookie consent banner interactions + * + * @category Theme Assets + * @author Scriptlog + * @license MIT + * @version 1.0 + */ + +(function() { + 'use strict'; + + const CookieConsent = { + cookieName: 'cookie_consent', + bannerId: 'cookie-consent-banner', + apiEndpoint: null, + + /** + * Initialize the cookie consent banner + */ + init: function() { + // Set API endpoint + this.apiEndpoint = this.getApiEndpoint(); + + // Check if consent already given + if (!this.hasConsentCookie()) { + // Show banner after a short delay + setTimeout(() => { + this.showBanner(); + }, 500); + } + + // Bind event listeners + this.bindEvents(); + }, + + /** + * Get the API endpoint for consent processing + */ + getApiEndpoint: function() { + // Try to get from data attribute first + const banner = document.getElementById(this.bannerId); + if (banner && banner.dataset.apiEndpoint) { + return banner.dataset.apiEndpoint; + } + // Fallback to default + return window.appUrl ? window.appUrl + '/api/v1/gdpr/consent' : '/api/v1/gdpr/consent'; + }, + + /** + * Check if consent cookie exists + */ + hasConsentCookie: function() { + const cookies = document.cookie.split(';'); + for (let i = 0; i < cookies.length; i++) { + const cookie = cookies[i].trim(); + if (cookie.indexOf(this.cookieName + '=') === 0) { + return true; + } + } + return false; + }, + + /** + * Get consent cookie value + */ + getConsentValue: function() { + const name = this.cookieName + '='; + const decodedCookie = decodeURIComponent(document.cookie); + const ca = decodedCookie.split(';'); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + while (c.charAt(0) === ' ') { + c = c.substring(1); + } + if (c.indexOf(name) === 0) { + return c.substring(name.length, c.length); + } + } + return null; + }, + + /** + * Show the consent banner + */ + showBanner: function() { + const banner = document.getElementById(this.bannerId); + if (banner) { + banner.classList.add('show'); + banner.classList.remove('hidden'); + // Trigger animation + setTimeout(() => { + banner.classList.add('animate'); + }, 10); + } + }, + + /** + * Hide the consent banner + */ + hideBanner: function() { + const banner = document.getElementById(this.bannerId); + if (banner) { + banner.classList.remove('show'); + setTimeout(() => { + banner.classList.add('hidden'); + }, 300); + } + }, + + /** + * Set consent cookie + */ + setConsentCookie: function(value, days = 365) { + const date = new Date(); + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + const expires = 'expires=' + date.toUTCString(); + document.cookie = this.cookieName + '=' + value + ';' + expires + ';path=/;samesite=Lax'; + }, + + /** + * Send consent to server + */ + sendConsentToServer: function(status) { + return fetch(this.apiEndpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ status: status }) + }) + .then(response => { + if (!response.ok) { + throw new Error('Network response was not ok'); + } + return response.json(); + }) + .catch(error => { + console.error('Error sending consent:', error); + // Continue anyway - cookie is the primary storage + return { success: true }; + }); + }, + + /** + * Handle accept button click + */ + acceptAll: function() { + const status = 'accepted'; + + // Set cookie locally + this.setConsentCookie(status); + + // Send to server + this.sendConsentToServer(status); + + // Hide banner + this.hideBanner(); + }, + + /** + * Handle reject button click + */ + rejectAll: function() { + const status = 'rejected'; + + // Set cookie locally + this.setConsentCookie(status); + + // Send to server + this.sendConsentToServer(status); + + // Hide banner + this.hideBanner(); + }, + + /** + * Handle learn more link click + */ + learnMore: function() { + // Redirect to privacy policy page + const privacyUrl = document.getElementById(this.bannerId); + if (privacyUrl && privacyUrl.dataset.privacyUrl) { + window.location.href = privacyUrl.dataset.privacyUrl; + } else { + window.location.href = '/privacy'; + } + }, + + /** + * Bind event listeners + */ + bindEvents: function() { + const banner = document.getElementById(this.bannerId); + if (!banner) return; + + // Accept button + const acceptBtn = banner.querySelector('.cookie-btn-accept'); + if (acceptBtn) { + acceptBtn.addEventListener('click', (e) => { + e.preventDefault(); + this.acceptAll(); + }); + } + + // Reject button + const rejectBtn = banner.querySelector('.cookie-btn-reject'); + if (rejectBtn) { + rejectBtn.addEventListener('click', (e) => { + e.preventDefault(); + this.rejectAll(); + }); + } + + // Learn more link + const learnMoreBtn = banner.querySelector('.cookie-btn-learn-more'); + if (learnMoreBtn) { + learnMoreBtn.addEventListener('click', (e) => { + e.preventDefault(); + this.learnMore(); + }); + } + + // Keyboard accessibility + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && banner.classList.contains('show')) { + // Allow closing with Escape but still require choice + // This is optional - some prefer to force a choice + } + }); + } + }; + + // Initialize when DOM is ready + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', function() { + CookieConsent.init(); + }); + } else { + CookieConsent.init(); + } + + // Expose to global scope for manual control + window.CookieConsent = CookieConsent; + +})(); diff --git a/src/public/themes/blog/assets/js/cookie-consent.min.js b/src/public/themes/blog/assets/js/cookie-consent.min.js new file mode 100755 index 000000000..846a6e311 --- /dev/null +++ b/src/public/themes/blog/assets/js/cookie-consent.min.js @@ -0,0 +1,162 @@ +(function() { + 'use strict'; + const CookieConsent = { + cookieName: 'cookie_consent', + bannerId: 'cookie-consent-banner', + apiEndpoint: null, + + init: function() { + this.apiEndpoint = this.getApiEndpoint(); + if (!this.hasConsentCookie()) { + setTimeout(() => { + this.showBanner(); + }, 500); + } + this.bindEvents(); + }, + + getApiEndpoint: function() { + const banner = document.getElementById(this.bannerId); + if (banner && banner.dataset.apiEndpoint) { + return banner.dataset.apiEndpoint; + } + return window.appUrl ? window.appUrl + '/api/v1/gdpr/consent' : '/api/v1/gdpr/consent'; + }, + + hasConsentCookie: function() { + const cookies = document.cookie.split(';'); + for (let i = 0; i < cookies.length; i++) { + const cookie = cookies[i].trim(); + if (cookie.indexOf(this.cookieName + '=') === 0) { + return true; + } + } + return false; + }, + + getConsentValue: function() { + const name = this.cookieName + '='; + const decodedCookie = decodeURIComponent(document.cookie); + const ca = decodedCookie.split(';'); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + while (c.charAt(0) === ' ') { + c = c.substring(1); + } + if (c.indexOf(name) === 0) { + return c.substring(name.length, c.length); + } + } + return null; + }, + + showBanner: function() { + const banner = document.getElementById(this.bannerId); + if (banner) { + banner.classList.add('show'); + banner.classList.remove('hidden'); + setTimeout(() => { + banner.classList.add('animate'); + }, 10); + } + }, + + hideBanner: function() { + const banner = document.getElementById(this.bannerId); + if (banner) { + banner.classList.remove('show'); + setTimeout(() => { + banner.classList.add('hidden'); + }, 300); + } + }, + + setConsentCookie: function(value, days = 365) { + const date = new Date(); + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + const expires = 'expires=' + date.toUTCString(); + document.cookie = this.cookieName + '=' + value + ';' + expires + ';path=/;samesite=Lax'; + }, + + sendConsentToServer: function(status) { + return fetch(this.apiEndpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ status: status }) + }) + .then(response => { + if (!response.ok) { + throw new Error('Network response was not ok'); + } + return response.json(); + }) + .catch(error => { + console.error('Error sending consent:', error); + return { success: true }; + }); + }, + + acceptAll: function() { + const status = 'accepted'; + this.setConsentCookie(status); + this.sendConsentToServer(status); + this.hideBanner(); + }, + + rejectAll: function() { + const status = 'rejected'; + this.setConsentCookie(status); + this.sendConsentToServer(status); + this.hideBanner(); + }, + + learnMore: function() { + const privacyUrl = document.getElementById(this.bannerId); + if (privacyUrl && privacyUrl.dataset.privacyUrl) { + window.location.href = privacyUrl.dataset.privacyUrl; + } else { + window.location.href = '/privacy'; + } + }, + + bindEvents: function() { + const banner = document.getElementById(this.bannerId); + if (!banner) return; + const acceptBtn = banner.querySelector('.cookie-btn-accept'); + if (acceptBtn) { + acceptBtn.addEventListener('click', (e) => { + e.preventDefault(); + this.acceptAll(); + }); + } + const rejectBtn = banner.querySelector('.cookie-btn-reject'); + if (rejectBtn) { + rejectBtn.addEventListener('click', (e) => { + e.preventDefault(); + this.rejectAll(); + }); + } + const learnMoreBtn = banner.querySelector('.cookie-btn-learn-more'); + if (learnMoreBtn) { + learnMoreBtn.addEventListener('click', (e) => { + e.preventDefault(); + this.learnMore(); + }); + } + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && banner.classList.contains('show')) { + } + }); + } + }; + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', function() { + CookieConsent.init(); + }); + } else { + CookieConsent.init(); + } + window.CookieConsent = CookieConsent; +})(); \ No newline at end of file diff --git a/src/public/themes/blog/assets/js/front.min.js b/src/public/themes/blog/assets/js/front.min.js new file mode 100755 index 000000000..069d28fec --- /dev/null +++ b/src/public/themes/blog/assets/js/front.min.js @@ -0,0 +1,55 @@ +$(document).ready(function () { + 'use strict'; + var stylesheet = $('link#theme-stylesheet'); + $( "" ).insertAfter(stylesheet); + var alternateColour = $('link#new-stylesheet'); + if ($.cookie("theme_csspath")) { + alternateColour.attr("href", $.cookie("theme_csspath")); + } + $("#colour").change(function () { + if ($(this).val() !== '') { + var theme_csspath = 'css/style.' + $(this).val() + '.css'; + alternateColour.attr("href", theme_csspath); + $.cookie("theme_csspath", theme_csspath, { expires: 365, path: document.URL.substr(0, document.URL.lastIndexOf('/')) }); + } + return false; + }); + function equalizeHeight(x, y) { + var textHeight = $(x).height(); + $(y).css('min-height', textHeight); + } + equalizeHeight('.featured-posts .text', '.featured-posts .image'); + $(window).resize(function () { + equalizeHeight('.featured-posts .text', '.featured-posts .image'); + }); + $('.link-scroll').bind('click', function (e) { + var anchor = $(this); + $('html, body').stop().animate({ + scrollTop: $(anchor.attr('href')).offset().top + 2 + }, 700); + e.preventDefault(); + }); + $("[data-fancybox]").fancybox(); + $(window).on('scroll', function () { + var scroll = $(this).scrollTop(); + if ($(window).width() > 1250) { + $('section.divider').css({ + 'background-position': 'left -' + scroll / 8 + 'px' + }); + } else { + $('section.divider').css({ + 'background-position': 'center bottom' + }); + } + }); + $('.search-btn').on('click', function (e) { + e.preventDefault(); + $('.search-area').fadeIn(); + }); + $('.search-area .close-btn').on('click', function () { + $('.search-area').fadeOut(); + }); + $('.navbar-toggler').on('click', function () { + $('.navbar-toggler').toggleClass('active'); + }); +}); \ No newline at end of file diff --git a/src/public/themes/blog/assets/js/html5shiv.min.js b/src/public/themes/blog/assets/js/html5shiv.min.js new file mode 100755 index 000000000..47a2266d2 --- /dev/null +++ b/src/public/themes/blog/assets/js/html5shiv.min.js @@ -0,0 +1,183 @@ +;(function(window, document) { + + var version = '3.7.3'; + + var options = window.html5 || {}; + + var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i; + + var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i; + + var supportsHtml5Styles; + + var expando = '_html5shiv'; + + var expanID = 0; + + var expandoData = {}; + + var supportsUnknownElements; + (function() { + try { + var a = document.createElement('a'); + a.innerHTML = ''; + supportsHtml5Styles = ('hidden' in a); + supportsUnknownElements = a.childNodes.length == 1 || (function() { + (document.createElement)('a'); + var frag = document.createDocumentFragment(); + return ( + typeof frag.cloneNode == 'undefined' || + typeof frag.createDocumentFragment == 'undefined' || + typeof frag.createElement == 'undefined' + ); + }()); + } catch(e) { + supportsHtml5Styles = true; + supportsUnknownElements = true; + } + }()); + + + function addStyleSheet(ownerDocument, cssText) { + var p = ownerDocument.createElement('p'), + parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement; + p.innerHTML = 'x'; + return parent.insertBefore(p.lastChild, parent.firstChild); + } + + function getElements() { + var elements = html5.elements; + return typeof elements == 'string' ? elements.split(' ') : elements; + } + + function addElements(newElements, ownerDocument) { + var elements = html5.elements; + if(typeof elements != 'string'){ + elements = elements.join(' '); + } + if(typeof newElements != 'string'){ + newElements = newElements.join(' '); + } + html5.elements = elements +' '+ newElements; + shivDocument(ownerDocument); + } + + function getExpandoData(ownerDocument) { + var data = expandoData[ownerDocument[expando]]; + if (!data) { + data = {}; + expanID++; + ownerDocument[expando] = expanID; + expandoData[expanID] = data; + } + return data; + } + + function createElement(nodeName, ownerDocument, data){ + if (!ownerDocument) { + ownerDocument = document; + } + if(supportsUnknownElements){ + return ownerDocument.createElement(nodeName); + } + if (!data) { + data = getExpandoData(ownerDocument); + } + var node; + if (data.cache[nodeName]) { + node = data.cache[nodeName].cloneNode(); + } else if (saveClones.test(nodeName)) { + node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode(); + } else { + node = data.createElem(nodeName); + } + return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node; + } + + function createDocumentFragment(ownerDocument, data){ + if (!ownerDocument) { + ownerDocument = document; + } + if(supportsUnknownElements){ + return ownerDocument.createDocumentFragment(); + } + data = data || getExpandoData(ownerDocument); + var clone = data.frag.cloneNode(), + i = 0, + elems = getElements(), + l = elems.length; + for(;i
    '); + var $el = $this.find('.js-marquee').css({ + 'margin-right': o.gap, + 'float': 'left' + }); + if (o.duplicated) { + $el.clone(true).appendTo($this); + } + $this.wrapInner('
    '); + $marqueeWrapper = $this.find('.js-marquee-wrapper'); + if (verticalDir) { + var containerHeight = $this.height(); + $marqueeWrapper.removeAttr('style'); + $this.height(containerHeight); + $this.find('.js-marquee').css({ + 'float': 'none', + 'margin-bottom': o.gap, + 'margin-right': 0 + }); + if (o.duplicated) { + $this.find('.js-marquee:last').css({ + 'margin-bottom': 0 + }); + } + var elHeight = $this.find('.js-marquee:first').height() + o.gap; + if (o.startVisible && !o.duplicated) { + o._completeDuration = ((parseInt(elHeight, 10) + parseInt(containerHeight, 10)) / parseInt(containerHeight, 10)) * o.duration; + o.duration = (parseInt(elHeight, 10) / parseInt(containerHeight, 10)) * o.duration; + } else { + o.duration = ((parseInt(elHeight, 10) + parseInt(containerHeight, 10)) / parseInt(containerHeight, 10)) * o.duration; + } + } else { + elWidth = $this.find('.js-marquee:first').width() + o.gap; + containerWidth = $this.width(); + if (o.startVisible && !o.duplicated) { + o._completeDuration = ((parseInt(elWidth, 10) + parseInt(containerWidth, 10)) / parseInt(containerWidth, 10)) * o.duration; + o.duration = (parseInt(elWidth, 10) / parseInt(containerWidth, 10)) * o.duration; + } else { + o.duration = ((parseInt(elWidth, 10) + parseInt(containerWidth, 10)) / parseInt(containerWidth, 10)) * o.duration; + } + } + if (o.duplicated) { + o.duration = o.duration / 2; + } + if (o.allowCss3Support) { + var elm = document.body || document.createElement('div'), + animationName = 'marqueeAnimation-' + Math.floor(Math.random() * 10000000), + domPrefixes = 'Webkit Moz O ms Khtml'.split(' '), + animationString = 'animation', + animationCss3Str = '', + keyframeString = ''; + if (elm.style.animation !== undefined) { + keyframeString = '@keyframes ' + animationName + ' '; + css3AnimationIsSupported = true; + } + if (css3AnimationIsSupported === false) { + for (var i = 0; i < domPrefixes.length; i++) { + if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) { + var prefix = '-' + domPrefixes[i].toLowerCase() + '-'; + animationString = prefix + animationString; + playState = prefix + playState; + keyframeString = '@' + prefix + 'keyframes ' + animationName + ' '; + css3AnimationIsSupported = true; + break; + } + } + } + if (css3AnimationIsSupported) { + animationCss3Str = animationName + ' ' + o.duration / 1000 + 's ' + o.delayBeforeStart / 1000 + 's infinite ' + o.css3easing; + $this.data('css3AnimationIsSupported', true); + } + } + var _rePositionVertically = function() { + $marqueeWrapper.css('transform', 'translateY(' + (o.direction === 'up' ? containerHeight + 'px' : '-' + elHeight + 'px') + ')'); + }, + _rePositionHorizontally = function() { + $marqueeWrapper.css('transform', 'translateX(' + (o.direction === 'left' ? containerWidth + 'px' : '-' + elWidth + 'px') + ')'); + }; + if (o.duplicated) { + if (verticalDir) { + if (o.startVisible) { + $marqueeWrapper.css('transform', 'translateY(0)'); + } else { + $marqueeWrapper.css('transform', 'translateY(' + (o.direction === 'up' ? containerHeight + 'px' : '-' + ((elHeight * 2) - o.gap) + 'px') + ')'); + } + } else { + if (o.startVisible) { + $marqueeWrapper.css('transform', 'translateX(0)'); + } else { + $marqueeWrapper.css('transform', 'translateX(' + (o.direction === 'left' ? containerWidth + 'px' : '-' + ((elWidth * 2) - o.gap) + 'px') + ')'); + } + } + if (!o.startVisible) { + loopCount = 1; + } + } else if (o.startVisible) { + loopCount = 2; + } else { + if (verticalDir) { + _rePositionVertically(); + } else { + _rePositionHorizontally(); + } + } + var animate = function() { + if (o.duplicated) { + if (loopCount === 1) { + o._originalDuration = o.duration; + if (verticalDir) { + o.duration = o.direction === 'up' ? o.duration + (containerHeight / ((elHeight) / o.duration)) : o.duration * 2; + } else { + o.duration = o.direction === 'left' ? o.duration + (containerWidth / ((elWidth) / o.duration)) : o.duration * 2; + } + if (animationCss3Str) { + animationCss3Str = animationName + ' ' + o.duration / 1000 + 's ' + o.delayBeforeStart / 1000 + 's ' + o.css3easing; + } + loopCount++; + } + else if (loopCount === 2) { + o.duration = o._originalDuration; + if (animationCss3Str) { + animationName = animationName + '0'; + keyframeString = $.trim(keyframeString) + '0 '; + animationCss3Str = animationName + ' ' + o.duration / 1000 + 's 0s infinite ' + o.css3easing; + } + loopCount++; + } + } + if (verticalDir) { + if (o.duplicated) { + if (loopCount > 2) { + $marqueeWrapper.css('transform', 'translateY(' + (o.direction === 'up' ? 0 : '-' + elHeight + 'px') + ')'); + } + animationCss = { + 'transform': 'translateY(' + (o.direction === 'up' ? '-' + elHeight + 'px' : 0) + ')' + }; + } else if (o.startVisible) { + if (loopCount === 2) { + if (animationCss3Str) { + animationCss3Str = animationName + ' ' + o.duration / 1000 + 's ' + o.delayBeforeStart / 1000 + 's ' + o.css3easing; + } + animationCss = { + 'transform': 'translateY(' + (o.direction === 'up' ? '-' + elHeight + 'px' : containerHeight + 'px') + ')' + }; + loopCount++; + } else if (loopCount === 3) { + o.duration = o._completeDuration; + if (animationCss3Str) { + animationName = animationName + '0'; + keyframeString = $.trim(keyframeString) + '0 '; + animationCss3Str = animationName + ' ' + o.duration / 1000 + 's 0s infinite ' + o.css3easing; + } + _rePositionVertically(); + } + } else { + _rePositionVertically(); + animationCss = { + 'transform': 'translateY(' + (o.direction === 'up' ? '-' + ($marqueeWrapper.height()) + 'px' : containerHeight + 'px') + ')' + }; + } + } else { + if (o.duplicated) { + if (loopCount > 2) { + $marqueeWrapper.css('transform', 'translateX(' + (o.direction === 'left' ? 0 : '-' + elWidth + 'px') + ')'); + } + animationCss = { + 'transform': 'translateX(' + (o.direction === 'left' ? '-' + elWidth + 'px' : 0) + ')' + }; + } else if (o.startVisible) { + if (loopCount === 2) { + if (animationCss3Str) { + animationCss3Str = animationName + ' ' + o.duration / 1000 + 's ' + o.delayBeforeStart / 1000 + 's ' + o.css3easing; + } + animationCss = { + 'transform': 'translateX(' + (o.direction === 'left' ? '-' + elWidth + 'px' : containerWidth + 'px') + ')' + }; + loopCount++; + } else if (loopCount === 3) { + o.duration = o._completeDuration; + if (animationCss3Str) { + animationName = animationName + '0'; + keyframeString = $.trim(keyframeString) + '0 '; + animationCss3Str = animationName + ' ' + o.duration / 1000 + 's 0s infinite ' + o.css3easing; + } + _rePositionHorizontally(); + } + } else { + _rePositionHorizontally(); + animationCss = { + 'transform': 'translateX(' + (o.direction === 'left' ? '-' + elWidth + 'px' : containerWidth + 'px') + ')' + }; + } + } + $this.trigger('beforeStarting'); + if (css3AnimationIsSupported) { + $marqueeWrapper.css(animationString, animationCss3Str); + var keyframeCss = keyframeString + ' { 100% ' + _objToString(animationCss) + '}', + $styles = $marqueeWrapper.find('style'); + if ($styles.length !== 0) { + $styles.filter(":last").html(keyframeCss); + } else { + $('head').append(''); + } + _prefixedEvent($marqueeWrapper[0], "AnimationIteration", function() { + $this.trigger('finished'); + }); + _prefixedEvent($marqueeWrapper[0], "AnimationEnd", function() { + animate(); + $this.trigger('finished'); + }); + } else { + $marqueeWrapper.animate(animationCss, o.duration, o.easing, function() { + $this.trigger('finished'); + if (o.pauseOnCycle) { + _startAnimationWithDelay(); + } else { + animate(); + } + }); + } + $this.data('runningStatus', 'resumed'); + }; + $this.on('pause', methods.pause); + $this.on('resume', methods.resume); + if (o.pauseOnHover) { + $this.on('mouseenter', methods.pause); + $this.on('mouseleave', methods.resume); + } + if (css3AnimationIsSupported && o.allowCss3Support) { + animate(); + } else { + _startAnimationWithDelay(); + } + }); + }; // End of Plugin + $.fn.marquee.defaults = { + allowCss3Support: true, + css3easing: 'linear', + easing: 'linear', + delayBeforeStart: 1000, + direction: 'left', + duplicated: false, + duration: 5000, + speed: 0, + gap: 20, + pauseOnCycle: false, + pauseOnHover: false, + startVisible: false + }; +}); \ No newline at end of file diff --git a/src/public/themes/blog/assets/js/load-comment.js b/src/public/themes/blog/assets/js/load-comment.js old mode 100644 new mode 100755 diff --git a/src/public/themes/blog/assets/js/load-comment.min.js b/src/public/themes/blog/assets/js/load-comment.min.js new file mode 100755 index 000000000..1d4215042 --- /dev/null +++ b/src/public/themes/blog/assets/js/load-comment.min.js @@ -0,0 +1,55 @@ +$(document).ready(function () { + let offset = 0; + + const $commentsContainer = $("#comments"); + const $loadMoreBtn = $("#load-more"); + const post_id = window.CommentSettings?.postId; + const limit = window.CommentSettings?.limit ?? 3; // fallback just in case + if (!post_id) { + console.error("Post ID missing in #comments data attribute."); + $commentsContainer.html("

    Cannot load comments. Missing post ID.

    "); + $loadMoreBtn.hide(); + return; + } + function escapeHtml(text) { + return $('
    ').text(text).html(); + } + function loadComments() { + $.ajax({ + url: "/fetch-comments.php", + type: "GET", + data: { post_id: post_id, offset: offset }, + dataType: "json", + success: function (comments) { + if (Array.isArray(comments) && comments.length > 0) { + comments.forEach(comment => { + $commentsContainer.append(` +
    +
    +
    ${escapeHtml(comment.comment_author_name)}
    +

    ${escapeHtml(comment.comment_content)}

    +

    ${comment.comment_date}

    +
    +
    + `); + }); + offset += comments.length; + if (comments.length < limit) { + $loadMoreBtn.text("No More Comments").prop("disabled", true); + } + } else { + $loadMoreBtn.text("No More Comments").prop("disabled", true); + } + }, + error: function (xhr, status, error) { + console.error("Error loading comments:", error); + $commentsContainer.append(`

    Failed to load comments. Please try again later.

    `); + $loadMoreBtn.hide(); + } + }); + } + $loadMoreBtn.on("click", function () { + loadComments(); + }); + loadComments(); +}); \ No newline at end of file diff --git a/src/public/themes/blog/assets/js/rtl.js b/src/public/themes/blog/assets/js/rtl.js new file mode 100755 index 000000000..72f14385c --- /dev/null +++ b/src/public/themes/blog/assets/js/rtl.js @@ -0,0 +1,284 @@ +/** + * RTL (Right-to-Left) JavaScript Handler for Blogware Theme + * + * Handles dynamic RTL/LTR switching and related functionality. + * + * @version 1.0 + * @since 1.0 + */ + +(function() { + 'use strict'; + + /** + * RTL Manager Class + */ + var RTLManager = { + config: { + cookieName: 'scriptlog_locale_dir', + cookieExpiry: 365, + bodyClass: 'rtl', + defaultDirection: 'ltr' + }, + + /** + * Initialize RTL handling + */ + init: function() { + this.bindEvents(); + this.updateIcons(); + this.updateFormDirections(); + }, + + /** + * Bind event listeners + */ + bindEvents: function() { + var self = this; + + // Handle language switch + document.addEventListener('click', function(e) { + var target = e.target; + if (target.matches('[data-locale-switch]') || target.closest('[data-locale-switch]')) { + var locale = target.dataset.locale || target.closest('[data-locale-switch]').dataset.locale; + if (locale) { + self.switchLocale(locale); + } + } + }); + + // Handle direction toggle + document.addEventListener('click', function(e) { + if (e.target.matches('[data-toggle-direction]') || e.target.closest('[data-toggle-direction]')) { + e.preventDefault(); + self.toggleDirection(); + } + }); + + // Listen for custom direction change events + document.addEventListener('scriptlog:direction:change', function(e) { + if (e.detail && e.detail.direction) { + self.setDirection(e.detail.direction); + } + }); + + // Listen for locale change events + document.addEventListener('scriptlog:locale:change', function(e) { + if (e.detail && e.detail.locale) { + self.onLocaleChange(e.detail.locale); + } + }); + }, + + /** + * Check if current direction is RTL + */ + isRtl: function() { + return document.documentElement.dir === 'rtl' || + document.body.classList.contains(this.config.bodyClass); + }, + + /** + * Get current direction + */ + getDirection: function() { + return this.isRtl() ? 'rtl' : 'ltr'; + }, + + /** + * Set document direction + */ + setDirection: function(direction) { + var isRtl = direction === 'rtl'; + + // Update document dir attribute + document.documentElement.dir = direction; + document.documentElement.lang = direction === 'rtl' ? 'ar' : 'en'; + + // Toggle body class + if (isRtl) { + document.body.classList.add(this.config.bodyClass); + } else { + document.body.classList.remove(this.config.bodyClass); + } + + // Update meta viewport for RTL + this.updateMetaViewport(direction); + + // Save preference + this.savePreference(direction); + + // Dispatch event + this.dispatchEvent('scriptlog:direction:changed', { direction: direction }); + }, + + /** + * Toggle between RTL and LTR + */ + toggleDirection: function() { + var newDirection = this.isRtl() ? 'ltr' : 'rtl'; + this.setDirection(newDirection); + }, + + /** + * Switch locale and update direction accordingly + */ + switchLocale: function(locale) { + var rtlLocales = ['ar', 'he', 'fa', 'ur']; + var direction = rtlLocales.indexOf(locale) !== -1 ? 'rtl' : 'ltr'; + + this.setDirection(direction); + this.saveLocaleCookie(locale); + }, + + /** + * Handle locale change event + */ + onLocaleChange: function(locale) { + var rtlLocales = ['ar', 'he', 'fa', 'ur']; + var direction = rtlLocales.indexOf(locale) !== -1 ? 'rtl' : 'ltr'; + + this.setDirection(direction); + this.updateIcons(); + }, + + /** + * Update meta viewport tag for RTL + */ + updateMetaViewport: function(direction) { + var meta = document.querySelector('meta[name="viewport"]'); + if (meta) { + var content = meta.getAttribute('content'); + if (direction === 'rtl') { + // For RTL, we might want to adjust viewport + // Most modern devices handle this automatically + } + } + }, + + /** + * Save direction preference to cookie + */ + savePreference: function(direction) { + var expires = new Date(); + expires.setTime(expires.getTime() + (this.config.cookieExpiry * 24 * 60 * 60 * 1000)); + document.cookie = this.config.cookieName + '=' + direction + + ';expires=' + expires.toUTCString() + + ';path=/'; + }, + + /** + * Save locale cookie + */ + saveLocaleCookie: function(locale) { + var expires = new Date(); + expires.setTime(expires.getTime() + (365 * 24 * 60 * 60 * 1000)); + document.cookie = 'scriptlog_locale=' + locale + + ';expires=' + expires.toUTCString() + + ';path=/'; + }, + + /** + * Load saved direction preference + */ + loadPreference: function() { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = cookies[i].trim(); + if (cookie.indexOf(this.config.cookieName) === 0) { + return cookie.split('=')[1]; + } + } + return null; + }, + + /** + * Update FontAwesome icons for RTL + */ + updateIcons: function() { + if (!this.isRtl()) return; + + var self = this; + var iconMap = { + 'fa-arrow-left': 'fa-arrow-right', + 'fa-arrow-right': 'fa-arrow-left', + 'fa-chevron-left': 'fa-chevron-right', + 'fa-chevron-right': 'fa-chevron-left', + 'fa-angle-left': 'fa-angle-right', + 'fa-angle-right': 'fa-angle-left', + 'fa-long-arrow-left': 'fa-long-arrow-right', + 'fa-long-arrow-right': 'fa-long-arrow-left' + }; + + Object.keys(iconMap).forEach(function(oldClass) { + var newClass = iconMap[oldClass]; + var elements = document.querySelectorAll('.' + oldClass); + elements.forEach(function(el) { + el.classList.remove(oldClass); + el.classList.add(newClass); + }); + }); + }, + + /** + * Update form directions + */ + updateFormDirections: function() { + var inputs = document.querySelectorAll('input, textarea, select'); + inputs.forEach(function(input) { + // Don't override explicit direction settings + if (!input.hasAttribute('dir')) { + input.dir = 'auto'; + } + }); + }, + + /** + * Dispatch custom event + */ + dispatchEvent: function(eventName, detail) { + var event; + if (typeof CustomEvent === 'function') { + event = new CustomEvent(eventName, { detail: detail }); + } else { + event = document.createEvent('CustomEvent'); + event.initCustomEvent(eventName, true, true, detail); + } + document.dispatchEvent(event); + } + }; + + /** + * Initialize when DOM is ready + */ + function init() { + // Check for saved preference + var savedDirection = RTLManager.loadPreference(); + if (savedDirection) { + RTLManager.setDirection(savedDirection); + } + + // Initialize RTL Manager + RTLManager.init(); + } + + // Initialize on DOM ready + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } + + // Expose globally + window.RTLManager = RTLManager; + + // Expose helper function + window.isRtl = function() { + return RTLManager.isRtl(); + }; + + window.toggleDirection = function() { + RTLManager.toggleDirection(); + }; + +})(); diff --git a/src/public/themes/blog/assets/js/rtl.min.js b/src/public/themes/blog/assets/js/rtl.min.js new file mode 100755 index 000000000..05c2c6818 --- /dev/null +++ b/src/public/themes/blog/assets/js/rtl.min.js @@ -0,0 +1,190 @@ +(function() { + 'use strict'; + + var RTLManager = { + config: { + cookieName: 'scriptlog_locale_dir', + cookieExpiry: 365, + bodyClass: 'rtl', + defaultDirection: 'ltr' + }, + + init: function() { + this.bindEvents(); + this.updateIcons(); + this.updateFormDirections(); + }, + + bindEvents: function() { + var self = this; + document.addEventListener('click', function(e) { + var target = e.target; + if (target.matches('[data-locale-switch]') || target.closest('[data-locale-switch]')) { + var locale = target.dataset.locale || target.closest('[data-locale-switch]').dataset.locale; + if (locale) { + self.switchLocale(locale); + } + } + }); + document.addEventListener('click', function(e) { + if (e.target.matches('[data-toggle-direction]') || e.target.closest('[data-toggle-direction]')) { + e.preventDefault(); + self.toggleDirection(); + } + }); + document.addEventListener('scriptlog:direction:change', function(e) { + if (e.detail && e.detail.direction) { + self.setDirection(e.detail.direction); + } + }); + document.addEventListener('scriptlog:locale:change', function(e) { + if (e.detail && e.detail.locale) { + self.onLocaleChange(e.detail.locale); + } + }); + }, + + isRtl: function() { + return document.documentElement.dir === 'rtl' || + document.body.classList.contains(this.config.bodyClass); + }, + + getDirection: function() { + return this.isRtl() ? 'rtl' : 'ltr'; + }, + + setDirection: function(direction) { + var isRtl = direction === 'rtl'; + document.documentElement.dir = direction; + document.documentElement.lang = direction === 'rtl' ? 'ar' : 'en'; + if (isRtl) { + document.body.classList.add(this.config.bodyClass); + } else { + document.body.classList.remove(this.config.bodyClass); + } + this.updateMetaViewport(direction); + this.savePreference(direction); + this.dispatchEvent('scriptlog:direction:changed', { direction: direction }); + }, + + toggleDirection: function() { + var newDirection = this.isRtl() ? 'ltr' : 'rtl'; + this.setDirection(newDirection); + }, + + switchLocale: function(locale) { + var rtlLocales = ['ar', 'he', 'fa', 'ur']; + var direction = rtlLocales.indexOf(locale) !== -1 ? 'rtl' : 'ltr'; + + this.setDirection(direction); + this.saveLocaleCookie(locale); + }, + + onLocaleChange: function(locale) { + var rtlLocales = ['ar', 'he', 'fa', 'ur']; + var direction = rtlLocales.indexOf(locale) !== -1 ? 'rtl' : 'ltr'; + + this.setDirection(direction); + this.updateIcons(); + }, + + updateMetaViewport: function(direction) { + var meta = document.querySelector('meta[name="viewport"]'); + if (meta) { + var content = meta.getAttribute('content'); + if (direction === 'rtl') { + } + } + }, + + savePreference: function(direction) { + var expires = new Date(); + expires.setTime(expires.getTime() + (this.config.cookieExpiry * 24 * 60 * 60 * 1000)); + document.cookie = this.config.cookieName + '=' + direction + + ';expires=' + expires.toUTCString() + + ';path=/'; + }, + + saveLocaleCookie: function(locale) { + var expires = new Date(); + expires.setTime(expires.getTime() + (365 * 24 * 60 * 60 * 1000)); + document.cookie = 'scriptlog_locale=' + locale + + ';expires=' + expires.toUTCString() + + ';path=/'; + }, + + loadPreference: function() { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = cookies[i].trim(); + if (cookie.indexOf(this.config.cookieName) === 0) { + return cookie.split('=')[1]; + } + } + return null; + }, + + updateIcons: function() { + if (!this.isRtl()) return; + var self = this; + var iconMap = { + 'fa-arrow-left': 'fa-arrow-right', + 'fa-arrow-right': 'fa-arrow-left', + 'fa-chevron-left': 'fa-chevron-right', + 'fa-chevron-right': 'fa-chevron-left', + 'fa-angle-left': 'fa-angle-right', + 'fa-angle-right': 'fa-angle-left', + 'fa-long-arrow-left': 'fa-long-arrow-right', + 'fa-long-arrow-right': 'fa-long-arrow-left' + }; + Object.keys(iconMap).forEach(function(oldClass) { + var newClass = iconMap[oldClass]; + var elements = document.querySelectorAll('.' + oldClass); + elements.forEach(function(el) { + el.classList.remove(oldClass); + el.classList.add(newClass); + }); + }); + }, + + updateFormDirections: function() { + var inputs = document.querySelectorAll('input, textarea, select'); + inputs.forEach(function(input) { + if (!input.hasAttribute('dir')) { + input.dir = 'auto'; + } + }); + }, + + dispatchEvent: function(eventName, detail) { + var event; + if (typeof CustomEvent === 'function') { + event = new CustomEvent(eventName, { detail: detail }); + } else { + event = document.createEvent('CustomEvent'); + event.initCustomEvent(eventName, true, true, detail); + } + document.dispatchEvent(event); + } + }; + + function init() { + var savedDirection = RTLManager.loadPreference(); + if (savedDirection) { + RTLManager.setDirection(savedDirection); + } + RTLManager.init(); + } + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } + window.RTLManager = RTLManager; + window.isRtl = function() { + return RTLManager.isRtl(); + }; + window.toggleDirection = function() { + RTLManager.toggleDirection(); + }; +})(); \ No newline at end of file diff --git a/src/public/themes/blog/assets/js/search.js b/src/public/themes/blog/assets/js/search.js new file mode 100755 index 000000000..9fae9752a --- /dev/null +++ b/src/public/themes/blog/assets/js/search.js @@ -0,0 +1,168 @@ +/** + * AJAX Search Functionality + * Handles search form submission via AJAX + * + * Security features: + * - CSRF token protection + * - Input sanitization (server-side) + * - XSS prevention in results + */ +(function($) { + 'use strict'; + + var SearchWidget = { + timer: null, + minLength: 2, + delay: 300, + + init: function() { + this.form = $('#ajax-search-form'); + this.input = $('#search-keyword'); + this.results = $('#search-results'); + this.error = $('#search-error'); + this.csrf = $('#search-csrf'); + + if (this.form.length === 0) { + return; + } + + this.bindEvents(); + }, + + bindEvents: function() { + var self = this; + + this.input.on('input', function() { + clearTimeout(self.timer); + var keyword = $(this).val().trim(); + + if (keyword.length < self.minLength) { + self.hideResults(); + return; + } + + self.timer = setTimeout(function() { + self.performSearch(keyword); + }, self.delay); + }); + + this.form.on('submit', function(e) { + e.preventDefault(); + var keyword = self.input.val().trim(); + + if (keyword.length >= self.minLength) { + self.performSearch(keyword); + } + }); + + $(document).on('click', function(e) { + if (!$(e.target).closest('.widget.search').length) { + self.hideResults(); + } + }); + }, + + performSearch: function(keyword) { + var self = this; + + this.showLoading(); + + $.ajax({ + url: scriptlog_vars.api_url + '/search', + type: 'GET', + data: { + q: keyword, + type: 'all' + }, + dataType: 'json', + success: function(response) { + if (response.success) { + self.displayResults(response.data); + } else { + self.showError(response.message || 'Search failed'); + } + }, + error: function(xhr, status, error) { + var message = 'An error occurred during search: ' + error; + try { + var response = JSON.parse(xhr.responseText); + if (response.message) { + message = response.message; + } + if (response.error) { + message += ' - ' + response.error; + } + } catch (e) { + message += ' (Response: ' + xhr.responseText + ')'; + } + self.showError(message); + } + }); + }, + + displayResults: function(data) { + this.hideError(); + + if (!data.results || data.results.length === 0) { + this.results.html( + '
    ' + + 'No results found for "' + this.escapeHtml(data.keyword) + '"' + + '
    ' + ).addClass('show'); + return; + } + + var html = '
    Found ' + data.total + ' result(s)
    '; + + var self = this; + $.each(data.results.slice(0, 10), function(index, item) { + var typeLabel = item.type === 'page' ? 'Page' : 'Post'; + html += + ''; + }); + + if (data.results.length > 10) { + html += ''; + } + + this.results.html(html).addClass('show'); + }, + + showLoading: function() { + this.results.html('
    Searching...
    ').addClass('show'); + }, + + showError: function(message) { + this.results.removeClass('show'); + this.error.text(message).addClass('show'); + }, + + hideError: function() { + this.error.removeClass('show').text(''); + }, + + hideResults: function() { + this.results.removeClass('show'); + }, + + escapeHtml: function(text) { + if (!text) return ''; + var div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } + }; + + $(document).ready(function() { + SearchWidget.init(); + }); + +})(jQuery); diff --git a/src/public/themes/blog/assets/js/search.min.js b/src/public/themes/blog/assets/js/search.min.js new file mode 100755 index 000000000..752d087bc --- /dev/null +++ b/src/public/themes/blog/assets/js/search.min.js @@ -0,0 +1,159 @@ +(function($) { + 'use strict'; + + var SearchWidget = { + timer: null, + minLength: 2, + delay: 300, + + init: function() { + this.form = $('#ajax-search-form'); + this.input = $('#search-keyword'); + this.results = $('#search-results'); + this.error = $('#search-error'); + this.csrf = $('#search-csrf'); + + if (this.form.length === 0) { + return; + } + + this.bindEvents(); + }, + + bindEvents: function() { + var self = this; + + this.input.on('input', function() { + clearTimeout(self.timer); + var keyword = $(this).val().trim(); + + if (keyword.length < self.minLength) { + self.hideResults(); + return; + } + + self.timer = setTimeout(function() { + self.performSearch(keyword); + }, self.delay); + }); + + this.form.on('submit', function(e) { + e.preventDefault(); + var keyword = self.input.val().trim(); + + if (keyword.length >= self.minLength) { + self.performSearch(keyword); + } + }); + + $(document).on('click', function(e) { + if (!$(e.target).closest('.widget.search').length) { + self.hideResults(); + } + }); + }, + + performSearch: function(keyword) { + var self = this; + + this.showLoading(); + + $.ajax({ + url: scriptlog_vars.api_url + '/search', + type: 'GET', + data: { + q: keyword, + type: 'all' + }, + dataType: 'json', + success: function(response) { + if (response.success) { + self.displayResults(response.data); + } else { + self.showError(response.message || 'Search failed'); + } + }, + error: function(xhr, status, error) { + var message = 'An error occurred during search: ' + error; + try { + var response = JSON.parse(xhr.responseText); + if (response.message) { + message = response.message; + } + if (response.error) { + message += ' - ' + response.error; + } + } catch (e) { + message += ' (Response: ' + xhr.responseText + ')'; + } + self.showError(message); + } + }); + }, + + displayResults: function(data) { + this.hideError(); + + if (!data.results || data.results.length === 0) { + this.results.html( + '
    ' + + 'No results found for "' + this.escapeHtml(data.keyword) + '"' + + '
    ' + ).addClass('show'); + return; + } + + var html = '
    Found ' + data.total + ' result(s)
    '; + + var self = this; + $.each(data.results.slice(0, 10), function(index, item) { + var typeLabel = item.type === 'page' ? 'Page' : 'Post'; + html += + ''; + }); + + if (data.results.length > 10) { + html += ''; + } + + this.results.html(html).addClass('show'); + }, + + showLoading: function() { + this.results.html('
    Searching...
    ').addClass('show'); + }, + + showError: function(message) { + this.results.removeClass('show'); + this.error.text(message).addClass('show'); + }, + + hideError: function() { + this.error.removeClass('show').text(''); + }, + + hideResults: function() { + this.results.removeClass('show'); + }, + + escapeHtml: function(text) { + if (!text) return ''; + var div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } + }; + + $(document).ready(function() { + SearchWidget.init(); + }); + +})(jQuery); \ No newline at end of file diff --git a/src/public/themes/blog/assets/js/sina-nav.min.js b/src/public/themes/blog/assets/js/sina-nav.min.js index 29ab0dd8f..051abacb3 100755 --- a/src/public/themes/blog/assets/js/sina-nav.min.js +++ b/src/public/themes/blog/assets/js/sina-nav.min.js @@ -1,7 +1,219 @@ -/** - * Template name: Sina-nav Multi Purpose Menu - * Template URI: https://github.com/shaonsina/sina-nav-4 - * Version: 2.2 - * Author: shaonsina - */ -!function(w){"use strict";w.fn.sinaNav=function(){return this.each(function(){var e=w(this),o=e.data("top")||e.offset().top,s=e.data("md-top")||e.offset().top,i=e.data("xl-top")||e.offset().top,n=e.find(".sina-menu"),a=w(window).outerWidth(),t=e.data("animate-prefix")||"",d=n.data("in"),l=n.data("out");if(w(window).on("resize",function(){a=w(window).outerWidth()}),e.find(".sina-menu").each(function(){var a=w(this);a.on("click",function(n){"A"==n.target.tagName&&(a.find("li.active").removeClass("active"),w(n.target).parent().addClass("active"))}),a.find("li.active").removeClass("active"),a.find('a[href="'+location.href+'"]').parent("li").addClass("active")}),e.hasClass("logo-center")){var r=e.find(".sina-menu"),c=r.clone(),f=r.children("li"),u=Math.round(f.length/2);r.empty(),c.empty();for(var m=0;m
    ');for(m=u;m
    ')}if(e.hasClass("mobile-sidebar")){var v=e.find(".navbar-collapse");w("body").children(".sina-nav-wrapper").length<1&&w("body").wrapInner('
    '),e.hasClass("navbar-reverse")?(v.on("shown.bs.collapse",function(){w("body").addClass("mobile-right")}),v.on("hide.bs.collapse",function(){w("body").removeClass("mobile-right")}),w(window).on("resize",function(){w("body").removeClass("mobile-right"),e.find(".navbar-collapse").removeClass("show"),e.find(".navbar-toggle .fa",this).removeClass("fa-times").addClass("fa-bars")})):(v.on("shown.bs.collapse",function(){w("body").addClass("mobile-left")}),v.on("hide.bs.collapse",function(){w("body").removeClass("mobile-left")}),w(window).on("resize",function(){w("body").removeClass("mobile-left"),e.find(".navbar-collapse").removeClass("show"),e.find(".navbar-toggle .fa",this).removeClass("fa-times").addClass("fa-bars")}))}function h(){var n=w(window).scrollTop(),a=w(window).outerWidth();1599o&&e.addClass("navbar-freez")),e.hasClass("navbar-transparent")&&(w(window).on("scroll",function(){p()}),w(window).on("resize",function(){p()}),1024o&&e.removeClass("navbar-transparent")),e.find(".extension-nav").each(function(){w(".search > a",this).on("click",function(n){n.preventDefault(),w(".search-box").slideToggle()})}),w(".search-addon.close-search").on("click",function(){w(".search-box").slideUp()}),e.find(".extension-nav").each(function(){w(".widget-bar-btn > a",this).on("click",function(n){n.preventDefault(),e.children(".sina-nav-overlay").fadeIn(400),e.children(".widget-bar").toggleClass("on")})}),e.find(".widget-bar .close-widget-bar").on("click",function(n){n.preventDefault(),e.children(".widget-bar").removeClass("on"),e.children(".sina-nav-overlay").fadeOut(600)}),e.children(".sina-nav-overlay").on("click",function(){e.children(".widget-bar").removeClass("on"),w(this).fadeOut(600)}),e.find(".navbar-toggle").on("click",function(){w(".fa",this).toggleClass("fa-bars").toggleClass("fa-times")}),e.find(".sina-menu, .extension-nav").each(function(){var n=this;w(".dropdown-toggle",n).on("click",function(n){return n.stopPropagation(),!1}),w(".dropdown-menu",n).addClass(t+"animated"),w(".dropdown",n).on("mouseenter",function(){w(".dropdown-menu",this).eq(0).removeClass(l).stop().fadeIn().addClass(d),w(this).addClass("on")}),w(".dropdown",n).on("mouseleave",function(){w(".dropdown-menu",this).eq(0).removeClass(d).stop().fadeOut().addClass(l),w(this).removeClass("on")}),w(".dropdown",n).on("focusin",function(){w(".dropdown-menu",this).eq(0).removeClass(l).stop().fadeIn().addClass(d),w(this).addClass("on")}),w(".dropdown",n).on("focusout",function(){w(".dropdown-menu",this).eq(0).removeClass(d).stop().fadeOut().addClass(l),w(this).removeClass("on")}),w(".mega-menu-col",n).children(".sub-menu").removeClass("dropdown-menu "+t+"animated")}),a<1025&&e.find(".menu-item-has-mega-menu").each(function(){var n=this,a=[];w(".mega-menu-col",n).children(".sub-menu").addClass("dropdown-menu "+t+"animated"),w(".mega-menu-col",n).each(function(){var n=this;w(".mega-menu-col-title",n).on("mouseenter",function(){w(this).closest(".mega-menu-col").addClass("on"),w(this).siblings(".sub-menu").stop().fadeIn().addClass(d)}),w(n).children().is(".mega-menu-col-title")||a.push(w(n).children(".sub-menu"))}),w(n).on("mouseenter",function(){var n;for(n in a)a[n].stop().fadeIn().addClass(d)}),w(n).on("mouseleave",function(){w(".dropdown-menu",n).stop().fadeOut().removeClass(d),w(".mega-menu-col",n).removeClass("on")})})})},w(".sina-nav").sinaNav()}(jQuery); \ No newline at end of file +(function ($) { + 'use strict'; + $.fn.sinaNav = function () { + return this.each( function() { + let getNav = $(this), + top = getNav.data('top') || getNav.offset().top, + mdTop = getNav.data('md-top') || getNav.offset().top, + xlTop = getNav.data('xl-top') || getNav.offset().top, + navigation = getNav.find('.sina-menu'), + getWindow = $(window).outerWidth(), + anim = getNav.data('animate-prefix') || '', + getIn = navigation.data('in'), + getOut = navigation.data('out'); + $(window).on('resize', function(){ + getWindow = $(window).outerWidth(); + }); + getNav.find('.sina-menu').each(function(){ + let $menu = $(this); + $menu.on('click', function(e) { + if ( 'A' == e.target.tagName ) { + $menu.find('li.active').removeClass('active'); + $(e.target).parent().addClass('active'); + } + }); + $menu.find('li.active').removeClass('active'); + $menu.find( 'a[href="'+ location.href +'"]' ).parent('li').addClass('active'); + }); + if( getNav.hasClass('logo-center')){ + let mainNav = getNav.find('.sina-menu'), + rightNav = mainNav.clone(), + lists = mainNav.children('li'), + divided = Math.round(lists.length / 2); + mainNav.empty(); + rightNav.empty(); + for (let i = 0; i < divided; i++) { + mainNav.append( lists[i] ); + } + mainNav.addClass('sina-menu-right').wrap('
    '); + for (let i = divided; i < lists.length; i++) { + rightNav.append( lists[i] ); + } + getNav.find('.col-half.left').after( rightNav.addClass('sina-menu-dropdown-right sina-menu-left') ); + rightNav.wrap('
    '); + } + if( getNav.hasClass('mobile-sidebar') ) { + let $collapse = getNav.find('.navbar-collapse'); + if ( $('body').children('.sina-nav-wrapper').length < 1 ) { + $('body').wrapInner('
    '); + } + if ( getNav.hasClass('navbar-reverse') ) { + $collapse.on('shown.bs.collapse', function() { + $('body').addClass('mobile-right'); + }); + $collapse.on('hide.bs.collapse', function() { + $('body').removeClass('mobile-right'); + }); + $(window).on('resize', function(){ + $('body').removeClass('mobile-right'); + getNav.find('.navbar-collapse').removeClass('show'); + getNav.find('.navbar-toggle .fa', this).removeClass('fa-times').addClass('fa-bars'); + }); + } + else{ + $collapse.on('shown.bs.collapse', function() { + $('body').addClass('mobile-left'); + }); + $collapse.on('hide.bs.collapse', function() { + $('body').removeClass('mobile-left'); + }); + $(window).on('resize', function(){ + $('body').removeClass('mobile-left'); + getNav.find('.navbar-collapse').removeClass('show'); + getNav.find('.navbar-toggle .fa', this).removeClass('fa-times').addClass('fa-bars'); + }); + } + } + function freezNav() { + let scrollTop = $(window).scrollTop(), + winWidth = $(window).outerWidth(); + if( winWidth > 1599 && scrollTop > xlTop ){ + getNav.addClass('navbar-freez'); + } + else if( winWidth < 1600 && winWidth > 1199 && scrollTop > top ){ + getNav.addClass('navbar-freez'); + } + else if( winWidth < 1200 && winWidth > 1024 && scrollTop > mdTop ){ + getNav.addClass('navbar-freez'); + } + else { + getNav.removeClass('navbar-freez'); + } + } + if( getNav.hasClass('navbar-fixed') ){ + $(window).on('scroll', function(){ + freezNav(); + }); + $(window).on('resize', function(){ + freezNav(); + }); + if ( getWindow > 1024 && $(window).scrollTop() > top ) { + getNav.addClass('navbar-freez'); + } + } + function transNav() { + let scrollTop = $(window).scrollTop(), + winWidth = $(window).outerWidth(); + if( winWidth > 1599 && scrollTop > xlTop ){ + getNav.removeClass('navbar-transparent'); + } + else if( winWidth < 1600 && winWidth > 1199 && scrollTop > top ){ + getNav.removeClass('navbar-transparent'); + } + else if( winWidth < 1200 && winWidth > 1024 && scrollTop > mdTop ){ + getNav.removeClass('navbar-transparent'); + } + else { + getNav.addClass('navbar-transparent'); + } + } + if( getNav.hasClass('navbar-transparent') ){ + $(window).on('scroll', function(){ + transNav(); + }); + $(window).on('resize', function(){ + transNav(); + }); + if ( getWindow > 1024 && $(window).scrollTop() > top ) { + getNav.removeClass('navbar-transparent'); + } + } + getNav.find('.extension-nav').each(function(){ + $('.search > a', this).on('click', function(e){ + e.preventDefault(); + $('.search-box').slideToggle(); + }); + }); + $('.search-addon.close-search').on('click', function(){ + $('.search-box').slideUp(); + }); + getNav.find('.extension-nav').each(function(){ + $('.widget-bar-btn > a', this).on('click', function(e){ + e.preventDefault(); + getNav.children('.sina-nav-overlay').fadeIn(400); + getNav.children('.widget-bar').toggleClass('on'); + }); + }); + getNav.find('.widget-bar .close-widget-bar').on('click', function(e){ + e.preventDefault(); + getNav.children('.widget-bar').removeClass('on'); + getNav.children('.sina-nav-overlay').fadeOut(600); + }); + getNav.children('.sina-nav-overlay').on('click', function() { + getNav.children('.widget-bar').removeClass('on'); + $(this).fadeOut(600); + }); + getNav.find('.navbar-toggle').on('click', function(){ + $('.fa', this).toggleClass('fa-bars').toggleClass('fa-times'); + }); + getNav.find('.sina-menu, .extension-nav').each(function(){ + let menu = this; + $('.dropdown-toggle', menu).on('click', function (e) { + e.stopPropagation(); + return false; + }); + $('.dropdown-menu', menu).addClass(anim+'animated'); + $('.dropdown', menu).on('mouseenter', function(){ + let dropdown = this; + $('.dropdown-menu', dropdown).eq(0).removeClass(getOut).stop().fadeIn().addClass(getIn); + $(dropdown).addClass('on'); + }); + $('.dropdown', menu).on('mouseleave', function(){ + let dropdown = this; + $('.dropdown-menu', dropdown).eq(0).removeClass(getIn).stop().fadeOut().addClass(getOut); + $(dropdown).removeClass('on'); + }); + $('.dropdown', menu).on('focusin', function(){ + let dropdown = this; + $('.dropdown-menu', dropdown).eq(0).removeClass(getOut).stop().fadeIn().addClass(getIn); + $(dropdown).addClass('on'); + }); + $('.dropdown', menu).on('focusout', function(){ + let dropdown = this; + $('.dropdown-menu', dropdown).eq(0).removeClass(getIn).stop().fadeOut().addClass(getOut); + $(dropdown).removeClass('on'); + }); + $('.mega-menu-col', menu).children('.sub-menu').removeClass('dropdown-menu '+anim+'animated'); + }); + if( getWindow < 1025 ) { + getNav.find('.menu-item-has-mega-menu').each(function(){ + let megamenu = this, + $columnMenus = []; + $('.mega-menu-col', megamenu).children('.sub-menu').addClass('dropdown-menu '+anim+'animated'); + $('.mega-menu-col', megamenu).each(function(){ + let megamenuColumn = this; + $('.mega-menu-col-title', megamenuColumn).on('mouseenter', function(){ + let title = this; + $(title).closest('.mega-menu-col').addClass('on'); + $(title).siblings('.sub-menu').stop().fadeIn().addClass(getIn); + }); + if( !$(megamenuColumn).children().is('.mega-menu-col-title') ) { + $columnMenus.push( $(megamenuColumn).children('.sub-menu') ); + } + }); + $(megamenu).on('mouseenter', function(){ + let submenu; + for (submenu in $columnMenus) { + $columnMenus[ submenu ].stop().fadeIn().addClass(getIn); + } + }); + $(megamenu).on('mouseleave', function() { + $('.dropdown-menu', megamenu).stop().fadeOut().removeClass(getIn); + $('.mega-menu-col', megamenu).removeClass('on'); + }); + }); + } + }); + } + $('.sina-nav').sinaNav(); +}(jQuery)); \ No newline at end of file diff --git a/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap-grid.css b/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap-grid.css deleted file mode 100755 index 6798f23d2..000000000 --- a/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap-grid.css +++ /dev/null @@ -1,1912 +0,0 @@ -/*! - * Bootstrap Grid v4.1.0 (https://getbootstrap.com/) - * Copyright 2011-2018 The Bootstrap Authors - * Copyright 2011-2018 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ -@-ms-viewport { - width: device-width; -} - -html { - box-sizing: border-box; - -ms-overflow-style: scrollbar; -} - -*, -*::before, -*::after { - box-sizing: inherit; -} - -.container { - width: 100%; - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto; -} - -@media (min-width: 576px) { - .container { - max-width: 540px; - } -} - -@media (min-width: 768px) { - .container { - max-width: 720px; - } -} - -@media (min-width: 992px) { - .container { - max-width: 960px; - } -} - -@media (min-width: 1200px) { - .container { - max-width: 1140px; - } -} - -.container-fluid { - width: 100%; - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto; -} - -.row { - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - margin-right: -15px; - margin-left: -15px; -} - -.no-gutters { - margin-right: 0; - margin-left: 0; -} - -.no-gutters > .col, -.no-gutters > [class*="col-"] { - padding-right: 0; - padding-left: 0; -} - -.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col, -.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm, -.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md, -.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg, -.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl, -.col-xl-auto { - position: relative; - width: 100%; - min-height: 1px; - padding-right: 15px; - padding-left: 15px; -} - -.col { - -ms-flex-preferred-size: 0; - flex-basis: 0; - -ms-flex-positive: 1; - flex-grow: 1; - max-width: 100%; -} - -.col-auto { - -ms-flex: 0 0 auto; - flex: 0 0 auto; - width: auto; - max-width: none; -} - -.col-1 { - -ms-flex: 0 0 8.333333%; - flex: 0 0 8.333333%; - max-width: 8.333333%; -} - -.col-2 { - -ms-flex: 0 0 16.666667%; - flex: 0 0 16.666667%; - max-width: 16.666667%; -} - -.col-3 { - -ms-flex: 0 0 25%; - flex: 0 0 25%; - max-width: 25%; -} - -.col-4 { - -ms-flex: 0 0 33.333333%; - flex: 0 0 33.333333%; - max-width: 33.333333%; -} - -.col-5 { - -ms-flex: 0 0 41.666667%; - flex: 0 0 41.666667%; - max-width: 41.666667%; -} - -.col-6 { - -ms-flex: 0 0 50%; - flex: 0 0 50%; - max-width: 50%; -} - -.col-7 { - -ms-flex: 0 0 58.333333%; - flex: 0 0 58.333333%; - max-width: 58.333333%; -} - -.col-8 { - -ms-flex: 0 0 66.666667%; - flex: 0 0 66.666667%; - max-width: 66.666667%; -} - -.col-9 { - -ms-flex: 0 0 75%; - flex: 0 0 75%; - max-width: 75%; -} - -.col-10 { - -ms-flex: 0 0 83.333333%; - flex: 0 0 83.333333%; - max-width: 83.333333%; -} - -.col-11 { - -ms-flex: 0 0 91.666667%; - flex: 0 0 91.666667%; - max-width: 91.666667%; -} - -.col-12 { - -ms-flex: 0 0 100%; - flex: 0 0 100%; - max-width: 100%; -} - -.order-first { - -ms-flex-order: -1; - order: -1; -} - -.order-last { - -ms-flex-order: 13; - order: 13; -} - -.order-0 { - -ms-flex-order: 0; - order: 0; -} - -.order-1 { - -ms-flex-order: 1; - order: 1; -} - -.order-2 { - -ms-flex-order: 2; - order: 2; -} - -.order-3 { - -ms-flex-order: 3; - order: 3; -} - -.order-4 { - -ms-flex-order: 4; - order: 4; -} - -.order-5 { - -ms-flex-order: 5; - order: 5; -} - -.order-6 { - -ms-flex-order: 6; - order: 6; -} - -.order-7 { - -ms-flex-order: 7; - order: 7; -} - -.order-8 { - -ms-flex-order: 8; - order: 8; -} - -.order-9 { - -ms-flex-order: 9; - order: 9; -} - -.order-10 { - -ms-flex-order: 10; - order: 10; -} - -.order-11 { - -ms-flex-order: 11; - order: 11; -} - -.order-12 { - -ms-flex-order: 12; - order: 12; -} - -.offset-1 { - margin-left: 8.333333%; -} - -.offset-2 { - margin-left: 16.666667%; -} - -.offset-3 { - margin-left: 25%; -} - -.offset-4 { - margin-left: 33.333333%; -} - -.offset-5 { - margin-left: 41.666667%; -} - -.offset-6 { - margin-left: 50%; -} - -.offset-7 { - margin-left: 58.333333%; -} - -.offset-8 { - margin-left: 66.666667%; -} - -.offset-9 { - margin-left: 75%; -} - -.offset-10 { - margin-left: 83.333333%; -} - -.offset-11 { - margin-left: 91.666667%; -} - -@media (min-width: 576px) { - .col-sm { - -ms-flex-preferred-size: 0; - flex-basis: 0; - -ms-flex-positive: 1; - flex-grow: 1; - max-width: 100%; - } - .col-sm-auto { - -ms-flex: 0 0 auto; - flex: 0 0 auto; - width: auto; - max-width: none; - } - .col-sm-1 { - -ms-flex: 0 0 8.333333%; - flex: 0 0 8.333333%; - max-width: 8.333333%; - } - .col-sm-2 { - -ms-flex: 0 0 16.666667%; - flex: 0 0 16.666667%; - max-width: 16.666667%; - } - .col-sm-3 { - -ms-flex: 0 0 25%; - flex: 0 0 25%; - max-width: 25%; - } - .col-sm-4 { - -ms-flex: 0 0 33.333333%; - flex: 0 0 33.333333%; - max-width: 33.333333%; - } - .col-sm-5 { - -ms-flex: 0 0 41.666667%; - flex: 0 0 41.666667%; - max-width: 41.666667%; - } - .col-sm-6 { - -ms-flex: 0 0 50%; - flex: 0 0 50%; - max-width: 50%; - } - .col-sm-7 { - -ms-flex: 0 0 58.333333%; - flex: 0 0 58.333333%; - max-width: 58.333333%; - } - .col-sm-8 { - -ms-flex: 0 0 66.666667%; - flex: 0 0 66.666667%; - max-width: 66.666667%; - } - .col-sm-9 { - -ms-flex: 0 0 75%; - flex: 0 0 75%; - max-width: 75%; - } - .col-sm-10 { - -ms-flex: 0 0 83.333333%; - flex: 0 0 83.333333%; - max-width: 83.333333%; - } - .col-sm-11 { - -ms-flex: 0 0 91.666667%; - flex: 0 0 91.666667%; - max-width: 91.666667%; - } - .col-sm-12 { - -ms-flex: 0 0 100%; - flex: 0 0 100%; - max-width: 100%; - } - .order-sm-first { - -ms-flex-order: -1; - order: -1; - } - .order-sm-last { - -ms-flex-order: 13; - order: 13; - } - .order-sm-0 { - -ms-flex-order: 0; - order: 0; - } - .order-sm-1 { - -ms-flex-order: 1; - order: 1; - } - .order-sm-2 { - -ms-flex-order: 2; - order: 2; - } - .order-sm-3 { - -ms-flex-order: 3; - order: 3; - } - .order-sm-4 { - -ms-flex-order: 4; - order: 4; - } - .order-sm-5 { - -ms-flex-order: 5; - order: 5; - } - .order-sm-6 { - -ms-flex-order: 6; - order: 6; - } - .order-sm-7 { - -ms-flex-order: 7; - order: 7; - } - .order-sm-8 { - -ms-flex-order: 8; - order: 8; - } - .order-sm-9 { - -ms-flex-order: 9; - order: 9; - } - .order-sm-10 { - -ms-flex-order: 10; - order: 10; - } - .order-sm-11 { - -ms-flex-order: 11; - order: 11; - } - .order-sm-12 { - -ms-flex-order: 12; - order: 12; - } - .offset-sm-0 { - margin-left: 0; - } - .offset-sm-1 { - margin-left: 8.333333%; - } - .offset-sm-2 { - margin-left: 16.666667%; - } - .offset-sm-3 { - margin-left: 25%; - } - .offset-sm-4 { - margin-left: 33.333333%; - } - .offset-sm-5 { - margin-left: 41.666667%; - } - .offset-sm-6 { - margin-left: 50%; - } - .offset-sm-7 { - margin-left: 58.333333%; - } - .offset-sm-8 { - margin-left: 66.666667%; - } - .offset-sm-9 { - margin-left: 75%; - } - .offset-sm-10 { - margin-left: 83.333333%; - } - .offset-sm-11 { - margin-left: 91.666667%; - } -} - -@media (min-width: 768px) { - .col-md { - -ms-flex-preferred-size: 0; - flex-basis: 0; - -ms-flex-positive: 1; - flex-grow: 1; - max-width: 100%; - } - .col-md-auto { - -ms-flex: 0 0 auto; - flex: 0 0 auto; - width: auto; - max-width: none; - } - .col-md-1 { - -ms-flex: 0 0 8.333333%; - flex: 0 0 8.333333%; - max-width: 8.333333%; - } - .col-md-2 { - -ms-flex: 0 0 16.666667%; - flex: 0 0 16.666667%; - max-width: 16.666667%; - } - .col-md-3 { - -ms-flex: 0 0 25%; - flex: 0 0 25%; - max-width: 25%; - } - .col-md-4 { - -ms-flex: 0 0 33.333333%; - flex: 0 0 33.333333%; - max-width: 33.333333%; - } - .col-md-5 { - -ms-flex: 0 0 41.666667%; - flex: 0 0 41.666667%; - max-width: 41.666667%; - } - .col-md-6 { - -ms-flex: 0 0 50%; - flex: 0 0 50%; - max-width: 50%; - } - .col-md-7 { - -ms-flex: 0 0 58.333333%; - flex: 0 0 58.333333%; - max-width: 58.333333%; - } - .col-md-8 { - -ms-flex: 0 0 66.666667%; - flex: 0 0 66.666667%; - max-width: 66.666667%; - } - .col-md-9 { - -ms-flex: 0 0 75%; - flex: 0 0 75%; - max-width: 75%; - } - .col-md-10 { - -ms-flex: 0 0 83.333333%; - flex: 0 0 83.333333%; - max-width: 83.333333%; - } - .col-md-11 { - -ms-flex: 0 0 91.666667%; - flex: 0 0 91.666667%; - max-width: 91.666667%; - } - .col-md-12 { - -ms-flex: 0 0 100%; - flex: 0 0 100%; - max-width: 100%; - } - .order-md-first { - -ms-flex-order: -1; - order: -1; - } - .order-md-last { - -ms-flex-order: 13; - order: 13; - } - .order-md-0 { - -ms-flex-order: 0; - order: 0; - } - .order-md-1 { - -ms-flex-order: 1; - order: 1; - } - .order-md-2 { - -ms-flex-order: 2; - order: 2; - } - .order-md-3 { - -ms-flex-order: 3; - order: 3; - } - .order-md-4 { - -ms-flex-order: 4; - order: 4; - } - .order-md-5 { - -ms-flex-order: 5; - order: 5; - } - .order-md-6 { - -ms-flex-order: 6; - order: 6; - } - .order-md-7 { - -ms-flex-order: 7; - order: 7; - } - .order-md-8 { - -ms-flex-order: 8; - order: 8; - } - .order-md-9 { - -ms-flex-order: 9; - order: 9; - } - .order-md-10 { - -ms-flex-order: 10; - order: 10; - } - .order-md-11 { - -ms-flex-order: 11; - order: 11; - } - .order-md-12 { - -ms-flex-order: 12; - order: 12; - } - .offset-md-0 { - margin-left: 0; - } - .offset-md-1 { - margin-left: 8.333333%; - } - .offset-md-2 { - margin-left: 16.666667%; - } - .offset-md-3 { - margin-left: 25%; - } - .offset-md-4 { - margin-left: 33.333333%; - } - .offset-md-5 { - margin-left: 41.666667%; - } - .offset-md-6 { - margin-left: 50%; - } - .offset-md-7 { - margin-left: 58.333333%; - } - .offset-md-8 { - margin-left: 66.666667%; - } - .offset-md-9 { - margin-left: 75%; - } - .offset-md-10 { - margin-left: 83.333333%; - } - .offset-md-11 { - margin-left: 91.666667%; - } -} - -@media (min-width: 992px) { - .col-lg { - -ms-flex-preferred-size: 0; - flex-basis: 0; - -ms-flex-positive: 1; - flex-grow: 1; - max-width: 100%; - } - .col-lg-auto { - -ms-flex: 0 0 auto; - flex: 0 0 auto; - width: auto; - max-width: none; - } - .col-lg-1 { - -ms-flex: 0 0 8.333333%; - flex: 0 0 8.333333%; - max-width: 8.333333%; - } - .col-lg-2 { - -ms-flex: 0 0 16.666667%; - flex: 0 0 16.666667%; - max-width: 16.666667%; - } - .col-lg-3 { - -ms-flex: 0 0 25%; - flex: 0 0 25%; - max-width: 25%; - } - .col-lg-4 { - -ms-flex: 0 0 33.333333%; - flex: 0 0 33.333333%; - max-width: 33.333333%; - } - .col-lg-5 { - -ms-flex: 0 0 41.666667%; - flex: 0 0 41.666667%; - max-width: 41.666667%; - } - .col-lg-6 { - -ms-flex: 0 0 50%; - flex: 0 0 50%; - max-width: 50%; - } - .col-lg-7 { - -ms-flex: 0 0 58.333333%; - flex: 0 0 58.333333%; - max-width: 58.333333%; - } - .col-lg-8 { - -ms-flex: 0 0 66.666667%; - flex: 0 0 66.666667%; - max-width: 66.666667%; - } - .col-lg-9 { - -ms-flex: 0 0 75%; - flex: 0 0 75%; - max-width: 75%; - } - .col-lg-10 { - -ms-flex: 0 0 83.333333%; - flex: 0 0 83.333333%; - max-width: 83.333333%; - } - .col-lg-11 { - -ms-flex: 0 0 91.666667%; - flex: 0 0 91.666667%; - max-width: 91.666667%; - } - .col-lg-12 { - -ms-flex: 0 0 100%; - flex: 0 0 100%; - max-width: 100%; - } - .order-lg-first { - -ms-flex-order: -1; - order: -1; - } - .order-lg-last { - -ms-flex-order: 13; - order: 13; - } - .order-lg-0 { - -ms-flex-order: 0; - order: 0; - } - .order-lg-1 { - -ms-flex-order: 1; - order: 1; - } - .order-lg-2 { - -ms-flex-order: 2; - order: 2; - } - .order-lg-3 { - -ms-flex-order: 3; - order: 3; - } - .order-lg-4 { - -ms-flex-order: 4; - order: 4; - } - .order-lg-5 { - -ms-flex-order: 5; - order: 5; - } - .order-lg-6 { - -ms-flex-order: 6; - order: 6; - } - .order-lg-7 { - -ms-flex-order: 7; - order: 7; - } - .order-lg-8 { - -ms-flex-order: 8; - order: 8; - } - .order-lg-9 { - -ms-flex-order: 9; - order: 9; - } - .order-lg-10 { - -ms-flex-order: 10; - order: 10; - } - .order-lg-11 { - -ms-flex-order: 11; - order: 11; - } - .order-lg-12 { - -ms-flex-order: 12; - order: 12; - } - .offset-lg-0 { - margin-left: 0; - } - .offset-lg-1 { - margin-left: 8.333333%; - } - .offset-lg-2 { - margin-left: 16.666667%; - } - .offset-lg-3 { - margin-left: 25%; - } - .offset-lg-4 { - margin-left: 33.333333%; - } - .offset-lg-5 { - margin-left: 41.666667%; - } - .offset-lg-6 { - margin-left: 50%; - } - .offset-lg-7 { - margin-left: 58.333333%; - } - .offset-lg-8 { - margin-left: 66.666667%; - } - .offset-lg-9 { - margin-left: 75%; - } - .offset-lg-10 { - margin-left: 83.333333%; - } - .offset-lg-11 { - margin-left: 91.666667%; - } -} - -@media (min-width: 1200px) { - .col-xl { - -ms-flex-preferred-size: 0; - flex-basis: 0; - -ms-flex-positive: 1; - flex-grow: 1; - max-width: 100%; - } - .col-xl-auto { - -ms-flex: 0 0 auto; - flex: 0 0 auto; - width: auto; - max-width: none; - } - .col-xl-1 { - -ms-flex: 0 0 8.333333%; - flex: 0 0 8.333333%; - max-width: 8.333333%; - } - .col-xl-2 { - -ms-flex: 0 0 16.666667%; - flex: 0 0 16.666667%; - max-width: 16.666667%; - } - .col-xl-3 { - -ms-flex: 0 0 25%; - flex: 0 0 25%; - max-width: 25%; - } - .col-xl-4 { - -ms-flex: 0 0 33.333333%; - flex: 0 0 33.333333%; - max-width: 33.333333%; - } - .col-xl-5 { - -ms-flex: 0 0 41.666667%; - flex: 0 0 41.666667%; - max-width: 41.666667%; - } - .col-xl-6 { - -ms-flex: 0 0 50%; - flex: 0 0 50%; - max-width: 50%; - } - .col-xl-7 { - -ms-flex: 0 0 58.333333%; - flex: 0 0 58.333333%; - max-width: 58.333333%; - } - .col-xl-8 { - -ms-flex: 0 0 66.666667%; - flex: 0 0 66.666667%; - max-width: 66.666667%; - } - .col-xl-9 { - -ms-flex: 0 0 75%; - flex: 0 0 75%; - max-width: 75%; - } - .col-xl-10 { - -ms-flex: 0 0 83.333333%; - flex: 0 0 83.333333%; - max-width: 83.333333%; - } - .col-xl-11 { - -ms-flex: 0 0 91.666667%; - flex: 0 0 91.666667%; - max-width: 91.666667%; - } - .col-xl-12 { - -ms-flex: 0 0 100%; - flex: 0 0 100%; - max-width: 100%; - } - .order-xl-first { - -ms-flex-order: -1; - order: -1; - } - .order-xl-last { - -ms-flex-order: 13; - order: 13; - } - .order-xl-0 { - -ms-flex-order: 0; - order: 0; - } - .order-xl-1 { - -ms-flex-order: 1; - order: 1; - } - .order-xl-2 { - -ms-flex-order: 2; - order: 2; - } - .order-xl-3 { - -ms-flex-order: 3; - order: 3; - } - .order-xl-4 { - -ms-flex-order: 4; - order: 4; - } - .order-xl-5 { - -ms-flex-order: 5; - order: 5; - } - .order-xl-6 { - -ms-flex-order: 6; - order: 6; - } - .order-xl-7 { - -ms-flex-order: 7; - order: 7; - } - .order-xl-8 { - -ms-flex-order: 8; - order: 8; - } - .order-xl-9 { - -ms-flex-order: 9; - order: 9; - } - .order-xl-10 { - -ms-flex-order: 10; - order: 10; - } - .order-xl-11 { - -ms-flex-order: 11; - order: 11; - } - .order-xl-12 { - -ms-flex-order: 12; - order: 12; - } - .offset-xl-0 { - margin-left: 0; - } - .offset-xl-1 { - margin-left: 8.333333%; - } - .offset-xl-2 { - margin-left: 16.666667%; - } - .offset-xl-3 { - margin-left: 25%; - } - .offset-xl-4 { - margin-left: 33.333333%; - } - .offset-xl-5 { - margin-left: 41.666667%; - } - .offset-xl-6 { - margin-left: 50%; - } - .offset-xl-7 { - margin-left: 58.333333%; - } - .offset-xl-8 { - margin-left: 66.666667%; - } - .offset-xl-9 { - margin-left: 75%; - } - .offset-xl-10 { - margin-left: 83.333333%; - } - .offset-xl-11 { - margin-left: 91.666667%; - } -} - -.d-none { - display: none !important; -} - -.d-inline { - display: inline !important; -} - -.d-inline-block { - display: inline-block !important; -} - -.d-block { - display: block !important; -} - -.d-table { - display: table !important; -} - -.d-table-row { - display: table-row !important; -} - -.d-table-cell { - display: table-cell !important; -} - -.d-flex { - display: -ms-flexbox !important; - display: flex !important; -} - -.d-inline-flex { - display: -ms-inline-flexbox !important; - display: inline-flex !important; -} - -@media (min-width: 576px) { - .d-sm-none { - display: none !important; - } - .d-sm-inline { - display: inline !important; - } - .d-sm-inline-block { - display: inline-block !important; - } - .d-sm-block { - display: block !important; - } - .d-sm-table { - display: table !important; - } - .d-sm-table-row { - display: table-row !important; - } - .d-sm-table-cell { - display: table-cell !important; - } - .d-sm-flex { - display: -ms-flexbox !important; - display: flex !important; - } - .d-sm-inline-flex { - display: -ms-inline-flexbox !important; - display: inline-flex !important; - } -} - -@media (min-width: 768px) { - .d-md-none { - display: none !important; - } - .d-md-inline { - display: inline !important; - } - .d-md-inline-block { - display: inline-block !important; - } - .d-md-block { - display: block !important; - } - .d-md-table { - display: table !important; - } - .d-md-table-row { - display: table-row !important; - } - .d-md-table-cell { - display: table-cell !important; - } - .d-md-flex { - display: -ms-flexbox !important; - display: flex !important; - } - .d-md-inline-flex { - display: -ms-inline-flexbox !important; - display: inline-flex !important; - } -} - -@media (min-width: 992px) { - .d-lg-none { - display: none !important; - } - .d-lg-inline { - display: inline !important; - } - .d-lg-inline-block { - display: inline-block !important; - } - .d-lg-block { - display: block !important; - } - .d-lg-table { - display: table !important; - } - .d-lg-table-row { - display: table-row !important; - } - .d-lg-table-cell { - display: table-cell !important; - } - .d-lg-flex { - display: -ms-flexbox !important; - display: flex !important; - } - .d-lg-inline-flex { - display: -ms-inline-flexbox !important; - display: inline-flex !important; - } -} - -@media (min-width: 1200px) { - .d-xl-none { - display: none !important; - } - .d-xl-inline { - display: inline !important; - } - .d-xl-inline-block { - display: inline-block !important; - } - .d-xl-block { - display: block !important; - } - .d-xl-table { - display: table !important; - } - .d-xl-table-row { - display: table-row !important; - } - .d-xl-table-cell { - display: table-cell !important; - } - .d-xl-flex { - display: -ms-flexbox !important; - display: flex !important; - } - .d-xl-inline-flex { - display: -ms-inline-flexbox !important; - display: inline-flex !important; - } -} - -@media print { - .d-print-none { - display: none !important; - } - .d-print-inline { - display: inline !important; - } - .d-print-inline-block { - display: inline-block !important; - } - .d-print-block { - display: block !important; - } - .d-print-table { - display: table !important; - } - .d-print-table-row { - display: table-row !important; - } - .d-print-table-cell { - display: table-cell !important; - } - .d-print-flex { - display: -ms-flexbox !important; - display: flex !important; - } - .d-print-inline-flex { - display: -ms-inline-flexbox !important; - display: inline-flex !important; - } -} - -.flex-row { - -ms-flex-direction: row !important; - flex-direction: row !important; -} - -.flex-column { - -ms-flex-direction: column !important; - flex-direction: column !important; -} - -.flex-row-reverse { - -ms-flex-direction: row-reverse !important; - flex-direction: row-reverse !important; -} - -.flex-column-reverse { - -ms-flex-direction: column-reverse !important; - flex-direction: column-reverse !important; -} - -.flex-wrap { - -ms-flex-wrap: wrap !important; - flex-wrap: wrap !important; -} - -.flex-nowrap { - -ms-flex-wrap: nowrap !important; - flex-wrap: nowrap !important; -} - -.flex-wrap-reverse { - -ms-flex-wrap: wrap-reverse !important; - flex-wrap: wrap-reverse !important; -} - -.flex-fill { - -ms-flex: 1 1 auto !important; - flex: 1 1 auto !important; -} - -.flex-grow-0 { - -ms-flex-positive: 0 !important; - flex-grow: 0 !important; -} - -.flex-grow-1 { - -ms-flex-positive: 1 !important; - flex-grow: 1 !important; -} - -.flex-shrink-0 { - -ms-flex-negative: 0 !important; - flex-shrink: 0 !important; -} - -.flex-shrink-1 { - -ms-flex-negative: 1 !important; - flex-shrink: 1 !important; -} - -.justify-content-start { - -ms-flex-pack: start !important; - justify-content: flex-start !important; -} - -.justify-content-end { - -ms-flex-pack: end !important; - justify-content: flex-end !important; -} - -.justify-content-center { - -ms-flex-pack: center !important; - justify-content: center !important; -} - -.justify-content-between { - -ms-flex-pack: justify !important; - justify-content: space-between !important; -} - -.justify-content-around { - -ms-flex-pack: distribute !important; - justify-content: space-around !important; -} - -.align-items-start { - -ms-flex-align: start !important; - align-items: flex-start !important; -} - -.align-items-end { - -ms-flex-align: end !important; - align-items: flex-end !important; -} - -.align-items-center { - -ms-flex-align: center !important; - align-items: center !important; -} - -.align-items-baseline { - -ms-flex-align: baseline !important; - align-items: baseline !important; -} - -.align-items-stretch { - -ms-flex-align: stretch !important; - align-items: stretch !important; -} - -.align-content-start { - -ms-flex-line-pack: start !important; - align-content: flex-start !important; -} - -.align-content-end { - -ms-flex-line-pack: end !important; - align-content: flex-end !important; -} - -.align-content-center { - -ms-flex-line-pack: center !important; - align-content: center !important; -} - -.align-content-between { - -ms-flex-line-pack: justify !important; - align-content: space-between !important; -} - -.align-content-around { - -ms-flex-line-pack: distribute !important; - align-content: space-around !important; -} - -.align-content-stretch { - -ms-flex-line-pack: stretch !important; - align-content: stretch !important; -} - -.align-self-auto { - -ms-flex-item-align: auto !important; - align-self: auto !important; -} - -.align-self-start { - -ms-flex-item-align: start !important; - align-self: flex-start !important; -} - -.align-self-end { - -ms-flex-item-align: end !important; - align-self: flex-end !important; -} - -.align-self-center { - -ms-flex-item-align: center !important; - align-self: center !important; -} - -.align-self-baseline { - -ms-flex-item-align: baseline !important; - align-self: baseline !important; -} - -.align-self-stretch { - -ms-flex-item-align: stretch !important; - align-self: stretch !important; -} - -@media (min-width: 576px) { - .flex-sm-row { - -ms-flex-direction: row !important; - flex-direction: row !important; - } - .flex-sm-column { - -ms-flex-direction: column !important; - flex-direction: column !important; - } - .flex-sm-row-reverse { - -ms-flex-direction: row-reverse !important; - flex-direction: row-reverse !important; - } - .flex-sm-column-reverse { - -ms-flex-direction: column-reverse !important; - flex-direction: column-reverse !important; - } - .flex-sm-wrap { - -ms-flex-wrap: wrap !important; - flex-wrap: wrap !important; - } - .flex-sm-nowrap { - -ms-flex-wrap: nowrap !important; - flex-wrap: nowrap !important; - } - .flex-sm-wrap-reverse { - -ms-flex-wrap: wrap-reverse !important; - flex-wrap: wrap-reverse !important; - } - .flex-sm-fill { - -ms-flex: 1 1 auto !important; - flex: 1 1 auto !important; - } - .flex-sm-grow-0 { - -ms-flex-positive: 0 !important; - flex-grow: 0 !important; - } - .flex-sm-grow-1 { - -ms-flex-positive: 1 !important; - flex-grow: 1 !important; - } - .flex-sm-shrink-0 { - -ms-flex-negative: 0 !important; - flex-shrink: 0 !important; - } - .flex-sm-shrink-1 { - -ms-flex-negative: 1 !important; - flex-shrink: 1 !important; - } - .justify-content-sm-start { - -ms-flex-pack: start !important; - justify-content: flex-start !important; - } - .justify-content-sm-end { - -ms-flex-pack: end !important; - justify-content: flex-end !important; - } - .justify-content-sm-center { - -ms-flex-pack: center !important; - justify-content: center !important; - } - .justify-content-sm-between { - -ms-flex-pack: justify !important; - justify-content: space-between !important; - } - .justify-content-sm-around { - -ms-flex-pack: distribute !important; - justify-content: space-around !important; - } - .align-items-sm-start { - -ms-flex-align: start !important; - align-items: flex-start !important; - } - .align-items-sm-end { - -ms-flex-align: end !important; - align-items: flex-end !important; - } - .align-items-sm-center { - -ms-flex-align: center !important; - align-items: center !important; - } - .align-items-sm-baseline { - -ms-flex-align: baseline !important; - align-items: baseline !important; - } - .align-items-sm-stretch { - -ms-flex-align: stretch !important; - align-items: stretch !important; - } - .align-content-sm-start { - -ms-flex-line-pack: start !important; - align-content: flex-start !important; - } - .align-content-sm-end { - -ms-flex-line-pack: end !important; - align-content: flex-end !important; - } - .align-content-sm-center { - -ms-flex-line-pack: center !important; - align-content: center !important; - } - .align-content-sm-between { - -ms-flex-line-pack: justify !important; - align-content: space-between !important; - } - .align-content-sm-around { - -ms-flex-line-pack: distribute !important; - align-content: space-around !important; - } - .align-content-sm-stretch { - -ms-flex-line-pack: stretch !important; - align-content: stretch !important; - } - .align-self-sm-auto { - -ms-flex-item-align: auto !important; - align-self: auto !important; - } - .align-self-sm-start { - -ms-flex-item-align: start !important; - align-self: flex-start !important; - } - .align-self-sm-end { - -ms-flex-item-align: end !important; - align-self: flex-end !important; - } - .align-self-sm-center { - -ms-flex-item-align: center !important; - align-self: center !important; - } - .align-self-sm-baseline { - -ms-flex-item-align: baseline !important; - align-self: baseline !important; - } - .align-self-sm-stretch { - -ms-flex-item-align: stretch !important; - align-self: stretch !important; - } -} - -@media (min-width: 768px) { - .flex-md-row { - -ms-flex-direction: row !important; - flex-direction: row !important; - } - .flex-md-column { - -ms-flex-direction: column !important; - flex-direction: column !important; - } - .flex-md-row-reverse { - -ms-flex-direction: row-reverse !important; - flex-direction: row-reverse !important; - } - .flex-md-column-reverse { - -ms-flex-direction: column-reverse !important; - flex-direction: column-reverse !important; - } - .flex-md-wrap { - -ms-flex-wrap: wrap !important; - flex-wrap: wrap !important; - } - .flex-md-nowrap { - -ms-flex-wrap: nowrap !important; - flex-wrap: nowrap !important; - } - .flex-md-wrap-reverse { - -ms-flex-wrap: wrap-reverse !important; - flex-wrap: wrap-reverse !important; - } - .flex-md-fill { - -ms-flex: 1 1 auto !important; - flex: 1 1 auto !important; - } - .flex-md-grow-0 { - -ms-flex-positive: 0 !important; - flex-grow: 0 !important; - } - .flex-md-grow-1 { - -ms-flex-positive: 1 !important; - flex-grow: 1 !important; - } - .flex-md-shrink-0 { - -ms-flex-negative: 0 !important; - flex-shrink: 0 !important; - } - .flex-md-shrink-1 { - -ms-flex-negative: 1 !important; - flex-shrink: 1 !important; - } - .justify-content-md-start { - -ms-flex-pack: start !important; - justify-content: flex-start !important; - } - .justify-content-md-end { - -ms-flex-pack: end !important; - justify-content: flex-end !important; - } - .justify-content-md-center { - -ms-flex-pack: center !important; - justify-content: center !important; - } - .justify-content-md-between { - -ms-flex-pack: justify !important; - justify-content: space-between !important; - } - .justify-content-md-around { - -ms-flex-pack: distribute !important; - justify-content: space-around !important; - } - .align-items-md-start { - -ms-flex-align: start !important; - align-items: flex-start !important; - } - .align-items-md-end { - -ms-flex-align: end !important; - align-items: flex-end !important; - } - .align-items-md-center { - -ms-flex-align: center !important; - align-items: center !important; - } - .align-items-md-baseline { - -ms-flex-align: baseline !important; - align-items: baseline !important; - } - .align-items-md-stretch { - -ms-flex-align: stretch !important; - align-items: stretch !important; - } - .align-content-md-start { - -ms-flex-line-pack: start !important; - align-content: flex-start !important; - } - .align-content-md-end { - -ms-flex-line-pack: end !important; - align-content: flex-end !important; - } - .align-content-md-center { - -ms-flex-line-pack: center !important; - align-content: center !important; - } - .align-content-md-between { - -ms-flex-line-pack: justify !important; - align-content: space-between !important; - } - .align-content-md-around { - -ms-flex-line-pack: distribute !important; - align-content: space-around !important; - } - .align-content-md-stretch { - -ms-flex-line-pack: stretch !important; - align-content: stretch !important; - } - .align-self-md-auto { - -ms-flex-item-align: auto !important; - align-self: auto !important; - } - .align-self-md-start { - -ms-flex-item-align: start !important; - align-self: flex-start !important; - } - .align-self-md-end { - -ms-flex-item-align: end !important; - align-self: flex-end !important; - } - .align-self-md-center { - -ms-flex-item-align: center !important; - align-self: center !important; - } - .align-self-md-baseline { - -ms-flex-item-align: baseline !important; - align-self: baseline !important; - } - .align-self-md-stretch { - -ms-flex-item-align: stretch !important; - align-self: stretch !important; - } -} - -@media (min-width: 992px) { - .flex-lg-row { - -ms-flex-direction: row !important; - flex-direction: row !important; - } - .flex-lg-column { - -ms-flex-direction: column !important; - flex-direction: column !important; - } - .flex-lg-row-reverse { - -ms-flex-direction: row-reverse !important; - flex-direction: row-reverse !important; - } - .flex-lg-column-reverse { - -ms-flex-direction: column-reverse !important; - flex-direction: column-reverse !important; - } - .flex-lg-wrap { - -ms-flex-wrap: wrap !important; - flex-wrap: wrap !important; - } - .flex-lg-nowrap { - -ms-flex-wrap: nowrap !important; - flex-wrap: nowrap !important; - } - .flex-lg-wrap-reverse { - -ms-flex-wrap: wrap-reverse !important; - flex-wrap: wrap-reverse !important; - } - .flex-lg-fill { - -ms-flex: 1 1 auto !important; - flex: 1 1 auto !important; - } - .flex-lg-grow-0 { - -ms-flex-positive: 0 !important; - flex-grow: 0 !important; - } - .flex-lg-grow-1 { - -ms-flex-positive: 1 !important; - flex-grow: 1 !important; - } - .flex-lg-shrink-0 { - -ms-flex-negative: 0 !important; - flex-shrink: 0 !important; - } - .flex-lg-shrink-1 { - -ms-flex-negative: 1 !important; - flex-shrink: 1 !important; - } - .justify-content-lg-start { - -ms-flex-pack: start !important; - justify-content: flex-start !important; - } - .justify-content-lg-end { - -ms-flex-pack: end !important; - justify-content: flex-end !important; - } - .justify-content-lg-center { - -ms-flex-pack: center !important; - justify-content: center !important; - } - .justify-content-lg-between { - -ms-flex-pack: justify !important; - justify-content: space-between !important; - } - .justify-content-lg-around { - -ms-flex-pack: distribute !important; - justify-content: space-around !important; - } - .align-items-lg-start { - -ms-flex-align: start !important; - align-items: flex-start !important; - } - .align-items-lg-end { - -ms-flex-align: end !important; - align-items: flex-end !important; - } - .align-items-lg-center { - -ms-flex-align: center !important; - align-items: center !important; - } - .align-items-lg-baseline { - -ms-flex-align: baseline !important; - align-items: baseline !important; - } - .align-items-lg-stretch { - -ms-flex-align: stretch !important; - align-items: stretch !important; - } - .align-content-lg-start { - -ms-flex-line-pack: start !important; - align-content: flex-start !important; - } - .align-content-lg-end { - -ms-flex-line-pack: end !important; - align-content: flex-end !important; - } - .align-content-lg-center { - -ms-flex-line-pack: center !important; - align-content: center !important; - } - .align-content-lg-between { - -ms-flex-line-pack: justify !important; - align-content: space-between !important; - } - .align-content-lg-around { - -ms-flex-line-pack: distribute !important; - align-content: space-around !important; - } - .align-content-lg-stretch { - -ms-flex-line-pack: stretch !important; - align-content: stretch !important; - } - .align-self-lg-auto { - -ms-flex-item-align: auto !important; - align-self: auto !important; - } - .align-self-lg-start { - -ms-flex-item-align: start !important; - align-self: flex-start !important; - } - .align-self-lg-end { - -ms-flex-item-align: end !important; - align-self: flex-end !important; - } - .align-self-lg-center { - -ms-flex-item-align: center !important; - align-self: center !important; - } - .align-self-lg-baseline { - -ms-flex-item-align: baseline !important; - align-self: baseline !important; - } - .align-self-lg-stretch { - -ms-flex-item-align: stretch !important; - align-self: stretch !important; - } -} - -@media (min-width: 1200px) { - .flex-xl-row { - -ms-flex-direction: row !important; - flex-direction: row !important; - } - .flex-xl-column { - -ms-flex-direction: column !important; - flex-direction: column !important; - } - .flex-xl-row-reverse { - -ms-flex-direction: row-reverse !important; - flex-direction: row-reverse !important; - } - .flex-xl-column-reverse { - -ms-flex-direction: column-reverse !important; - flex-direction: column-reverse !important; - } - .flex-xl-wrap { - -ms-flex-wrap: wrap !important; - flex-wrap: wrap !important; - } - .flex-xl-nowrap { - -ms-flex-wrap: nowrap !important; - flex-wrap: nowrap !important; - } - .flex-xl-wrap-reverse { - -ms-flex-wrap: wrap-reverse !important; - flex-wrap: wrap-reverse !important; - } - .flex-xl-fill { - -ms-flex: 1 1 auto !important; - flex: 1 1 auto !important; - } - .flex-xl-grow-0 { - -ms-flex-positive: 0 !important; - flex-grow: 0 !important; - } - .flex-xl-grow-1 { - -ms-flex-positive: 1 !important; - flex-grow: 1 !important; - } - .flex-xl-shrink-0 { - -ms-flex-negative: 0 !important; - flex-shrink: 0 !important; - } - .flex-xl-shrink-1 { - -ms-flex-negative: 1 !important; - flex-shrink: 1 !important; - } - .justify-content-xl-start { - -ms-flex-pack: start !important; - justify-content: flex-start !important; - } - .justify-content-xl-end { - -ms-flex-pack: end !important; - justify-content: flex-end !important; - } - .justify-content-xl-center { - -ms-flex-pack: center !important; - justify-content: center !important; - } - .justify-content-xl-between { - -ms-flex-pack: justify !important; - justify-content: space-between !important; - } - .justify-content-xl-around { - -ms-flex-pack: distribute !important; - justify-content: space-around !important; - } - .align-items-xl-start { - -ms-flex-align: start !important; - align-items: flex-start !important; - } - .align-items-xl-end { - -ms-flex-align: end !important; - align-items: flex-end !important; - } - .align-items-xl-center { - -ms-flex-align: center !important; - align-items: center !important; - } - .align-items-xl-baseline { - -ms-flex-align: baseline !important; - align-items: baseline !important; - } - .align-items-xl-stretch { - -ms-flex-align: stretch !important; - align-items: stretch !important; - } - .align-content-xl-start { - -ms-flex-line-pack: start !important; - align-content: flex-start !important; - } - .align-content-xl-end { - -ms-flex-line-pack: end !important; - align-content: flex-end !important; - } - .align-content-xl-center { - -ms-flex-line-pack: center !important; - align-content: center !important; - } - .align-content-xl-between { - -ms-flex-line-pack: justify !important; - align-content: space-between !important; - } - .align-content-xl-around { - -ms-flex-line-pack: distribute !important; - align-content: space-around !important; - } - .align-content-xl-stretch { - -ms-flex-line-pack: stretch !important; - align-content: stretch !important; - } - .align-self-xl-auto { - -ms-flex-item-align: auto !important; - align-self: auto !important; - } - .align-self-xl-start { - -ms-flex-item-align: start !important; - align-self: flex-start !important; - } - .align-self-xl-end { - -ms-flex-item-align: end !important; - align-self: flex-end !important; - } - .align-self-xl-center { - -ms-flex-item-align: center !important; - align-self: center !important; - } - .align-self-xl-baseline { - -ms-flex-item-align: baseline !important; - align-self: baseline !important; - } - .align-self-xl-stretch { - -ms-flex-item-align: stretch !important; - align-self: stretch !important; - } -} -/*# sourceMappingURL=bootstrap-grid.css.map */ \ No newline at end of file diff --git a/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap-grid.min.css b/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap-grid.min.css deleted file mode 100755 index 79c746da5..000000000 --- a/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap-grid.min.css +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap Grid v4.1.0 (https://getbootstrap.com/) - * Copyright 2011-2018 The Bootstrap Authors - * Copyright 2011-2018 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */@-ms-viewport{width:device-width}html{box-sizing:border-box;-ms-overflow-style:scrollbar}*,::after,::before{box-sizing:inherit}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-last{-ms-flex-order:13;order:13}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-last{-ms-flex-order:13;order:13}.order-sm-0{-ms-flex-order:0;order:0}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-last{-ms-flex-order:13;order:13}.order-md-0{-ms-flex-order:0;order:0}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-last{-ms-flex-order:13;order:13}.order-lg-0{-ms-flex-order:0;order:0}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-last{-ms-flex-order:13;order:13}.order-xl-0{-ms-flex-order:0;order:0}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-sm-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-sm-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-sm-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-sm-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-sm-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-md-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-md-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-md-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-md-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-md-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-lg-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-lg-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-lg-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-lg-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-lg-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-xl-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-xl-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-xl-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-xl-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-xl-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}} -/*# sourceMappingURL=bootstrap-grid.min.css.map */ \ No newline at end of file diff --git a/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap-reboot.css b/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap-reboot.css deleted file mode 100755 index 9f0f40ff1..000000000 --- a/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap-reboot.css +++ /dev/null @@ -1,330 +0,0 @@ -/*! - * Bootstrap Reboot v4.1.0 (https://getbootstrap.com/) - * Copyright 2011-2018 The Bootstrap Authors - * Copyright 2011-2018 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) - */ -*, -*::before, -*::after { - box-sizing: border-box; -} - -html { - font-family: sans-serif; - line-height: 1.15; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; - -ms-overflow-style: scrollbar; - -webkit-tap-highlight-color: transparent; -} - -@-ms-viewport { - width: device-width; -} - -article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section { - display: block; -} - -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; - font-size: 1rem; - font-weight: 400; - line-height: 1.5; - color: #212529; - text-align: left; - background-color: #fff; -} - -[tabindex="-1"]:focus { - outline: 0 !important; -} - -hr { - box-sizing: content-box; - height: 0; - overflow: visible; -} - -h1, h2, h3, h4, h5, h6 { - margin-top: 0; - margin-bottom: 0.5rem; -} - -p { - margin-top: 0; - margin-bottom: 1rem; -} - -abbr[title], -abbr[data-original-title] { - text-decoration: underline; - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; - cursor: help; - border-bottom: 0; -} - -address { - margin-bottom: 1rem; - font-style: normal; - line-height: inherit; -} - -ol, -ul, -dl { - margin-top: 0; - margin-bottom: 1rem; -} - -ol ol, -ul ul, -ol ul, -ul ol { - margin-bottom: 0; -} - -dt { - font-weight: 700; -} - -dd { - margin-bottom: .5rem; - margin-left: 0; -} - -blockquote { - margin: 0 0 1rem; -} - -dfn { - font-style: italic; -} - -b, -strong { - font-weight: bolder; -} - -small { - font-size: 80%; -} - -sub, -sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline; -} - -sub { - bottom: -.25em; -} - -sup { - top: -.5em; -} - -a { - color: #007bff; - text-decoration: none; - background-color: transparent; - -webkit-text-decoration-skip: objects; -} - -a:hover { - color: #0056b3; - text-decoration: underline; -} - -a:not([href]):not([tabindex]) { - color: inherit; - text-decoration: none; -} - -a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus { - color: inherit; - text-decoration: none; -} - -a:not([href]):not([tabindex]):focus { - outline: 0; -} - -pre, -code, -kbd, -samp { - font-family: monospace, monospace; - font-size: 1em; -} - -pre { - margin-top: 0; - margin-bottom: 1rem; - overflow: auto; - -ms-overflow-style: scrollbar; -} - -figure { - margin: 0 0 1rem; -} - -img { - vertical-align: middle; - border-style: none; -} - -svg:not(:root) { - overflow: hidden; -} - -table { - border-collapse: collapse; -} - -caption { - padding-top: 0.75rem; - padding-bottom: 0.75rem; - color: #6c757d; - text-align: left; - caption-side: bottom; -} - -th { - text-align: inherit; -} - -label { - display: inline-block; - margin-bottom: 0.5rem; -} - -button { - border-radius: 0; -} - -button:focus { - outline: 1px dotted; - outline: 5px auto -webkit-focus-ring-color; -} - -input, -button, -select, -optgroup, -textarea { - margin: 0; - font-family: inherit; - font-size: inherit; - line-height: inherit; -} - -button, -input { - overflow: visible; -} - -button, -select { - text-transform: none; -} - -button, -html [type="button"], -[type="reset"], -[type="submit"] { - -webkit-appearance: button; -} - -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - padding: 0; - border-style: none; -} - -input[type="radio"], -input[type="checkbox"] { - box-sizing: border-box; - padding: 0; -} - -input[type="date"], -input[type="time"], -input[type="datetime-local"], -input[type="month"] { - -webkit-appearance: listbox; -} - -textarea { - overflow: auto; - resize: vertical; -} - -fieldset { - min-width: 0; - padding: 0; - margin: 0; - border: 0; -} - -legend { - display: block; - width: 100%; - max-width: 100%; - padding: 0; - margin-bottom: .5rem; - font-size: 1.5rem; - line-height: inherit; - color: inherit; - white-space: normal; -} - -progress { - vertical-align: baseline; -} - -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -[type="search"] { - outline-offset: -2px; - -webkit-appearance: none; -} - -[type="search"]::-webkit-search-cancel-button, -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -::-webkit-file-upload-button { - font: inherit; - -webkit-appearance: button; -} - -output { - display: inline-block; -} - -summary { - display: list-item; - cursor: pointer; -} - -template { - display: none; -} - -[hidden] { - display: none !important; -} -/*# sourceMappingURL=bootstrap-reboot.css.map */ \ No newline at end of file diff --git a/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap-reboot.min.css b/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap-reboot.min.css deleted file mode 100755 index eb965cc50..000000000 --- a/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap-reboot.min.css +++ /dev/null @@ -1,8 +0,0 @@ -/*! - * Bootstrap Reboot v4.1.0 (https://getbootstrap.com/) - * Copyright 2011-2018 The Bootstrap Authors - * Copyright 2011-2018 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) - */*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important} -/*# sourceMappingURL=bootstrap-reboot.min.css.map */ \ No newline at end of file diff --git a/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap.css b/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap.css deleted file mode 100755 index 7220f3c05..000000000 --- a/src/public/themes/blog/assets/vendor/bootstrap/css/bootstrap.css +++ /dev/null @@ -1,8950 +0,0 @@ -/*! - * Bootstrap v4.1.0 (https://getbootstrap.com/) - * Copyright 2011-2018 The Bootstrap Authors - * Copyright 2011-2018 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ -:root { - --blue: #007bff; - --indigo: #6610f2; - --purple: #6f42c1; - --pink: #e83e8c; - --red: #dc3545; - --orange: #fd7e14; - --yellow: #ffc107; - --green: #28a745; - --teal: #20c997; - --cyan: #17a2b8; - --white: #fff; - --gray: #6c757d; - --gray-dark: #343a40; - --primary: #007bff; - --secondary: #6c757d; - --success: #28a745; - --info: #17a2b8; - --warning: #ffc107; - --danger: #dc3545; - --light: #f8f9fa; - --dark: #343a40; - --breakpoint-xs: 0; - --breakpoint-sm: 576px; - --breakpoint-md: 768px; - --breakpoint-lg: 992px; - --breakpoint-xl: 1200px; - --font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; - --font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; -} - -*, -*::before, -*::after { - box-sizing: border-box; -} - -html { - font-family: sans-serif; - line-height: 1.15; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; - -ms-overflow-style: scrollbar; - -webkit-tap-highlight-color: transparent; -} - -@-ms-viewport { - width: device-width; -} - -article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section { - display: block; -} - -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; - font-size: 1rem; - font-weight: 400; - line-height: 1.5; - color: #212529; - text-align: left; - background-color: #fff; -} - -[tabindex="-1"]:focus { - outline: 0 !important; -} - -hr { - box-sizing: content-box; - height: 0; - overflow: visible; -} - -h1, h2, h3, h4, h5, h6 { - margin-top: 0; - margin-bottom: 0.5rem; -} - -p { - margin-top: 0; - margin-bottom: 1rem; -} - -abbr[title], -abbr[data-original-title] { - text-decoration: underline; - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; - cursor: help; - border-bottom: 0; -} - -address { - margin-bottom: 1rem; - font-style: normal; - line-height: inherit; -} - -ol, -ul, -dl { - margin-top: 0; - margin-bottom: 1rem; -} - -ol ol, -ul ul, -ol ul, -ul ol { - margin-bottom: 0; -} - -dt { - font-weight: 700; -} - -dd { - margin-bottom: .5rem; - margin-left: 0; -} - -blockquote { - margin: 0 0 1rem; -} - -dfn { - font-style: italic; -} - -b, -strong { - font-weight: bolder; -} - -small { - font-size: 80%; -} - -sub, -sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline; -} - -sub { - bottom: -.25em; -} - -sup { - top: -.5em; -} - -a { - color: #007bff; - text-decoration: none; - background-color: transparent; - -webkit-text-decoration-skip: objects; -} - -a:hover { - color: #0056b3; - text-decoration: underline; -} - -a:not([href]):not([tabindex]) { - color: inherit; - text-decoration: none; -} - -a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus { - color: inherit; - text-decoration: none; -} - -a:not([href]):not([tabindex]):focus { - outline: 0; -} - -pre, -code, -kbd, -samp { - font-family: monospace, monospace; - font-size: 1em; -} - -pre { - margin-top: 0; - margin-bottom: 1rem; - overflow: auto; - -ms-overflow-style: scrollbar; -} - -figure { - margin: 0 0 1rem; -} - -img { - vertical-align: middle; - border-style: none; -} - -svg:not(:root) { - overflow: hidden; -} - -table { - border-collapse: collapse; -} - -caption { - padding-top: 0.75rem; - padding-bottom: 0.75rem; - color: #6c757d; - text-align: left; - caption-side: bottom; -} - -th { - text-align: inherit; -} - -label { - display: inline-block; - margin-bottom: 0.5rem; -} - -button { - border-radius: 0; -} - -button:focus { - outline: 1px dotted; - outline: 5px auto -webkit-focus-ring-color; -} - -input, -button, -select, -optgroup, -textarea { - margin: 0; - font-family: inherit; - font-size: inherit; - line-height: inherit; -} - -button, -input { - overflow: visible; -} - -button, -select { - text-transform: none; -} - -button, -html [type="button"], -[type="reset"], -[type="submit"] { - -webkit-appearance: button; -} - -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - padding: 0; - border-style: none; -} - -input[type="radio"], -input[type="checkbox"] { - box-sizing: border-box; - padding: 0; -} - -input[type="date"], -input[type="time"], -input[type="datetime-local"], -input[type="month"] { - -webkit-appearance: listbox; -} - -textarea { - overflow: auto; - resize: vertical; -} - -fieldset { - min-width: 0; - padding: 0; - margin: 0; - border: 0; -} - -legend { - display: block; - width: 100%; - max-width: 100%; - padding: 0; - margin-bottom: .5rem; - font-size: 1.5rem; - line-height: inherit; - color: inherit; - white-space: normal; -} - -progress { - vertical-align: baseline; -} - -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -[type="search"] { - outline-offset: -2px; - -webkit-appearance: none; -} - -[type="search"]::-webkit-search-cancel-button, -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -::-webkit-file-upload-button { - font: inherit; - -webkit-appearance: button; -} - -output { - display: inline-block; -} - -summary { - display: list-item; - cursor: pointer; -} - -template { - display: none; -} - -[hidden] { - display: none !important; -} - -h1, h2, h3, h4, h5, h6, -.h1, .h2, .h3, .h4, .h5, .h6 { - margin-bottom: 0.5rem; - font-family: inherit; - font-weight: 500; - line-height: 1.2; - color: inherit; -} - -h1, .h1 { - font-size: 2.5rem; -} - -h2, .h2 { - font-size: 2rem; -} - -h3, .h3 { - font-size: 1.75rem; -} - -h4, .h4 { - font-size: 1.5rem; -} - -h5, .h5 { - font-size: 1.25rem; -} - -h6, .h6 { - font-size: 1rem; -} - -.lead { - font-size: 1.25rem; - font-weight: 300; -} - -.display-1 { - font-size: 6rem; - font-weight: 300; - line-height: 1.2; -} - -.display-2 { - font-size: 5.5rem; - font-weight: 300; - line-height: 1.2; -} - -.display-3 { - font-size: 4.5rem; - font-weight: 300; - line-height: 1.2; -} - -.display-4 { - font-size: 3.5rem; - font-weight: 300; - line-height: 1.2; -} - -hr { - margin-top: 1rem; - margin-bottom: 1rem; - border: 0; - border-top: 1px solid rgba(0, 0, 0, 0.1); -} - -small, -.small { - font-size: 80%; - font-weight: 400; -} - -mark, -.mark { - padding: 0.2em; - background-color: #fcf8e3; -} - -.list-unstyled { - padding-left: 0; - list-style: none; -} - -.list-inline { - padding-left: 0; - list-style: none; -} - -.list-inline-item { - display: inline-block; -} - -.list-inline-item:not(:last-child) { - margin-right: 0.5rem; -} - -.initialism { - font-size: 90%; - text-transform: uppercase; -} - -.blockquote { - margin-bottom: 1rem; - font-size: 1.25rem; -} - -.blockquote-footer { - display: block; - font-size: 80%; - color: #6c757d; -} - -.blockquote-footer::before { - content: "\2014 \00A0"; -} - -.img-fluid { - max-width: 100%; - height: auto; -} - -.img-thumbnail { - padding: 0.25rem; - background-color: #fff; - border: 1px solid #dee2e6; - border-radius: 0.25rem; - max-width: 100%; - height: auto; -} - -.figure { - display: inline-block; -} - -.figure-img { - margin-bottom: 0.5rem; - line-height: 1; -} - -.figure-caption { - font-size: 90%; - color: #6c757d; -} - -code, -kbd, -pre, -samp { - font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; -} - -code { - font-size: 87.5%; - color: #e83e8c; - word-break: break-word; -} - -a > code { - color: inherit; -} - -kbd { - padding: 0.2rem 0.4rem; - font-size: 87.5%; - color: #fff; - background-color: #212529; - border-radius: 0.2rem; -} - -kbd kbd { - padding: 0; - font-size: 100%; - font-weight: 700; -} - -pre { - display: block; - font-size: 87.5%; - color: #212529; -} - -pre code { - font-size: inherit; - color: inherit; - word-break: normal; -} - -.pre-scrollable { - max-height: 340px; - overflow-y: scroll; -} - -.container { - width: 100%; - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto; -} - -@media (min-width: 576px) { - .container { - max-width: 540px; - } -} - -@media (min-width: 768px) { - .container { - max-width: 720px; - } -} - -@media (min-width: 992px) { - .container { - max-width: 960px; - } -} - -@media (min-width: 1200px) { - .container { - max-width: 1140px; - } -} - -.container-fluid { - width: 100%; - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto; -} - -.row { - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - margin-right: -15px; - margin-left: -15px; -} - -.no-gutters { - margin-right: 0; - margin-left: 0; -} - -.no-gutters > .col, -.no-gutters > [class*="col-"] { - padding-right: 0; - padding-left: 0; -} - -.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col, -.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm, -.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md, -.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg, -.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl, -.col-xl-auto { - position: relative; - width: 100%; - min-height: 1px; - padding-right: 15px; - padding-left: 15px; -} - -.col { - -ms-flex-preferred-size: 0; - flex-basis: 0; - -ms-flex-positive: 1; - flex-grow: 1; - max-width: 100%; -} - -.col-auto { - -ms-flex: 0 0 auto; - flex: 0 0 auto; - width: auto; - max-width: none; -} - -.col-1 { - -ms-flex: 0 0 8.333333%; - flex: 0 0 8.333333%; - max-width: 8.333333%; -} - -.col-2 { - -ms-flex: 0 0 16.666667%; - flex: 0 0 16.666667%; - max-width: 16.666667%; -} - -.col-3 { - -ms-flex: 0 0 25%; - flex: 0 0 25%; - max-width: 25%; -} - -.col-4 { - -ms-flex: 0 0 33.333333%; - flex: 0 0 33.333333%; - max-width: 33.333333%; -} - -.col-5 { - -ms-flex: 0 0 41.666667%; - flex: 0 0 41.666667%; - max-width: 41.666667%; -} - -.col-6 { - -ms-flex: 0 0 50%; - flex: 0 0 50%; - max-width: 50%; -} - -.col-7 { - -ms-flex: 0 0 58.333333%; - flex: 0 0 58.333333%; - max-width: 58.333333%; -} - -.col-8 { - -ms-flex: 0 0 66.666667%; - flex: 0 0 66.666667%; - max-width: 66.666667%; -} - -.col-9 { - -ms-flex: 0 0 75%; - flex: 0 0 75%; - max-width: 75%; -} - -.col-10 { - -ms-flex: 0 0 83.333333%; - flex: 0 0 83.333333%; - max-width: 83.333333%; -} - -.col-11 { - -ms-flex: 0 0 91.666667%; - flex: 0 0 91.666667%; - max-width: 91.666667%; -} - -.col-12 { - -ms-flex: 0 0 100%; - flex: 0 0 100%; - max-width: 100%; -} - -.order-first { - -ms-flex-order: -1; - order: -1; -} - -.order-last { - -ms-flex-order: 13; - order: 13; -} - -.order-0 { - -ms-flex-order: 0; - order: 0; -} - -.order-1 { - -ms-flex-order: 1; - order: 1; -} - -.order-2 { - -ms-flex-order: 2; - order: 2; -} - -.order-3 { - -ms-flex-order: 3; - order: 3; -} - -.order-4 { - -ms-flex-order: 4; - order: 4; -} - -.order-5 { - -ms-flex-order: 5; - order: 5; -} - -.order-6 { - -ms-flex-order: 6; - order: 6; -} - -.order-7 { - -ms-flex-order: 7; - order: 7; -} - -.order-8 { - -ms-flex-order: 8; - order: 8; -} - -.order-9 { - -ms-flex-order: 9; - order: 9; -} - -.order-10 { - -ms-flex-order: 10; - order: 10; -} - -.order-11 { - -ms-flex-order: 11; - order: 11; -} - -.order-12 { - -ms-flex-order: 12; - order: 12; -} - -.offset-1 { - margin-left: 8.333333%; -} - -.offset-2 { - margin-left: 16.666667%; -} - -.offset-3 { - margin-left: 25%; -} - -.offset-4 { - margin-left: 33.333333%; -} - -.offset-5 { - margin-left: 41.666667%; -} - -.offset-6 { - margin-left: 50%; -} - -.offset-7 { - margin-left: 58.333333%; -} - -.offset-8 { - margin-left: 66.666667%; -} - -.offset-9 { - margin-left: 75%; -} - -.offset-10 { - margin-left: 83.333333%; -} - -.offset-11 { - margin-left: 91.666667%; -} - -@media (min-width: 576px) { - .col-sm { - -ms-flex-preferred-size: 0; - flex-basis: 0; - -ms-flex-positive: 1; - flex-grow: 1; - max-width: 100%; - } - .col-sm-auto { - -ms-flex: 0 0 auto; - flex: 0 0 auto; - width: auto; - max-width: none; - } - .col-sm-1 { - -ms-flex: 0 0 8.333333%; - flex: 0 0 8.333333%; - max-width: 8.333333%; - } - .col-sm-2 { - -ms-flex: 0 0 16.666667%; - flex: 0 0 16.666667%; - max-width: 16.666667%; - } - .col-sm-3 { - -ms-flex: 0 0 25%; - flex: 0 0 25%; - max-width: 25%; - } - .col-sm-4 { - -ms-flex: 0 0 33.333333%; - flex: 0 0 33.333333%; - max-width: 33.333333%; - } - .col-sm-5 { - -ms-flex: 0 0 41.666667%; - flex: 0 0 41.666667%; - max-width: 41.666667%; - } - .col-sm-6 { - -ms-flex: 0 0 50%; - flex: 0 0 50%; - max-width: 50%; - } - .col-sm-7 { - -ms-flex: 0 0 58.333333%; - flex: 0 0 58.333333%; - max-width: 58.333333%; - } - .col-sm-8 { - -ms-flex: 0 0 66.666667%; - flex: 0 0 66.666667%; - max-width: 66.666667%; - } - .col-sm-9 { - -ms-flex: 0 0 75%; - flex: 0 0 75%; - max-width: 75%; - } - .col-sm-10 { - -ms-flex: 0 0 83.333333%; - flex: 0 0 83.333333%; - max-width: 83.333333%; - } - .col-sm-11 { - -ms-flex: 0 0 91.666667%; - flex: 0 0 91.666667%; - max-width: 91.666667%; - } - .col-sm-12 { - -ms-flex: 0 0 100%; - flex: 0 0 100%; - max-width: 100%; - } - .order-sm-first { - -ms-flex-order: -1; - order: -1; - } - .order-sm-last { - -ms-flex-order: 13; - order: 13; - } - .order-sm-0 { - -ms-flex-order: 0; - order: 0; - } - .order-sm-1 { - -ms-flex-order: 1; - order: 1; - } - .order-sm-2 { - -ms-flex-order: 2; - order: 2; - } - .order-sm-3 { - -ms-flex-order: 3; - order: 3; - } - .order-sm-4 { - -ms-flex-order: 4; - order: 4; - } - .order-sm-5 { - -ms-flex-order: 5; - order: 5; - } - .order-sm-6 { - -ms-flex-order: 6; - order: 6; - } - .order-sm-7 { - -ms-flex-order: 7; - order: 7; - } - .order-sm-8 { - -ms-flex-order: 8; - order: 8; - } - .order-sm-9 { - -ms-flex-order: 9; - order: 9; - } - .order-sm-10 { - -ms-flex-order: 10; - order: 10; - } - .order-sm-11 { - -ms-flex-order: 11; - order: 11; - } - .order-sm-12 { - -ms-flex-order: 12; - order: 12; - } - .offset-sm-0 { - margin-left: 0; - } - .offset-sm-1 { - margin-left: 8.333333%; - } - .offset-sm-2 { - margin-left: 16.666667%; - } - .offset-sm-3 { - margin-left: 25%; - } - .offset-sm-4 { - margin-left: 33.333333%; - } - .offset-sm-5 { - margin-left: 41.666667%; - } - .offset-sm-6 { - margin-left: 50%; - } - .offset-sm-7 { - margin-left: 58.333333%; - } - .offset-sm-8 { - margin-left: 66.666667%; - } - .offset-sm-9 { - margin-left: 75%; - } - .offset-sm-10 { - margin-left: 83.333333%; - } - .offset-sm-11 { - margin-left: 91.666667%; - } -} - -@media (min-width: 768px) { - .col-md { - -ms-flex-preferred-size: 0; - flex-basis: 0; - -ms-flex-positive: 1; - flex-grow: 1; - max-width: 100%; - } - .col-md-auto { - -ms-flex: 0 0 auto; - flex: 0 0 auto; - width: auto; - max-width: none; - } - .col-md-1 { - -ms-flex: 0 0 8.333333%; - flex: 0 0 8.333333%; - max-width: 8.333333%; - } - .col-md-2 { - -ms-flex: 0 0 16.666667%; - flex: 0 0 16.666667%; - max-width: 16.666667%; - } - .col-md-3 { - -ms-flex: 0 0 25%; - flex: 0 0 25%; - max-width: 25%; - } - .col-md-4 { - -ms-flex: 0 0 33.333333%; - flex: 0 0 33.333333%; - max-width: 33.333333%; - } - .col-md-5 { - -ms-flex: 0 0 41.666667%; - flex: 0 0 41.666667%; - max-width: 41.666667%; - } - .col-md-6 { - -ms-flex: 0 0 50%; - flex: 0 0 50%; - max-width: 50%; - } - .col-md-7 { - -ms-flex: 0 0 58.333333%; - flex: 0 0 58.333333%; - max-width: 58.333333%; - } - .col-md-8 { - -ms-flex: 0 0 66.666667%; - flex: 0 0 66.666667%; - max-width: 66.666667%; - } - .col-md-9 { - -ms-flex: 0 0 75%; - flex: 0 0 75%; - max-width: 75%; - } - .col-md-10 { - -ms-flex: 0 0 83.333333%; - flex: 0 0 83.333333%; - max-width: 83.333333%; - } - .col-md-11 { - -ms-flex: 0 0 91.666667%; - flex: 0 0 91.666667%; - max-width: 91.666667%; - } - .col-md-12 { - -ms-flex: 0 0 100%; - flex: 0 0 100%; - max-width: 100%; - } - .order-md-first { - -ms-flex-order: -1; - order: -1; - } - .order-md-last { - -ms-flex-order: 13; - order: 13; - } - .order-md-0 { - -ms-flex-order: 0; - order: 0; - } - .order-md-1 { - -ms-flex-order: 1; - order: 1; - } - .order-md-2 { - -ms-flex-order: 2; - order: 2; - } - .order-md-3 { - -ms-flex-order: 3; - order: 3; - } - .order-md-4 { - -ms-flex-order: 4; - order: 4; - } - .order-md-5 { - -ms-flex-order: 5; - order: 5; - } - .order-md-6 { - -ms-flex-order: 6; - order: 6; - } - .order-md-7 { - -ms-flex-order: 7; - order: 7; - } - .order-md-8 { - -ms-flex-order: 8; - order: 8; - } - .order-md-9 { - -ms-flex-order: 9; - order: 9; - } - .order-md-10 { - -ms-flex-order: 10; - order: 10; - } - .order-md-11 { - -ms-flex-order: 11; - order: 11; - } - .order-md-12 { - -ms-flex-order: 12; - order: 12; - } - .offset-md-0 { - margin-left: 0; - } - .offset-md-1 { - margin-left: 8.333333%; - } - .offset-md-2 { - margin-left: 16.666667%; - } - .offset-md-3 { - margin-left: 25%; - } - .offset-md-4 { - margin-left: 33.333333%; - } - .offset-md-5 { - margin-left: 41.666667%; - } - .offset-md-6 { - margin-left: 50%; - } - .offset-md-7 { - margin-left: 58.333333%; - } - .offset-md-8 { - margin-left: 66.666667%; - } - .offset-md-9 { - margin-left: 75%; - } - .offset-md-10 { - margin-left: 83.333333%; - } - .offset-md-11 { - margin-left: 91.666667%; - } -} - -@media (min-width: 992px) { - .col-lg { - -ms-flex-preferred-size: 0; - flex-basis: 0; - -ms-flex-positive: 1; - flex-grow: 1; - max-width: 100%; - } - .col-lg-auto { - -ms-flex: 0 0 auto; - flex: 0 0 auto; - width: auto; - max-width: none; - } - .col-lg-1 { - -ms-flex: 0 0 8.333333%; - flex: 0 0 8.333333%; - max-width: 8.333333%; - } - .col-lg-2 { - -ms-flex: 0 0 16.666667%; - flex: 0 0 16.666667%; - max-width: 16.666667%; - } - .col-lg-3 { - -ms-flex: 0 0 25%; - flex: 0 0 25%; - max-width: 25%; - } - .col-lg-4 { - -ms-flex: 0 0 33.333333%; - flex: 0 0 33.333333%; - max-width: 33.333333%; - } - .col-lg-5 { - -ms-flex: 0 0 41.666667%; - flex: 0 0 41.666667%; - max-width: 41.666667%; - } - .col-lg-6 { - -ms-flex: 0 0 50%; - flex: 0 0 50%; - max-width: 50%; - } - .col-lg-7 { - -ms-flex: 0 0 58.333333%; - flex: 0 0 58.333333%; - max-width: 58.333333%; - } - .col-lg-8 { - -ms-flex: 0 0 66.666667%; - flex: 0 0 66.666667%; - max-width: 66.666667%; - } - .col-lg-9 { - -ms-flex: 0 0 75%; - flex: 0 0 75%; - max-width: 75%; - } - .col-lg-10 { - -ms-flex: 0 0 83.333333%; - flex: 0 0 83.333333%; - max-width: 83.333333%; - } - .col-lg-11 { - -ms-flex: 0 0 91.666667%; - flex: 0 0 91.666667%; - max-width: 91.666667%; - } - .col-lg-12 { - -ms-flex: 0 0 100%; - flex: 0 0 100%; - max-width: 100%; - } - .order-lg-first { - -ms-flex-order: -1; - order: -1; - } - .order-lg-last { - -ms-flex-order: 13; - order: 13; - } - .order-lg-0 { - -ms-flex-order: 0; - order: 0; - } - .order-lg-1 { - -ms-flex-order: 1; - order: 1; - } - .order-lg-2 { - -ms-flex-order: 2; - order: 2; - } - .order-lg-3 { - -ms-flex-order: 3; - order: 3; - } - .order-lg-4 { - -ms-flex-order: 4; - order: 4; - } - .order-lg-5 { - -ms-flex-order: 5; - order: 5; - } - .order-lg-6 { - -ms-flex-order: 6; - order: 6; - } - .order-lg-7 { - -ms-flex-order: 7; - order: 7; - } - .order-lg-8 { - -ms-flex-order: 8; - order: 8; - } - .order-lg-9 { - -ms-flex-order: 9; - order: 9; - } - .order-lg-10 { - -ms-flex-order: 10; - order: 10; - } - .order-lg-11 { - -ms-flex-order: 11; - order: 11; - } - .order-lg-12 { - -ms-flex-order: 12; - order: 12; - } - .offset-lg-0 { - margin-left: 0; - } - .offset-lg-1 { - margin-left: 8.333333%; - } - .offset-lg-2 { - margin-left: 16.666667%; - } - .offset-lg-3 { - margin-left: 25%; - } - .offset-lg-4 { - margin-left: 33.333333%; - } - .offset-lg-5 { - margin-left: 41.666667%; - } - .offset-lg-6 { - margin-left: 50%; - } - .offset-lg-7 { - margin-left: 58.333333%; - } - .offset-lg-8 { - margin-left: 66.666667%; - } - .offset-lg-9 { - margin-left: 75%; - } - .offset-lg-10 { - margin-left: 83.333333%; - } - .offset-lg-11 { - margin-left: 91.666667%; - } -} - -@media (min-width: 1200px) { - .col-xl { - -ms-flex-preferred-size: 0; - flex-basis: 0; - -ms-flex-positive: 1; - flex-grow: 1; - max-width: 100%; - } - .col-xl-auto { - -ms-flex: 0 0 auto; - flex: 0 0 auto; - width: auto; - max-width: none; - } - .col-xl-1 { - -ms-flex: 0 0 8.333333%; - flex: 0 0 8.333333%; - max-width: 8.333333%; - } - .col-xl-2 { - -ms-flex: 0 0 16.666667%; - flex: 0 0 16.666667%; - max-width: 16.666667%; - } - .col-xl-3 { - -ms-flex: 0 0 25%; - flex: 0 0 25%; - max-width: 25%; - } - .col-xl-4 { - -ms-flex: 0 0 33.333333%; - flex: 0 0 33.333333%; - max-width: 33.333333%; - } - .col-xl-5 { - -ms-flex: 0 0 41.666667%; - flex: 0 0 41.666667%; - max-width: 41.666667%; - } - .col-xl-6 { - -ms-flex: 0 0 50%; - flex: 0 0 50%; - max-width: 50%; - } - .col-xl-7 { - -ms-flex: 0 0 58.333333%; - flex: 0 0 58.333333%; - max-width: 58.333333%; - } - .col-xl-8 { - -ms-flex: 0 0 66.666667%; - flex: 0 0 66.666667%; - max-width: 66.666667%; - } - .col-xl-9 { - -ms-flex: 0 0 75%; - flex: 0 0 75%; - max-width: 75%; - } - .col-xl-10 { - -ms-flex: 0 0 83.333333%; - flex: 0 0 83.333333%; - max-width: 83.333333%; - } - .col-xl-11 { - -ms-flex: 0 0 91.666667%; - flex: 0 0 91.666667%; - max-width: 91.666667%; - } - .col-xl-12 { - -ms-flex: 0 0 100%; - flex: 0 0 100%; - max-width: 100%; - } - .order-xl-first { - -ms-flex-order: -1; - order: -1; - } - .order-xl-last { - -ms-flex-order: 13; - order: 13; - } - .order-xl-0 { - -ms-flex-order: 0; - order: 0; - } - .order-xl-1 { - -ms-flex-order: 1; - order: 1; - } - .order-xl-2 { - -ms-flex-order: 2; - order: 2; - } - .order-xl-3 { - -ms-flex-order: 3; - order: 3; - } - .order-xl-4 { - -ms-flex-order: 4; - order: 4; - } - .order-xl-5 { - -ms-flex-order: 5; - order: 5; - } - .order-xl-6 { - -ms-flex-order: 6; - order: 6; - } - .order-xl-7 { - -ms-flex-order: 7; - order: 7; - } - .order-xl-8 { - -ms-flex-order: 8; - order: 8; - } - .order-xl-9 { - -ms-flex-order: 9; - order: 9; - } - .order-xl-10 { - -ms-flex-order: 10; - order: 10; - } - .order-xl-11 { - -ms-flex-order: 11; - order: 11; - } - .order-xl-12 { - -ms-flex-order: 12; - order: 12; - } - .offset-xl-0 { - margin-left: 0; - } - .offset-xl-1 { - margin-left: 8.333333%; - } - .offset-xl-2 { - margin-left: 16.666667%; - } - .offset-xl-3 { - margin-left: 25%; - } - .offset-xl-4 { - margin-left: 33.333333%; - } - .offset-xl-5 { - margin-left: 41.666667%; - } - .offset-xl-6 { - margin-left: 50%; - } - .offset-xl-7 { - margin-left: 58.333333%; - } - .offset-xl-8 { - margin-left: 66.666667%; - } - .offset-xl-9 { - margin-left: 75%; - } - .offset-xl-10 { - margin-left: 83.333333%; - } - .offset-xl-11 { - margin-left: 91.666667%; - } -} - -.table { - width: 100%; - max-width: 100%; - margin-bottom: 1rem; - background-color: transparent; -} - -.table th, -.table td { - padding: 0.75rem; - vertical-align: top; - border-top: 1px solid #dee2e6; -} - -.table thead th { - vertical-align: bottom; - border-bottom: 2px solid #dee2e6; -} - -.table tbody + tbody { - border-top: 2px solid #dee2e6; -} - -.table .table { - background-color: #fff; -} - -.table-sm th, -.table-sm td { - padding: 0.3rem; -} - -.table-bordered { - border: 1px solid #dee2e6; -} - -.table-bordered th, -.table-bordered td { - border: 1px solid #dee2e6; -} - -.table-bordered thead th, -.table-bordered thead td { - border-bottom-width: 2px; -} - -.table-borderless th, -.table-borderless td, -.table-borderless thead th, -.table-borderless tbody + tbody { - border: 0; -} - -.table-striped tbody tr:nth-of-type(odd) { - background-color: rgba(0, 0, 0, 0.05); -} - -.table-hover tbody tr:hover { - background-color: rgba(0, 0, 0, 0.075); -} - -.table-primary, -.table-primary > th, -.table-primary > td { - background-color: #b8daff; -} - -.table-hover .table-primary:hover { - background-color: #9fcdff; -} - -.table-hover .table-primary:hover > td, -.table-hover .table-primary:hover > th { - background-color: #9fcdff; -} - -.table-secondary, -.table-secondary > th, -.table-secondary > td { - background-color: #d6d8db; -} - -.table-hover .table-secondary:hover { - background-color: #c8cbcf; -} - -.table-hover .table-secondary:hover > td, -.table-hover .table-secondary:hover > th { - background-color: #c8cbcf; -} - -.table-success, -.table-success > th, -.table-success > td { - background-color: #c3e6cb; -} - -.table-hover .table-success:hover { - background-color: #b1dfbb; -} - -.table-hover .table-success:hover > td, -.table-hover .table-success:hover > th { - background-color: #b1dfbb; -} - -.table-info, -.table-info > th, -.table-info > td { - background-color: #bee5eb; -} - -.table-hover .table-info:hover { - background-color: #abdde5; -} - -.table-hover .table-info:hover > td, -.table-hover .table-info:hover > th { - background-color: #abdde5; -} - -.table-warning, -.table-warning > th, -.table-warning > td { - background-color: #ffeeba; -} - -.table-hover .table-warning:hover { - background-color: #ffe8a1; -} - -.table-hover .table-warning:hover > td, -.table-hover .table-warning:hover > th { - background-color: #ffe8a1; -} - -.table-danger, -.table-danger > th, -.table-danger > td { - background-color: #f5c6cb; -} - -.table-hover .table-danger:hover { - background-color: #f1b0b7; -} - -.table-hover .table-danger:hover > td, -.table-hover .table-danger:hover > th { - background-color: #f1b0b7; -} - -.table-light, -.table-light > th, -.table-light > td { - background-color: #fdfdfe; -} - -.table-hover .table-light:hover { - background-color: #ececf6; -} - -.table-hover .table-light:hover > td, -.table-hover .table-light:hover > th { - background-color: #ececf6; -} - -.table-dark, -.table-dark > th, -.table-dark > td { - background-color: #c6c8ca; -} - -.table-hover .table-dark:hover { - background-color: #b9bbbe; -} - -.table-hover .table-dark:hover > td, -.table-hover .table-dark:hover > th { - background-color: #b9bbbe; -} - -.table-active, -.table-active > th, -.table-active > td { - background-color: rgba(0, 0, 0, 0.075); -} - -.table-hover .table-active:hover { - background-color: rgba(0, 0, 0, 0.075); -} - -.table-hover .table-active:hover > td, -.table-hover .table-active:hover > th { - background-color: rgba(0, 0, 0, 0.075); -} - -.table .thead-dark th { - color: #fff; - background-color: #212529; - border-color: #32383e; -} - -.table .thead-light th { - color: #495057; - background-color: #e9ecef; - border-color: #dee2e6; -} - -.table-dark { - color: #fff; - background-color: #212529; -} - -.table-dark th, -.table-dark td, -.table-dark thead th { - border-color: #32383e; -} - -.table-dark.table-bordered { - border: 0; -} - -.table-dark.table-striped tbody tr:nth-of-type(odd) { - background-color: rgba(255, 255, 255, 0.05); -} - -.table-dark.table-hover tbody tr:hover { - background-color: rgba(255, 255, 255, 0.075); -} - -@media (max-width: 575.98px) { - .table-responsive-sm { - display: block; - width: 100%; - overflow-x: auto; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; - } - .table-responsive-sm > .table-bordered { - border: 0; - } -} - -@media (max-width: 767.98px) { - .table-responsive-md { - display: block; - width: 100%; - overflow-x: auto; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; - } - .table-responsive-md > .table-bordered { - border: 0; - } -} - -@media (max-width: 991.98px) { - .table-responsive-lg { - display: block; - width: 100%; - overflow-x: auto; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; - } - .table-responsive-lg > .table-bordered { - border: 0; - } -} - -@media (max-width: 1199.98px) { - .table-responsive-xl { - display: block; - width: 100%; - overflow-x: auto; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; - } - .table-responsive-xl > .table-bordered { - border: 0; - } -} - -.table-responsive { - display: block; - width: 100%; - overflow-x: auto; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; -} - -.table-responsive > .table-bordered { - border: 0; -} - -.form-control { - display: block; - width: 100%; - padding: 0.375rem 0.75rem; - font-size: 1rem; - line-height: 1.5; - color: #495057; - background-color: #fff; - background-clip: padding-box; - border: 1px solid #ced4da; - border-radius: 0.25rem; - transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; -} - -@media screen and (prefers-reduced-motion: reduce) { - .form-control { - transition: none; - } -} - -.form-control::-ms-expand { - background-color: transparent; - border: 0; -} - -.form-control:focus { - color: #495057; - background-color: #fff; - border-color: #80bdff; - outline: 0; - box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); -} - -.form-control::-webkit-input-placeholder { - color: #6c757d; - opacity: 1; -} - -.form-control::-moz-placeholder { - color: #6c757d; - opacity: 1; -} - -.form-control:-ms-input-placeholder { - color: #6c757d; - opacity: 1; -} - -.form-control::-ms-input-placeholder { - color: #6c757d; - opacity: 1; -} - -.form-control::placeholder { - color: #6c757d; - opacity: 1; -} - -.form-control:disabled, .form-control[readonly] { - background-color: #e9ecef; - opacity: 1; -} - -select.form-control:not([size]):not([multiple]) { - height: calc(2.25rem + 2px); -} - -select.form-control:focus::-ms-value { - color: #495057; - background-color: #fff; -} - -.form-control-file, -.form-control-range { - display: block; - width: 100%; -} - -.col-form-label { - padding-top: calc(0.375rem + 1px); - padding-bottom: calc(0.375rem + 1px); - margin-bottom: 0; - font-size: inherit; - line-height: 1.5; -} - -.col-form-label-lg { - padding-top: calc(0.5rem + 1px); - padding-bottom: calc(0.5rem + 1px); - font-size: 1.25rem; - line-height: 1.5; -} - -.col-form-label-sm { - padding-top: calc(0.25rem + 1px); - padding-bottom: calc(0.25rem + 1px); - font-size: 0.875rem; - line-height: 1.5; -} - -.form-control-plaintext { - display: block; - width: 100%; - padding-top: 0.375rem; - padding-bottom: 0.375rem; - margin-bottom: 0; - line-height: 1.5; - color: #212529; - background-color: transparent; - border: solid transparent; - border-width: 1px 0; -} - -.form-control-plaintext.form-control-sm, .input-group-sm > .form-control-plaintext.form-control, -.input-group-sm > .input-group-prepend > .form-control-plaintext.input-group-text, -.input-group-sm > .input-group-append > .form-control-plaintext.input-group-text, -.input-group-sm > .input-group-prepend > .form-control-plaintext.btn, -.input-group-sm > .input-group-append > .form-control-plaintext.btn, .form-control-plaintext.form-control-lg, .input-group-lg > .form-control-plaintext.form-control, -.input-group-lg > .input-group-prepend > .form-control-plaintext.input-group-text, -.input-group-lg > .input-group-append > .form-control-plaintext.input-group-text, -.input-group-lg > .input-group-prepend > .form-control-plaintext.btn, -.input-group-lg > .input-group-append > .form-control-plaintext.btn { - padding-right: 0; - padding-left: 0; -} - -.form-control-sm, .input-group-sm > .form-control, -.input-group-sm > .input-group-prepend > .input-group-text, -.input-group-sm > .input-group-append > .input-group-text, -.input-group-sm > .input-group-prepend > .btn, -.input-group-sm > .input-group-append > .btn { - padding: 0.25rem 0.5rem; - font-size: 0.875rem; - line-height: 1.5; - border-radius: 0.2rem; -} - -select.form-control-sm:not([size]):not([multiple]), .input-group-sm > select.form-control:not([size]):not([multiple]), -.input-group-sm > .input-group-prepend > select.input-group-text:not([size]):not([multiple]), -.input-group-sm > .input-group-append > select.input-group-text:not([size]):not([multiple]), -.input-group-sm > .input-group-prepend > select.btn:not([size]):not([multiple]), -.input-group-sm > .input-group-append > select.btn:not([size]):not([multiple]) { - height: calc(1.8125rem + 2px); -} - -.form-control-lg, .input-group-lg > .form-control, -.input-group-lg > .input-group-prepend > .input-group-text, -.input-group-lg > .input-group-append > .input-group-text, -.input-group-lg > .input-group-prepend > .btn, -.input-group-lg > .input-group-append > .btn { - padding: 0.5rem 1rem; - font-size: 1.25rem; - line-height: 1.5; - border-radius: 0.3rem; -} - -select.form-control-lg:not([size]):not([multiple]), .input-group-lg > select.form-control:not([size]):not([multiple]), -.input-group-lg > .input-group-prepend > select.input-group-text:not([size]):not([multiple]), -.input-group-lg > .input-group-append > select.input-group-text:not([size]):not([multiple]), -.input-group-lg > .input-group-prepend > select.btn:not([size]):not([multiple]), -.input-group-lg > .input-group-append > select.btn:not([size]):not([multiple]) { - height: calc(2.875rem + 2px); -} - -.form-group { - margin-bottom: 1rem; -} - -.form-text { - display: block; - margin-top: 0.25rem; -} - -.form-row { - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - margin-right: -5px; - margin-left: -5px; -} - -.form-row > .col, -.form-row > [class*="col-"] { - padding-right: 5px; - padding-left: 5px; -} - -.form-check { - position: relative; - display: block; - padding-left: 1.25rem; -} - -.form-check-input { - position: absolute; - margin-top: 0.3rem; - margin-left: -1.25rem; -} - -.form-check-input:disabled ~ .form-check-label { - color: #6c757d; -} - -.form-check-label { - margin-bottom: 0; -} - -.form-check-inline { - display: -ms-inline-flexbox; - display: inline-flex; - -ms-flex-align: center; - align-items: center; - padding-left: 0; - margin-right: 0.75rem; -} - -.form-check-inline .form-check-input { - position: static; - margin-top: 0; - margin-right: 0.3125rem; - margin-left: 0; -} - -.valid-feedback { - display: none; - width: 100%; - margin-top: 0.25rem; - font-size: 80%; - color: #28a745; -} - -.valid-tooltip { - position: absolute; - top: 100%; - z-index: 5; - display: none; - max-width: 100%; - padding: .5rem; - margin-top: .1rem; - font-size: .875rem; - line-height: 1; - color: #fff; - background-color: rgba(40, 167, 69, 0.8); - border-radius: .2rem; -} - -.was-validated .form-control:valid, .form-control.is-valid, .was-validated -.custom-select:valid, -.custom-select.is-valid { - border-color: #28a745; -} - -.was-validated .form-control:valid:focus, .form-control.is-valid:focus, .was-validated -.custom-select:valid:focus, -.custom-select.is-valid:focus { - border-color: #28a745; - box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); -} - -.was-validated .form-control:valid ~ .valid-feedback, -.was-validated .form-control:valid ~ .valid-tooltip, .form-control.is-valid ~ .valid-feedback, -.form-control.is-valid ~ .valid-tooltip, .was-validated -.custom-select:valid ~ .valid-feedback, -.was-validated -.custom-select:valid ~ .valid-tooltip, -.custom-select.is-valid ~ .valid-feedback, -.custom-select.is-valid ~ .valid-tooltip { - display: block; -} - -.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label { - color: #28a745; -} - -.was-validated .form-check-input:valid ~ .valid-feedback, -.was-validated .form-check-input:valid ~ .valid-tooltip, .form-check-input.is-valid ~ .valid-feedback, -.form-check-input.is-valid ~ .valid-tooltip { - display: block; -} - -.was-validated .custom-control-input:valid ~ .custom-control-label, .custom-control-input.is-valid ~ .custom-control-label { - color: #28a745; -} - -.was-validated .custom-control-input:valid ~ .custom-control-label::before, .custom-control-input.is-valid ~ .custom-control-label::before { - background-color: #71dd8a; -} - -.was-validated .custom-control-input:valid ~ .valid-feedback, -.was-validated .custom-control-input:valid ~ .valid-tooltip, .custom-control-input.is-valid ~ .valid-feedback, -.custom-control-input.is-valid ~ .valid-tooltip { - display: block; -} - -.was-validated .custom-control-input:valid:checked ~ .custom-control-label::before, .custom-control-input.is-valid:checked ~ .custom-control-label::before { - background-color: #34ce57; -} - -.was-validated .custom-control-input:valid:focus ~ .custom-control-label::before, .custom-control-input.is-valid:focus ~ .custom-control-label::before { - box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(40, 167, 69, 0.25); -} - -.was-validated .custom-file-input:valid ~ .custom-file-label, .custom-file-input.is-valid ~ .custom-file-label { - border-color: #28a745; -} - -.was-validated .custom-file-input:valid ~ .custom-file-label::before, .custom-file-input.is-valid ~ .custom-file-label::before { - border-color: inherit; -} - -.was-validated .custom-file-input:valid ~ .valid-feedback, -.was-validated .custom-file-input:valid ~ .valid-tooltip, .custom-file-input.is-valid ~ .valid-feedback, -.custom-file-input.is-valid ~ .valid-tooltip { - display: block; -} - -.was-validated .custom-file-input:valid:focus ~ .custom-file-label, .custom-file-input.is-valid:focus ~ .custom-file-label { - box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); -} - -.invalid-feedback { - display: none; - width: 100%; - margin-top: 0.25rem; - font-size: 80%; - color: #dc3545; -} - -.invalid-tooltip { - position: absolute; - top: 100%; - z-index: 5; - display: none; - max-width: 100%; - padding: .5rem; - margin-top: .1rem; - font-size: .875rem; - line-height: 1; - color: #fff; - background-color: rgba(220, 53, 69, 0.8); - border-radius: .2rem; -} - -.was-validated .form-control:invalid, .form-control.is-invalid, .was-validated -.custom-select:invalid, -.custom-select.is-invalid { - border-color: #dc3545; -} - -.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus, .was-validated -.custom-select:invalid:focus, -.custom-select.is-invalid:focus { - border-color: #dc3545; - box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); -} - -.was-validated .form-control:invalid ~ .invalid-feedback, -.was-validated .form-control:invalid ~ .invalid-tooltip, .form-control.is-invalid ~ .invalid-feedback, -.form-control.is-invalid ~ .invalid-tooltip, .was-validated -.custom-select:invalid ~ .invalid-feedback, -.was-validated -.custom-select:invalid ~ .invalid-tooltip, -.custom-select.is-invalid ~ .invalid-feedback, -.custom-select.is-invalid ~ .invalid-tooltip { - display: block; -} - -.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label { - color: #dc3545; -} - -.was-validated .form-check-input:invalid ~ .invalid-feedback, -.was-validated .form-check-input:invalid ~ .invalid-tooltip, .form-check-input.is-invalid ~ .invalid-feedback, -.form-check-input.is-invalid ~ .invalid-tooltip { - display: block; -} - -.was-validated .custom-control-input:invalid ~ .custom-control-label, .custom-control-input.is-invalid ~ .custom-control-label { - color: #dc3545; -} - -.was-validated .custom-control-input:invalid ~ .custom-control-label::before, .custom-control-input.is-invalid ~ .custom-control-label::before { - background-color: #efa2a9; -} - -.was-validated .custom-control-input:invalid ~ .invalid-feedback, -.was-validated .custom-control-input:invalid ~ .invalid-tooltip, .custom-control-input.is-invalid ~ .invalid-feedback, -.custom-control-input.is-invalid ~ .invalid-tooltip { - display: block; -} - -.was-validated .custom-control-input:invalid:checked ~ .custom-control-label::before, .custom-control-input.is-invalid:checked ~ .custom-control-label::before { - background-color: #e4606d; -} - -.was-validated .custom-control-input:invalid:focus ~ .custom-control-label::before, .custom-control-input.is-invalid:focus ~ .custom-control-label::before { - box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(220, 53, 69, 0.25); -} - -.was-validated .custom-file-input:invalid ~ .custom-file-label, .custom-file-input.is-invalid ~ .custom-file-label { - border-color: #dc3545; -} - -.was-validated .custom-file-input:invalid ~ .custom-file-label::before, .custom-file-input.is-invalid ~ .custom-file-label::before { - border-color: inherit; -} - -.was-validated .custom-file-input:invalid ~ .invalid-feedback, -.was-validated .custom-file-input:invalid ~ .invalid-tooltip, .custom-file-input.is-invalid ~ .invalid-feedback, -.custom-file-input.is-invalid ~ .invalid-tooltip { - display: block; -} - -.was-validated .custom-file-input:invalid:focus ~ .custom-file-label, .custom-file-input.is-invalid:focus ~ .custom-file-label { - box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); -} - -.form-inline { - display: -ms-flexbox; - display: flex; - -ms-flex-flow: row wrap; - flex-flow: row wrap; - -ms-flex-align: center; - align-items: center; -} - -.form-inline .form-check { - width: 100%; -} - -@media (min-width: 576px) { - .form-inline label { - display: -ms-flexbox; - display: flex; - -ms-flex-align: center; - align-items: center; - -ms-flex-pack: center; - justify-content: center; - margin-bottom: 0; - } - .form-inline .form-group { - display: -ms-flexbox; - display: flex; - -ms-flex: 0 0 auto; - flex: 0 0 auto; - -ms-flex-flow: row wrap; - flex-flow: row wrap; - -ms-flex-align: center; - align-items: center; - margin-bottom: 0; - } - .form-inline .form-control { - display: inline-block; - width: auto; - vertical-align: middle; - } - .form-inline .form-control-plaintext { - display: inline-block; - } - .form-inline .input-group, - .form-inline .custom-select { - width: auto; - } - .form-inline .form-check { - display: -ms-flexbox; - display: flex; - -ms-flex-align: center; - align-items: center; - -ms-flex-pack: center; - justify-content: center; - width: auto; - padding-left: 0; - } - .form-inline .form-check-input { - position: relative; - margin-top: 0; - margin-right: 0.25rem; - margin-left: 0; - } - .form-inline .custom-control { - -ms-flex-align: center; - align-items: center; - -ms-flex-pack: center; - justify-content: center; - } - .form-inline .custom-control-label { - margin-bottom: 0; - } -} - -.btn { - display: inline-block; - font-weight: 400; - text-align: center; - white-space: nowrap; - vertical-align: middle; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - border: 1px solid transparent; - padding: 0.375rem 0.75rem; - font-size: 1rem; - line-height: 1.5; - border-radius: 0.25rem; - transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; -} - -@media screen and (prefers-reduced-motion: reduce) { - .btn { - transition: none; - } -} - -.btn:hover, .btn:focus { - text-decoration: none; -} - -.btn:focus, .btn.focus { - outline: 0; - box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); -} - -.btn.disabled, .btn:disabled { - opacity: 0.65; -} - -.btn:not(:disabled):not(.disabled) { - cursor: pointer; -} - -.btn:not(:disabled):not(.disabled):active, .btn:not(:disabled):not(.disabled).active { - background-image: none; -} - -a.btn.disabled, -fieldset:disabled a.btn { - pointer-events: none; -} - -.btn-primary { - color: #fff; - background-color: #007bff; - border-color: #007bff; -} - -.btn-primary:hover { - color: #fff; - background-color: #0069d9; - border-color: #0062cc; -} - -.btn-primary:focus, .btn-primary.focus { - box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); -} - -.btn-primary.disabled, .btn-primary:disabled { - color: #fff; - background-color: #007bff; - border-color: #007bff; -} - -.btn-primary:not(:disabled):not(.disabled):active, .btn-primary:not(:disabled):not(.disabled).active, -.show > .btn-primary.dropdown-toggle { - color: #fff; - background-color: #0062cc; - border-color: #005cbf; -} - -.btn-primary:not(:disabled):not(.disabled):active:focus, .btn-primary:not(:disabled):not(.disabled).active:focus, -.show > .btn-primary.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); -} - -.btn-secondary { - color: #fff; - background-color: #6c757d; - border-color: #6c757d; -} - -.btn-secondary:hover { - color: #fff; - background-color: #5a6268; - border-color: #545b62; -} - -.btn-secondary:focus, .btn-secondary.focus { - box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); -} - -.btn-secondary.disabled, .btn-secondary:disabled { - color: #fff; - background-color: #6c757d; - border-color: #6c757d; -} - -.btn-secondary:not(:disabled):not(.disabled):active, .btn-secondary:not(:disabled):not(.disabled).active, -.show > .btn-secondary.dropdown-toggle { - color: #fff; - background-color: #545b62; - border-color: #4e555b; -} - -.btn-secondary:not(:disabled):not(.disabled):active:focus, .btn-secondary:not(:disabled):not(.disabled).active:focus, -.show > .btn-secondary.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); -} - -.btn-success { - color: #fff; - background-color: #28a745; - border-color: #28a745; -} - -.btn-success:hover { - color: #fff; - background-color: #218838; - border-color: #1e7e34; -} - -.btn-success:focus, .btn-success.focus { - box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); -} - -.btn-success.disabled, .btn-success:disabled { - color: #fff; - background-color: #28a745; - border-color: #28a745; -} - -.btn-success:not(:disabled):not(.disabled):active, .btn-success:not(:disabled):not(.disabled).active, -.show > .btn-success.dropdown-toggle { - color: #fff; - background-color: #1e7e34; - border-color: #1c7430; -} - -.btn-success:not(:disabled):not(.disabled):active:focus, .btn-success:not(:disabled):not(.disabled).active:focus, -.show > .btn-success.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); -} - -.btn-info { - color: #fff; - background-color: #17a2b8; - border-color: #17a2b8; -} - -.btn-info:hover { - color: #fff; - background-color: #138496; - border-color: #117a8b; -} - -.btn-info:focus, .btn-info.focus { - box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); -} - -.btn-info.disabled, .btn-info:disabled { - color: #fff; - background-color: #17a2b8; - border-color: #17a2b8; -} - -.btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active, -.show > .btn-info.dropdown-toggle { - color: #fff; - background-color: #117a8b; - border-color: #10707f; -} - -.btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus, -.show > .btn-info.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); -} - -.btn-warning { - color: #212529; - background-color: #ffc107; - border-color: #ffc107; -} - -.btn-warning:hover { - color: #212529; - background-color: #e0a800; - border-color: #d39e00; -} - -.btn-warning:focus, .btn-warning.focus { - box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); -} - -.btn-warning.disabled, .btn-warning:disabled { - color: #212529; - background-color: #ffc107; - border-color: #ffc107; -} - -.btn-warning:not(:disabled):not(.disabled):active, .btn-warning:not(:disabled):not(.disabled).active, -.show > .btn-warning.dropdown-toggle { - color: #212529; - background-color: #d39e00; - border-color: #c69500; -} - -.btn-warning:not(:disabled):not(.disabled):active:focus, .btn-warning:not(:disabled):not(.disabled).active:focus, -.show > .btn-warning.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); -} - -.btn-danger { - color: #fff; - background-color: #dc3545; - border-color: #dc3545; -} - -.btn-danger:hover { - color: #fff; - background-color: #c82333; - border-color: #bd2130; -} - -.btn-danger:focus, .btn-danger.focus { - box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); -} - -.btn-danger.disabled, .btn-danger:disabled { - color: #fff; - background-color: #dc3545; - border-color: #dc3545; -} - -.btn-danger:not(:disabled):not(.disabled):active, .btn-danger:not(:disabled):not(.disabled).active, -.show > .btn-danger.dropdown-toggle { - color: #fff; - background-color: #bd2130; - border-color: #b21f2d; -} - -.btn-danger:not(:disabled):not(.disabled):active:focus, .btn-danger:not(:disabled):not(.disabled).active:focus, -.show > .btn-danger.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); -} - -.btn-light { - color: #212529; - background-color: #f8f9fa; - border-color: #f8f9fa; -} - -.btn-light:hover { - color: #212529; - background-color: #e2e6ea; - border-color: #dae0e5; -} - -.btn-light:focus, .btn-light.focus { - box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); -} - -.btn-light.disabled, .btn-light:disabled { - color: #212529; - background-color: #f8f9fa; - border-color: #f8f9fa; -} - -.btn-light:not(:disabled):not(.disabled):active, .btn-light:not(:disabled):not(.disabled).active, -.show > .btn-light.dropdown-toggle { - color: #212529; - background-color: #dae0e5; - border-color: #d3d9df; -} - -.btn-light:not(:disabled):not(.disabled):active:focus, .btn-light:not(:disabled):not(.disabled).active:focus, -.show > .btn-light.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); -} - -.btn-dark { - color: #fff; - background-color: #343a40; - border-color: #343a40; -} - -.btn-dark:hover { - color: #fff; - background-color: #23272b; - border-color: #1d2124; -} - -.btn-dark:focus, .btn-dark.focus { - box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); -} - -.btn-dark.disabled, .btn-dark:disabled { - color: #fff; - background-color: #343a40; - border-color: #343a40; -} - -.btn-dark:not(:disabled):not(.disabled):active, .btn-dark:not(:disabled):not(.disabled).active, -.show > .btn-dark.dropdown-toggle { - color: #fff; - background-color: #1d2124; - border-color: #171a1d; -} - -.btn-dark:not(:disabled):not(.disabled):active:focus, .btn-dark:not(:disabled):not(.disabled).active:focus, -.show > .btn-dark.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); -} - -.btn-outline-primary { - color: #007bff; - background-color: transparent; - background-image: none; - border-color: #007bff; -} - -.btn-outline-primary:hover { - color: #fff; - background-color: #007bff; - border-color: #007bff; -} - -.btn-outline-primary:focus, .btn-outline-primary.focus { - box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); -} - -.btn-outline-primary.disabled, .btn-outline-primary:disabled { - color: #007bff; - background-color: transparent; -} - -.btn-outline-primary:not(:disabled):not(.disabled):active, .btn-outline-primary:not(:disabled):not(.disabled).active, -.show > .btn-outline-primary.dropdown-toggle { - color: #fff; - background-color: #007bff; - border-color: #007bff; -} - -.btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus, -.show > .btn-outline-primary.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); -} - -.btn-outline-secondary { - color: #6c757d; - background-color: transparent; - background-image: none; - border-color: #6c757d; -} - -.btn-outline-secondary:hover { - color: #fff; - background-color: #6c757d; - border-color: #6c757d; -} - -.btn-outline-secondary:focus, .btn-outline-secondary.focus { - box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); -} - -.btn-outline-secondary.disabled, .btn-outline-secondary:disabled { - color: #6c757d; - background-color: transparent; -} - -.btn-outline-secondary:not(:disabled):not(.disabled):active, .btn-outline-secondary:not(:disabled):not(.disabled).active, -.show > .btn-outline-secondary.dropdown-toggle { - color: #fff; - background-color: #6c757d; - border-color: #6c757d; -} - -.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, .btn-outline-secondary:not(:disabled):not(.disabled).active:focus, -.show > .btn-outline-secondary.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); -} - -.btn-outline-success { - color: #28a745; - background-color: transparent; - background-image: none; - border-color: #28a745; -} - -.btn-outline-success:hover { - color: #fff; - background-color: #28a745; - border-color: #28a745; -} - -.btn-outline-success:focus, .btn-outline-success.focus { - box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); -} - -.btn-outline-success.disabled, .btn-outline-success:disabled { - color: #28a745; - background-color: transparent; -} - -.btn-outline-success:not(:disabled):not(.disabled):active, .btn-outline-success:not(:disabled):not(.disabled).active, -.show > .btn-outline-success.dropdown-toggle { - color: #fff; - background-color: #28a745; - border-color: #28a745; -} - -.btn-outline-success:not(:disabled):not(.disabled):active:focus, .btn-outline-success:not(:disabled):not(.disabled).active:focus, -.show > .btn-outline-success.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); -} - -.btn-outline-info { - color: #17a2b8; - background-color: transparent; - background-image: none; - border-color: #17a2b8; -} - -.btn-outline-info:hover { - color: #fff; - background-color: #17a2b8; - border-color: #17a2b8; -} - -.btn-outline-info:focus, .btn-outline-info.focus { - box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); -} - -.btn-outline-info.disabled, .btn-outline-info:disabled { - color: #17a2b8; - background-color: transparent; -} - -.btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active, -.show > .btn-outline-info.dropdown-toggle { - color: #fff; - background-color: #17a2b8; - border-color: #17a2b8; -} - -.btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus, -.show > .btn-outline-info.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); -} - -.btn-outline-warning { - color: #ffc107; - background-color: transparent; - background-image: none; - border-color: #ffc107; -} - -.btn-outline-warning:hover { - color: #212529; - background-color: #ffc107; - border-color: #ffc107; -} - -.btn-outline-warning:focus, .btn-outline-warning.focus { - box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); -} - -.btn-outline-warning.disabled, .btn-outline-warning:disabled { - color: #ffc107; - background-color: transparent; -} - -.btn-outline-warning:not(:disabled):not(.disabled):active, .btn-outline-warning:not(:disabled):not(.disabled).active, -.show > .btn-outline-warning.dropdown-toggle { - color: #212529; - background-color: #ffc107; - border-color: #ffc107; -} - -.btn-outline-warning:not(:disabled):not(.disabled):active:focus, .btn-outline-warning:not(:disabled):not(.disabled).active:focus, -.show > .btn-outline-warning.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); -} - -.btn-outline-danger { - color: #dc3545; - background-color: transparent; - background-image: none; - border-color: #dc3545; -} - -.btn-outline-danger:hover { - color: #fff; - background-color: #dc3545; - border-color: #dc3545; -} - -.btn-outline-danger:focus, .btn-outline-danger.focus { - box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); -} - -.btn-outline-danger.disabled, .btn-outline-danger:disabled { - color: #dc3545; - background-color: transparent; -} - -.btn-outline-danger:not(:disabled):not(.disabled):active, .btn-outline-danger:not(:disabled):not(.disabled).active, -.show > .btn-outline-danger.dropdown-toggle { - color: #fff; - background-color: #dc3545; - border-color: #dc3545; -} - -.btn-outline-danger:not(:disabled):not(.disabled):active:focus, .btn-outline-danger:not(:disabled):not(.disabled).active:focus, -.show > .btn-outline-danger.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); -} - -.btn-outline-light { - color: #f8f9fa; - background-color: transparent; - background-image: none; - border-color: #f8f9fa; -} - -.btn-outline-light:hover { - color: #212529; - background-color: #f8f9fa; - border-color: #f8f9fa; -} - -.btn-outline-light:focus, .btn-outline-light.focus { - box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); -} - -.btn-outline-light.disabled, .btn-outline-light:disabled { - color: #f8f9fa; - background-color: transparent; -} - -.btn-outline-light:not(:disabled):not(.disabled):active, .btn-outline-light:not(:disabled):not(.disabled).active, -.show > .btn-outline-light.dropdown-toggle { - color: #212529; - background-color: #f8f9fa; - border-color: #f8f9fa; -} - -.btn-outline-light:not(:disabled):not(.disabled):active:focus, .btn-outline-light:not(:disabled):not(.disabled).active:focus, -.show > .btn-outline-light.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); -} - -.btn-outline-dark { - color: #343a40; - background-color: transparent; - background-image: none; - border-color: #343a40; -} - -.btn-outline-dark:hover { - color: #fff; - background-color: #343a40; - border-color: #343a40; -} - -.btn-outline-dark:focus, .btn-outline-dark.focus { - box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); -} - -.btn-outline-dark.disabled, .btn-outline-dark:disabled { - color: #343a40; - background-color: transparent; -} - -.btn-outline-dark:not(:disabled):not(.disabled):active, .btn-outline-dark:not(:disabled):not(.disabled).active, -.show > .btn-outline-dark.dropdown-toggle { - color: #fff; - background-color: #343a40; - border-color: #343a40; -} - -.btn-outline-dark:not(:disabled):not(.disabled):active:focus, .btn-outline-dark:not(:disabled):not(.disabled).active:focus, -.show > .btn-outline-dark.dropdown-toggle:focus { - box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); -} - -.btn-link { - font-weight: 400; - color: #007bff; - background-color: transparent; -} - -.btn-link:hover { - color: #0056b3; - text-decoration: underline; - background-color: transparent; - border-color: transparent; -} - -.btn-link:focus, .btn-link.focus { - text-decoration: underline; - border-color: transparent; - box-shadow: none; -} - -.btn-link:disabled, .btn-link.disabled { - color: #6c757d; - pointer-events: none; -} - -.btn-lg, .btn-group-lg > .btn { - padding: 0.5rem 1rem; - font-size: 1.25rem; - line-height: 1.5; - border-radius: 0.3rem; -} - -.btn-sm, .btn-group-sm > .btn { - padding: 0.25rem 0.5rem; - font-size: 0.875rem; - line-height: 1.5; - border-radius: 0.2rem; -} - -.btn-block { - display: block; - width: 100%; -} - -.btn-block + .btn-block { - margin-top: 0.5rem; -} - -input[type="submit"].btn-block, -input[type="reset"].btn-block, -input[type="button"].btn-block { - width: 100%; -} - -.fade { - transition: opacity 0.15s linear; -} - -@media screen and (prefers-reduced-motion: reduce) { - .fade { - transition: none; - } -} - -.fade:not(.show) { - opacity: 0; -} - -.collapse:not(.show) { - display: none; -} - -.collapsing { - position: relative; - height: 0; - overflow: hidden; - transition: height 0.35s ease; -} - -@media screen and (prefers-reduced-motion: reduce) { - .collapsing { - transition: none; - } -} - -.dropup, -.dropright, -.dropdown, -.dropleft { - position: relative; -} - -.dropdown-toggle::after { - display: inline-block; - width: 0; - height: 0; - margin-left: 0.255em; - vertical-align: 0.255em; - content: ""; - border-top: 0.3em solid; - border-right: 0.3em solid transparent; - border-bottom: 0; - border-left: 0.3em solid transparent; -} - -.dropdown-toggle:empty::after { - margin-left: 0; -} - -.dropdown-menu { - position: absolute; - top: 100%; - left: 0; - z-index: 1000; - display: none; - float: left; - min-width: 10rem; - padding: 0.5rem 0; - margin: 0.125rem 0 0; - font-size: 1rem; - color: #212529; - text-align: left; - list-style: none; - background-color: #fff; - background-clip: padding-box; - border: 1px solid rgba(0, 0, 0, 0.15); - border-radius: 0.25rem; -} - -.dropdown-menu-right { - right: 0; - left: auto; -} - -.dropup .dropdown-menu { - top: auto; - bottom: 100%; - margin-top: 0; - margin-bottom: 0.125rem; -} - -.dropup .dropdown-toggle::after { - display: inline-block; - width: 0; - height: 0; - margin-left: 0.255em; - vertical-align: 0.255em; - content: ""; - border-top: 0; - border-right: 0.3em solid transparent; - border-bottom: 0.3em solid; - border-left: 0.3em solid transparent; -} - -.dropup .dropdown-toggle:empty::after { - margin-left: 0; -} - -.dropright .dropdown-menu { - top: 0; - right: auto; - left: 100%; - margin-top: 0; - margin-left: 0.125rem; -} - -.dropright .dropdown-toggle::after { - display: inline-block; - width: 0; - height: 0; - margin-left: 0.255em; - vertical-align: 0.255em; - content: ""; - border-top: 0.3em solid transparent; - border-right: 0; - border-bottom: 0.3em solid transparent; - border-left: 0.3em solid; -} - -.dropright .dropdown-toggle:empty::after { - margin-left: 0; -} - -.dropright .dropdown-toggle::after { - vertical-align: 0; -} - -.dropleft .dropdown-menu { - top: 0; - right: 100%; - left: auto; - margin-top: 0; - margin-right: 0.125rem; -} - -.dropleft .dropdown-toggle::after { - display: inline-block; - width: 0; - height: 0; - margin-left: 0.255em; - vertical-align: 0.255em; - content: ""; -} - -.dropleft .dropdown-toggle::after { - display: none; -} - -.dropleft .dropdown-toggle::before { - display: inline-block; - width: 0; - height: 0; - margin-right: 0.255em; - vertical-align: 0.255em; - content: ""; - border-top: 0.3em solid transparent; - border-right: 0.3em solid; - border-bottom: 0.3em solid transparent; -} - -.dropleft .dropdown-toggle:empty::after { - margin-left: 0; -} - -.dropleft .dropdown-toggle::before { - vertical-align: 0; -} - -.dropdown-menu[x-placement^="top"], .dropdown-menu[x-placement^="right"], .dropdown-menu[x-placement^="bottom"], .dropdown-menu[x-placement^="left"] { - right: auto; - bottom: auto; -} - -.dropdown-divider { - height: 0; - margin: 0.5rem 0; - overflow: hidden; - border-top: 1px solid #e9ecef; -} - -.dropdown-item { - display: block; - width: 100%; - padding: 0.25rem 1.5rem; - clear: both; - font-weight: 400; - color: #212529; - text-align: inherit; - white-space: nowrap; - background-color: transparent; - border: 0; -} - -.dropdown-item:hover, .dropdown-item:focus { - color: #16181b; - text-decoration: none; - background-color: #f8f9fa; -} - -.dropdown-item.active, .dropdown-item:active { - color: #fff; - text-decoration: none; - background-color: #007bff; -} - -.dropdown-item.disabled, .dropdown-item:disabled { - color: #6c757d; - background-color: transparent; -} - -.dropdown-menu.show { - display: block; -} - -.dropdown-header { - display: block; - padding: 0.5rem 1.5rem; - margin-bottom: 0; - font-size: 0.875rem; - color: #6c757d; - white-space: nowrap; -} - -.dropdown-item-text { - display: block; - padding: 0.25rem 1.5rem; - color: #212529; -} - -.btn-group, -.btn-group-vertical { - position: relative; - display: -ms-inline-flexbox; - display: inline-flex; - vertical-align: middle; -} - -.btn-group > .btn, -.btn-group-vertical > .btn { - position: relative; - -ms-flex: 0 1 auto; - flex: 0 1 auto; -} - -.btn-group > .btn:hover, -.btn-group-vertical > .btn:hover { - z-index: 1; -} - -.btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active, -.btn-group-vertical > .btn:focus, -.btn-group-vertical > .btn:active, -.btn-group-vertical > .btn.active { - z-index: 1; -} - -.btn-group .btn + .btn, -.btn-group .btn + .btn-group, -.btn-group .btn-group + .btn, -.btn-group .btn-group + .btn-group, -.btn-group-vertical .btn + .btn, -.btn-group-vertical .btn + .btn-group, -.btn-group-vertical .btn-group + .btn, -.btn-group-vertical .btn-group + .btn-group { - margin-left: -1px; -} - -.btn-toolbar { - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - -ms-flex-pack: start; - justify-content: flex-start; -} - -.btn-toolbar .input-group { - width: auto; -} - -.btn-group > .btn:first-child { - margin-left: 0; -} - -.btn-group > .btn:not(:last-child):not(.dropdown-toggle), -.btn-group > .btn-group:not(:last-child) > .btn { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -.btn-group > .btn:not(:first-child), -.btn-group > .btn-group:not(:first-child) > .btn { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -.dropdown-toggle-split { - padding-right: 0.5625rem; - padding-left: 0.5625rem; -} - -.dropdown-toggle-split::after, -.dropup .dropdown-toggle-split::after, -.dropright .dropdown-toggle-split::after { - margin-left: 0; -} - -.dropleft .dropdown-toggle-split::before { - margin-right: 0; -} - -.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split { - padding-right: 0.375rem; - padding-left: 0.375rem; -} - -.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split { - padding-right: 0.75rem; - padding-left: 0.75rem; -} - -.btn-group-vertical { - -ms-flex-direction: column; - flex-direction: column; - -ms-flex-align: start; - align-items: flex-start; - -ms-flex-pack: center; - justify-content: center; -} - -.btn-group-vertical .btn, -.btn-group-vertical .btn-group { - width: 100%; -} - -.btn-group-vertical > .btn + .btn, -.btn-group-vertical > .btn + .btn-group, -.btn-group-vertical > .btn-group + .btn, -.btn-group-vertical > .btn-group + .btn-group { - margin-top: -1px; - margin-left: 0; -} - -.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle), -.btn-group-vertical > .btn-group:not(:last-child) > .btn { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} - -.btn-group-vertical > .btn:not(:first-child), -.btn-group-vertical > .btn-group:not(:first-child) > .btn { - border-top-left-radius: 0; - border-top-right-radius: 0; -} - -.btn-group-toggle > .btn, -.btn-group-toggle > .btn-group > .btn { - margin-bottom: 0; -} - -.btn-group-toggle > .btn input[type="radio"], -.btn-group-toggle > .btn input[type="checkbox"], -.btn-group-toggle > .btn-group > .btn input[type="radio"], -.btn-group-toggle > .btn-group > .btn input[type="checkbox"] { - position: absolute; - clip: rect(0, 0, 0, 0); - pointer-events: none; -} - -.input-group { - position: relative; - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - -ms-flex-align: stretch; - align-items: stretch; - width: 100%; -} - -.input-group > .form-control, -.input-group > .custom-select, -.input-group > .custom-file { - position: relative; - -ms-flex: 1 1 auto; - flex: 1 1 auto; - width: 1%; - margin-bottom: 0; -} - -.input-group > .form-control:focus, -.input-group > .custom-select:focus, -.input-group > .custom-file:focus { - z-index: 3; -} - -.input-group > .form-control + .form-control, -.input-group > .form-control + .custom-select, -.input-group > .form-control + .custom-file, -.input-group > .custom-select + .form-control, -.input-group > .custom-select + .custom-select, -.input-group > .custom-select + .custom-file, -.input-group > .custom-file + .form-control, -.input-group > .custom-file + .custom-select, -.input-group > .custom-file + .custom-file { - margin-left: -1px; -} - -.input-group > .form-control:not(:last-child), -.input-group > .custom-select:not(:last-child) { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -.input-group > .form-control:not(:first-child), -.input-group > .custom-select:not(:first-child) { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -.input-group > .custom-file { - display: -ms-flexbox; - display: flex; - -ms-flex-align: center; - align-items: center; -} - -.input-group > .custom-file:not(:last-child) .custom-file-label, -.input-group > .custom-file:not(:last-child) .custom-file-label::after { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -.input-group > .custom-file:not(:first-child) .custom-file-label, -.input-group > .custom-file:not(:first-child) .custom-file-label::after { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -.input-group-prepend, -.input-group-append { - display: -ms-flexbox; - display: flex; -} - -.input-group-prepend .btn, -.input-group-append .btn { - position: relative; - z-index: 2; -} - -.input-group-prepend .btn + .btn, -.input-group-prepend .btn + .input-group-text, -.input-group-prepend .input-group-text + .input-group-text, -.input-group-prepend .input-group-text + .btn, -.input-group-append .btn + .btn, -.input-group-append .btn + .input-group-text, -.input-group-append .input-group-text + .input-group-text, -.input-group-append .input-group-text + .btn { - margin-left: -1px; -} - -.input-group-prepend { - margin-right: -1px; -} - -.input-group-append { - margin-left: -1px; -} - -.input-group-text { - display: -ms-flexbox; - display: flex; - -ms-flex-align: center; - align-items: center; - padding: 0.375rem 0.75rem; - margin-bottom: 0; - font-size: 1rem; - font-weight: 400; - line-height: 1.5; - color: #495057; - text-align: center; - white-space: nowrap; - background-color: #e9ecef; - border: 1px solid #ced4da; - border-radius: 0.25rem; -} - -.input-group-text input[type="radio"], -.input-group-text input[type="checkbox"] { - margin-top: 0; -} - -.input-group > .input-group-prepend > .btn, -.input-group > .input-group-prepend > .input-group-text, -.input-group > .input-group-append:not(:last-child) > .btn, -.input-group > .input-group-append:not(:last-child) > .input-group-text, -.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle), -.input-group > .input-group-append:last-child > .input-group-text:not(:last-child) { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -.input-group > .input-group-append > .btn, -.input-group > .input-group-append > .input-group-text, -.input-group > .input-group-prepend:not(:first-child) > .btn, -.input-group > .input-group-prepend:not(:first-child) > .input-group-text, -.input-group > .input-group-prepend:first-child > .btn:not(:first-child), -.input-group > .input-group-prepend:first-child > .input-group-text:not(:first-child) { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -.custom-control { - position: relative; - display: block; - min-height: 1.5rem; - padding-left: 1.5rem; -} - -.custom-control-inline { - display: -ms-inline-flexbox; - display: inline-flex; - margin-right: 1rem; -} - -.custom-control-input { - position: absolute; - z-index: -1; - opacity: 0; -} - -.custom-control-input:checked ~ .custom-control-label::before { - color: #fff; - background-color: #007bff; -} - -.custom-control-input:focus ~ .custom-control-label::before { - box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); -} - -.custom-control-input:active ~ .custom-control-label::before { - color: #fff; - background-color: #b3d7ff; -} - -.custom-control-input:disabled ~ .custom-control-label { - color: #6c757d; -} - -.custom-control-input:disabled ~ .custom-control-label::before { - background-color: #e9ecef; -} - -.custom-control-label { - margin-bottom: 0; -} - -.custom-control-label::before { - position: absolute; - top: 0.25rem; - left: 0; - display: block; - width: 1rem; - height: 1rem; - pointer-events: none; - content: ""; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - background-color: #dee2e6; -} - -.custom-control-label::after { - position: absolute; - top: 0.25rem; - left: 0; - display: block; - width: 1rem; - height: 1rem; - content: ""; - background-repeat: no-repeat; - background-position: center center; - background-size: 50% 50%; -} - -.custom-checkbox .custom-control-label::before { - border-radius: 0.25rem; -} - -.custom-checkbox .custom-control-input:checked ~ .custom-control-label::before { - background-color: #007bff; -} - -.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after { - background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E"); -} - -.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::before { - background-color: #007bff; -} - -.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::after { - background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E"); -} - -.custom-checkbox .custom-control-input:disabled:checked ~ .custom-control-label::before { - background-color: rgba(0, 123, 255, 0.5); -} - -.custom-checkbox .custom-control-input:disabled:indeterminate ~ .custom-control-label::before { - background-color: rgba(0, 123, 255, 0.5); -} - -.custom-radio .custom-control-label::before { - border-radius: 50%; -} - -.custom-radio .custom-control-input:checked ~ .custom-control-label::before { - background-color: #007bff; -} - -.custom-radio .custom-control-input:checked ~ .custom-control-label::after { - background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E"); -} - -.custom-radio .custom-control-input:disabled:checked ~ .custom-control-label::before { - background-color: rgba(0, 123, 255, 0.5); -} - -.custom-select { - display: inline-block; - width: 100%; - height: calc(2.25rem + 2px); - padding: 0.375rem 1.75rem 0.375rem 0.75rem; - line-height: 1.5; - color: #495057; - vertical-align: middle; - background: #fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right 0.75rem center; - background-size: 8px 10px; - border: 1px solid #ced4da; - border-radius: 0.25rem; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; -} - -.custom-select:focus { - border-color: #80bdff; - outline: 0; - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075), 0 0 5px rgba(128, 189, 255, 0.5); -} - -.custom-select:focus::-ms-value { - color: #495057; - background-color: #fff; -} - -.custom-select[multiple], .custom-select[size]:not([size="1"]) { - height: auto; - padding-right: 0.75rem; - background-image: none; -} - -.custom-select:disabled { - color: #6c757d; - background-color: #e9ecef; -} - -.custom-select::-ms-expand { - opacity: 0; -} - -.custom-select-sm { - height: calc(1.8125rem + 2px); - padding-top: 0.375rem; - padding-bottom: 0.375rem; - font-size: 75%; -} - -.custom-select-lg { - height: calc(2.875rem + 2px); - padding-top: 0.375rem; - padding-bottom: 0.375rem; - font-size: 125%; -} - -.custom-file { - position: relative; - display: inline-block; - width: 100%; - height: calc(2.25rem + 2px); - margin-bottom: 0; -} - -.custom-file-input { - position: relative; - z-index: 2; - width: 100%; - height: calc(2.25rem + 2px); - margin: 0; - opacity: 0; -} - -.custom-file-input:focus ~ .custom-file-label { - border-color: #80bdff; - box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); -} - -.custom-file-input:focus ~ .custom-file-label::after { - border-color: #80bdff; -} - -.custom-file-input:lang(en) ~ .custom-file-label::after { - content: "Browse"; -} - -.custom-file-label { - position: absolute; - top: 0; - right: 0; - left: 0; - z-index: 1; - height: calc(2.25rem + 2px); - padding: 0.375rem 0.75rem; - line-height: 1.5; - color: #495057; - background-color: #fff; - border: 1px solid #ced4da; - border-radius: 0.25rem; -} - -.custom-file-label::after { - position: absolute; - top: 0; - right: 0; - bottom: 0; - z-index: 3; - display: block; - height: calc(calc(2.25rem + 2px) - 1px * 2); - padding: 0.375rem 0.75rem; - line-height: 1.5; - color: #495057; - content: "Browse"; - background-color: #e9ecef; - border-left: 1px solid #ced4da; - border-radius: 0 0.25rem 0.25rem 0; -} - -.custom-range { - width: 100%; - padding-left: 0; - background-color: transparent; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; -} - -.custom-range:focus { - outline: none; -} - -.custom-range::-moz-focus-outer { - border: 0; -} - -.custom-range::-webkit-slider-thumb { - width: 1rem; - height: 1rem; - margin-top: -0.25rem; - background-color: #007bff; - border: 0; - border-radius: 1rem; - -webkit-appearance: none; - appearance: none; -} - -.custom-range::-webkit-slider-thumb:focus { - outline: none; - box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); -} - -.custom-range::-webkit-slider-thumb:active { - background-color: #b3d7ff; -} - -.custom-range::-webkit-slider-runnable-track { - width: 100%; - height: 0.5rem; - color: transparent; - cursor: pointer; - background-color: #dee2e6; - border-color: transparent; - border-radius: 1rem; -} - -.custom-range::-moz-range-thumb { - width: 1rem; - height: 1rem; - background-color: #007bff; - border: 0; - border-radius: 1rem; - -moz-appearance: none; - appearance: none; -} - -.custom-range::-moz-range-thumb:focus { - outline: none; - box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); -} - -.custom-range::-moz-range-thumb:active { - background-color: #b3d7ff; -} - -.custom-range::-moz-range-track { - width: 100%; - height: 0.5rem; - color: transparent; - cursor: pointer; - background-color: #dee2e6; - border-color: transparent; - border-radius: 1rem; -} - -.custom-range::-ms-thumb { - width: 1rem; - height: 1rem; - background-color: #007bff; - border: 0; - border-radius: 1rem; - appearance: none; -} - -.custom-range::-ms-thumb:focus { - outline: none; - box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); -} - -.custom-range::-ms-thumb:active { - background-color: #b3d7ff; -} - -.custom-range::-ms-track { - width: 100%; - height: 0.5rem; - color: transparent; - cursor: pointer; - background-color: transparent; - border-color: transparent; - border-width: 0.5rem; -} - -.custom-range::-ms-fill-lower { - background-color: #dee2e6; - border-radius: 1rem; -} - -.custom-range::-ms-fill-upper { - margin-right: 15px; - background-color: #dee2e6; - border-radius: 1rem; -} - -.nav { - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - padding-left: 0; - margin-bottom: 0; - list-style: none; -} - -.nav-link { - display: block; - padding: 0.5rem 1rem; -} - -.nav-link:hover, .nav-link:focus { - text-decoration: none; -} - -.nav-link.disabled { - color: #6c757d; -} - -.nav-tabs { - border-bottom: 1px solid #dee2e6; -} - -.nav-tabs .nav-item { - margin-bottom: -1px; -} - -.nav-tabs .nav-link { - border: 1px solid transparent; - border-top-left-radius: 0.25rem; - border-top-right-radius: 0.25rem; -} - -.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus { - border-color: #e9ecef #e9ecef #dee2e6; -} - -.nav-tabs .nav-link.disabled { - color: #6c757d; - background-color: transparent; - border-color: transparent; -} - -.nav-tabs .nav-link.active, -.nav-tabs .nav-item.show .nav-link { - color: #495057; - background-color: #fff; - border-color: #dee2e6 #dee2e6 #fff; -} - -.nav-tabs .dropdown-menu { - margin-top: -1px; - border-top-left-radius: 0; - border-top-right-radius: 0; -} - -.nav-pills .nav-link { - border-radius: 0.25rem; -} - -.nav-pills .nav-link.active, -.nav-pills .show > .nav-link { - color: #fff; - background-color: #007bff; -} - -.nav-fill .nav-item { - -ms-flex: 1 1 auto; - flex: 1 1 auto; - text-align: center; -} - -.nav-justified .nav-item { - -ms-flex-preferred-size: 0; - flex-basis: 0; - -ms-flex-positive: 1; - flex-grow: 1; - text-align: center; -} - -.tab-content > .tab-pane { - display: none; -} - -.tab-content > .active { - display: block; -} - -.navbar { - position: relative; - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - -ms-flex-align: center; - align-items: center; - -ms-flex-pack: justify; - justify-content: space-between; - padding: 0.5rem 1rem; -} - -.navbar > .container, -.navbar > .container-fluid { - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - -ms-flex-align: center; - align-items: center; - -ms-flex-pack: justify; - justify-content: space-between; -} - -.navbar-brand { - display: inline-block; - padding-top: 0.3125rem; - padding-bottom: 0.3125rem; - margin-right: 1rem; - font-size: 1.25rem; - line-height: inherit; - white-space: nowrap; -} - -.navbar-brand:hover, .navbar-brand:focus { - text-decoration: none; -} - -.navbar-nav { - display: -ms-flexbox; - display: flex; - -ms-flex-direction: column; - flex-direction: column; - padding-left: 0; - margin-bottom: 0; - list-style: none; -} - -.navbar-nav .nav-link { - padding-right: 0; - padding-left: 0; -} - -.navbar-nav .dropdown-menu { - position: static; - float: none; -} - -.navbar-text { - display: inline-block; - padding-top: 0.5rem; - padding-bottom: 0.5rem; -} - -.navbar-collapse { - -ms-flex-preferred-size: 100%; - flex-basis: 100%; - -ms-flex-positive: 1; - flex-grow: 1; - -ms-flex-align: center; - align-items: center; -} - -.navbar-toggler { - padding: 0.25rem 0.75rem; - font-size: 1.25rem; - line-height: 1; - background-color: transparent; - border: 1px solid transparent; - border-radius: 0.25rem; -} - -.navbar-toggler:hover, .navbar-toggler:focus { - text-decoration: none; -} - -.navbar-toggler:not(:disabled):not(.disabled) { - cursor: pointer; -} - -.navbar-toggler-icon { - display: inline-block; - width: 1.5em; - height: 1.5em; - vertical-align: middle; - content: ""; - background: no-repeat center center; - background-size: 100% 100%; -} - -@media (max-width: 575.98px) { - .navbar-expand-sm > .container, - .navbar-expand-sm > .container-fluid { - padding-right: 0; - padding-left: 0; - } -} - -@media (min-width: 576px) { - .navbar-expand-sm { - -ms-flex-flow: row nowrap; - flex-flow: row nowrap; - -ms-flex-pack: start; - justify-content: flex-start; - } - .navbar-expand-sm .navbar-nav { - -ms-flex-direction: row; - flex-direction: row; - } - .navbar-expand-sm .navbar-nav .dropdown-menu { - position: absolute; - } - .navbar-expand-sm .navbar-nav .nav-link { - padding-right: 0.5rem; - padding-left: 0.5rem; - } - .navbar-expand-sm > .container, - .navbar-expand-sm > .container-fluid { - -ms-flex-wrap: nowrap; - flex-wrap: nowrap; - } - .navbar-expand-sm .navbar-collapse { - display: -ms-flexbox !important; - display: flex !important; - -ms-flex-preferred-size: auto; - flex-basis: auto; - } - .navbar-expand-sm .navbar-toggler { - display: none; - } -} - -@media (max-width: 767.98px) { - .navbar-expand-md > .container, - .navbar-expand-md > .container-fluid { - padding-right: 0; - padding-left: 0; - } -} - -@media (min-width: 768px) { - .navbar-expand-md { - -ms-flex-flow: row nowrap; - flex-flow: row nowrap; - -ms-flex-pack: start; - justify-content: flex-start; - } - .navbar-expand-md .navbar-nav { - -ms-flex-direction: row; - flex-direction: row; - } - .navbar-expand-md .navbar-nav .dropdown-menu { - position: absolute; - } - .navbar-expand-md .navbar-nav .nav-link { - padding-right: 0.5rem; - padding-left: 0.5rem; - } - .navbar-expand-md > .container, - .navbar-expand-md > .container-fluid { - -ms-flex-wrap: nowrap; - flex-wrap: nowrap; - } - .navbar-expand-md .navbar-collapse { - display: -ms-flexbox !important; - display: flex !important; - -ms-flex-preferred-size: auto; - flex-basis: auto; - } - .navbar-expand-md .navbar-toggler { - display: none; - } -} - -@media (max-width: 991.98px) { - .navbar-expand-lg > .container, - .navbar-expand-lg > .container-fluid { - padding-right: 0; - padding-left: 0; - } -} - -@media (min-width: 992px) { - .navbar-expand-lg { - -ms-flex-flow: row nowrap; - flex-flow: row nowrap; - -ms-flex-pack: start; - justify-content: flex-start; - } - .navbar-expand-lg .navbar-nav { - -ms-flex-direction: row; - flex-direction: row; - } - .navbar-expand-lg .navbar-nav .dropdown-menu { - position: absolute; - } - .navbar-expand-lg .navbar-nav .nav-link { - padding-right: 0.5rem; - padding-left: 0.5rem; - } - .navbar-expand-lg > .container, - .navbar-expand-lg > .container-fluid { - -ms-flex-wrap: nowrap; - flex-wrap: nowrap; - } - .navbar-expand-lg .navbar-collapse { - display: -ms-flexbox !important; - display: flex !important; - -ms-flex-preferred-size: auto; - flex-basis: auto; - } - .navbar-expand-lg .navbar-toggler { - display: none; - } -} - -@media (max-width: 1199.98px) { - .navbar-expand-xl > .container, - .navbar-expand-xl > .container-fluid { - padding-right: 0; - padding-left: 0; - } -} - -@media (min-width: 1200px) { - .navbar-expand-xl { - -ms-flex-flow: row nowrap; - flex-flow: row nowrap; - -ms-flex-pack: start; - justify-content: flex-start; - } - .navbar-expand-xl .navbar-nav { - -ms-flex-direction: row; - flex-direction: row; - } - .navbar-expand-xl .navbar-nav .dropdown-menu { - position: absolute; - } - .navbar-expand-xl .navbar-nav .nav-link { - padding-right: 0.5rem; - padding-left: 0.5rem; - } - .navbar-expand-xl > .container, - .navbar-expand-xl > .container-fluid { - -ms-flex-wrap: nowrap; - flex-wrap: nowrap; - } - .navbar-expand-xl .navbar-collapse { - display: -ms-flexbox !important; - display: flex !important; - -ms-flex-preferred-size: auto; - flex-basis: auto; - } - .navbar-expand-xl .navbar-toggler { - display: none; - } -} - -.navbar-expand { - -ms-flex-flow: row nowrap; - flex-flow: row nowrap; - -ms-flex-pack: start; - justify-content: flex-start; -} - -.navbar-expand > .container, -.navbar-expand > .container-fluid { - padding-right: 0; - padding-left: 0; -} - -.navbar-expand .navbar-nav { - -ms-flex-direction: row; - flex-direction: row; -} - -.navbar-expand .navbar-nav .dropdown-menu { - position: absolute; -} - -.navbar-expand .navbar-nav .nav-link { - padding-right: 0.5rem; - padding-left: 0.5rem; -} - -.navbar-expand > .container, -.navbar-expand > .container-fluid { - -ms-flex-wrap: nowrap; - flex-wrap: nowrap; -} - -.navbar-expand .navbar-collapse { - display: -ms-flexbox !important; - display: flex !important; - -ms-flex-preferred-size: auto; - flex-basis: auto; -} - -.navbar-expand .navbar-toggler { - display: none; -} - -.navbar-light .navbar-brand { - color: rgba(0, 0, 0, 0.9); -} - -.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus { - color: rgba(0, 0, 0, 0.9); -} - -.navbar-light .navbar-nav .nav-link { - color: rgba(0, 0, 0, 0.5); -} - -.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus { - color: rgba(0, 0, 0, 0.7); -} - -.navbar-light .navbar-nav .nav-link.disabled { - color: rgba(0, 0, 0, 0.3); -} - -.navbar-light .navbar-nav .show > .nav-link, -.navbar-light .navbar-nav .active > .nav-link, -.navbar-light .navbar-nav .nav-link.show, -.navbar-light .navbar-nav .nav-link.active { - color: rgba(0, 0, 0, 0.9); -} - -.navbar-light .navbar-toggler { - color: rgba(0, 0, 0, 0.5); - border-color: rgba(0, 0, 0, 0.1); -} - -.navbar-light .navbar-toggler-icon { - background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"); -} - -.navbar-light .navbar-text { - color: rgba(0, 0, 0, 0.5); -} - -.navbar-light .navbar-text a { - color: rgba(0, 0, 0, 0.9); -} - -.navbar-light .navbar-text a:hover, .navbar-light .navbar-text a:focus { - color: rgba(0, 0, 0, 0.9); -} - -.navbar-dark .navbar-brand { - color: #fff; -} - -.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus { - color: #fff; -} - -.navbar-dark .navbar-nav .nav-link { - color: rgba(255, 255, 255, 0.5); -} - -.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus { - color: rgba(255, 255, 255, 0.75); -} - -.navbar-dark .navbar-nav .nav-link.disabled { - color: rgba(255, 255, 255, 0.25); -} - -.navbar-dark .navbar-nav .show > .nav-link, -.navbar-dark .navbar-nav .active > .nav-link, -.navbar-dark .navbar-nav .nav-link.show, -.navbar-dark .navbar-nav .nav-link.active { - color: #fff; -} - -.navbar-dark .navbar-toggler { - color: rgba(255, 255, 255, 0.5); - border-color: rgba(255, 255, 255, 0.1); -} - -.navbar-dark .navbar-toggler-icon { - background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"); -} - -.navbar-dark .navbar-text { - color: rgba(255, 255, 255, 0.5); -} - -.navbar-dark .navbar-text a { - color: #fff; -} - -.navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus { - color: #fff; -} - -.card { - position: relative; - display: -ms-flexbox; - display: flex; - -ms-flex-direction: column; - flex-direction: column; - min-width: 0; - word-wrap: break-word; - background-color: #fff; - background-clip: border-box; - border: 1px solid rgba(0, 0, 0, 0.125); - border-radius: 0.25rem; -} - -.card > hr { - margin-right: 0; - margin-left: 0; -} - -.card > .list-group:first-child .list-group-item:first-child { - border-top-left-radius: 0.25rem; - border-top-right-radius: 0.25rem; -} - -.card > .list-group:last-child .list-group-item:last-child { - border-bottom-right-radius: 0.25rem; - border-bottom-left-radius: 0.25rem; -} - -.card-body { - -ms-flex: 1 1 auto; - flex: 1 1 auto; - padding: 1.25rem; -} - -.card-title { - margin-bottom: 0.75rem; -} - -.card-subtitle { - margin-top: -0.375rem; - margin-bottom: 0; -} - -.card-text:last-child { - margin-bottom: 0; -} - -.card-link:hover { - text-decoration: none; -} - -.card-link + .card-link { - margin-left: 1.25rem; -} - -.card-header { - padding: 0.75rem 1.25rem; - margin-bottom: 0; - background-color: rgba(0, 0, 0, 0.03); - border-bottom: 1px solid rgba(0, 0, 0, 0.125); -} - -.card-header:first-child { - border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0; -} - -.card-header + .list-group .list-group-item:first-child { - border-top: 0; -} - -.card-footer { - padding: 0.75rem 1.25rem; - background-color: rgba(0, 0, 0, 0.03); - border-top: 1px solid rgba(0, 0, 0, 0.125); -} - -.card-footer:last-child { - border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px); -} - -.card-header-tabs { - margin-right: -0.625rem; - margin-bottom: -0.75rem; - margin-left: -0.625rem; - border-bottom: 0; -} - -.card-header-pills { - margin-right: -0.625rem; - margin-left: -0.625rem; -} - -.card-img-overlay { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - padding: 1.25rem; -} - -.card-img { - width: 100%; - border-radius: calc(0.25rem - 1px); -} - -.card-img-top { - width: 100%; - border-top-left-radius: calc(0.25rem - 1px); - border-top-right-radius: calc(0.25rem - 1px); -} - -.card-img-bottom { - width: 100%; - border-bottom-right-radius: calc(0.25rem - 1px); - border-bottom-left-radius: calc(0.25rem - 1px); -} - -.card-deck { - display: -ms-flexbox; - display: flex; - -ms-flex-direction: column; - flex-direction: column; -} - -.card-deck .card { - margin-bottom: 15px; -} - -@media (min-width: 576px) { - .card-deck { - -ms-flex-flow: row wrap; - flex-flow: row wrap; - margin-right: -15px; - margin-left: -15px; - } - .card-deck .card { - display: -ms-flexbox; - display: flex; - -ms-flex: 1 0 0%; - flex: 1 0 0%; - -ms-flex-direction: column; - flex-direction: column; - margin-right: 15px; - margin-bottom: 0; - margin-left: 15px; - } -} - -.card-group { - display: -ms-flexbox; - display: flex; - -ms-flex-direction: column; - flex-direction: column; -} - -.card-group > .card { - margin-bottom: 15px; -} - -@media (min-width: 576px) { - .card-group { - -ms-flex-flow: row wrap; - flex-flow: row wrap; - } - .card-group > .card { - -ms-flex: 1 0 0%; - flex: 1 0 0%; - margin-bottom: 0; - } - .card-group > .card + .card { - margin-left: 0; - border-left: 0; - } - .card-group > .card:first-child { - border-top-right-radius: 0; - border-bottom-right-radius: 0; - } - .card-group > .card:first-child .card-img-top, - .card-group > .card:first-child .card-header { - border-top-right-radius: 0; - } - .card-group > .card:first-child .card-img-bottom, - .card-group > .card:first-child .card-footer { - border-bottom-right-radius: 0; - } - .card-group > .card:last-child { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - } - .card-group > .card:last-child .card-img-top, - .card-group > .card:last-child .card-header { - border-top-left-radius: 0; - } - .card-group > .card:last-child .card-img-bottom, - .card-group > .card:last-child .card-footer { - border-bottom-left-radius: 0; - } - .card-group > .card:only-child { - border-radius: 0.25rem; - } - .card-group > .card:only-child .card-img-top, - .card-group > .card:only-child .card-header { - border-top-left-radius: 0.25rem; - border-top-right-radius: 0.25rem; - } - .card-group > .card:only-child .card-img-bottom, - .card-group > .card:only-child .card-footer { - border-bottom-right-radius: 0.25rem; - border-bottom-left-radius: 0.25rem; - } - .card-group > .card:not(:first-child):not(:last-child):not(:only-child) { - border-radius: 0; - } - .card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-img-top, - .card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom, - .card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-header, - .card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-footer { - border-radius: 0; - } -} - -.card-columns .card { - margin-bottom: 0.75rem; -} - -@media (min-width: 576px) { - .card-columns { - -webkit-column-count: 3; - -moz-column-count: 3; - column-count: 3; - -webkit-column-gap: 1.25rem; - -moz-column-gap: 1.25rem; - column-gap: 1.25rem; - orphans: 1; - widows: 1; - } - .card-columns .card { - display: inline-block; - width: 100%; - } -} - -.accordion .card:not(:first-of-type):not(:last-of-type) { - border-bottom: 0; - border-radius: 0; -} - -.accordion .card:not(:first-of-type) .card-header:first-child { - border-radius: 0; -} - -.accordion .card:first-of-type { - border-bottom: 0; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} - -.accordion .card:last-of-type { - border-top-left-radius: 0; - border-top-right-radius: 0; -} - -.breadcrumb { - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - padding: 0.75rem 1rem; - margin-bottom: 1rem; - list-style: none; - background-color: #e9ecef; - border-radius: 0.25rem; -} - -.breadcrumb-item + .breadcrumb-item { - padding-left: 0.5rem; -} - -.breadcrumb-item + .breadcrumb-item::before { - display: inline-block; - padding-right: 0.5rem; - color: #6c757d; - content: "/"; -} - -.breadcrumb-item + .breadcrumb-item:hover::before { - text-decoration: underline; -} - -.breadcrumb-item + .breadcrumb-item:hover::before { - text-decoration: none; -} - -.breadcrumb-item.active { - color: #6c757d; -} - -.pagination { - display: -ms-flexbox; - display: flex; - padding-left: 0; - list-style: none; - border-radius: 0.25rem; -} - -.page-link { - position: relative; - display: block; - padding: 0.5rem 0.75rem; - margin-left: -1px; - line-height: 1.25; - color: #007bff; - background-color: #fff; - border: 1px solid #dee2e6; -} - -.page-link:hover { - z-index: 2; - color: #0056b3; - text-decoration: none; - background-color: #e9ecef; - border-color: #dee2e6; -} - -.page-link:focus { - z-index: 2; - outline: 0; - box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); -} - -.page-link:not(:disabled):not(.disabled) { - cursor: pointer; -} - -.page-item:first-child .page-link { - margin-left: 0; - border-top-left-radius: 0.25rem; - border-bottom-left-radius: 0.25rem; -} - -.page-item:last-child .page-link { - border-top-right-radius: 0.25rem; - border-bottom-right-radius: 0.25rem; -} - -.page-item.active .page-link { - z-index: 1; - color: #fff; - background-color: #007bff; - border-color: #007bff; -} - -.page-item.disabled .page-link { - color: #6c757d; - pointer-events: none; - cursor: auto; - background-color: #fff; - border-color: #dee2e6; -} - -.pagination-lg .page-link { - padding: 0.75rem 1.5rem; - font-size: 1.25rem; - line-height: 1.5; -} - -.pagination-lg .page-item:first-child .page-link { - border-top-left-radius: 0.3rem; - border-bottom-left-radius: 0.3rem; -} - -.pagination-lg .page-item:last-child .page-link { - border-top-right-radius: 0.3rem; - border-bottom-right-radius: 0.3rem; -} - -.pagination-sm .page-link { - padding: 0.25rem 0.5rem; - font-size: 0.875rem; - line-height: 1.5; -} - -.pagination-sm .page-item:first-child .page-link { - border-top-left-radius: 0.2rem; - border-bottom-left-radius: 0.2rem; -} - -.pagination-sm .page-item:last-child .page-link { - border-top-right-radius: 0.2rem; - border-bottom-right-radius: 0.2rem; -} - -.badge { - display: inline-block; - padding: 0.25em 0.4em; - font-size: 75%; - font-weight: 700; - line-height: 1; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - border-radius: 0.25rem; -} - -.badge:empty { - display: none; -} - -.btn .badge { - position: relative; - top: -1px; -} - -.badge-pill { - padding-right: 0.6em; - padding-left: 0.6em; - border-radius: 10rem; -} - -.badge-primary { - color: #fff; - background-color: #007bff; -} - -.badge-primary[href]:hover, .badge-primary[href]:focus { - color: #fff; - text-decoration: none; - background-color: #0062cc; -} - -.badge-secondary { - color: #fff; - background-color: #6c757d; -} - -.badge-secondary[href]:hover, .badge-secondary[href]:focus { - color: #fff; - text-decoration: none; - background-color: #545b62; -} - -.badge-success { - color: #fff; - background-color: #28a745; -} - -.badge-success[href]:hover, .badge-success[href]:focus { - color: #fff; - text-decoration: none; - background-color: #1e7e34; -} - -.badge-info { - color: #fff; - background-color: #17a2b8; -} - -.badge-info[href]:hover, .badge-info[href]:focus { - color: #fff; - text-decoration: none; - background-color: #117a8b; -} - -.badge-warning { - color: #212529; - background-color: #ffc107; -} - -.badge-warning[href]:hover, .badge-warning[href]:focus { - color: #212529; - text-decoration: none; - background-color: #d39e00; -} - -.badge-danger { - color: #fff; - background-color: #dc3545; -} - -.badge-danger[href]:hover, .badge-danger[href]:focus { - color: #fff; - text-decoration: none; - background-color: #bd2130; -} - -.badge-light { - color: #212529; - background-color: #f8f9fa; -} - -.badge-light[href]:hover, .badge-light[href]:focus { - color: #212529; - text-decoration: none; - background-color: #dae0e5; -} - -.badge-dark { - color: #fff; - background-color: #343a40; -} - -.badge-dark[href]:hover, .badge-dark[href]:focus { - color: #fff; - text-decoration: none; - background-color: #1d2124; -} - -.jumbotron { - padding: 2rem 1rem; - margin-bottom: 2rem; - background-color: #e9ecef; - border-radius: 0.3rem; -} - -@media (min-width: 576px) { - .jumbotron { - padding: 4rem 2rem; - } -} - -.jumbotron-fluid { - padding-right: 0; - padding-left: 0; - border-radius: 0; -} - -.alert { - position: relative; - padding: 0.75rem 1.25rem; - margin-bottom: 1rem; - border: 1px solid transparent; - border-radius: 0.25rem; -} - -.alert-heading { - color: inherit; -} - -.alert-link { - font-weight: 700; -} - -.alert-dismissible { - padding-right: 4rem; -} - -.alert-dismissible .close { - position: absolute; - top: 0; - right: 0; - padding: 0.75rem 1.25rem; - color: inherit; -} - -.alert-primary { - color: #004085; - background-color: #cce5ff; - border-color: #b8daff; -} - -.alert-primary hr { - border-top-color: #9fcdff; -} - -.alert-primary .alert-link { - color: #002752; -} - -.alert-secondary { - color: #383d41; - background-color: #e2e3e5; - border-color: #d6d8db; -} - -.alert-secondary hr { - border-top-color: #c8cbcf; -} - -.alert-secondary .alert-link { - color: #202326; -} - -.alert-success { - color: #155724; - background-color: #d4edda; - border-color: #c3e6cb; -} - -.alert-success hr { - border-top-color: #b1dfbb; -} - -.alert-success .alert-link { - color: #0b2e13; -} - -.alert-info { - color: #0c5460; - background-color: #d1ecf1; - border-color: #bee5eb; -} - -.alert-info hr { - border-top-color: #abdde5; -} - -.alert-info .alert-link { - color: #062c33; -} - -.alert-warning { - color: #856404; - background-color: #fff3cd; - border-color: #ffeeba; -} - -.alert-warning hr { - border-top-color: #ffe8a1; -} - -.alert-warning .alert-link { - color: #533f03; -} - -.alert-danger { - color: #721c24; - background-color: #f8d7da; - border-color: #f5c6cb; -} - -.alert-danger hr { - border-top-color: #f1b0b7; -} - -.alert-danger .alert-link { - color: #491217; -} - -.alert-light { - color: #818182; - background-color: #fefefe; - border-color: #fdfdfe; -} - -.alert-light hr { - border-top-color: #ececf6; -} - -.alert-light .alert-link { - color: #686868; -} - -.alert-dark { - color: #1b1e21; - background-color: #d6d8d9; - border-color: #c6c8ca; -} - -.alert-dark hr { - border-top-color: #b9bbbe; -} - -.alert-dark .alert-link { - color: #040505; -} - -@-webkit-keyframes progress-bar-stripes { - from { - background-position: 1rem 0; - } - to { - background-position: 0 0; - } -} - -@keyframes progress-bar-stripes { - from { - background-position: 1rem 0; - } - to { - background-position: 0 0; - } -} - -.progress { - display: -ms-flexbox; - display: flex; - height: 1rem; - overflow: hidden; - font-size: 0.75rem; - background-color: #e9ecef; - border-radius: 0.25rem; -} - -.progress-bar { - display: -ms-flexbox; - display: flex; - -ms-flex-direction: column; - flex-direction: column; - -ms-flex-pack: center; - justify-content: center; - color: #fff; - text-align: center; - white-space: nowrap; - background-color: #007bff; - transition: width 0.6s ease; -} - -@media screen and (prefers-reduced-motion: reduce) { - .progress-bar { - transition: none; - } -} - -.progress-bar-striped { - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-size: 1rem 1rem; -} - -.progress-bar-animated { - -webkit-animation: progress-bar-stripes 1s linear infinite; - animation: progress-bar-stripes 1s linear infinite; -} - -.media { - display: -ms-flexbox; - display: flex; - -ms-flex-align: start; - align-items: flex-start; -} - -.media-body { - -ms-flex: 1; - flex: 1; -} - -.list-group { - display: -ms-flexbox; - display: flex; - -ms-flex-direction: column; - flex-direction: column; - padding-left: 0; - margin-bottom: 0; -} - -.list-group-item-action { - width: 100%; - color: #495057; - text-align: inherit; -} - -.list-group-item-action:hover, .list-group-item-action:focus { - color: #495057; - text-decoration: none; - background-color: #f8f9fa; -} - -.list-group-item-action:active { - color: #212529; - background-color: #e9ecef; -} - -.list-group-item { - position: relative; - display: block; - padding: 0.75rem 1.25rem; - margin-bottom: -1px; - background-color: #fff; - border: 1px solid rgba(0, 0, 0, 0.125); -} - -.list-group-item:first-child { - border-top-left-radius: 0.25rem; - border-top-right-radius: 0.25rem; -} - -.list-group-item:last-child { - margin-bottom: 0; - border-bottom-right-radius: 0.25rem; - border-bottom-left-radius: 0.25rem; -} - -.list-group-item:hover, .list-group-item:focus { - z-index: 1; - text-decoration: none; -} - -.list-group-item.disabled, .list-group-item:disabled { - color: #6c757d; - background-color: #fff; -} - -.list-group-item.active { - z-index: 2; - color: #fff; - background-color: #007bff; - border-color: #007bff; -} - -.list-group-flush .list-group-item { - border-right: 0; - border-left: 0; - border-radius: 0; -} - -.list-group-flush:first-child .list-group-item:first-child { - border-top: 0; -} - -.list-group-flush:last-child .list-group-item:last-child { - border-bottom: 0; -} - -.list-group-item-primary { - color: #004085; - background-color: #b8daff; -} - -.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus { - color: #004085; - background-color: #9fcdff; -} - -.list-group-item-primary.list-group-item-action.active { - color: #fff; - background-color: #004085; - border-color: #004085; -} - -.list-group-item-secondary { - color: #383d41; - background-color: #d6d8db; -} - -.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus { - color: #383d41; - background-color: #c8cbcf; -} - -.list-group-item-secondary.list-group-item-action.active { - color: #fff; - background-color: #383d41; - border-color: #383d41; -} - -.list-group-item-success { - color: #155724; - background-color: #c3e6cb; -} - -.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus { - color: #155724; - background-color: #b1dfbb; -} - -.list-group-item-success.list-group-item-action.active { - color: #fff; - background-color: #155724; - border-color: #155724; -} - -.list-group-item-info { - color: #0c5460; - background-color: #bee5eb; -} - -.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus { - color: #0c5460; - background-color: #abdde5; -} - -.list-group-item-info.list-group-item-action.active { - color: #fff; - background-color: #0c5460; - border-color: #0c5460; -} - -.list-group-item-warning { - color: #856404; - background-color: #ffeeba; -} - -.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus { - color: #856404; - background-color: #ffe8a1; -} - -.list-group-item-warning.list-group-item-action.active { - color: #fff; - background-color: #856404; - border-color: #856404; -} - -.list-group-item-danger { - color: #721c24; - background-color: #f5c6cb; -} - -.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus { - color: #721c24; - background-color: #f1b0b7; -} - -.list-group-item-danger.list-group-item-action.active { - color: #fff; - background-color: #721c24; - border-color: #721c24; -} - -.list-group-item-light { - color: #818182; - background-color: #fdfdfe; -} - -.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus { - color: #818182; - background-color: #ececf6; -} - -.list-group-item-light.list-group-item-action.active { - color: #fff; - background-color: #818182; - border-color: #818182; -} - -.list-group-item-dark { - color: #1b1e21; - background-color: #c6c8ca; -} - -.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus { - color: #1b1e21; - background-color: #b9bbbe; -} - -.list-group-item-dark.list-group-item-action.active { - color: #fff; - background-color: #1b1e21; - border-color: #1b1e21; -} - -.close { - float: right; - font-size: 1.5rem; - font-weight: 700; - line-height: 1; - color: #000; - text-shadow: 0 1px 0 #fff; - opacity: .5; -} - -.close:hover, .close:focus { - color: #000; - text-decoration: none; - opacity: .75; -} - -.close:not(:disabled):not(.disabled) { - cursor: pointer; -} - -button.close { - padding: 0; - background-color: transparent; - border: 0; - -webkit-appearance: none; -} - -.modal-open { - overflow: hidden; -} - -.modal { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1050; - display: none; - overflow: hidden; - outline: 0; -} - -.modal-open .modal { - overflow-x: hidden; - overflow-y: auto; -} - -.modal-dialog { - position: relative; - width: auto; - margin: 0.5rem; - pointer-events: none; -} - -.modal.fade .modal-dialog { - transition: -webkit-transform 0.3s ease-out; - transition: transform 0.3s ease-out; - transition: transform 0.3s ease-out, -webkit-transform 0.3s ease-out; - -webkit-transform: translate(0, -25%); - transform: translate(0, -25%); -} - -@media screen and (prefers-reduced-motion: reduce) { - .modal.fade .modal-dialog { - transition: none; - } -} - -.modal.show .modal-dialog { - -webkit-transform: translate(0, 0); - transform: translate(0, 0); -} - -.modal-dialog-centered { - display: -ms-flexbox; - display: flex; - -ms-flex-align: center; - align-items: center; - min-height: calc(100% - (0.5rem * 2)); -} - -.modal-content { - position: relative; - display: -ms-flexbox; - display: flex; - -ms-flex-direction: column; - flex-direction: column; - width: 100%; - pointer-events: auto; - background-color: #fff; - background-clip: padding-box; - border: 1px solid rgba(0, 0, 0, 0.2); - border-radius: 0.3rem; - outline: 0; -} - -.modal-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1040; - background-color: #000; -} - -.modal-backdrop.fade { - opacity: 0; -} - -.modal-backdrop.show { - opacity: 0.5; -} - -.modal-header { - display: -ms-flexbox; - display: flex; - -ms-flex-align: start; - align-items: flex-start; - -ms-flex-pack: justify; - justify-content: space-between; - padding: 1rem; - border-bottom: 1px solid #e9ecef; - border-top-left-radius: 0.3rem; - border-top-right-radius: 0.3rem; -} - -.modal-header .close { - padding: 1rem; - margin: -1rem -1rem -1rem auto; -} - -.modal-title { - margin-bottom: 0; - line-height: 1.5; -} - -.modal-body { - position: relative; - -ms-flex: 1 1 auto; - flex: 1 1 auto; - padding: 1rem; -} - -.modal-footer { - display: -ms-flexbox; - display: flex; - -ms-flex-align: center; - align-items: center; - -ms-flex-pack: end; - justify-content: flex-end; - padding: 1rem; - border-top: 1px solid #e9ecef; -} - -.modal-footer > :not(:first-child) { - margin-left: .25rem; -} - -.modal-footer > :not(:last-child) { - margin-right: .25rem; -} - -.modal-scrollbar-measure { - position: absolute; - top: -9999px; - width: 50px; - height: 50px; - overflow: scroll; -} - -@media (min-width: 576px) { - .modal-dialog { - max-width: 500px; - margin: 1.75rem auto; - } - .modal-dialog-centered { - min-height: calc(100% - (1.75rem * 2)); - } - .modal-sm { - max-width: 300px; - } -} - -@media (min-width: 992px) { - .modal-lg { - max-width: 800px; - } -} - -.tooltip { - position: absolute; - z-index: 1070; - display: block; - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; - font-style: normal; - font-weight: 400; - line-height: 1.5; - text-align: left; - text-align: start; - text-decoration: none; - text-shadow: none; - text-transform: none; - letter-spacing: normal; - word-break: normal; - word-spacing: normal; - white-space: normal; - line-break: auto; - font-size: 0.875rem; - word-wrap: break-word; - opacity: 0; -} - -.tooltip.show { - opacity: 0.9; -} - -.tooltip .arrow { - position: absolute; - display: block; - width: 0.8rem; - height: 0.4rem; -} - -.tooltip .arrow::before { - position: absolute; - content: ""; - border-color: transparent; - border-style: solid; -} - -.bs-tooltip-top, .bs-tooltip-auto[x-placement^="top"] { - padding: 0.4rem 0; -} - -.bs-tooltip-top .arrow, .bs-tooltip-auto[x-placement^="top"] .arrow { - bottom: 0; -} - -.bs-tooltip-top .arrow::before, .bs-tooltip-auto[x-placement^="top"] .arrow::before { - top: 0; - border-width: 0.4rem 0.4rem 0; - border-top-color: #000; -} - -.bs-tooltip-right, .bs-tooltip-auto[x-placement^="right"] { - padding: 0 0.4rem; -} - -.bs-tooltip-right .arrow, .bs-tooltip-auto[x-placement^="right"] .arrow { - left: 0; - width: 0.4rem; - height: 0.8rem; -} - -.bs-tooltip-right .arrow::before, .bs-tooltip-auto[x-placement^="right"] .arrow::before { - right: 0; - border-width: 0.4rem 0.4rem 0.4rem 0; - border-right-color: #000; -} - -.bs-tooltip-bottom, .bs-tooltip-auto[x-placement^="bottom"] { - padding: 0.4rem 0; -} - -.bs-tooltip-bottom .arrow, .bs-tooltip-auto[x-placement^="bottom"] .arrow { - top: 0; -} - -.bs-tooltip-bottom .arrow::before, .bs-tooltip-auto[x-placement^="bottom"] .arrow::before { - bottom: 0; - border-width: 0 0.4rem 0.4rem; - border-bottom-color: #000; -} - -.bs-tooltip-left, .bs-tooltip-auto[x-placement^="left"] { - padding: 0 0.4rem; -} - -.bs-tooltip-left .arrow, .bs-tooltip-auto[x-placement^="left"] .arrow { - right: 0; - width: 0.4rem; - height: 0.8rem; -} - -.bs-tooltip-left .arrow::before, .bs-tooltip-auto[x-placement^="left"] .arrow::before { - left: 0; - border-width: 0.4rem 0 0.4rem 0.4rem; - border-left-color: #000; -} - -.tooltip-inner { - max-width: 200px; - padding: 0.25rem 0.5rem; - color: #fff; - text-align: center; - background-color: #000; - border-radius: 0.25rem; -} - -.popover { - position: absolute; - top: 0; - left: 0; - z-index: 1060; - display: block; - max-width: 276px; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; - font-style: normal; - font-weight: 400; - line-height: 1.5; - text-align: left; - text-align: start; - text-decoration: none; - text-shadow: none; - text-transform: none; - letter-spacing: normal; - word-break: normal; - word-spacing: normal; - white-space: normal; - line-break: auto; - font-size: 0.875rem; - word-wrap: break-word; - background-color: #fff; - background-clip: padding-box; - border: 1px solid rgba(0, 0, 0, 0.2); - border-radius: 0.3rem; -} - -.popover .arrow { - position: absolute; - display: block; - width: 1rem; - height: 0.5rem; - margin: 0 0.3rem; -} - -.popover .arrow::before, .popover .arrow::after { - position: absolute; - display: block; - content: ""; - border-color: transparent; - border-style: solid; -} - -.bs-popover-top, .bs-popover-auto[x-placement^="top"] { - margin-bottom: 0.5rem; -} - -.bs-popover-top .arrow, .bs-popover-auto[x-placement^="top"] .arrow { - bottom: calc((0.5rem + 1px) * -1); -} - -.bs-popover-top .arrow::before, .bs-popover-auto[x-placement^="top"] .arrow::before, -.bs-popover-top .arrow::after, .bs-popover-auto[x-placement^="top"] .arrow::after { - border-width: 0.5rem 0.5rem 0; -} - -.bs-popover-top .arrow::before, .bs-popover-auto[x-placement^="top"] .arrow::before { - bottom: 0; - border-top-color: rgba(0, 0, 0, 0.25); -} - -.bs-popover-top .arrow::after, .bs-popover-auto[x-placement^="top"] .arrow::after { - bottom: 1px; - border-top-color: #fff; -} - -.bs-popover-right, .bs-popover-auto[x-placement^="right"] { - margin-left: 0.5rem; -} - -.bs-popover-right .arrow, .bs-popover-auto[x-placement^="right"] .arrow { - left: calc((0.5rem + 1px) * -1); - width: 0.5rem; - height: 1rem; - margin: 0.3rem 0; -} - -.bs-popover-right .arrow::before, .bs-popover-auto[x-placement^="right"] .arrow::before, -.bs-popover-right .arrow::after, .bs-popover-auto[x-placement^="right"] .arrow::after { - border-width: 0.5rem 0.5rem 0.5rem 0; -} - -.bs-popover-right .arrow::before, .bs-popover-auto[x-placement^="right"] .arrow::before { - left: 0; - border-right-color: rgba(0, 0, 0, 0.25); -} - -.bs-popover-right .arrow::after, .bs-popover-auto[x-placement^="right"] .arrow::after { - left: 1px; - border-right-color: #fff; -} - -.bs-popover-bottom, .bs-popover-auto[x-placement^="bottom"] { - margin-top: 0.5rem; -} - -.bs-popover-bottom .arrow, .bs-popover-auto[x-placement^="bottom"] .arrow { - top: calc((0.5rem + 1px) * -1); -} - -.bs-popover-bottom .arrow::before, .bs-popover-auto[x-placement^="bottom"] .arrow::before, -.bs-popover-bottom .arrow::after, .bs-popover-auto[x-placement^="bottom"] .arrow::after { - border-width: 0 0.5rem 0.5rem 0.5rem; -} - -.bs-popover-bottom .arrow::before, .bs-popover-auto[x-placement^="bottom"] .arrow::before { - top: 0; - border-bottom-color: rgba(0, 0, 0, 0.25); -} - -.bs-popover-bottom .arrow::after, .bs-popover-auto[x-placement^="bottom"] .arrow::after { - top: 1px; - border-bottom-color: #fff; -} - -.bs-popover-bottom .popover-header::before, .bs-popover-auto[x-placement^="bottom"] .popover-header::before { - position: absolute; - top: 0; - left: 50%; - display: block; - width: 1rem; - margin-left: -0.5rem; - content: ""; - border-bottom: 1px solid #f7f7f7; -} - -.bs-popover-left, .bs-popover-auto[x-placement^="left"] { - margin-right: 0.5rem; -} - -.bs-popover-left .arrow, .bs-popover-auto[x-placement^="left"] .arrow { - right: calc((0.5rem + 1px) * -1); - width: 0.5rem; - height: 1rem; - margin: 0.3rem 0; -} - -.bs-popover-left .arrow::before, .bs-popover-auto[x-placement^="left"] .arrow::before, -.bs-popover-left .arrow::after, .bs-popover-auto[x-placement^="left"] .arrow::after { - border-width: 0.5rem 0 0.5rem 0.5rem; -} - -.bs-popover-left .arrow::before, .bs-popover-auto[x-placement^="left"] .arrow::before { - right: 0; - border-left-color: rgba(0, 0, 0, 0.25); -} - -.bs-popover-left .arrow::after, .bs-popover-auto[x-placement^="left"] .arrow::after { - right: 1px; - border-left-color: #fff; -} - -.popover-header { - padding: 0.5rem 0.75rem; - margin-bottom: 0; - font-size: 1rem; - color: inherit; - background-color: #f7f7f7; - border-bottom: 1px solid #ebebeb; - border-top-left-radius: calc(0.3rem - 1px); - border-top-right-radius: calc(0.3rem - 1px); -} - -.popover-header:empty { - display: none; -} - -.popover-body { - padding: 0.5rem 0.75rem; - color: #212529; -} - -.carousel { - position: relative; -} - -.carousel-inner { - position: relative; - width: 100%; - overflow: hidden; -} - -.carousel-item { - position: relative; - display: none; - -ms-flex-align: center; - align-items: center; - width: 100%; - transition: -webkit-transform 0.6s ease; - transition: transform 0.6s ease; - transition: transform 0.6s ease, -webkit-transform 0.6s ease; - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - -webkit-perspective: 1000px; - perspective: 1000px; -} - -@media screen and (prefers-reduced-motion: reduce) { - .carousel-item { - transition: none; - } -} - -.carousel-item.active, -.carousel-item-next, -.carousel-item-prev { - display: block; -} - -.carousel-item-next, -.carousel-item-prev { - position: absolute; - top: 0; -} - -.carousel-item-next.carousel-item-left, -.carousel-item-prev.carousel-item-right { - -webkit-transform: translateX(0); - transform: translateX(0); -} - -@supports ((-webkit-transform-style: preserve-3d) or (transform-style: preserve-3d)) { - .carousel-item-next.carousel-item-left, - .carousel-item-prev.carousel-item-right { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.carousel-item-next, -.active.carousel-item-right { - -webkit-transform: translateX(100%); - transform: translateX(100%); -} - -@supports ((-webkit-transform-style: preserve-3d) or (transform-style: preserve-3d)) { - .carousel-item-next, - .active.carousel-item-right { - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -.carousel-item-prev, -.active.carousel-item-left { - -webkit-transform: translateX(-100%); - transform: translateX(-100%); -} - -@supports ((-webkit-transform-style: preserve-3d) or (transform-style: preserve-3d)) { - .carousel-item-prev, - .active.carousel-item-left { - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -.carousel-fade .carousel-item { - opacity: 0; - transition-duration: .6s; - transition-property: opacity; -} - -.carousel-fade .carousel-item.active, -.carousel-fade .carousel-item-next.carousel-item-left, -.carousel-fade .carousel-item-prev.carousel-item-right { - opacity: 1; -} - -.carousel-fade .active.carousel-item-left, -.carousel-fade .active.carousel-item-right { - opacity: 0; -} - -.carousel-fade .carousel-item-next, -.carousel-fade .carousel-item-prev, -.carousel-fade .carousel-item.active, -.carousel-fade .active.carousel-item-left, -.carousel-fade .active.carousel-item-prev { - -webkit-transform: translateX(0); - transform: translateX(0); -} - -@supports ((-webkit-transform-style: preserve-3d) or (transform-style: preserve-3d)) { - .carousel-fade .carousel-item-next, - .carousel-fade .carousel-item-prev, - .carousel-fade .carousel-item.active, - .carousel-fade .active.carousel-item-left, - .carousel-fade .active.carousel-item-prev { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.carousel-control-prev, -.carousel-control-next { - position: absolute; - top: 0; - bottom: 0; - display: -ms-flexbox; - display: flex; - -ms-flex-align: center; - align-items: center; - -ms-flex-pack: center; - justify-content: center; - width: 15%; - color: #fff; - text-align: center; - opacity: 0.5; -} - -.carousel-control-prev:hover, .carousel-control-prev:focus, -.carousel-control-next:hover, -.carousel-control-next:focus { - color: #fff; - text-decoration: none; - outline: 0; - opacity: .9; -} - -.carousel-control-prev { - left: 0; -} - -.carousel-control-next { - right: 0; -} - -.carousel-control-prev-icon, -.carousel-control-next-icon { - display: inline-block; - width: 20px; - height: 20px; - background: transparent no-repeat center center; - background-size: 100% 100%; -} - -.carousel-control-prev-icon { - background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E"); -} - -.carousel-control-next-icon { - background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E"); -} - -.carousel-indicators { - position: absolute; - right: 0; - bottom: 10px; - left: 0; - z-index: 15; - display: -ms-flexbox; - display: flex; - -ms-flex-pack: center; - justify-content: center; - padding-left: 0; - margin-right: 15%; - margin-left: 15%; - list-style: none; -} - -.carousel-indicators li { - position: relative; - -ms-flex: 0 1 auto; - flex: 0 1 auto; - width: 30px; - height: 3px; - margin-right: 3px; - margin-left: 3px; - text-indent: -999px; - background-color: rgba(255, 255, 255, 0.5); -} - -.carousel-indicators li::before { - position: absolute; - top: -10px; - left: 0; - display: inline-block; - width: 100%; - height: 10px; - content: ""; -} - -.carousel-indicators li::after { - position: absolute; - bottom: -10px; - left: 0; - display: inline-block; - width: 100%; - height: 10px; - content: ""; -} - -.carousel-indicators .active { - background-color: #fff; -} - -.carousel-caption { - position: absolute; - right: 15%; - bottom: 20px; - left: 15%; - z-index: 10; - padding-top: 20px; - padding-bottom: 20px; - color: #fff; - text-align: center; -} - -.align-baseline { - vertical-align: baseline !important; -} - -.align-top { - vertical-align: top !important; -} - -.align-middle { - vertical-align: middle !important; -} - -.align-bottom { - vertical-align: bottom !important; -} - -.align-text-bottom { - vertical-align: text-bottom !important; -} - -.align-text-top { - vertical-align: text-top !important; -} - -.bg-primary { - background-color: #007bff !important; -} - -a.bg-primary:hover, a.bg-primary:focus, -button.bg-primary:hover, -button.bg-primary:focus { - background-color: #0062cc !important; -} - -.bg-secondary { - background-color: #6c757d !important; -} - -a.bg-secondary:hover, a.bg-secondary:focus, -button.bg-secondary:hover, -button.bg-secondary:focus { - background-color: #545b62 !important; -} - -.bg-success { - background-color: #28a745 !important; -} - -a.bg-success:hover, a.bg-success:focus, -button.bg-success:hover, -button.bg-success:focus { - background-color: #1e7e34 !important; -} - -.bg-info { - background-color: #17a2b8 !important; -} - -a.bg-info:hover, a.bg-info:focus, -button.bg-info:hover, -button.bg-info:focus { - background-color: #117a8b !important; -} - -.bg-warning { - background-color: #ffc107 !important; -} - -a.bg-warning:hover, a.bg-warning:focus, -button.bg-warning:hover, -button.bg-warning:focus { - background-color: #d39e00 !important; -} - -.bg-danger { - background-color: #dc3545 !important; -} - -a.bg-danger:hover, a.bg-danger:focus, -button.bg-danger:hover, -button.bg-danger:focus { - background-color: #bd2130 !important; -} - -.bg-light { - background-color: #f8f9fa !important; -} - -a.bg-light:hover, a.bg-light:focus, -button.bg-light:hover, -button.bg-light:focus { - background-color: #dae0e5 !important; -} - -.bg-dark { - background-color: #343a40 !important; -} - -a.bg-dark:hover, a.bg-dark:focus, -button.bg-dark:hover, -button.bg-dark:focus { - background-color: #1d2124 !important; -} - -.bg-white { - background-color: #fff !important; -} - -.bg-transparent { - background-color: transparent !important; -} - -.border { - border: 1px solid #dee2e6 !important; -} - -.border-top { - border-top: 1px solid #dee2e6 !important; -} - -.border-right { - border-right: 1px solid #dee2e6 !important; -} - -.border-bottom { - border-bottom: 1px solid #dee2e6 !important; -} - -.border-left { - border-left: 1px solid #dee2e6 !important; -} - -.border-0 { - border: 0 !important; -} - -.border-top-0 { - border-top: 0 !important; -} - -.border-right-0 { - border-right: 0 !important; -} - -.border-bottom-0 { - border-bottom: 0 !important; -} - -.border-left-0 { - border-left: 0 !important; -} - -.border-primary { - border-color: #007bff !important; -} - -.border-secondary { - border-color: #6c757d !important; -} - -.border-success { - border-color: #28a745 !important; -} - -.border-info { - border-color: #17a2b8 !important; -} - -.border-warning { - border-color: #ffc107 !important; -} - -.border-danger { - border-color: #dc3545 !important; -} - -.border-light { - border-color: #f8f9fa !important; -} - -.border-dark { - border-color: #343a40 !important; -} - -.border-white { - border-color: #fff !important; -} - -.rounded { - border-radius: 0.25rem !important; -} - -.rounded-top { - border-top-left-radius: 0.25rem !important; - border-top-right-radius: 0.25rem !important; -} - -.rounded-right { - border-top-right-radius: 0.25rem !important; - border-bottom-right-radius: 0.25rem !important; -} - -.rounded-bottom { - border-bottom-right-radius: 0.25rem !important; - border-bottom-left-radius: 0.25rem !important; -} - -.rounded-left { - border-top-left-radius: 0.25rem !important; - border-bottom-left-radius: 0.25rem !important; -} - -.rounded-circle { - border-radius: 50% !important; -} - -.rounded-0 { - border-radius: 0 !important; -} - -.clearfix::after { - display: block; - clear: both; - content: ""; -} - -.d-none { - display: none !important; -} - -.d-inline { - display: inline !important; -} - -.d-inline-block { - display: inline-block !important; -} - -.d-block { - display: block !important; -} - -.d-table { - display: table !important; -} - -.d-table-row { - display: table-row !important; -} - -.d-table-cell { - display: table-cell !important; -} - -.d-flex { - display: -ms-flexbox !important; - display: flex !important; -} - -.d-inline-flex { - display: -ms-inline-flexbox !important; - display: inline-flex !important; -} - -@media (min-width: 576px) { - .d-sm-none { - display: none !important; - } - .d-sm-inline { - display: inline !important; - } - .d-sm-inline-block { - display: inline-block !important; - } - .d-sm-block { - display: block !important; - } - .d-sm-table { - display: table !important; - } - .d-sm-table-row { - display: table-row !important; - } - .d-sm-table-cell { - display: table-cell !important; - } - .d-sm-flex { - display: -ms-flexbox !important; - display: flex !important; - } - .d-sm-inline-flex { - display: -ms-inline-flexbox !important; - display: inline-flex !important; - } -} - -@media (min-width: 768px) { - .d-md-none { - display: none !important; - } - .d-md-inline { - display: inline !important; - } - .d-md-inline-block { - display: inline-block !important; - } - .d-md-block { - display: block !important; - } - .d-md-table { - display: table !important; - } - .d-md-table-row { - display: table-row !important; - } - .d-md-table-cell { - display: table-cell !important; - } - .d-md-flex { - display: -ms-flexbox !important; - display: flex !important; - } - .d-md-inline-flex { - display: -ms-inline-flexbox !important; - display: inline-flex !important; - } -} - -@media (min-width: 992px) { - .d-lg-none { - display: none !important; - } - .d-lg-inline { - display: inline !important; - } - .d-lg-inline-block { - display: inline-block !important; - } - .d-lg-block { - display: block !important; - } - .d-lg-table { - display: table !important; - } - .d-lg-table-row { - display: table-row !important; - } - .d-lg-table-cell { - display: table-cell !important; - } - .d-lg-flex { - display: -ms-flexbox !important; - display: flex !important; - } - .d-lg-inline-flex { - display: -ms-inline-flexbox !important; - display: inline-flex !important; - } -} - -@media (min-width: 1200px) { - .d-xl-none { - display: none !important; - } - .d-xl-inline { - display: inline !important; - } - .d-xl-inline-block { - display: inline-block !important; - } - .d-xl-block { - display: block !important; - } - .d-xl-table { - display: table !important; - } - .d-xl-table-row { - display: table-row !important; - } - .d-xl-table-cell { - display: table-cell !important; - } - .d-xl-flex { - display: -ms-flexbox !important; - display: flex !important; - } - .d-xl-inline-flex { - display: -ms-inline-flexbox !important; - display: inline-flex !important; - } -} - -@media print { - .d-print-none { - display: none !important; - } - .d-print-inline { - display: inline !important; - } - .d-print-inline-block { - display: inline-block !important; - } - .d-print-block { - display: block !important; - } - .d-print-table { - display: table !important; - } - .d-print-table-row { - display: table-row !important; - } - .d-print-table-cell { - display: table-cell !important; - } - .d-print-flex { - display: -ms-flexbox !important; - display: flex !important; - } - .d-print-inline-flex { - display: -ms-inline-flexbox !important; - display: inline-flex !important; - } -} - -.embed-responsive { - position: relative; - display: block; - width: 100%; - padding: 0; - overflow: hidden; -} - -.embed-responsive::before { - display: block; - content: ""; -} - -.embed-responsive .embed-responsive-item, -.embed-responsive iframe, -.embed-responsive embed, -.embed-responsive object, -.embed-responsive video { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 100%; - height: 100%; - border: 0; -} - -.embed-responsive-21by9::before { - padding-top: 42.857143%; -} - -.embed-responsive-16by9::before { - padding-top: 56.25%; -} - -.embed-responsive-4by3::before { - padding-top: 75%; -} - -.embed-responsive-1by1::before { - padding-top: 100%; -} - -.flex-row { - -ms-flex-direction: row !important; - flex-direction: row !important; -} - -.flex-column { - -ms-flex-direction: column !important; - flex-direction: column !important; -} - -.flex-row-reverse { - -ms-flex-direction: row-reverse !important; - flex-direction: row-reverse !important; -} - -.flex-column-reverse { - -ms-flex-direction: column-reverse !important; - flex-direction: column-reverse !important; -} - -.flex-wrap { - -ms-flex-wrap: wrap !important; - flex-wrap: wrap !important; -} - -.flex-nowrap { - -ms-flex-wrap: nowrap !important; - flex-wrap: nowrap !important; -} - -.flex-wrap-reverse { - -ms-flex-wrap: wrap-reverse !important; - flex-wrap: wrap-reverse !important; -} - -.flex-fill { - -ms-flex: 1 1 auto !important; - flex: 1 1 auto !important; -} - -.flex-grow-0 { - -ms-flex-positive: 0 !important; - flex-grow: 0 !important; -} - -.flex-grow-1 { - -ms-flex-positive: 1 !important; - flex-grow: 1 !important; -} - -.flex-shrink-0 { - -ms-flex-negative: 0 !important; - flex-shrink: 0 !important; -} - -.flex-shrink-1 { - -ms-flex-negative: 1 !important; - flex-shrink: 1 !important; -} - -.justify-content-start { - -ms-flex-pack: start !important; - justify-content: flex-start !important; -} - -.justify-content-end { - -ms-flex-pack: end !important; - justify-content: flex-end !important; -} - -.justify-content-center { - -ms-flex-pack: center !important; - justify-content: center !important; -} - -.justify-content-between { - -ms-flex-pack: justify !important; - justify-content: space-between !important; -} - -.justify-content-around { - -ms-flex-pack: distribute !important; - justify-content: space-around !important; -} - -.align-items-start { - -ms-flex-align: start !important; - align-items: flex-start !important; -} - -.align-items-end { - -ms-flex-align: end !important; - align-items: flex-end !important; -} - -.align-items-center { - -ms-flex-align: center !important; - align-items: center !important; -} - -.align-items-baseline { - -ms-flex-align: baseline !important; - align-items: baseline !important; -} - -.align-items-stretch { - -ms-flex-align: stretch !important; - align-items: stretch !important; -} - -.align-content-start { - -ms-flex-line-pack: start !important; - align-content: flex-start !important; -} - -.align-content-end { - -ms-flex-line-pack: end !important; - align-content: flex-end !important; -} - -.align-content-center { - -ms-flex-line-pack: center !important; - align-content: center !important; -} - -.align-content-between { - -ms-flex-line-pack: justify !important; - align-content: space-between !important; -} - -.align-content-around { - -ms-flex-line-pack: distribute !important; - align-content: space-around !important; -} - -.align-content-stretch { - -ms-flex-line-pack: stretch !important; - align-content: stretch !important; -} - -.align-self-auto { - -ms-flex-item-align: auto !important; - align-self: auto !important; -} - -.align-self-start { - -ms-flex-item-align: start !important; - align-self: flex-start !important; -} - -.align-self-end { - -ms-flex-item-align: end !important; - align-self: flex-end !important; -} - -.align-self-center { - -ms-flex-item-align: center !important; - align-self: center !important; -} - -.align-self-baseline { - -ms-flex-item-align: baseline !important; - align-self: baseline !important; -} - -.align-self-stretch { - -ms-flex-item-align: stretch !important; - align-self: stretch !important; -} - -@media (min-width: 576px) { - .flex-sm-row { - -ms-flex-direction: row !important; - flex-direction: row !important; - } - .flex-sm-column { - -ms-flex-direction: column !important; - flex-direction: column !important; - } - .flex-sm-row-reverse { - -ms-flex-direction: row-reverse !important; - flex-direction: row-reverse !important; - } - .flex-sm-column-reverse { - -ms-flex-direction: column-reverse !important; - flex-direction: column-reverse !important; - } - .flex-sm-wrap { - -ms-flex-wrap: wrap !important; - flex-wrap: wrap !important; - } - .flex-sm-nowrap { - -ms-flex-wrap: nowrap !important; - flex-wrap: nowrap !important; - } - .flex-sm-wrap-reverse { - -ms-flex-wrap: wrap-reverse !important; - flex-wrap: wrap-reverse !important; - } - .flex-sm-fill { - -ms-flex: 1 1 auto !important; - flex: 1 1 auto !important; - } - .flex-sm-grow-0 { - -ms-flex-positive: 0 !important; - flex-grow: 0 !important; - } - .flex-sm-grow-1 { - -ms-flex-positive: 1 !important; - flex-grow: 1 !important; - } - .flex-sm-shrink-0 { - -ms-flex-negative: 0 !important; - flex-shrink: 0 !important; - } - .flex-sm-shrink-1 { - -ms-flex-negative: 1 !important; - flex-shrink: 1 !important; - } - .justify-content-sm-start { - -ms-flex-pack: start !important; - justify-content: flex-start !important; - } - .justify-content-sm-end { - -ms-flex-pack: end !important; - justify-content: flex-end !important; - } - .justify-content-sm-center { - -ms-flex-pack: center !important; - justify-content: center !important; - } - .justify-content-sm-between { - -ms-flex-pack: justify !important; - justify-content: space-between !important; - } - .justify-content-sm-around { - -ms-flex-pack: distribute !important; - justify-content: space-around !important; - } - .align-items-sm-start { - -ms-flex-align: start !important; - align-items: flex-start !important; - } - .align-items-sm-end { - -ms-flex-align: end !important; - align-items: flex-end !important; - } - .align-items-sm-center { - -ms-flex-align: center !important; - align-items: center !important; - } - .align-items-sm-baseline { - -ms-flex-align: baseline !important; - align-items: baseline !important; - } - .align-items-sm-stretch { - -ms-flex-align: stretch !important; - align-items: stretch !important; - } - .align-content-sm-start { - -ms-flex-line-pack: start !important; - align-content: flex-start !important; - } - .align-content-sm-end { - -ms-flex-line-pack: end !important; - align-content: flex-end !important; - } - .align-content-sm-center { - -ms-flex-line-pack: center !important; - align-content: center !important; - } - .align-content-sm-between { - -ms-flex-line-pack: justify !important; - align-content: space-between !important; - } - .align-content-sm-around { - -ms-flex-line-pack: distribute !important; - align-content: space-around !important; - } - .align-content-sm-stretch { - -ms-flex-line-pack: stretch !important; - align-content: stretch !important; - } - .align-self-sm-auto { - -ms-flex-item-align: auto !important; - align-self: auto !important; - } - .align-self-sm-start { - -ms-flex-item-align: start !important; - align-self: flex-start !important; - } - .align-self-sm-end { - -ms-flex-item-align: end !important; - align-self: flex-end !important; - } - .align-self-sm-center { - -ms-flex-item-align: center !important; - align-self: center !important; - } - .align-self-sm-baseline { - -ms-flex-item-align: baseline !important; - align-self: baseline !important; - } - .align-self-sm-stretch { - -ms-flex-item-align: stretch !important; - align-self: stretch !important; - } -} - -@media (min-width: 768px) { - .flex-md-row { - -ms-flex-direction: row !important; - flex-direction: row !important; - } - .flex-md-column { - -ms-flex-direction: column !important; - flex-direction: column !important; - } - .flex-md-row-reverse { - -ms-flex-direction: row-reverse !important; - flex-direction: row-reverse !important; - } - .flex-md-column-reverse { - -ms-flex-direction: column-reverse !important; - flex-direction: column-reverse !important; - } - .flex-md-wrap { - -ms-flex-wrap: wrap !important; - flex-wrap: wrap !important; - } - .flex-md-nowrap { - -ms-flex-wrap: nowrap !important; - flex-wrap: nowrap !important; - } - .flex-md-wrap-reverse { - -ms-flex-wrap: wrap-reverse !important; - flex-wrap: wrap-reverse !important; - } - .flex-md-fill { - -ms-flex: 1 1 auto !important; - flex: 1 1 auto !important; - } - .flex-md-grow-0 { - -ms-flex-positive: 0 !important; - flex-grow: 0 !important; - } - .flex-md-grow-1 { - -ms-flex-positive: 1 !important; - flex-grow: 1 !important; - } - .flex-md-shrink-0 { - -ms-flex-negative: 0 !important; - flex-shrink: 0 !important; - } - .flex-md-shrink-1 { - -ms-flex-negative: 1 !important; - flex-shrink: 1 !important; - } - .justify-content-md-start { - -ms-flex-pack: start !important; - justify-content: flex-start !important; - } - .justify-content-md-end { - -ms-flex-pack: end !important; - justify-content: flex-end !important; - } - .justify-content-md-center { - -ms-flex-pack: center !important; - justify-content: center !important; - } - .justify-content-md-between { - -ms-flex-pack: justify !important; - justify-content: space-between !important; - } - .justify-content-md-around { - -ms-flex-pack: distribute !important; - justify-content: space-around !important; - } - .align-items-md-start { - -ms-flex-align: start !important; - align-items: flex-start !important; - } - .align-items-md-end { - -ms-flex-align: end !important; - align-items: flex-end !important; - } - .align-items-md-center { - -ms-flex-align: center !important; - align-items: center !important; - } - .align-items-md-baseline { - -ms-flex-align: baseline !important; - align-items: baseline !important; - } - .align-items-md-stretch { - -ms-flex-align: stretch !important; - align-items: stretch !important; - } - .align-content-md-start { - -ms-flex-line-pack: start !important; - align-content: flex-start !important; - } - .align-content-md-end { - -ms-flex-line-pack: end !important; - align-content: flex-end !important; - } - .align-content-md-center { - -ms-flex-line-pack: center !important; - align-content: center !important; - } - .align-content-md-between { - -ms-flex-line-pack: justify !important; - align-content: space-between !important; - } - .align-content-md-around { - -ms-flex-line-pack: distribute !important; - align-content: space-around !important; - } - .align-content-md-stretch { - -ms-flex-line-pack: stretch !important; - align-content: stretch !important; - } - .align-self-md-auto { - -ms-flex-item-align: auto !important; - align-self: auto !important; - } - .align-self-md-start { - -ms-flex-item-align: start !important; - align-self: flex-start !important; - } - .align-self-md-end { - -ms-flex-item-align: end !important; - align-self: flex-end !important; - } - .align-self-md-center { - -ms-flex-item-align: center !important; - align-self: center !important; - } - .align-self-md-baseline { - -ms-flex-item-align: baseline !important; - align-self: baseline !important; - } - .align-self-md-stretch { - -ms-flex-item-align: stretch !important; - align-self: stretch !important; - } -} - -@media (min-width: 992px) { - .flex-lg-row { - -ms-flex-direction: row !important; - flex-direction: row !important; - } - .flex-lg-column { - -ms-flex-direction: column !important; - flex-direction: column !important; - } - .flex-lg-row-reverse { - -ms-flex-direction: row-reverse !important; - flex-direction: row-reverse !important; - } - .flex-lg-column-reverse { - -ms-flex-direction: column-reverse !important; - flex-direction: column-reverse !important; - } - .flex-lg-wrap { - -ms-flex-wrap: wrap !important; - flex-wrap: wrap !important; - } - .flex-lg-nowrap { - -ms-flex-wrap: nowrap !important; - flex-wrap: nowrap !important; - } - .flex-lg-wrap-reverse { - -ms-flex-wrap: wrap-reverse !important; - flex-wrap: wrap-reverse !important; - } - .flex-lg-fill { - -ms-flex: 1 1 auto !important; - flex: 1 1 auto !important; - } - .flex-lg-grow-0 { - -ms-flex-positive: 0 !important; - flex-grow: 0 !important; - } - .flex-lg-grow-1 { - -ms-flex-positive: 1 !important; - flex-grow: 1 !important; - } - .flex-lg-shrink-0 { - -ms-flex-negative: 0 !important; - flex-shrink: 0 !important; - } - .flex-lg-shrink-1 { - -ms-flex-negative: 1 !important; - flex-shrink: 1 !important; - } - .justify-content-lg-start { - -ms-flex-pack: start !important; - justify-content: flex-start !important; - } - .justify-content-lg-end { - -ms-flex-pack: end !important; - justify-content: flex-end !important; - } - .justify-content-lg-center { - -ms-flex-pack: center !important; - justify-content: center !important; - } - .justify-content-lg-between { - -ms-flex-pack: justify !important; - justify-content: space-between !important; - } - .justify-content-lg-around { - -ms-flex-pack: distribute !important; - justify-content: space-around !important; - } - .align-items-lg-start { - -ms-flex-align: start !important; - align-items: flex-start !important; - } - .align-items-lg-end { - -ms-flex-align: end !important; - align-items: flex-end !important; - } - .align-items-lg-center { - -ms-flex-align: center !important; - align-items: center !important; - } - .align-items-lg-baseline { - -ms-flex-align: baseline !important; - align-items: baseline !important; - } - .align-items-lg-stretch { - -ms-flex-align: stretch !important; - align-items: stretch !important; - } - .align-content-lg-start { - -ms-flex-line-pack: start !important; - align-content: flex-start !important; - } - .align-content-lg-end { - -ms-flex-line-pack: end !important; - align-content: flex-end !important; - } - .align-content-lg-center { - -ms-flex-line-pack: center !important; - align-content: center !important; - } - .align-content-lg-between { - -ms-flex-line-pack: justify !important; - align-content: space-between !important; - } - .align-content-lg-around { - -ms-flex-line-pack: distribute !important; - align-content: space-around !important; - } - .align-content-lg-stretch { - -ms-flex-line-pack: stretch !important; - align-content: stretch !important; - } - .align-self-lg-auto { - -ms-flex-item-align: auto !important; - align-self: auto !important; - } - .align-self-lg-start { - -ms-flex-item-align: start !important; - align-self: flex-start !important; - } - .align-self-lg-end { - -ms-flex-item-align: end !important; - align-self: flex-end !important; - } - .align-self-lg-center { - -ms-flex-item-align: center !important; - align-self: center !important; - } - .align-self-lg-baseline { - -ms-flex-item-align: baseline !important; - align-self: baseline !important; - } - .align-self-lg-stretch { - -ms-flex-item-align: stretch !important; - align-self: stretch !important; - } -} - -@media (min-width: 1200px) { - .flex-xl-row { - -ms-flex-direction: row !important; - flex-direction: row !important; - } - .flex-xl-column { - -ms-flex-direction: column !important; - flex-direction: column !important; - } - .flex-xl-row-reverse { - -ms-flex-direction: row-reverse !important; - flex-direction: row-reverse !important; - } - .flex-xl-column-reverse { - -ms-flex-direction: column-reverse !important; - flex-direction: column-reverse !important; - } - .flex-xl-wrap { - -ms-flex-wrap: wrap !important; - flex-wrap: wrap !important; - } - .flex-xl-nowrap { - -ms-flex-wrap: nowrap !important; - flex-wrap: nowrap !important; - } - .flex-xl-wrap-reverse { - -ms-flex-wrap: wrap-reverse !important; - flex-wrap: wrap-reverse !important; - } - .flex-xl-fill { - -ms-flex: 1 1 auto !important; - flex: 1 1 auto !important; - } - .flex-xl-grow-0 { - -ms-flex-positive: 0 !important; - flex-grow: 0 !important; - } - .flex-xl-grow-1 { - -ms-flex-positive: 1 !important; - flex-grow: 1 !important; - } - .flex-xl-shrink-0 { - -ms-flex-negative: 0 !important; - flex-shrink: 0 !important; - } - .flex-xl-shrink-1 { - -ms-flex-negative: 1 !important; - flex-shrink: 1 !important; - } - .justify-content-xl-start { - -ms-flex-pack: start !important; - justify-content: flex-start !important; - } - .justify-content-xl-end { - -ms-flex-pack: end !important; - justify-content: flex-end !important; - } - .justify-content-xl-center { - -ms-flex-pack: center !important; - justify-content: center !important; - } - .justify-content-xl-between { - -ms-flex-pack: justify !important; - justify-content: space-between !important; - } - .justify-content-xl-around { - -ms-flex-pack: distribute !important; - justify-content: space-around !important; - } - .align-items-xl-start { - -ms-flex-align: start !important; - align-items: flex-start !important; - } - .align-items-xl-end { - -ms-flex-align: end !important; - align-items: flex-end !important; - } - .align-items-xl-center { - -ms-flex-align: center !important; - align-items: center !important; - } - .align-items-xl-baseline { - -ms-flex-align: baseline !important; - align-items: baseline !important; - } - .align-items-xl-stretch { - -ms-flex-align: stretch !important; - align-items: stretch !important; - } - .align-content-xl-start { - -ms-flex-line-pack: start !important; - align-content: flex-start !important; - } - .align-content-xl-end { - -ms-flex-line-pack: end !important; - align-content: flex-end !important; - } - .align-content-xl-center { - -ms-flex-line-pack: center !important; - align-content: center !important; - } - .align-content-xl-between { - -ms-flex-line-pack: justify !important; - align-content: space-between !important; - } - .align-content-xl-around { - -ms-flex-line-pack: distribute !important; - align-content: space-around !important; - } - .align-content-xl-stretch { - -ms-flex-line-pack: stretch !important; - align-content: stretch !important; - } - .align-self-xl-auto { - -ms-flex-item-align: auto !important; - align-self: auto !important; - } - .align-self-xl-start { - -ms-flex-item-align: start !important; - align-self: flex-start !important; - } - .align-self-xl-end { - -ms-flex-item-align: end !important; - align-self: flex-end !important; - } - .align-self-xl-center { - -ms-flex-item-align: center !important; - align-self: center !important; - } - .align-self-xl-baseline { - -ms-flex-item-align: baseline !important; - align-self: baseline !important; - } - .align-self-xl-stretch { - -ms-flex-item-align: stretch !important; - align-self: stretch !important; - } -} - -.float-left { - float: left !important; -} - -.float-right { - float: right !important; -} - -.float-none { - float: none !important; -} - -@media (min-width: 576px) { - .float-sm-left { - float: left !important; - } - .float-sm-right { - float: right !important; - } - .float-sm-none { - float: none !important; - } -} - -@media (min-width: 768px) { - .float-md-left { - float: left !important; - } - .float-md-right { - float: right !important; - } - .float-md-none { - float: none !important; - } -} - -@media (min-width: 992px) { - .float-lg-left { - float: left !important; - } - .float-lg-right { - float: right !important; - } - .float-lg-none { - float: none !important; - } -} - -@media (min-width: 1200px) { - .float-xl-left { - float: left !important; - } - .float-xl-right { - float: right !important; - } - .float-xl-none { - float: none !important; - } -} - -.position-static { - position: static !important; -} - -.position-relative { - position: relative !important; -} - -.position-absolute { - position: absolute !important; -} - -.position-fixed { - position: fixed !important; -} - -.position-sticky { - position: -webkit-sticky !important; - position: sticky !important; -} - -.fixed-top { - position: fixed; - top: 0; - right: 0; - left: 0; - z-index: 1030; -} - -.fixed-bottom { - position: fixed; - right: 0; - bottom: 0; - left: 0; - z-index: 1030; -} - -@supports ((position: -webkit-sticky) or (position: sticky)) { - .sticky-top { - position: -webkit-sticky; - position: sticky; - top: 0; - z-index: 1020; - } -} - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; -} - -.sr-only-focusable:active, .sr-only-focusable:focus { - position: static; - width: auto; - height: auto; - overflow: visible; - clip: auto; - white-space: normal; -} - -.shadow-sm { - box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; -} - -.shadow { - box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; -} - -.shadow-lg { - box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important; -} - -.shadow-none { - box-shadow: none !important; -} - -.w-25 { - width: 25% !important; -} - -.w-50 { - width: 50% !important; -} - -.w-75 { - width: 75% !important; -} - -.w-100 { - width: 100% !important; -} - -.w-auto { - width: auto !important; -} - -.h-25 { - height: 25% !important; -} - -.h-50 { - height: 50% !important; -} - -.h-75 { - height: 75% !important; -} - -.h-100 { - height: 100% !important; -} - -.h-auto { - height: auto !important; -} - -.mw-100 { - max-width: 100% !important; -} - -.mh-100 { - max-height: 100% !important; -} - -.m-0 { - margin: 0 !important; -} - -.mt-0, -.my-0 { - margin-top: 0 !important; -} - -.mr-0, -.mx-0 { - margin-right: 0 !important; -} - -.mb-0, -.my-0 { - margin-bottom: 0 !important; -} - -.ml-0, -.mx-0 { - margin-left: 0 !important; -} - -.m-1 { - margin: 0.25rem !important; -} - -.mt-1, -.my-1 { - margin-top: 0.25rem !important; -} - -.mr-1, -.mx-1 { - margin-right: 0.25rem !important; -} - -.mb-1, -.my-1 { - margin-bottom: 0.25rem !important; -} - -.ml-1, -.mx-1 { - margin-left: 0.25rem !important; -} - -.m-2 { - margin: 0.5rem !important; -} - -.mt-2, -.my-2 { - margin-top: 0.5rem !important; -} - -.mr-2, -.mx-2 { - margin-right: 0.5rem !important; -} - -.mb-2, -.my-2 { - margin-bottom: 0.5rem !important; -} - -.ml-2, -.mx-2 { - margin-left: 0.5rem !important; -} - -.m-3 { - margin: 1rem !important; -} - -.mt-3, -.my-3 { - margin-top: 1rem !important; -} - -.mr-3, -.mx-3 { - margin-right: 1rem !important; -} - -.mb-3, -.my-3 { - margin-bottom: 1rem !important; -} - -.ml-3, -.mx-3 { - margin-left: 1rem !important; -} - -.m-4 { - margin: 1.5rem !important; -} - -.mt-4, -.my-4 { - margin-top: 1.5rem !important; -} - -.mr-4, -.mx-4 { - margin-right: 1.5rem !important; -} - -.mb-4, -.my-4 { - margin-bottom: 1.5rem !important; -} - -.ml-4, -.mx-4 { - margin-left: 1.5rem !important; -} - -.m-5 { - margin: 3rem !important; -} - -.mt-5, -.my-5 { - margin-top: 3rem !important; -} - -.mr-5, -.mx-5 { - margin-right: 3rem !important; -} - -.mb-5, -.my-5 { - margin-bottom: 3rem !important; -} - -.ml-5, -.mx-5 { - margin-left: 3rem !important; -} - -.p-0 { - padding: 0 !important; -} - -.pt-0, -.py-0 { - padding-top: 0 !important; -} - -.pr-0, -.px-0 { - padding-right: 0 !important; -} - -.pb-0, -.py-0 { - padding-bottom: 0 !important; -} - -.pl-0, -.px-0 { - padding-left: 0 !important; -} - -.p-1 { - padding: 0.25rem !important; -} - -.pt-1, -.py-1 { - padding-top: 0.25rem !important; -} - -.pr-1, -.px-1 { - padding-right: 0.25rem !important; -} - -.pb-1, -.py-1 { - padding-bottom: 0.25rem !important; -} - -.pl-1, -.px-1 { - padding-left: 0.25rem !important; -} - -.p-2 { - padding: 0.5rem !important; -} - -.pt-2, -.py-2 { - padding-top: 0.5rem !important; -} - -.pr-2, -.px-2 { - padding-right: 0.5rem !important; -} - -.pb-2, -.py-2 { - padding-bottom: 0.5rem !important; -} - -.pl-2, -.px-2 { - padding-left: 0.5rem !important; -} - -.p-3 { - padding: 1rem !important; -} - -.pt-3, -.py-3 { - padding-top: 1rem !important; -} - -.pr-3, -.px-3 { - padding-right: 1rem !important; -} - -.pb-3, -.py-3 { - padding-bottom: 1rem !important; -} - -.pl-3, -.px-3 { - padding-left: 1rem !important; -} - -.p-4 { - padding: 1.5rem !important; -} - -.pt-4, -.py-4 { - padding-top: 1.5rem !important; -} - -.pr-4, -.px-4 { - padding-right: 1.5rem !important; -} - -.pb-4, -.py-4 { - padding-bottom: 1.5rem !important; -} - -.pl-4, -.px-4 { - padding-left: 1.5rem !important; -} - -.p-5 { - padding: 3rem !important; -} - -.pt-5, -.py-5 { - padding-top: 3rem !important; -} - -.pr-5, -.px-5 { - padding-right: 3rem !important; -} - -.pb-5, -.py-5 { - padding-bottom: 3rem !important; -} - -.pl-5, -.px-5 { - padding-left: 3rem !important; -} - -.m-auto { - margin: auto !important; -} - -.mt-auto, -.my-auto { - margin-top: auto !important; -} - -.mr-auto, -.mx-auto { - margin-right: auto !important; -} - -.mb-auto, -.my-auto { - margin-bottom: auto !important; -} - -.ml-auto, -.mx-auto { - margin-left: auto !important; -} - -@media (min-width: 576px) { - .m-sm-0 { - margin: 0 !important; - } - .mt-sm-0, - .my-sm-0 { - margin-top: 0 !important; - } - .mr-sm-0, - .mx-sm-0 { - margin-right: 0 !important; - } - .mb-sm-0, - .my-sm-0 { - margin-bottom: 0 !important; - } - .ml-sm-0, - .mx-sm-0 { - margin-left: 0 !important; - } - .m-sm-1 { - margin: 0.25rem !important; - } - .mt-sm-1, - .my-sm-1 { - margin-top: 0.25rem !important; - } - .mr-sm-1, - .mx-sm-1 { - margin-right: 0.25rem !important; - } - .mb-sm-1, - .my-sm-1 { - margin-bottom: 0.25rem !important; - } - .ml-sm-1, - .mx-sm-1 { - margin-left: 0.25rem !important; - } - .m-sm-2 { - margin: 0.5rem !important; - } - .mt-sm-2, - .my-sm-2 { - margin-top: 0.5rem !important; - } - .mr-sm-2, - .mx-sm-2 { - margin-right: 0.5rem !important; - } - .mb-sm-2, - .my-sm-2 { - margin-bottom: 0.5rem !important; - } - .ml-sm-2, - .mx-sm-2 { - margin-left: 0.5rem !important; - } - .m-sm-3 { - margin: 1rem !important; - } - .mt-sm-3, - .my-sm-3 { - margin-top: 1rem !important; - } - .mr-sm-3, - .mx-sm-3 { - margin-right: 1rem !important; - } - .mb-sm-3, - .my-sm-3 { - margin-bottom: 1rem !important; - } - .ml-sm-3, - .mx-sm-3 { - margin-left: 1rem !important; - } - .m-sm-4 { - margin: 1.5rem !important; - } - .mt-sm-4, - .my-sm-4 { - margin-top: 1.5rem !important; - } - .mr-sm-4, - .mx-sm-4 { - margin-right: 1.5rem !important; - } - .mb-sm-4, - .my-sm-4 { - margin-bottom: 1.5rem !important; - } - .ml-sm-4, - .mx-sm-4 { - margin-left: 1.5rem !important; - } - .m-sm-5 { - margin: 3rem !important; - } - .mt-sm-5, - .my-sm-5 { - margin-top: 3rem !important; - } - .mr-sm-5, - .mx-sm-5 { - margin-right: 3rem !important; - } - .mb-sm-5, - .my-sm-5 { - margin-bottom: 3rem !important; - } - .ml-sm-5, - .mx-sm-5 { - margin-left: 3rem !important; - } - .p-sm-0 { - padding: 0 !important; - } - .pt-sm-0, - .py-sm-0 { - padding-top: 0 !important; - } - .pr-sm-0, - .px-sm-0 { - padding-right: 0 !important; - } - .pb-sm-0, - .py-sm-0 { - padding-bottom: 0 !important; - } - .pl-sm-0, - .px-sm-0 { - padding-left: 0 !important; - } - .p-sm-1 { - padding: 0.25rem !important; - } - .pt-sm-1, - .py-sm-1 { - padding-top: 0.25rem !important; - } - .pr-sm-1, - .px-sm-1 { - padding-right: 0.25rem !important; - } - .pb-sm-1, - .py-sm-1 { - padding-bottom: 0.25rem !important; - } - .pl-sm-1, - .px-sm-1 { - padding-left: 0.25rem !important; - } - .p-sm-2 { - padding: 0.5rem !important; - } - .pt-sm-2, - .py-sm-2 { - padding-top: 0.5rem !important; - } - .pr-sm-2, - .px-sm-2 { - padding-right: 0.5rem !important; - } - .pb-sm-2, - .py-sm-2 { - padding-bottom: 0.5rem !important; - } - .pl-sm-2, - .px-sm-2 { - padding-left: 0.5rem !important; - } - .p-sm-3 { - padding: 1rem !important; - } - .pt-sm-3, - .py-sm-3 { - padding-top: 1rem !important; - } - .pr-sm-3, - .px-sm-3 { - padding-right: 1rem !important; - } - .pb-sm-3, - .py-sm-3 { - padding-bottom: 1rem !important; - } - .pl-sm-3, - .px-sm-3 { - padding-left: 1rem !important; - } - .p-sm-4 { - padding: 1.5rem !important; - } - .pt-sm-4, - .py-sm-4 { - padding-top: 1.5rem !important; - } - .pr-sm-4, - .px-sm-4 { - padding-right: 1.5rem !important; - } - .pb-sm-4, - .py-sm-4 { - padding-bottom: 1.5rem !important; - } - .pl-sm-4, - .px-sm-4 { - padding-left: 1.5rem !important; - } - .p-sm-5 { - padding: 3rem !important; - } - .pt-sm-5, - .py-sm-5 { - padding-top: 3rem !important; - } - .pr-sm-5, - .px-sm-5 { - padding-right: 3rem !important; - } - .pb-sm-5, - .py-sm-5 { - padding-bottom: 3rem !important; - } - .pl-sm-5, - .px-sm-5 { - padding-left: 3rem !important; - } - .m-sm-auto { - margin: auto !important; - } - .mt-sm-auto, - .my-sm-auto { - margin-top: auto !important; - } - .mr-sm-auto, - .mx-sm-auto { - margin-right: auto !important; - } - .mb-sm-auto, - .my-sm-auto { - margin-bottom: auto !important; - } - .ml-sm-auto, - .mx-sm-auto { - margin-left: auto !important; - } -} - -@media (min-width: 768px) { - .m-md-0 { - margin: 0 !important; - } - .mt-md-0, - .my-md-0 { - margin-top: 0 !important; - } - .mr-md-0, - .mx-md-0 { - margin-right: 0 !important; - } - .mb-md-0, - .my-md-0 { - margin-bottom: 0 !important; - } - .ml-md-0, - .mx-md-0 { - margin-left: 0 !important; - } - .m-md-1 { - margin: 0.25rem !important; - } - .mt-md-1, - .my-md-1 { - margin-top: 0.25rem !important; - } - .mr-md-1, - .mx-md-1 { - margin-right: 0.25rem !important; - } - .mb-md-1, - .my-md-1 { - margin-bottom: 0.25rem !important; - } - .ml-md-1, - .mx-md-1 { - margin-left: 0.25rem !important; - } - .m-md-2 { - margin: 0.5rem !important; - } - .mt-md-2, - .my-md-2 { - margin-top: 0.5rem !important; - } - .mr-md-2, - .mx-md-2 { - margin-right: 0.5rem !important; - } - .mb-md-2, - .my-md-2 { - margin-bottom: 0.5rem !important; - } - .ml-md-2, - .mx-md-2 { - margin-left: 0.5rem !important; - } - .m-md-3 { - margin: 1rem !important; - } - .mt-md-3, - .my-md-3 { - margin-top: 1rem !important; - } - .mr-md-3, - .mx-md-3 { - margin-right: 1rem !important; - } - .mb-md-3, - .my-md-3 { - margin-bottom: 1rem !important; - } - .ml-md-3, - .mx-md-3 { - margin-left: 1rem !important; - } - .m-md-4 { - margin: 1.5rem !important; - } - .mt-md-4, - .my-md-4 { - margin-top: 1.5rem !important; - } - .mr-md-4, - .mx-md-4 { - margin-right: 1.5rem !important; - } - .mb-md-4, - .my-md-4 { - margin-bottom: 1.5rem !important; - } - .ml-md-4, - .mx-md-4 { - margin-left: 1.5rem !important; - } - .m-md-5 { - margin: 3rem !important; - } - .mt-md-5, - .my-md-5 { - margin-top: 3rem !important; - } - .mr-md-5, - .mx-md-5 { - margin-right: 3rem !important; - } - .mb-md-5, - .my-md-5 { - margin-bottom: 3rem !important; - } - .ml-md-5, - .mx-md-5 { - margin-left: 3rem !important; - } - .p-md-0 { - padding: 0 !important; - } - .pt-md-0, - .py-md-0 { - padding-top: 0 !important; - } - .pr-md-0, - .px-md-0 { - padding-right: 0 !important; - } - .pb-md-0, - .py-md-0 { - padding-bottom: 0 !important; - } - .pl-md-0, - .px-md-0 { - padding-left: 0 !important; - } - .p-md-1 { - padding: 0.25rem !important; - } - .pt-md-1, - .py-md-1 { - padding-top: 0.25rem !important; - } - .pr-md-1, - .px-md-1 { - padding-right: 0.25rem !important; - } - .pb-md-1, - .py-md-1 { - padding-bottom: 0.25rem !important; - } - .pl-md-1, - .px-md-1 { - padding-left: 0.25rem !important; - } - .p-md-2 { - padding: 0.5rem !important; - } - .pt-md-2, - .py-md-2 { - padding-top: 0.5rem !important; - } - .pr-md-2, - .px-md-2 { - padding-right: 0.5rem !important; - } - .pb-md-2, - .py-md-2 { - padding-bottom: 0.5rem !important; - } - .pl-md-2, - .px-md-2 { - padding-left: 0.5rem !important; - } - .p-md-3 { - padding: 1rem !important; - } - .pt-md-3, - .py-md-3 { - padding-top: 1rem !important; - } - .pr-md-3, - .px-md-3 { - padding-right: 1rem !important; - } - .pb-md-3, - .py-md-3 { - padding-bottom: 1rem !important; - } - .pl-md-3, - .px-md-3 { - padding-left: 1rem !important; - } - .p-md-4 { - padding: 1.5rem !important; - } - .pt-md-4, - .py-md-4 { - padding-top: 1.5rem !important; - } - .pr-md-4, - .px-md-4 { - padding-right: 1.5rem !important; - } - .pb-md-4, - .py-md-4 { - padding-bottom: 1.5rem !important; - } - .pl-md-4, - .px-md-4 { - padding-left: 1.5rem !important; - } - .p-md-5 { - padding: 3rem !important; - } - .pt-md-5, - .py-md-5 { - padding-top: 3rem !important; - } - .pr-md-5, - .px-md-5 { - padding-right: 3rem !important; - } - .pb-md-5, - .py-md-5 { - padding-bottom: 3rem !important; - } - .pl-md-5, - .px-md-5 { - padding-left: 3rem !important; - } - .m-md-auto { - margin: auto !important; - } - .mt-md-auto, - .my-md-auto { - margin-top: auto !important; - } - .mr-md-auto, - .mx-md-auto { - margin-right: auto !important; - } - .mb-md-auto, - .my-md-auto { - margin-bottom: auto !important; - } - .ml-md-auto, - .mx-md-auto { - margin-left: auto !important; - } -} - -@media (min-width: 992px) { - .m-lg-0 { - margin: 0 !important; - } - .mt-lg-0, - .my-lg-0 { - margin-top: 0 !important; - } - .mr-lg-0, - .mx-lg-0 { - margin-right: 0 !important; - } - .mb-lg-0, - .my-lg-0 { - margin-bottom: 0 !important; - } - .ml-lg-0, - .mx-lg-0 { - margin-left: 0 !important; - } - .m-lg-1 { - margin: 0.25rem !important; - } - .mt-lg-1, - .my-lg-1 { - margin-top: 0.25rem !important; - } - .mr-lg-1, - .mx-lg-1 { - margin-right: 0.25rem !important; - } - .mb-lg-1, - .my-lg-1 { - margin-bottom: 0.25rem !important; - } - .ml-lg-1, - .mx-lg-1 { - margin-left: 0.25rem !important; - } - .m-lg-2 { - margin: 0.5rem !important; - } - .mt-lg-2, - .my-lg-2 { - margin-top: 0.5rem !important; - } - .mr-lg-2, - .mx-lg-2 { - margin-right: 0.5rem !important; - } - .mb-lg-2, - .my-lg-2 { - margin-bottom: 0.5rem !important; - } - .ml-lg-2, - .mx-lg-2 { - margin-left: 0.5rem !important; - } - .m-lg-3 { - margin: 1rem !important; - } - .mt-lg-3, - .my-lg-3 { - margin-top: 1rem !important; - } - .mr-lg-3, - .mx-lg-3 { - margin-right: 1rem !important; - } - .mb-lg-3, - .my-lg-3 { - margin-bottom: 1rem !important; - } - .ml-lg-3, - .mx-lg-3 { - margin-left: 1rem !important; - } - .m-lg-4 { - margin: 1.5rem !important; - } - .mt-lg-4, - .my-lg-4 { - margin-top: 1.5rem !important; - } - .mr-lg-4, - .mx-lg-4 { - margin-right: 1.5rem !important; - } - .mb-lg-4, - .my-lg-4 { - margin-bottom: 1.5rem !important; - } - .ml-lg-4, - .mx-lg-4 { - margin-left: 1.5rem !important; - } - .m-lg-5 { - margin: 3rem !important; - } - .mt-lg-5, - .my-lg-5 { - margin-top: 3rem !important; - } - .mr-lg-5, - .mx-lg-5 { - margin-right: 3rem !important; - } - .mb-lg-5, - .my-lg-5 { - margin-bottom: 3rem !important; - } - .ml-lg-5, - .mx-lg-5 { - margin-left: 3rem !important; - } - .p-lg-0 { - padding: 0 !important; - } - .pt-lg-0, - .py-lg-0 { - padding-top: 0 !important; - } - .pr-lg-0, - .px-lg-0 { - padding-right: 0 !important; - } - .pb-lg-0, - .py-lg-0 { - padding-bottom: 0 !important; - } - .pl-lg-0, - .px-lg-0 { - padding-left: 0 !important; - } - .p-lg-1 { - padding: 0.25rem !important; - } - .pt-lg-1, - .py-lg-1 { - padding-top: 0.25rem !important; - } - .pr-lg-1, - .px-lg-1 { - padding-right: 0.25rem !important; - } - .pb-lg-1, - .py-lg-1 { - padding-bottom: 0.25rem !important; - } - .pl-lg-1, - .px-lg-1 { - padding-left: 0.25rem !important; - } - .p-lg-2 { - padding: 0.5rem !important; - } - .pt-lg-2, - .py-lg-2 { - padding-top: 0.5rem !important; - } - .pr-lg-2, - .px-lg-2 { - padding-right: 0.5rem !important; - } - .pb-lg-2, - .py-lg-2 { - padding-bottom: 0.5rem !important; - } - .pl-lg-2, - .px-lg-2 { - padding-left: 0.5rem !important; - } - .p-lg-3 { - padding: 1rem !important; - } - .pt-lg-3, - .py-lg-3 { - padding-top: 1rem !important; - } - .pr-lg-3, - .px-lg-3 { - padding-right: 1rem !important; - } - .pb-lg-3, - .py-lg-3 { - padding-bottom: 1rem !important; - } - .pl-lg-3, - .px-lg-3 { - padding-left: 1rem !important; - } - .p-lg-4 { - padding: 1.5rem !important; - } - .pt-lg-4, - .py-lg-4 { - padding-top: 1.5rem !important; - } - .pr-lg-4, - .px-lg-4 { - padding-right: 1.5rem !important; - } - .pb-lg-4, - .py-lg-4 { - padding-bottom: 1.5rem !important; - } - .pl-lg-4, - .px-lg-4 { - padding-left: 1.5rem !important; - } - .p-lg-5 { - padding: 3rem !important; - } - .pt-lg-5, - .py-lg-5 { - padding-top: 3rem !important; - } - .pr-lg-5, - .px-lg-5 { - padding-right: 3rem !important; - } - .pb-lg-5, - .py-lg-5 { - padding-bottom: 3rem !important; - } - .pl-lg-5, - .px-lg-5 { - padding-left: 3rem !important; - } - .m-lg-auto { - margin: auto !important; - } - .mt-lg-auto, - .my-lg-auto { - margin-top: auto !important; - } - .mr-lg-auto, - .mx-lg-auto { - margin-right: auto !important; - } - .mb-lg-auto, - .my-lg-auto { - margin-bottom: auto !important; - } - .ml-lg-auto, - .mx-lg-auto { - margin-left: auto !important; - } -} - -@media (min-width: 1200px) { - .m-xl-0 { - margin: 0 !important; - } - .mt-xl-0, - .my-xl-0 { - margin-top: 0 !important; - } - .mr-xl-0, - .mx-xl-0 { - margin-right: 0 !important; - } - .mb-xl-0, - .my-xl-0 { - margin-bottom: 0 !important; - } - .ml-xl-0, - .mx-xl-0 { - margin-left: 0 !important; - } - .m-xl-1 { - margin: 0.25rem !important; - } - .mt-xl-1, - .my-xl-1 { - margin-top: 0.25rem !important; - } - .mr-xl-1, - .mx-xl-1 { - margin-right: 0.25rem !important; - } - .mb-xl-1, - .my-xl-1 { - margin-bottom: 0.25rem !important; - } - .ml-xl-1, - .mx-xl-1 { - margin-left: 0.25rem !important; - } - .m-xl-2 { - margin: 0.5rem !important; - } - .mt-xl-2, - .my-xl-2 { - margin-top: 0.5rem !important; - } - .mr-xl-2, - .mx-xl-2 { - margin-right: 0.5rem !important; - } - .mb-xl-2, - .my-xl-2 { - margin-bottom: 0.5rem !important; - } - .ml-xl-2, - .mx-xl-2 { - margin-left: 0.5rem !important; - } - .m-xl-3 { - margin: 1rem !important; - } - .mt-xl-3, - .my-xl-3 { - margin-top: 1rem !important; - } - .mr-xl-3, - .mx-xl-3 { - margin-right: 1rem !important; - } - .mb-xl-3, - .my-xl-3 { - margin-bottom: 1rem !important; - } - .ml-xl-3, - .mx-xl-3 { - margin-left: 1rem !important; - } - .m-xl-4 { - margin: 1.5rem !important; - } - .mt-xl-4, - .my-xl-4 { - margin-top: 1.5rem !important; - } - .mr-xl-4, - .mx-xl-4 { - margin-right: 1.5rem !important; - } - .mb-xl-4, - .my-xl-4 { - margin-bottom: 1.5rem !important; - } - .ml-xl-4, - .mx-xl-4 { - margin-left: 1.5rem !important; - } - .m-xl-5 { - margin: 3rem !important; - } - .mt-xl-5, - .my-xl-5 { - margin-top: 3rem !important; - } - .mr-xl-5, - .mx-xl-5 { - margin-right: 3rem !important; - } - .mb-xl-5, - .my-xl-5 { - margin-bottom: 3rem !important; - } - .ml-xl-5, - .mx-xl-5 { - margin-left: 3rem !important; - } - .p-xl-0 { - padding: 0 !important; - } - .pt-xl-0, - .py-xl-0 { - padding-top: 0 !important; - } - .pr-xl-0, - .px-xl-0 { - padding-right: 0 !important; - } - .pb-xl-0, - .py-xl-0 { - padding-bottom: 0 !important; - } - .pl-xl-0, - .px-xl-0 { - padding-left: 0 !important; - } - .p-xl-1 { - padding: 0.25rem !important; - } - .pt-xl-1, - .py-xl-1 { - padding-top: 0.25rem !important; - } - .pr-xl-1, - .px-xl-1 { - padding-right: 0.25rem !important; - } - .pb-xl-1, - .py-xl-1 { - padding-bottom: 0.25rem !important; - } - .pl-xl-1, - .px-xl-1 { - padding-left: 0.25rem !important; - } - .p-xl-2 { - padding: 0.5rem !important; - } - .pt-xl-2, - .py-xl-2 { - padding-top: 0.5rem !important; - } - .pr-xl-2, - .px-xl-2 { - padding-right: 0.5rem !important; - } - .pb-xl-2, - .py-xl-2 { - padding-bottom: 0.5rem !important; - } - .pl-xl-2, - .px-xl-2 { - padding-left: 0.5rem !important; - } - .p-xl-3 { - padding: 1rem !important; - } - .pt-xl-3, - .py-xl-3 { - padding-top: 1rem !important; - } - .pr-xl-3, - .px-xl-3 { - padding-right: 1rem !important; - } - .pb-xl-3, - .py-xl-3 { - padding-bottom: 1rem !important; - } - .pl-xl-3, - .px-xl-3 { - padding-left: 1rem !important; - } - .p-xl-4 { - padding: 1.5rem !important; - } - .pt-xl-4, - .py-xl-4 { - padding-top: 1.5rem !important; - } - .pr-xl-4, - .px-xl-4 { - padding-right: 1.5rem !important; - } - .pb-xl-4, - .py-xl-4 { - padding-bottom: 1.5rem !important; - } - .pl-xl-4, - .px-xl-4 { - padding-left: 1.5rem !important; - } - .p-xl-5 { - padding: 3rem !important; - } - .pt-xl-5, - .py-xl-5 { - padding-top: 3rem !important; - } - .pr-xl-5, - .px-xl-5 { - padding-right: 3rem !important; - } - .pb-xl-5, - .py-xl-5 { - padding-bottom: 3rem !important; - } - .pl-xl-5, - .px-xl-5 { - padding-left: 3rem !important; - } - .m-xl-auto { - margin: auto !important; - } - .mt-xl-auto, - .my-xl-auto { - margin-top: auto !important; - } - .mr-xl-auto, - .mx-xl-auto { - margin-right: auto !important; - } - .mb-xl-auto, - .my-xl-auto { - margin-bottom: auto !important; - } - .ml-xl-auto, - .mx-xl-auto { - margin-left: auto !important; - } -} - -.text-monospace { - font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; -} - -.text-justify { - text-align: justify !important; -} - -.text-nowrap { - white-space: nowrap !important; -} - -.text-truncate { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.text-left { - text-align: left !important; -} - -.text-right { - text-align: right !important; -} - -.text-center { - text-align: center !important; -} - -@media (min-width: 576px) { - .text-sm-left { - text-align: left !important; - } - .text-sm-right { - text-align: right !important; - } - .text-sm-center { - text-align: center !important; - } -} - -@media (min-width: 768px) { - .text-md-left { - text-align: left !important; - } - .text-md-right { - text-align: right !important; - } - .text-md-center { - text-align: center !important; - } -} - -@media (min-width: 992px) { - .text-lg-left { - text-align: left !important; - } - .text-lg-right { - text-align: right !important; - } - .text-lg-center { - text-align: center !important; - } -} - -@media (min-width: 1200px) { - .text-xl-left { - text-align: left !important; - } - .text-xl-right { - text-align: right !important; - } - .text-xl-center { - text-align: center !important; - } -} - -.text-lowercase { - text-transform: lowercase !important; -} - -.text-uppercase { - text-transform: uppercase !important; -} - -.text-capitalize { - text-transform: capitalize !important; -} - -.font-weight-light { - font-weight: 300 !important; -} - -.font-weight-normal { - font-weight: 400 !important; -} - -.font-weight-bold { - font-weight: 700 !important; -} - -.font-italic { - font-style: italic !important; -} - -.text-white { - color: #fff !important; -} - -.text-primary { - color: #007bff !important; -} - -a.text-primary:hover, a.text-primary:focus { - color: #0062cc !important; -} - -.text-secondary { - color: #6c757d !important; -} - -a.text-secondary:hover, a.text-secondary:focus { - color: #545b62 !important; -} - -.text-success { - color: #28a745 !important; -} - -a.text-success:hover, a.text-success:focus { - color: #1e7e34 !important; -} - -.text-info { - color: #17a2b8 !important; -} - -a.text-info:hover, a.text-info:focus { - color: #117a8b !important; -} - -.text-warning { - color: #ffc107 !important; -} - -a.text-warning:hover, a.text-warning:focus { - color: #d39e00 !important; -} - -.text-danger { - color: #dc3545 !important; -} - -a.text-danger:hover, a.text-danger:focus { - color: #bd2130 !important; -} - -.text-light { - color: #f8f9fa !important; -} - -a.text-light:hover, a.text-light:focus { - color: #dae0e5 !important; -} - -.text-dark { - color: #343a40 !important; -} - -a.text-dark:hover, a.text-dark:focus { - color: #1d2124 !important; -} - -.text-body { - color: #212529 !important; -} - -.text-muted { - color: #6c757d !important; -} - -.text-black-50 { - color: rgba(0, 0, 0, 0.5) !important; -} - -.text-white-50 { - color: rgba(255, 255, 255, 0.5) !important; -} - -.text-hide { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} - -.visible { - visibility: visible !important; -} - -.invisible { - visibility: hidden !important; -} - -@media print { - *, - *::before, - *::after { - text-shadow: none !important; - box-shadow: none !important; - } - a:not(.btn) { - text-decoration: underline; - } - abbr[title]::after { - content: " (" attr(title) ")"; - } - pre { - white-space: pre-wrap !important; - } - pre, - blockquote { - border: 1px solid #adb5bd; - page-break-inside: avoid; - } - thead { - display: table-header-group; - } - tr, - img { - page-break-inside: avoid; - } - p, - h2, - h3 { - orphans: 3; - widows: 3; - } - h2, - h3 { - page-break-after: avoid; - } - @page { - size: a3; - } - body { - min-width: 992px !important; - } - .container { - min-width: 992px !important; - } - .navbar { - display: none; - } - .badge { - border: 1px solid #000; - } - .table { - border-collapse: collapse !important; - } - .table td, - .table th { - background-color: #fff !important; - } - .table-bordered th, - .table-bordered td { - border: 1px solid #dee2e6 !important; - } -} -/*# sourceMappingURL=bootstrap.css.map */ \ No newline at end of file diff --git a/src/public/themes/blog/assets/vendor/bootstrap/js/bootstrap.bundle.js b/src/public/themes/blog/assets/vendor/bootstrap/js/bootstrap.bundle.js deleted file mode 100755 index 9bea2ea30..000000000 --- a/src/public/themes/blog/assets/vendor/bootstrap/js/bootstrap.bundle.js +++ /dev/null @@ -1,6433 +0,0 @@ -/*! - * Bootstrap v4.1.0 (https://getbootstrap.com/) - * Copyright 2011-2018 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('jquery')) : - typeof define === 'function' && define.amd ? define(['exports', 'jquery'], factory) : - (factory((global.bootstrap = {}),global.jQuery)); -}(this, (function (exports,$) { 'use strict'; - - $ = $ && $.hasOwnProperty('default') ? $['default'] : $; - - function _defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - - function _createClass(Constructor, protoProps, staticProps) { - if (protoProps) _defineProperties(Constructor.prototype, protoProps); - if (staticProps) _defineProperties(Constructor, staticProps); - return Constructor; - } - - function _defineProperty(obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } - - return obj; - } - - function _objectSpread(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i] != null ? arguments[i] : {}; - var ownKeys = Object.keys(source); - - if (typeof Object.getOwnPropertySymbols === 'function') { - ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { - return Object.getOwnPropertyDescriptor(source, sym).enumerable; - })); - } - - ownKeys.forEach(function (key) { - _defineProperty(target, key, source[key]); - }); - } - - return target; - } - - function _inheritsLoose(subClass, superClass) { - subClass.prototype = Object.create(superClass.prototype); - subClass.prototype.constructor = subClass; - subClass.__proto__ = superClass; - } - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): util.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Util = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Private TransitionEnd Helpers - * ------------------------------------------------------------------------ - */ - var TRANSITION_END = 'transitionend'; - var MAX_UID = 1000000; - var MILLISECONDS_MULTIPLIER = 1000; // Shoutout AngusCroll (https://goo.gl/pxwQGp) - - function toType(obj) { - return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase(); - } - - function getSpecialTransitionEndEvent() { - return { - bindType: TRANSITION_END, - delegateType: TRANSITION_END, - handle: function handle(event) { - if ($$$1(event.target).is(this)) { - return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params - } - - return undefined; // eslint-disable-line no-undefined - } - }; - } - - function transitionEndEmulator(duration) { - var _this = this; - - var called = false; - $$$1(this).one(Util.TRANSITION_END, function () { - called = true; - }); - setTimeout(function () { - if (!called) { - Util.triggerTransitionEnd(_this); - } - }, duration); - return this; - } - - function setTransitionEndSupport() { - $$$1.fn.emulateTransitionEnd = transitionEndEmulator; - $$$1.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent(); - } - /** - * -------------------------------------------------------------------------- - * Public Util Api - * -------------------------------------------------------------------------- - */ - - - var Util = { - TRANSITION_END: 'bsTransitionEnd', - getUID: function getUID(prefix) { - do { - // eslint-disable-next-line no-bitwise - prefix += ~~(Math.random() * MAX_UID); // "~~" acts like a faster Math.floor() here - } while (document.getElementById(prefix)); - - return prefix; - }, - getSelectorFromElement: function getSelectorFromElement(element) { - var selector = element.getAttribute('data-target'); - - if (!selector || selector === '#') { - selector = element.getAttribute('href') || ''; - } - - try { - var $selector = $$$1(document).find(selector); - return $selector.length > 0 ? selector : null; - } catch (err) { - return null; - } - }, - getTransitionDurationFromElement: function getTransitionDurationFromElement(element) { - if (!element) { - return 0; - } // Get transition-duration of the element - - - var transitionDuration = $$$1(element).css('transition-duration'); - var floatTransitionDuration = parseFloat(transitionDuration); // Return 0 if element or transition duration is not found - - if (!floatTransitionDuration) { - return 0; - } // If multiple durations are defined, take the first - - - transitionDuration = transitionDuration.split(',')[0]; - return parseFloat(transitionDuration) * MILLISECONDS_MULTIPLIER; - }, - reflow: function reflow(element) { - return element.offsetHeight; - }, - triggerTransitionEnd: function triggerTransitionEnd(element) { - $$$1(element).trigger(TRANSITION_END); - }, - // TODO: Remove in v5 - supportsTransitionEnd: function supportsTransitionEnd() { - return Boolean(TRANSITION_END); - }, - isElement: function isElement(obj) { - return (obj[0] || obj).nodeType; - }, - typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) { - for (var property in configTypes) { - if (Object.prototype.hasOwnProperty.call(configTypes, property)) { - var expectedTypes = configTypes[property]; - var value = config[property]; - var valueType = value && Util.isElement(value) ? 'element' : toType(value); - - if (!new RegExp(expectedTypes).test(valueType)) { - throw new Error(componentName.toUpperCase() + ": " + ("Option \"" + property + "\" provided type \"" + valueType + "\" ") + ("but expected type \"" + expectedTypes + "\".")); - } - } - } - } - }; - setTransitionEndSupport(); - return Util; - }($); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): alert.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Alert = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'alert'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.alert'; - var EVENT_KEY = "." + DATA_KEY; - var DATA_API_KEY = '.data-api'; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var Selector = { - DISMISS: '[data-dismiss="alert"]' - }; - var Event = { - CLOSE: "close" + EVENT_KEY, - CLOSED: "closed" + EVENT_KEY, - CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY - }; - var ClassName = { - ALERT: 'alert', - FADE: 'fade', - SHOW: 'show' - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Alert = - /*#__PURE__*/ - function () { - function Alert(element) { - this._element = element; - } // Getters - - - var _proto = Alert.prototype; - - // Public - _proto.close = function close(element) { - element = element || this._element; - - var rootElement = this._getRootElement(element); - - var customEvent = this._triggerCloseEvent(rootElement); - - if (customEvent.isDefaultPrevented()) { - return; - } - - this._removeElement(rootElement); - }; - - _proto.dispose = function dispose() { - $$$1.removeData(this._element, DATA_KEY); - this._element = null; - }; // Private - - - _proto._getRootElement = function _getRootElement(element) { - var selector = Util.getSelectorFromElement(element); - var parent = false; - - if (selector) { - parent = $$$1(selector)[0]; - } - - if (!parent) { - parent = $$$1(element).closest("." + ClassName.ALERT)[0]; - } - - return parent; - }; - - _proto._triggerCloseEvent = function _triggerCloseEvent(element) { - var closeEvent = $$$1.Event(Event.CLOSE); - $$$1(element).trigger(closeEvent); - return closeEvent; - }; - - _proto._removeElement = function _removeElement(element) { - var _this = this; - - $$$1(element).removeClass(ClassName.SHOW); - - if (!$$$1(element).hasClass(ClassName.FADE)) { - this._destroyElement(element); - - return; - } - - var transitionDuration = Util.getTransitionDurationFromElement(element); - $$$1(element).one(Util.TRANSITION_END, function (event) { - return _this._destroyElement(element, event); - }).emulateTransitionEnd(transitionDuration); - }; - - _proto._destroyElement = function _destroyElement(element) { - $$$1(element).detach().trigger(Event.CLOSED).remove(); - }; // Static - - - Alert._jQueryInterface = function _jQueryInterface(config) { - return this.each(function () { - var $element = $$$1(this); - var data = $element.data(DATA_KEY); - - if (!data) { - data = new Alert(this); - $element.data(DATA_KEY, data); - } - - if (config === 'close') { - data[config](this); - } - }); - }; - - Alert._handleDismiss = function _handleDismiss(alertInstance) { - return function (event) { - if (event) { - event.preventDefault(); - } - - alertInstance.close(this); - }; - }; - - _createClass(Alert, null, [{ - key: "VERSION", - get: function get() { - return VERSION; - } - }]); - - return Alert; - }(); - /** - * ------------------------------------------------------------------------ - * Data Api implementation - * ------------------------------------------------------------------------ - */ - - - $$$1(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert())); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - $$$1.fn[NAME] = Alert._jQueryInterface; - $$$1.fn[NAME].Constructor = Alert; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Alert._jQueryInterface; - }; - - return Alert; - }($); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): button.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Button = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'button'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.button'; - var EVENT_KEY = "." + DATA_KEY; - var DATA_API_KEY = '.data-api'; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var ClassName = { - ACTIVE: 'active', - BUTTON: 'btn', - FOCUS: 'focus' - }; - var Selector = { - DATA_TOGGLE_CARROT: '[data-toggle^="button"]', - DATA_TOGGLE: '[data-toggle="buttons"]', - INPUT: 'input', - ACTIVE: '.active', - BUTTON: '.btn' - }; - var Event = { - CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY, - FOCUS_BLUR_DATA_API: "focus" + EVENT_KEY + DATA_API_KEY + " " + ("blur" + EVENT_KEY + DATA_API_KEY) - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Button = - /*#__PURE__*/ - function () { - function Button(element) { - this._element = element; - } // Getters - - - var _proto = Button.prototype; - - // Public - _proto.toggle = function toggle() { - var triggerChangeEvent = true; - var addAriaPressed = true; - var rootElement = $$$1(this._element).closest(Selector.DATA_TOGGLE)[0]; - - if (rootElement) { - var input = $$$1(this._element).find(Selector.INPUT)[0]; - - if (input) { - if (input.type === 'radio') { - if (input.checked && $$$1(this._element).hasClass(ClassName.ACTIVE)) { - triggerChangeEvent = false; - } else { - var activeElement = $$$1(rootElement).find(Selector.ACTIVE)[0]; - - if (activeElement) { - $$$1(activeElement).removeClass(ClassName.ACTIVE); - } - } - } - - if (triggerChangeEvent) { - if (input.hasAttribute('disabled') || rootElement.hasAttribute('disabled') || input.classList.contains('disabled') || rootElement.classList.contains('disabled')) { - return; - } - - input.checked = !$$$1(this._element).hasClass(ClassName.ACTIVE); - $$$1(input).trigger('change'); - } - - input.focus(); - addAriaPressed = false; - } - } - - if (addAriaPressed) { - this._element.setAttribute('aria-pressed', !$$$1(this._element).hasClass(ClassName.ACTIVE)); - } - - if (triggerChangeEvent) { - $$$1(this._element).toggleClass(ClassName.ACTIVE); - } - }; - - _proto.dispose = function dispose() { - $$$1.removeData(this._element, DATA_KEY); - this._element = null; - }; // Static - - - Button._jQueryInterface = function _jQueryInterface(config) { - return this.each(function () { - var data = $$$1(this).data(DATA_KEY); - - if (!data) { - data = new Button(this); - $$$1(this).data(DATA_KEY, data); - } - - if (config === 'toggle') { - data[config](); - } - }); - }; - - _createClass(Button, null, [{ - key: "VERSION", - get: function get() { - return VERSION; - } - }]); - - return Button; - }(); - /** - * ------------------------------------------------------------------------ - * Data Api implementation - * ------------------------------------------------------------------------ - */ - - - $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) { - event.preventDefault(); - var button = event.target; - - if (!$$$1(button).hasClass(ClassName.BUTTON)) { - button = $$$1(button).closest(Selector.BUTTON); - } - - Button._jQueryInterface.call($$$1(button), 'toggle'); - }).on(Event.FOCUS_BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) { - var button = $$$1(event.target).closest(Selector.BUTTON)[0]; - $$$1(button).toggleClass(ClassName.FOCUS, /^focus(in)?$/.test(event.type)); - }); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - $$$1.fn[NAME] = Button._jQueryInterface; - $$$1.fn[NAME].Constructor = Button; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Button._jQueryInterface; - }; - - return Button; - }($); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): carousel.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Carousel = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'carousel'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.carousel'; - var EVENT_KEY = "." + DATA_KEY; - var DATA_API_KEY = '.data-api'; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key - - var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key - - var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch - - var Default = { - interval: 5000, - keyboard: true, - slide: false, - pause: 'hover', - wrap: true - }; - var DefaultType = { - interval: '(number|boolean)', - keyboard: 'boolean', - slide: '(boolean|string)', - pause: '(string|boolean)', - wrap: 'boolean' - }; - var Direction = { - NEXT: 'next', - PREV: 'prev', - LEFT: 'left', - RIGHT: 'right' - }; - var Event = { - SLIDE: "slide" + EVENT_KEY, - SLID: "slid" + EVENT_KEY, - KEYDOWN: "keydown" + EVENT_KEY, - MOUSEENTER: "mouseenter" + EVENT_KEY, - MOUSELEAVE: "mouseleave" + EVENT_KEY, - TOUCHEND: "touchend" + EVENT_KEY, - LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY, - CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY - }; - var ClassName = { - CAROUSEL: 'carousel', - ACTIVE: 'active', - SLIDE: 'slide', - RIGHT: 'carousel-item-right', - LEFT: 'carousel-item-left', - NEXT: 'carousel-item-next', - PREV: 'carousel-item-prev', - ITEM: 'carousel-item' - }; - var Selector = { - ACTIVE: '.active', - ACTIVE_ITEM: '.active.carousel-item', - ITEM: '.carousel-item', - NEXT_PREV: '.carousel-item-next, .carousel-item-prev', - INDICATORS: '.carousel-indicators', - DATA_SLIDE: '[data-slide], [data-slide-to]', - DATA_RIDE: '[data-ride="carousel"]' - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Carousel = - /*#__PURE__*/ - function () { - function Carousel(element, config) { - this._items = null; - this._interval = null; - this._activeElement = null; - this._isPaused = false; - this._isSliding = false; - this.touchTimeout = null; - this._config = this._getConfig(config); - this._element = $$$1(element)[0]; - this._indicatorsElement = $$$1(this._element).find(Selector.INDICATORS)[0]; - - this._addEventListeners(); - } // Getters - - - var _proto = Carousel.prototype; - - // Public - _proto.next = function next() { - if (!this._isSliding) { - this._slide(Direction.NEXT); - } - }; - - _proto.nextWhenVisible = function nextWhenVisible() { - // Don't call next when the page isn't visible - // or the carousel or its parent isn't visible - if (!document.hidden && $$$1(this._element).is(':visible') && $$$1(this._element).css('visibility') !== 'hidden') { - this.next(); - } - }; - - _proto.prev = function prev() { - if (!this._isSliding) { - this._slide(Direction.PREV); - } - }; - - _proto.pause = function pause(event) { - if (!event) { - this._isPaused = true; - } - - if ($$$1(this._element).find(Selector.NEXT_PREV)[0]) { - Util.triggerTransitionEnd(this._element); - this.cycle(true); - } - - clearInterval(this._interval); - this._interval = null; - }; - - _proto.cycle = function cycle(event) { - if (!event) { - this._isPaused = false; - } - - if (this._interval) { - clearInterval(this._interval); - this._interval = null; - } - - if (this._config.interval && !this._isPaused) { - this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval); - } - }; - - _proto.to = function to(index) { - var _this = this; - - this._activeElement = $$$1(this._element).find(Selector.ACTIVE_ITEM)[0]; - - var activeIndex = this._getItemIndex(this._activeElement); - - if (index > this._items.length - 1 || index < 0) { - return; - } - - if (this._isSliding) { - $$$1(this._element).one(Event.SLID, function () { - return _this.to(index); - }); - return; - } - - if (activeIndex === index) { - this.pause(); - this.cycle(); - return; - } - - var direction = index > activeIndex ? Direction.NEXT : Direction.PREV; - - this._slide(direction, this._items[index]); - }; - - _proto.dispose = function dispose() { - $$$1(this._element).off(EVENT_KEY); - $$$1.removeData(this._element, DATA_KEY); - this._items = null; - this._config = null; - this._element = null; - this._interval = null; - this._isPaused = null; - this._isSliding = null; - this._activeElement = null; - this._indicatorsElement = null; - }; // Private - - - _proto._getConfig = function _getConfig(config) { - config = _objectSpread({}, Default, config); - Util.typeCheckConfig(NAME, config, DefaultType); - return config; - }; - - _proto._addEventListeners = function _addEventListeners() { - var _this2 = this; - - if (this._config.keyboard) { - $$$1(this._element).on(Event.KEYDOWN, function (event) { - return _this2._keydown(event); - }); - } - - if (this._config.pause === 'hover') { - $$$1(this._element).on(Event.MOUSEENTER, function (event) { - return _this2.pause(event); - }).on(Event.MOUSELEAVE, function (event) { - return _this2.cycle(event); - }); - - if ('ontouchstart' in document.documentElement) { - // If it's a touch-enabled device, mouseenter/leave are fired as - // part of the mouse compatibility events on first tap - the carousel - // would stop cycling until user tapped out of it; - // here, we listen for touchend, explicitly pause the carousel - // (as if it's the second time we tap on it, mouseenter compat event - // is NOT fired) and after a timeout (to allow for mouse compatibility - // events to fire) we explicitly restart cycling - $$$1(this._element).on(Event.TOUCHEND, function () { - _this2.pause(); - - if (_this2.touchTimeout) { - clearTimeout(_this2.touchTimeout); - } - - _this2.touchTimeout = setTimeout(function (event) { - return _this2.cycle(event); - }, TOUCHEVENT_COMPAT_WAIT + _this2._config.interval); - }); - } - } - }; - - _proto._keydown = function _keydown(event) { - if (/input|textarea/i.test(event.target.tagName)) { - return; - } - - switch (event.which) { - case ARROW_LEFT_KEYCODE: - event.preventDefault(); - this.prev(); - break; - - case ARROW_RIGHT_KEYCODE: - event.preventDefault(); - this.next(); - break; - - default: - } - }; - - _proto._getItemIndex = function _getItemIndex(element) { - this._items = $$$1.makeArray($$$1(element).parent().find(Selector.ITEM)); - return this._items.indexOf(element); - }; - - _proto._getItemByDirection = function _getItemByDirection(direction, activeElement) { - var isNextDirection = direction === Direction.NEXT; - var isPrevDirection = direction === Direction.PREV; - - var activeIndex = this._getItemIndex(activeElement); - - var lastItemIndex = this._items.length - 1; - var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex; - - if (isGoingToWrap && !this._config.wrap) { - return activeElement; - } - - var delta = direction === Direction.PREV ? -1 : 1; - var itemIndex = (activeIndex + delta) % this._items.length; - return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex]; - }; - - _proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) { - var targetIndex = this._getItemIndex(relatedTarget); - - var fromIndex = this._getItemIndex($$$1(this._element).find(Selector.ACTIVE_ITEM)[0]); - - var slideEvent = $$$1.Event(Event.SLIDE, { - relatedTarget: relatedTarget, - direction: eventDirectionName, - from: fromIndex, - to: targetIndex - }); - $$$1(this._element).trigger(slideEvent); - return slideEvent; - }; - - _proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) { - if (this._indicatorsElement) { - $$$1(this._indicatorsElement).find(Selector.ACTIVE).removeClass(ClassName.ACTIVE); - - var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)]; - - if (nextIndicator) { - $$$1(nextIndicator).addClass(ClassName.ACTIVE); - } - } - }; - - _proto._slide = function _slide(direction, element) { - var _this3 = this; - - var activeElement = $$$1(this._element).find(Selector.ACTIVE_ITEM)[0]; - - var activeElementIndex = this._getItemIndex(activeElement); - - var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement); - - var nextElementIndex = this._getItemIndex(nextElement); - - var isCycling = Boolean(this._interval); - var directionalClassName; - var orderClassName; - var eventDirectionName; - - if (direction === Direction.NEXT) { - directionalClassName = ClassName.LEFT; - orderClassName = ClassName.NEXT; - eventDirectionName = Direction.LEFT; - } else { - directionalClassName = ClassName.RIGHT; - orderClassName = ClassName.PREV; - eventDirectionName = Direction.RIGHT; - } - - if (nextElement && $$$1(nextElement).hasClass(ClassName.ACTIVE)) { - this._isSliding = false; - return; - } - - var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName); - - if (slideEvent.isDefaultPrevented()) { - return; - } - - if (!activeElement || !nextElement) { - // Some weirdness is happening, so we bail - return; - } - - this._isSliding = true; - - if (isCycling) { - this.pause(); - } - - this._setActiveIndicatorElement(nextElement); - - var slidEvent = $$$1.Event(Event.SLID, { - relatedTarget: nextElement, - direction: eventDirectionName, - from: activeElementIndex, - to: nextElementIndex - }); - - if ($$$1(this._element).hasClass(ClassName.SLIDE)) { - $$$1(nextElement).addClass(orderClassName); - Util.reflow(nextElement); - $$$1(activeElement).addClass(directionalClassName); - $$$1(nextElement).addClass(directionalClassName); - var transitionDuration = Util.getTransitionDurationFromElement(activeElement); - $$$1(activeElement).one(Util.TRANSITION_END, function () { - $$$1(nextElement).removeClass(directionalClassName + " " + orderClassName).addClass(ClassName.ACTIVE); - $$$1(activeElement).removeClass(ClassName.ACTIVE + " " + orderClassName + " " + directionalClassName); - _this3._isSliding = false; - setTimeout(function () { - return $$$1(_this3._element).trigger(slidEvent); - }, 0); - }).emulateTransitionEnd(transitionDuration); - } else { - $$$1(activeElement).removeClass(ClassName.ACTIVE); - $$$1(nextElement).addClass(ClassName.ACTIVE); - this._isSliding = false; - $$$1(this._element).trigger(slidEvent); - } - - if (isCycling) { - this.cycle(); - } - }; // Static - - - Carousel._jQueryInterface = function _jQueryInterface(config) { - return this.each(function () { - var data = $$$1(this).data(DATA_KEY); - - var _config = _objectSpread({}, Default, $$$1(this).data()); - - if (typeof config === 'object') { - _config = _objectSpread({}, _config, config); - } - - var action = typeof config === 'string' ? config : _config.slide; - - if (!data) { - data = new Carousel(this, _config); - $$$1(this).data(DATA_KEY, data); - } - - if (typeof config === 'number') { - data.to(config); - } else if (typeof action === 'string') { - if (typeof data[action] === 'undefined') { - throw new TypeError("No method named \"" + action + "\""); - } - - data[action](); - } else if (_config.interval) { - data.pause(); - data.cycle(); - } - }); - }; - - Carousel._dataApiClickHandler = function _dataApiClickHandler(event) { - var selector = Util.getSelectorFromElement(this); - - if (!selector) { - return; - } - - var target = $$$1(selector)[0]; - - if (!target || !$$$1(target).hasClass(ClassName.CAROUSEL)) { - return; - } - - var config = _objectSpread({}, $$$1(target).data(), $$$1(this).data()); - - var slideIndex = this.getAttribute('data-slide-to'); - - if (slideIndex) { - config.interval = false; - } - - Carousel._jQueryInterface.call($$$1(target), config); - - if (slideIndex) { - $$$1(target).data(DATA_KEY).to(slideIndex); - } - - event.preventDefault(); - }; - - _createClass(Carousel, null, [{ - key: "VERSION", - get: function get() { - return VERSION; - } - }, { - key: "Default", - get: function get() { - return Default; - } - }]); - - return Carousel; - }(); - /** - * ------------------------------------------------------------------------ - * Data Api implementation - * ------------------------------------------------------------------------ - */ - - - $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler); - $$$1(window).on(Event.LOAD_DATA_API, function () { - $$$1(Selector.DATA_RIDE).each(function () { - var $carousel = $$$1(this); - - Carousel._jQueryInterface.call($carousel, $carousel.data()); - }); - }); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - $$$1.fn[NAME] = Carousel._jQueryInterface; - $$$1.fn[NAME].Constructor = Carousel; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Carousel._jQueryInterface; - }; - - return Carousel; - }($); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): collapse.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Collapse = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'collapse'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.collapse'; - var EVENT_KEY = "." + DATA_KEY; - var DATA_API_KEY = '.data-api'; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var Default = { - toggle: true, - parent: '' - }; - var DefaultType = { - toggle: 'boolean', - parent: '(string|element)' - }; - var Event = { - SHOW: "show" + EVENT_KEY, - SHOWN: "shown" + EVENT_KEY, - HIDE: "hide" + EVENT_KEY, - HIDDEN: "hidden" + EVENT_KEY, - CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY - }; - var ClassName = { - SHOW: 'show', - COLLAPSE: 'collapse', - COLLAPSING: 'collapsing', - COLLAPSED: 'collapsed' - }; - var Dimension = { - WIDTH: 'width', - HEIGHT: 'height' - }; - var Selector = { - ACTIVES: '.show, .collapsing', - DATA_TOGGLE: '[data-toggle="collapse"]' - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Collapse = - /*#__PURE__*/ - function () { - function Collapse(element, config) { - this._isTransitioning = false; - this._element = element; - this._config = this._getConfig(config); - this._triggerArray = $$$1.makeArray($$$1("[data-toggle=\"collapse\"][href=\"#" + element.id + "\"]," + ("[data-toggle=\"collapse\"][data-target=\"#" + element.id + "\"]"))); - var tabToggles = $$$1(Selector.DATA_TOGGLE); - - for (var i = 0; i < tabToggles.length; i++) { - var elem = tabToggles[i]; - var selector = Util.getSelectorFromElement(elem); - - if (selector !== null && $$$1(selector).filter(element).length > 0) { - this._selector = selector; - - this._triggerArray.push(elem); - } - } - - this._parent = this._config.parent ? this._getParent() : null; - - if (!this._config.parent) { - this._addAriaAndCollapsedClass(this._element, this._triggerArray); - } - - if (this._config.toggle) { - this.toggle(); - } - } // Getters - - - var _proto = Collapse.prototype; - - // Public - _proto.toggle = function toggle() { - if ($$$1(this._element).hasClass(ClassName.SHOW)) { - this.hide(); - } else { - this.show(); - } - }; - - _proto.show = function show() { - var _this = this; - - if (this._isTransitioning || $$$1(this._element).hasClass(ClassName.SHOW)) { - return; - } - - var actives; - var activesData; - - if (this._parent) { - actives = $$$1.makeArray($$$1(this._parent).find(Selector.ACTIVES).filter("[data-parent=\"" + this._config.parent + "\"]")); - - if (actives.length === 0) { - actives = null; - } - } - - if (actives) { - activesData = $$$1(actives).not(this._selector).data(DATA_KEY); - - if (activesData && activesData._isTransitioning) { - return; - } - } - - var startEvent = $$$1.Event(Event.SHOW); - $$$1(this._element).trigger(startEvent); - - if (startEvent.isDefaultPrevented()) { - return; - } - - if (actives) { - Collapse._jQueryInterface.call($$$1(actives).not(this._selector), 'hide'); - - if (!activesData) { - $$$1(actives).data(DATA_KEY, null); - } - } - - var dimension = this._getDimension(); - - $$$1(this._element).removeClass(ClassName.COLLAPSE).addClass(ClassName.COLLAPSING); - this._element.style[dimension] = 0; - - if (this._triggerArray.length > 0) { - $$$1(this._triggerArray).removeClass(ClassName.COLLAPSED).attr('aria-expanded', true); - } - - this.setTransitioning(true); - - var complete = function complete() { - $$$1(_this._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).addClass(ClassName.SHOW); - _this._element.style[dimension] = ''; - - _this.setTransitioning(false); - - $$$1(_this._element).trigger(Event.SHOWN); - }; - - var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1); - var scrollSize = "scroll" + capitalizedDimension; - var transitionDuration = Util.getTransitionDurationFromElement(this._element); - $$$1(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); - this._element.style[dimension] = this._element[scrollSize] + "px"; - }; - - _proto.hide = function hide() { - var _this2 = this; - - if (this._isTransitioning || !$$$1(this._element).hasClass(ClassName.SHOW)) { - return; - } - - var startEvent = $$$1.Event(Event.HIDE); - $$$1(this._element).trigger(startEvent); - - if (startEvent.isDefaultPrevented()) { - return; - } - - var dimension = this._getDimension(); - - this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + "px"; - Util.reflow(this._element); - $$$1(this._element).addClass(ClassName.COLLAPSING).removeClass(ClassName.COLLAPSE).removeClass(ClassName.SHOW); - - if (this._triggerArray.length > 0) { - for (var i = 0; i < this._triggerArray.length; i++) { - var trigger = this._triggerArray[i]; - var selector = Util.getSelectorFromElement(trigger); - - if (selector !== null) { - var $elem = $$$1(selector); - - if (!$elem.hasClass(ClassName.SHOW)) { - $$$1(trigger).addClass(ClassName.COLLAPSED).attr('aria-expanded', false); - } - } - } - } - - this.setTransitioning(true); - - var complete = function complete() { - _this2.setTransitioning(false); - - $$$1(_this2._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).trigger(Event.HIDDEN); - }; - - this._element.style[dimension] = ''; - var transitionDuration = Util.getTransitionDurationFromElement(this._element); - $$$1(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); - }; - - _proto.setTransitioning = function setTransitioning(isTransitioning) { - this._isTransitioning = isTransitioning; - }; - - _proto.dispose = function dispose() { - $$$1.removeData(this._element, DATA_KEY); - this._config = null; - this._parent = null; - this._element = null; - this._triggerArray = null; - this._isTransitioning = null; - }; // Private - - - _proto._getConfig = function _getConfig(config) { - config = _objectSpread({}, Default, config); - config.toggle = Boolean(config.toggle); // Coerce string values - - Util.typeCheckConfig(NAME, config, DefaultType); - return config; - }; - - _proto._getDimension = function _getDimension() { - var hasWidth = $$$1(this._element).hasClass(Dimension.WIDTH); - return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT; - }; - - _proto._getParent = function _getParent() { - var _this3 = this; - - var parent = null; - - if (Util.isElement(this._config.parent)) { - parent = this._config.parent; // It's a jQuery object - - if (typeof this._config.parent.jquery !== 'undefined') { - parent = this._config.parent[0]; - } - } else { - parent = $$$1(this._config.parent)[0]; - } - - var selector = "[data-toggle=\"collapse\"][data-parent=\"" + this._config.parent + "\"]"; - $$$1(parent).find(selector).each(function (i, element) { - _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]); - }); - return parent; - }; - - _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) { - if (element) { - var isOpen = $$$1(element).hasClass(ClassName.SHOW); - - if (triggerArray.length > 0) { - $$$1(triggerArray).toggleClass(ClassName.COLLAPSED, !isOpen).attr('aria-expanded', isOpen); - } - } - }; // Static - - - Collapse._getTargetFromElement = function _getTargetFromElement(element) { - var selector = Util.getSelectorFromElement(element); - return selector ? $$$1(selector)[0] : null; - }; - - Collapse._jQueryInterface = function _jQueryInterface(config) { - return this.each(function () { - var $this = $$$1(this); - var data = $this.data(DATA_KEY); - - var _config = _objectSpread({}, Default, $this.data(), typeof config === 'object' && config); - - if (!data && _config.toggle && /show|hide/.test(config)) { - _config.toggle = false; - } - - if (!data) { - data = new Collapse(this, _config); - $this.data(DATA_KEY, data); - } - - if (typeof config === 'string') { - if (typeof data[config] === 'undefined') { - throw new TypeError("No method named \"" + config + "\""); - } - - data[config](); - } - }); - }; - - _createClass(Collapse, null, [{ - key: "VERSION", - get: function get() { - return VERSION; - } - }, { - key: "Default", - get: function get() { - return Default; - } - }]); - - return Collapse; - }(); - /** - * ------------------------------------------------------------------------ - * Data Api implementation - * ------------------------------------------------------------------------ - */ - - - $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { - // preventDefault only for elements (which change the URL) not inside the collapsible element - if (event.currentTarget.tagName === 'A') { - event.preventDefault(); - } - - var $trigger = $$$1(this); - var selector = Util.getSelectorFromElement(this); - $$$1(selector).each(function () { - var $target = $$$1(this); - var data = $target.data(DATA_KEY); - var config = data ? 'toggle' : $trigger.data(); - - Collapse._jQueryInterface.call($target, config); - }); - }); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - $$$1.fn[NAME] = Collapse._jQueryInterface; - $$$1.fn[NAME].Constructor = Collapse; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Collapse._jQueryInterface; - }; - - return Collapse; - }($); - - /**! - * @fileOverview Kickass library to create and place poppers near their reference elements. - * @version 1.14.1 - * @license - * Copyright (c) 2016 Federico Zivolo and contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined'; - var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox']; - var timeoutDuration = 0; - for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) { - if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) { - timeoutDuration = 1; - break; - } - } - - function microtaskDebounce(fn) { - var called = false; - return function () { - if (called) { - return; - } - called = true; - window.Promise.resolve().then(function () { - called = false; - fn(); - }); - }; - } - - function taskDebounce(fn) { - var scheduled = false; - return function () { - if (!scheduled) { - scheduled = true; - setTimeout(function () { - scheduled = false; - fn(); - }, timeoutDuration); - } - }; - } - - var supportsMicroTasks = isBrowser && window.Promise; - - /** - * Create a debounced version of a method, that's asynchronously deferred - * but called in the minimum time possible. - * - * @method - * @memberof Popper.Utils - * @argument {Function} fn - * @returns {Function} - */ - var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce; - - /** - * Check if the given variable is a function - * @method - * @memberof Popper.Utils - * @argument {Any} functionToCheck - variable to check - * @returns {Boolean} answer to: is a function? - */ - function isFunction(functionToCheck) { - var getType = {}; - return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; - } - - /** - * Get CSS computed property of the given element - * @method - * @memberof Popper.Utils - * @argument {Eement} element - * @argument {String} property - */ - function getStyleComputedProperty(element, property) { - if (element.nodeType !== 1) { - return []; - } - // NOTE: 1 DOM access here - var css = getComputedStyle(element, null); - return property ? css[property] : css; - } - - /** - * Returns the parentNode or the host of the element - * @method - * @memberof Popper.Utils - * @argument {Element} element - * @returns {Element} parent - */ - function getParentNode(element) { - if (element.nodeName === 'HTML') { - return element; - } - return element.parentNode || element.host; - } - - /** - * Returns the scrolling parent of the given element - * @method - * @memberof Popper.Utils - * @argument {Element} element - * @returns {Element} scroll parent - */ - function getScrollParent(element) { - // Return body, `getScroll` will take care to get the correct `scrollTop` from it - if (!element) { - return document.body; - } - - switch (element.nodeName) { - case 'HTML': - case 'BODY': - return element.ownerDocument.body; - case '#document': - return element.body; - } - - // Firefox want us to check `-x` and `-y` variations as well - - var _getStyleComputedProp = getStyleComputedProperty(element), - overflow = _getStyleComputedProp.overflow, - overflowX = _getStyleComputedProp.overflowX, - overflowY = _getStyleComputedProp.overflowY; - - if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) { - return element; - } - - return getScrollParent(getParentNode(element)); - } - - /** - * Tells if you are running Internet Explorer - * @method - * @memberof Popper.Utils - * @argument {number} version to check - * @returns {Boolean} isIE - */ - var cache = {}; - - var isIE = function () { - var version = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'all'; - - version = version.toString(); - if (cache.hasOwnProperty(version)) { - return cache[version]; - } - switch (version) { - case '11': - cache[version] = navigator.userAgent.indexOf('Trident') !== -1; - break; - case '10': - cache[version] = navigator.appVersion.indexOf('MSIE 10') !== -1; - break; - case 'all': - cache[version] = navigator.userAgent.indexOf('Trident') !== -1 || navigator.userAgent.indexOf('MSIE') !== -1; - break; - } - - //Set IE - cache.all = cache.all || Object.keys(cache).some(function (key) { - return cache[key]; - }); - return cache[version]; - }; - - /** - * Returns the offset parent of the given element - * @method - * @memberof Popper.Utils - * @argument {Element} element - * @returns {Element} offset parent - */ - function getOffsetParent(element) { - if (!element) { - return document.documentElement; - } - - var noOffsetParent = isIE(10) ? document.body : null; - - // NOTE: 1 DOM access here - var offsetParent = element.offsetParent; - // Skip hidden elements which don't have an offsetParent - while (offsetParent === noOffsetParent && element.nextElementSibling) { - offsetParent = (element = element.nextElementSibling).offsetParent; - } - - var nodeName = offsetParent && offsetParent.nodeName; - - if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') { - return element ? element.ownerDocument.documentElement : document.documentElement; - } - - // .offsetParent will return the closest TD or TABLE in case - // no offsetParent is present, I hate this job... - if (['TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') { - return getOffsetParent(offsetParent); - } - - return offsetParent; - } - - function isOffsetContainer(element) { - var nodeName = element.nodeName; - - if (nodeName === 'BODY') { - return false; - } - return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element; - } - - /** - * Finds the root node (document, shadowDOM root) of the given element - * @method - * @memberof Popper.Utils - * @argument {Element} node - * @returns {Element} root node - */ - function getRoot(node) { - if (node.parentNode !== null) { - return getRoot(node.parentNode); - } - - return node; - } - - /** - * Finds the offset parent common to the two provided nodes - * @method - * @memberof Popper.Utils - * @argument {Element} element1 - * @argument {Element} element2 - * @returns {Element} common offset parent - */ - function findCommonOffsetParent(element1, element2) { - // This check is needed to avoid errors in case one of the elements isn't defined for any reason - if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) { - return document.documentElement; - } - - // Here we make sure to give as "start" the element that comes first in the DOM - var order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING; - var start = order ? element1 : element2; - var end = order ? element2 : element1; - - // Get common ancestor container - var range = document.createRange(); - range.setStart(start, 0); - range.setEnd(end, 0); - var commonAncestorContainer = range.commonAncestorContainer; - - // Both nodes are inside #document - - if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) { - if (isOffsetContainer(commonAncestorContainer)) { - return commonAncestorContainer; - } - - return getOffsetParent(commonAncestorContainer); - } - - // one of the nodes is inside shadowDOM, find which one - var element1root = getRoot(element1); - if (element1root.host) { - return findCommonOffsetParent(element1root.host, element2); - } else { - return findCommonOffsetParent(element1, getRoot(element2).host); - } - } - - /** - * Gets the scroll value of the given element in the given side (top and left) - * @method - * @memberof Popper.Utils - * @argument {Element} element - * @argument {String} side `top` or `left` - * @returns {number} amount of scrolled pixels - */ - function getScroll(element) { - var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top'; - - var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft'; - var nodeName = element.nodeName; - - if (nodeName === 'BODY' || nodeName === 'HTML') { - var html = element.ownerDocument.documentElement; - var scrollingElement = element.ownerDocument.scrollingElement || html; - return scrollingElement[upperSide]; - } - - return element[upperSide]; - } - - /* - * Sum or subtract the element scroll values (left and top) from a given rect object - * @method - * @memberof Popper.Utils - * @param {Object} rect - Rect object you want to change - * @param {HTMLElement} element - The element from the function reads the scroll values - * @param {Boolean} subtract - set to true if you want to subtract the scroll values - * @return {Object} rect - The modifier rect object - */ - function includeScroll(rect, element) { - var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; - - var scrollTop = getScroll(element, 'top'); - var scrollLeft = getScroll(element, 'left'); - var modifier = subtract ? -1 : 1; - rect.top += scrollTop * modifier; - rect.bottom += scrollTop * modifier; - rect.left += scrollLeft * modifier; - rect.right += scrollLeft * modifier; - return rect; - } - - /* - * Helper to detect borders of a given element - * @method - * @memberof Popper.Utils - * @param {CSSStyleDeclaration} styles - * Result of `getStyleComputedProperty` on the given element - * @param {String} axis - `x` or `y` - * @return {number} borders - The borders size of the given axis - */ - - function getBordersSize(styles, axis) { - var sideA = axis === 'x' ? 'Left' : 'Top'; - var sideB = sideA === 'Left' ? 'Right' : 'Bottom'; - - return parseFloat(styles['border' + sideA + 'Width'], 10) + parseFloat(styles['border' + sideB + 'Width'], 10); - } - - function getSize(axis, body, html, computedStyle) { - return Math.max(body['offset' + axis], body['scroll' + axis], html['client' + axis], html['offset' + axis], html['scroll' + axis], isIE(10) ? html['offset' + axis] + computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')] + computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')] : 0); - } - - function getWindowSizes() { - var body = document.body; - var html = document.documentElement; - var computedStyle = isIE(10) && getComputedStyle(html); - - return { - height: getSize('Height', body, html, computedStyle), - width: getSize('Width', body, html, computedStyle) - }; - } - - var classCallCheck = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } - }; - - var createClass = function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; - }(); - - - - - - var defineProperty = function (obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } - - return obj; - }; - - var _extends = Object.assign || function (target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } - - return target; - }; - - /** - * Given element offsets, generate an output similar to getBoundingClientRect - * @method - * @memberof Popper.Utils - * @argument {Object} offsets - * @returns {Object} ClientRect like output - */ - function getClientRect(offsets) { - return _extends({}, offsets, { - right: offsets.left + offsets.width, - bottom: offsets.top + offsets.height - }); - } - - /** - * Get bounding client rect of given element - * @method - * @memberof Popper.Utils - * @param {HTMLElement} element - * @return {Object} client rect - */ - function getBoundingClientRect(element) { - var rect = {}; - - // IE10 10 FIX: Please, don't ask, the element isn't - // considered in DOM in some circumstances... - // This isn't reproducible in IE10 compatibility mode of IE11 - try { - if (isIE(10)) { - rect = element.getBoundingClientRect(); - var scrollTop = getScroll(element, 'top'); - var scrollLeft = getScroll(element, 'left'); - rect.top += scrollTop; - rect.left += scrollLeft; - rect.bottom += scrollTop; - rect.right += scrollLeft; - } else { - rect = element.getBoundingClientRect(); - } - } catch (e) {} - - var result = { - left: rect.left, - top: rect.top, - width: rect.right - rect.left, - height: rect.bottom - rect.top - }; - - // subtract scrollbar size from sizes - var sizes = element.nodeName === 'HTML' ? getWindowSizes() : {}; - var width = sizes.width || element.clientWidth || result.right - result.left; - var height = sizes.height || element.clientHeight || result.bottom - result.top; - - var horizScrollbar = element.offsetWidth - width; - var vertScrollbar = element.offsetHeight - height; - - // if an hypothetical scrollbar is detected, we must be sure it's not a `border` - // we make this check conditional for performance reasons - if (horizScrollbar || vertScrollbar) { - var styles = getStyleComputedProperty(element); - horizScrollbar -= getBordersSize(styles, 'x'); - vertScrollbar -= getBordersSize(styles, 'y'); - - result.width -= horizScrollbar; - result.height -= vertScrollbar; - } - - return getClientRect(result); - } - - function getOffsetRectRelativeToArbitraryNode(children, parent) { - var fixedPosition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; - - var isIE10 = isIE(10); - var isHTML = parent.nodeName === 'HTML'; - var childrenRect = getBoundingClientRect(children); - var parentRect = getBoundingClientRect(parent); - var scrollParent = getScrollParent(children); - - var styles = getStyleComputedProperty(parent); - var borderTopWidth = parseFloat(styles.borderTopWidth, 10); - var borderLeftWidth = parseFloat(styles.borderLeftWidth, 10); - - // In cases where the parent is fixed, we must ignore negative scroll in offset calc - if (fixedPosition && parent.nodeName === 'HTML') { - parentRect.top = Math.max(parentRect.top, 0); - parentRect.left = Math.max(parentRect.left, 0); - } - var offsets = getClientRect({ - top: childrenRect.top - parentRect.top - borderTopWidth, - left: childrenRect.left - parentRect.left - borderLeftWidth, - width: childrenRect.width, - height: childrenRect.height - }); - offsets.marginTop = 0; - offsets.marginLeft = 0; - - // Subtract margins of documentElement in case it's being used as parent - // we do this only on HTML because it's the only element that behaves - // differently when margins are applied to it. The margins are included in - // the box of the documentElement, in the other cases not. - if (!isIE10 && isHTML) { - var marginTop = parseFloat(styles.marginTop, 10); - var marginLeft = parseFloat(styles.marginLeft, 10); - - offsets.top -= borderTopWidth - marginTop; - offsets.bottom -= borderTopWidth - marginTop; - offsets.left -= borderLeftWidth - marginLeft; - offsets.right -= borderLeftWidth - marginLeft; - - // Attach marginTop and marginLeft because in some circumstances we may need them - offsets.marginTop = marginTop; - offsets.marginLeft = marginLeft; - } - - if (isIE10 && !fixedPosition ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') { - offsets = includeScroll(offsets, parent); - } - - return offsets; - } - - function getViewportOffsetRectRelativeToArtbitraryNode(element) { - var excludeScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; - - var html = element.ownerDocument.documentElement; - var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html); - var width = Math.max(html.clientWidth, window.innerWidth || 0); - var height = Math.max(html.clientHeight, window.innerHeight || 0); - - var scrollTop = !excludeScroll ? getScroll(html) : 0; - var scrollLeft = !excludeScroll ? getScroll(html, 'left') : 0; - - var offset = { - top: scrollTop - relativeOffset.top + relativeOffset.marginTop, - left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft, - width: width, - height: height - }; - - return getClientRect(offset); - } - - /** - * Check if the given element is fixed or is inside a fixed parent - * @method - * @memberof Popper.Utils - * @argument {Element} element - * @argument {Element} customContainer - * @returns {Boolean} answer to "isFixed?" - */ - function isFixed(element) { - var nodeName = element.nodeName; - if (nodeName === 'BODY' || nodeName === 'HTML') { - return false; - } - if (getStyleComputedProperty(element, 'position') === 'fixed') { - return true; - } - return isFixed(getParentNode(element)); - } - - /** - * Finds the first parent of an element that has a transformed property defined - * @method - * @memberof Popper.Utils - * @argument {Element} element - * @returns {Element} first transformed parent or documentElement - */ - - function getFixedPositionOffsetParent(element) { - // This check is needed to avoid errors in case one of the elements isn't defined for any reason - if (!element || !element.parentElement || isIE()) { - return document.documentElement; - } - var el = element.parentElement; - while (el && getStyleComputedProperty(el, 'transform') === 'none') { - el = el.parentElement; - } - return el || document.documentElement; - } - - /** - * Computed the boundaries limits and return them - * @method - * @memberof Popper.Utils - * @param {HTMLElement} popper - * @param {HTMLElement} reference - * @param {number} padding - * @param {HTMLElement} boundariesElement - Element used to define the boundaries - * @param {Boolean} fixedPosition - Is in fixed position mode - * @returns {Object} Coordinates of the boundaries - */ - function getBoundaries(popper, reference, padding, boundariesElement) { - var fixedPosition = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; - - // NOTE: 1 DOM access here - - var boundaries = { top: 0, left: 0 }; - var offsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference); - - // Handle viewport case - if (boundariesElement === 'viewport') { - boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent, fixedPosition); - } else { - // Handle other cases based on DOM element used as boundaries - var boundariesNode = void 0; - if (boundariesElement === 'scrollParent') { - boundariesNode = getScrollParent(getParentNode(reference)); - if (boundariesNode.nodeName === 'BODY') { - boundariesNode = popper.ownerDocument.documentElement; - } - } else if (boundariesElement === 'window') { - boundariesNode = popper.ownerDocument.documentElement; - } else { - boundariesNode = boundariesElement; - } - - var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent, fixedPosition); - - // In case of HTML, we need a different computation - if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) { - var _getWindowSizes = getWindowSizes(), - height = _getWindowSizes.height, - width = _getWindowSizes.width; - - boundaries.top += offsets.top - offsets.marginTop; - boundaries.bottom = height + offsets.top; - boundaries.left += offsets.left - offsets.marginLeft; - boundaries.right = width + offsets.left; - } else { - // for all the other DOM elements, this one is good - boundaries = offsets; - } - } - - // Add paddings - boundaries.left += padding; - boundaries.top += padding; - boundaries.right -= padding; - boundaries.bottom -= padding; - - return boundaries; - } - - function getArea(_ref) { - var width = _ref.width, - height = _ref.height; - - return width * height; - } - - /** - * Utility used to transform the `auto` placement to the placement with more - * available space. - * @method - * @memberof Popper.Utils - * @argument {Object} data - The data object generated by update method - * @argument {Object} options - Modifiers configuration and options - * @returns {Object} The data object, properly modified - */ - function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement) { - var padding = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0; - - if (placement.indexOf('auto') === -1) { - return placement; - } - - var boundaries = getBoundaries(popper, reference, padding, boundariesElement); - - var rects = { - top: { - width: boundaries.width, - height: refRect.top - boundaries.top - }, - right: { - width: boundaries.right - refRect.right, - height: boundaries.height - }, - bottom: { - width: boundaries.width, - height: boundaries.bottom - refRect.bottom - }, - left: { - width: refRect.left - boundaries.left, - height: boundaries.height - } - }; - - var sortedAreas = Object.keys(rects).map(function (key) { - return _extends({ - key: key - }, rects[key], { - area: getArea(rects[key]) - }); - }).sort(function (a, b) { - return b.area - a.area; - }); - - var filteredAreas = sortedAreas.filter(function (_ref2) { - var width = _ref2.width, - height = _ref2.height; - return width >= popper.clientWidth && height >= popper.clientHeight; - }); - - var computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key; - - var variation = placement.split('-')[1]; - - return computedPlacement + (variation ? '-' + variation : ''); - } - - /** - * Get offsets to the reference element - * @method - * @memberof Popper.Utils - * @param {Object} state - * @param {Element} popper - the popper element - * @param {Element} reference - the reference element (the popper will be relative to this) - * @param {Element} fixedPosition - is in fixed position mode - * @returns {Object} An object containing the offsets which will be applied to the popper - */ - function getReferenceOffsets(state, popper, reference) { - var fixedPosition = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; - - var commonOffsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference); - return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent, fixedPosition); - } - - /** - * Get the outer sizes of the given element (offset size + margins) - * @method - * @memberof Popper.Utils - * @argument {Element} element - * @returns {Object} object containing width and height properties - */ - function getOuterSizes(element) { - var styles = getComputedStyle(element); - var x = parseFloat(styles.marginTop) + parseFloat(styles.marginBottom); - var y = parseFloat(styles.marginLeft) + parseFloat(styles.marginRight); - var result = { - width: element.offsetWidth + y, - height: element.offsetHeight + x - }; - return result; - } - - /** - * Get the opposite placement of the given one - * @method - * @memberof Popper.Utils - * @argument {String} placement - * @returns {String} flipped placement - */ - function getOppositePlacement(placement) { - var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' }; - return placement.replace(/left|right|bottom|top/g, function (matched) { - return hash[matched]; - }); - } - - /** - * Get offsets to the popper - * @method - * @memberof Popper.Utils - * @param {Object} position - CSS position the Popper will get applied - * @param {HTMLElement} popper - the popper element - * @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this) - * @param {String} placement - one of the valid placement options - * @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper - */ - function getPopperOffsets(popper, referenceOffsets, placement) { - placement = placement.split('-')[0]; - - // Get popper node sizes - var popperRect = getOuterSizes(popper); - - // Add position, width and height to our offsets object - var popperOffsets = { - width: popperRect.width, - height: popperRect.height - }; - - // depending by the popper placement we have to compute its offsets slightly differently - var isHoriz = ['right', 'left'].indexOf(placement) !== -1; - var mainSide = isHoriz ? 'top' : 'left'; - var secondarySide = isHoriz ? 'left' : 'top'; - var measurement = isHoriz ? 'height' : 'width'; - var secondaryMeasurement = !isHoriz ? 'height' : 'width'; - - popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2; - if (placement === secondarySide) { - popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement]; - } else { - popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)]; - } - - return popperOffsets; - } - - /** - * Mimics the `find` method of Array - * @method - * @memberof Popper.Utils - * @argument {Array} arr - * @argument prop - * @argument value - * @returns index or -1 - */ - function find(arr, check) { - // use native find if supported - if (Array.prototype.find) { - return arr.find(check); - } - - // use `filter` to obtain the same behavior of `find` - return arr.filter(check)[0]; - } - - /** - * Return the index of the matching object - * @method - * @memberof Popper.Utils - * @argument {Array} arr - * @argument prop - * @argument value - * @returns index or -1 - */ - function findIndex(arr, prop, value) { - // use native findIndex if supported - if (Array.prototype.findIndex) { - return arr.findIndex(function (cur) { - return cur[prop] === value; - }); - } - - // use `find` + `indexOf` if `findIndex` isn't supported - var match = find(arr, function (obj) { - return obj[prop] === value; - }); - return arr.indexOf(match); - } - - /** - * Loop trough the list of modifiers and run them in order, - * each of them will then edit the data object. - * @method - * @memberof Popper.Utils - * @param {dataObject} data - * @param {Array} modifiers - * @param {String} ends - Optional modifier name used as stopper - * @returns {dataObject} - */ - function runModifiers(modifiers, data, ends) { - var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends)); - - modifiersToRun.forEach(function (modifier) { - if (modifier['function']) { - // eslint-disable-line dot-notation - console.warn('`modifier.function` is deprecated, use `modifier.fn`!'); - } - var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation - if (modifier.enabled && isFunction(fn)) { - // Add properties to offsets to make them a complete clientRect object - // we do this before each modifier to make sure the previous one doesn't - // mess with these values - data.offsets.popper = getClientRect(data.offsets.popper); - data.offsets.reference = getClientRect(data.offsets.reference); - - data = fn(data, modifier); - } - }); - - return data; - } - - /** - * Updates the position of the popper, computing the new offsets and applying - * the new style.
    - * Prefer `scheduleUpdate` over `update` because of performance reasons. - * @method - * @memberof Popper - */ - function update() { - // if popper is destroyed, don't perform any further update - if (this.state.isDestroyed) { - return; - } - - var data = { - instance: this, - styles: {}, - arrowStyles: {}, - attributes: {}, - flipped: false, - offsets: {} - }; - - // compute reference element offsets - data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference, this.options.positionFixed); - - // compute auto placement, store placement inside the data object, - // modifiers will be able to edit `placement` if needed - // and refer to originalPlacement to know the original value - data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper, this.reference, this.options.modifiers.flip.boundariesElement, this.options.modifiers.flip.padding); - - // store the computed placement inside `originalPlacement` - data.originalPlacement = data.placement; - - data.positionFixed = this.options.positionFixed; - - // compute the popper offsets - data.offsets.popper = getPopperOffsets(this.popper, data.offsets.reference, data.placement); - data.offsets.popper.position = this.options.positionFixed ? 'fixed' : 'absolute'; - - // run the modifiers - data = runModifiers(this.modifiers, data); - - // the first `update` will call `onCreate` callback - // the other ones will call `onUpdate` callback - if (!this.state.isCreated) { - this.state.isCreated = true; - this.options.onCreate(data); - } else { - this.options.onUpdate(data); - } - } - - /** - * Helper used to know if the given modifier is enabled. - * @method - * @memberof Popper.Utils - * @returns {Boolean} - */ - function isModifierEnabled(modifiers, modifierName) { - return modifiers.some(function (_ref) { - var name = _ref.name, - enabled = _ref.enabled; - return enabled && name === modifierName; - }); - } - - /** - * Get the prefixed supported property name - * @method - * @memberof Popper.Utils - * @argument {String} property (camelCase) - * @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix) - */ - function getSupportedPropertyName(property) { - var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O']; - var upperProp = property.charAt(0).toUpperCase() + property.slice(1); - - for (var i = 0; i < prefixes.length; i++) { - var prefix = prefixes[i]; - var toCheck = prefix ? '' + prefix + upperProp : property; - if (typeof document.body.style[toCheck] !== 'undefined') { - return toCheck; - } - } - return null; - } - - /** - * Destroy the popper - * @method - * @memberof Popper - */ - function destroy() { - this.state.isDestroyed = true; - - // touch DOM only if `applyStyle` modifier is enabled - if (isModifierEnabled(this.modifiers, 'applyStyle')) { - this.popper.removeAttribute('x-placement'); - this.popper.style.position = ''; - this.popper.style.top = ''; - this.popper.style.left = ''; - this.popper.style.right = ''; - this.popper.style.bottom = ''; - this.popper.style.willChange = ''; - this.popper.style[getSupportedPropertyName('transform')] = ''; - } - - this.disableEventListeners(); - - // remove the popper if user explicity asked for the deletion on destroy - // do not use `remove` because IE11 doesn't support it - if (this.options.removeOnDestroy) { - this.popper.parentNode.removeChild(this.popper); - } - return this; - } - - /** - * Get the window associated with the element - * @argument {Element} element - * @returns {Window} - */ - function getWindow(element) { - var ownerDocument = element.ownerDocument; - return ownerDocument ? ownerDocument.defaultView : window; - } - - function attachToScrollParents(scrollParent, event, callback, scrollParents) { - var isBody = scrollParent.nodeName === 'BODY'; - var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent; - target.addEventListener(event, callback, { passive: true }); - - if (!isBody) { - attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents); - } - scrollParents.push(target); - } - - /** - * Setup needed event listeners used to update the popper position - * @method - * @memberof Popper.Utils - * @private - */ - function setupEventListeners(reference, options, state, updateBound) { - // Resize event listener on window - state.updateBound = updateBound; - getWindow(reference).addEventListener('resize', state.updateBound, { passive: true }); - - // Scroll event listener on scroll parents - var scrollElement = getScrollParent(reference); - attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents); - state.scrollElement = scrollElement; - state.eventsEnabled = true; - - return state; - } - - /** - * It will add resize/scroll events and start recalculating - * position of the popper element when they are triggered. - * @method - * @memberof Popper - */ - function enableEventListeners() { - if (!this.state.eventsEnabled) { - this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate); - } - } - - /** - * Remove event listeners used to update the popper position - * @method - * @memberof Popper.Utils - * @private - */ - function removeEventListeners(reference, state) { - // Remove resize event listener on window - getWindow(reference).removeEventListener('resize', state.updateBound); - - // Remove scroll event listener on scroll parents - state.scrollParents.forEach(function (target) { - target.removeEventListener('scroll', state.updateBound); - }); - - // Reset state - state.updateBound = null; - state.scrollParents = []; - state.scrollElement = null; - state.eventsEnabled = false; - return state; - } - - /** - * It will remove resize/scroll events and won't recalculate popper position - * when they are triggered. It also won't trigger onUpdate callback anymore, - * unless you call `update` method manually. - * @method - * @memberof Popper - */ - function disableEventListeners() { - if (this.state.eventsEnabled) { - cancelAnimationFrame(this.scheduleUpdate); - this.state = removeEventListeners(this.reference, this.state); - } - } - - /** - * Tells if a given input is a number - * @method - * @memberof Popper.Utils - * @param {*} input to check - * @return {Boolean} - */ - function isNumeric(n) { - return n !== '' && !isNaN(parseFloat(n)) && isFinite(n); - } - - /** - * Set the style to the given popper - * @method - * @memberof Popper.Utils - * @argument {Element} element - Element to apply the style to - * @argument {Object} styles - * Object with a list of properties and values which will be applied to the element - */ - function setStyles(element, styles) { - Object.keys(styles).forEach(function (prop) { - var unit = ''; - // add unit if the value is numeric and is one of the following - if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) { - unit = 'px'; - } - element.style[prop] = styles[prop] + unit; - }); - } - - /** - * Set the attributes to the given popper - * @method - * @memberof Popper.Utils - * @argument {Element} element - Element to apply the attributes to - * @argument {Object} styles - * Object with a list of properties and values which will be applied to the element - */ - function setAttributes(element, attributes) { - Object.keys(attributes).forEach(function (prop) { - var value = attributes[prop]; - if (value !== false) { - element.setAttribute(prop, attributes[prop]); - } else { - element.removeAttribute(prop); - } - }); - } - - /** - * @function - * @memberof Modifiers - * @argument {Object} data - The data object generated by `update` method - * @argument {Object} data.styles - List of style properties - values to apply to popper element - * @argument {Object} data.attributes - List of attribute properties - values to apply to popper element - * @argument {Object} options - Modifiers configuration and options - * @returns {Object} The same data object - */ - function applyStyle(data) { - // any property present in `data.styles` will be applied to the popper, - // in this way we can make the 3rd party modifiers add custom styles to it - // Be aware, modifiers could override the properties defined in the previous - // lines of this modifier! - setStyles(data.instance.popper, data.styles); - - // any property present in `data.attributes` will be applied to the popper, - // they will be set as HTML attributes of the element - setAttributes(data.instance.popper, data.attributes); - - // if arrowElement is defined and arrowStyles has some properties - if (data.arrowElement && Object.keys(data.arrowStyles).length) { - setStyles(data.arrowElement, data.arrowStyles); - } - - return data; - } - - /** - * Set the x-placement attribute before everything else because it could be used - * to add margins to the popper margins needs to be calculated to get the - * correct popper offsets. - * @method - * @memberof Popper.modifiers - * @param {HTMLElement} reference - The reference element used to position the popper - * @param {HTMLElement} popper - The HTML element used as popper - * @param {Object} options - Popper.js options - */ - function applyStyleOnLoad(reference, popper, options, modifierOptions, state) { - // compute reference element offsets - var referenceOffsets = getReferenceOffsets(state, popper, reference, options.positionFixed); - - // compute auto placement, store placement inside the data object, - // modifiers will be able to edit `placement` if needed - // and refer to originalPlacement to know the original value - var placement = computeAutoPlacement(options.placement, referenceOffsets, popper, reference, options.modifiers.flip.boundariesElement, options.modifiers.flip.padding); - - popper.setAttribute('x-placement', placement); - - // Apply `position` to popper before anything else because - // without the position applied we can't guarantee correct computations - setStyles(popper, { position: options.positionFixed ? 'fixed' : 'absolute' }); - - return options; - } - - /** - * @function - * @memberof Modifiers - * @argument {Object} data - The data object generated by `update` method - * @argument {Object} options - Modifiers configuration and options - * @returns {Object} The data object, properly modified - */ - function computeStyle(data, options) { - var x = options.x, - y = options.y; - var popper = data.offsets.popper; - - // Remove this legacy support in Popper.js v2 - - var legacyGpuAccelerationOption = find(data.instance.modifiers, function (modifier) { - return modifier.name === 'applyStyle'; - }).gpuAcceleration; - if (legacyGpuAccelerationOption !== undefined) { - console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!'); - } - var gpuAcceleration = legacyGpuAccelerationOption !== undefined ? legacyGpuAccelerationOption : options.gpuAcceleration; - - var offsetParent = getOffsetParent(data.instance.popper); - var offsetParentRect = getBoundingClientRect(offsetParent); - - // Styles - var styles = { - position: popper.position - }; - - // floor sides to avoid blurry text - var offsets = { - left: Math.floor(popper.left), - top: Math.floor(popper.top), - bottom: Math.floor(popper.bottom), - right: Math.floor(popper.right) - }; - - var sideA = x === 'bottom' ? 'top' : 'bottom'; - var sideB = y === 'right' ? 'left' : 'right'; - - // if gpuAcceleration is set to `true` and transform is supported, - // we use `translate3d` to apply the position to the popper we - // automatically use the supported prefixed version if needed - var prefixedProperty = getSupportedPropertyName('transform'); - - // now, let's make a step back and look at this code closely (wtf?) - // If the content of the popper grows once it's been positioned, it - // may happen that the popper gets misplaced because of the new content - // overflowing its reference element - // To avoid this problem, we provide two options (x and y), which allow - // the consumer to define the offset origin. - // If we position a popper on top of a reference element, we can set - // `x` to `top` to make the popper grow towards its top instead of - // its bottom. - var left = void 0, - top = void 0; - if (sideA === 'bottom') { - top = -offsetParentRect.height + offsets.bottom; - } else { - top = offsets.top; - } - if (sideB === 'right') { - left = -offsetParentRect.width + offsets.right; - } else { - left = offsets.left; - } - if (gpuAcceleration && prefixedProperty) { - styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)'; - styles[sideA] = 0; - styles[sideB] = 0; - styles.willChange = 'transform'; - } else { - // othwerise, we use the standard `top`, `left`, `bottom` and `right` properties - var invertTop = sideA === 'bottom' ? -1 : 1; - var invertLeft = sideB === 'right' ? -1 : 1; - styles[sideA] = top * invertTop; - styles[sideB] = left * invertLeft; - styles.willChange = sideA + ', ' + sideB; - } - - // Attributes - var attributes = { - 'x-placement': data.placement - }; - - // Update `data` attributes, styles and arrowStyles - data.attributes = _extends({}, attributes, data.attributes); - data.styles = _extends({}, styles, data.styles); - data.arrowStyles = _extends({}, data.offsets.arrow, data.arrowStyles); - - return data; - } - - /** - * Helper used to know if the given modifier depends from another one.
    - * It checks if the needed modifier is listed and enabled. - * @method - * @memberof Popper.Utils - * @param {Array} modifiers - list of modifiers - * @param {String} requestingName - name of requesting modifier - * @param {String} requestedName - name of requested modifier - * @returns {Boolean} - */ - function isModifierRequired(modifiers, requestingName, requestedName) { - var requesting = find(modifiers, function (_ref) { - var name = _ref.name; - return name === requestingName; - }); - - var isRequired = !!requesting && modifiers.some(function (modifier) { - return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order; - }); - - if (!isRequired) { - var _requesting = '`' + requestingName + '`'; - var requested = '`' + requestedName + '`'; - console.warn(requested + ' modifier is required by ' + _requesting + ' modifier in order to work, be sure to include it before ' + _requesting + '!'); - } - return isRequired; - } - - /** - * @function - * @memberof Modifiers - * @argument {Object} data - The data object generated by update method - * @argument {Object} options - Modifiers configuration and options - * @returns {Object} The data object, properly modified - */ - function arrow(data, options) { - var _data$offsets$arrow; - - // arrow depends on keepTogether in order to work - if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) { - return data; - } - - var arrowElement = options.element; - - // if arrowElement is a string, suppose it's a CSS selector - if (typeof arrowElement === 'string') { - arrowElement = data.instance.popper.querySelector(arrowElement); - - // if arrowElement is not found, don't run the modifier - if (!arrowElement) { - return data; - } - } else { - // if the arrowElement isn't a query selector we must check that the - // provided DOM node is child of its popper node - if (!data.instance.popper.contains(arrowElement)) { - console.warn('WARNING: `arrow.element` must be child of its popper element!'); - return data; - } - } - - var placement = data.placement.split('-')[0]; - var _data$offsets = data.offsets, - popper = _data$offsets.popper, - reference = _data$offsets.reference; - - var isVertical = ['left', 'right'].indexOf(placement) !== -1; - - var len = isVertical ? 'height' : 'width'; - var sideCapitalized = isVertical ? 'Top' : 'Left'; - var side = sideCapitalized.toLowerCase(); - var altSide = isVertical ? 'left' : 'top'; - var opSide = isVertical ? 'bottom' : 'right'; - var arrowElementSize = getOuterSizes(arrowElement)[len]; - - // - // extends keepTogether behavior making sure the popper and its - // reference have enough pixels in conjuction - // - - // top/left side - if (reference[opSide] - arrowElementSize < popper[side]) { - data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize); - } - // bottom/right side - if (reference[side] + arrowElementSize > popper[opSide]) { - data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide]; - } - data.offsets.popper = getClientRect(data.offsets.popper); - - // compute center of the popper - var center = reference[side] + reference[len] / 2 - arrowElementSize / 2; - - // Compute the sideValue using the updated popper offsets - // take popper margin in account because we don't have this info available - var css = getStyleComputedProperty(data.instance.popper); - var popperMarginSide = parseFloat(css['margin' + sideCapitalized], 10); - var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width'], 10); - var sideValue = center - data.offsets.popper[side] - popperMarginSide - popperBorderSide; - - // prevent arrowElement from being placed not contiguously to its popper - sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0); - - data.arrowElement = arrowElement; - data.offsets.arrow = (_data$offsets$arrow = {}, defineProperty(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty(_data$offsets$arrow, altSide, ''), _data$offsets$arrow); - - return data; - } - - /** - * Get the opposite placement variation of the given one - * @method - * @memberof Popper.Utils - * @argument {String} placement variation - * @returns {String} flipped placement variation - */ - function getOppositeVariation(variation) { - if (variation === 'end') { - return 'start'; - } else if (variation === 'start') { - return 'end'; - } - return variation; - } - - /** - * List of accepted placements to use as values of the `placement` option.
    - * Valid placements are: - * - `auto` - * - `top` - * - `right` - * - `bottom` - * - `left` - * - * Each placement can have a variation from this list: - * - `-start` - * - `-end` - * - * Variations are interpreted easily if you think of them as the left to right - * written languages. Horizontally (`top` and `bottom`), `start` is left and `end` - * is right.
    - * Vertically (`left` and `right`), `start` is top and `end` is bottom. - * - * Some valid examples are: - * - `top-end` (on top of reference, right aligned) - * - `right-start` (on right of reference, top aligned) - * - `bottom` (on bottom, centered) - * - `auto-right` (on the side with more space available, alignment depends by placement) - * - * @static - * @type {Array} - * @enum {String} - * @readonly - * @method placements - * @memberof Popper - */ - var placements = ['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start']; - - // Get rid of `auto` `auto-start` and `auto-end` - var validPlacements = placements.slice(3); - - /** - * Given an initial placement, returns all the subsequent placements - * clockwise (or counter-clockwise). - * - * @method - * @memberof Popper.Utils - * @argument {String} placement - A valid placement (it accepts variations) - * @argument {Boolean} counter - Set to true to walk the placements counterclockwise - * @returns {Array} placements including their variations - */ - function clockwise(placement) { - var counter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; - - var index = validPlacements.indexOf(placement); - var arr = validPlacements.slice(index + 1).concat(validPlacements.slice(0, index)); - return counter ? arr.reverse() : arr; - } - - var BEHAVIORS = { - FLIP: 'flip', - CLOCKWISE: 'clockwise', - COUNTERCLOCKWISE: 'counterclockwise' - }; - - /** - * @function - * @memberof Modifiers - * @argument {Object} data - The data object generated by update method - * @argument {Object} options - Modifiers configuration and options - * @returns {Object} The data object, properly modified - */ - function flip(data, options) { - // if `inner` modifier is enabled, we can't use the `flip` modifier - if (isModifierEnabled(data.instance.modifiers, 'inner')) { - return data; - } - - if (data.flipped && data.placement === data.originalPlacement) { - // seems like flip is trying to loop, probably there's not enough space on any of the flippable sides - return data; - } - - var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement, data.positionFixed); - - var placement = data.placement.split('-')[0]; - var placementOpposite = getOppositePlacement(placement); - var variation = data.placement.split('-')[1] || ''; - - var flipOrder = []; - - switch (options.behavior) { - case BEHAVIORS.FLIP: - flipOrder = [placement, placementOpposite]; - break; - case BEHAVIORS.CLOCKWISE: - flipOrder = clockwise(placement); - break; - case BEHAVIORS.COUNTERCLOCKWISE: - flipOrder = clockwise(placement, true); - break; - default: - flipOrder = options.behavior; - } - - flipOrder.forEach(function (step, index) { - if (placement !== step || flipOrder.length === index + 1) { - return data; - } - - placement = data.placement.split('-')[0]; - placementOpposite = getOppositePlacement(placement); - - var popperOffsets = data.offsets.popper; - var refOffsets = data.offsets.reference; - - // using floor because the reference offsets may contain decimals we are not going to consider here - var floor = Math.floor; - var overlapsRef = placement === 'left' && floor(popperOffsets.right) > floor(refOffsets.left) || placement === 'right' && floor(popperOffsets.left) < floor(refOffsets.right) || placement === 'top' && floor(popperOffsets.bottom) > floor(refOffsets.top) || placement === 'bottom' && floor(popperOffsets.top) < floor(refOffsets.bottom); - - var overflowsLeft = floor(popperOffsets.left) < floor(boundaries.left); - var overflowsRight = floor(popperOffsets.right) > floor(boundaries.right); - var overflowsTop = floor(popperOffsets.top) < floor(boundaries.top); - var overflowsBottom = floor(popperOffsets.bottom) > floor(boundaries.bottom); - - var overflowsBoundaries = placement === 'left' && overflowsLeft || placement === 'right' && overflowsRight || placement === 'top' && overflowsTop || placement === 'bottom' && overflowsBottom; - - // flip the variation if required - var isVertical = ['top', 'bottom'].indexOf(placement) !== -1; - var flippedVariation = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom); - - if (overlapsRef || overflowsBoundaries || flippedVariation) { - // this boolean to detect any flip loop - data.flipped = true; - - if (overlapsRef || overflowsBoundaries) { - placement = flipOrder[index + 1]; - } - - if (flippedVariation) { - variation = getOppositeVariation(variation); - } - - data.placement = placement + (variation ? '-' + variation : ''); - - // this object contains `position`, we want to preserve it along with - // any additional property we may add in the future - data.offsets.popper = _extends({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement)); - - data = runModifiers(data.instance.modifiers, data, 'flip'); - } - }); - return data; - } - - /** - * @function - * @memberof Modifiers - * @argument {Object} data - The data object generated by update method - * @argument {Object} options - Modifiers configuration and options - * @returns {Object} The data object, properly modified - */ - function keepTogether(data) { - var _data$offsets = data.offsets, - popper = _data$offsets.popper, - reference = _data$offsets.reference; - - var placement = data.placement.split('-')[0]; - var floor = Math.floor; - var isVertical = ['top', 'bottom'].indexOf(placement) !== -1; - var side = isVertical ? 'right' : 'bottom'; - var opSide = isVertical ? 'left' : 'top'; - var measurement = isVertical ? 'width' : 'height'; - - if (popper[side] < floor(reference[opSide])) { - data.offsets.popper[opSide] = floor(reference[opSide]) - popper[measurement]; - } - if (popper[opSide] > floor(reference[side])) { - data.offsets.popper[opSide] = floor(reference[side]); - } - - return data; - } - - /** - * Converts a string containing value + unit into a px value number - * @function - * @memberof {modifiers~offset} - * @private - * @argument {String} str - Value + unit string - * @argument {String} measurement - `height` or `width` - * @argument {Object} popperOffsets - * @argument {Object} referenceOffsets - * @returns {Number|String} - * Value in pixels, or original string if no values were extracted - */ - function toValue(str, measurement, popperOffsets, referenceOffsets) { - // separate value from unit - var split = str.match(/((?:\-|\+)?\d*\.?\d*)(.*)/); - var value = +split[1]; - var unit = split[2]; - - // If it's not a number it's an operator, I guess - if (!value) { - return str; - } - - if (unit.indexOf('%') === 0) { - var element = void 0; - switch (unit) { - case '%p': - element = popperOffsets; - break; - case '%': - case '%r': - default: - element = referenceOffsets; - } - - var rect = getClientRect(element); - return rect[measurement] / 100 * value; - } else if (unit === 'vh' || unit === 'vw') { - // if is a vh or vw, we calculate the size based on the viewport - var size = void 0; - if (unit === 'vh') { - size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); - } else { - size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); - } - return size / 100 * value; - } else { - // if is an explicit pixel unit, we get rid of the unit and keep the value - // if is an implicit unit, it's px, and we return just the value - return value; - } - } - - /** - * Parse an `offset` string to extrapolate `x` and `y` numeric offsets. - * @function - * @memberof {modifiers~offset} - * @private - * @argument {String} offset - * @argument {Object} popperOffsets - * @argument {Object} referenceOffsets - * @argument {String} basePlacement - * @returns {Array} a two cells array with x and y offsets in numbers - */ - function parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) { - var offsets = [0, 0]; - - // Use height if placement is left or right and index is 0 otherwise use width - // in this way the first offset will use an axis and the second one - // will use the other one - var useHeight = ['right', 'left'].indexOf(basePlacement) !== -1; - - // Split the offset string to obtain a list of values and operands - // The regex addresses values with the plus or minus sign in front (+10, -20, etc) - var fragments = offset.split(/(\+|\-)/).map(function (frag) { - return frag.trim(); - }); - - // Detect if the offset string contains a pair of values or a single one - // they could be separated by comma or space - var divider = fragments.indexOf(find(fragments, function (frag) { - return frag.search(/,|\s/) !== -1; - })); - - if (fragments[divider] && fragments[divider].indexOf(',') === -1) { - console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.'); - } - - // If divider is found, we divide the list of values and operands to divide - // them by ofset X and Y. - var splitRegex = /\s*,\s*|\s+/; - var ops = divider !== -1 ? [fragments.slice(0, divider).concat([fragments[divider].split(splitRegex)[0]]), [fragments[divider].split(splitRegex)[1]].concat(fragments.slice(divider + 1))] : [fragments]; - - // Convert the values with units to absolute pixels to allow our computations - ops = ops.map(function (op, index) { - // Most of the units rely on the orientation of the popper - var measurement = (index === 1 ? !useHeight : useHeight) ? 'height' : 'width'; - var mergeWithPrevious = false; - return op - // This aggregates any `+` or `-` sign that aren't considered operators - // e.g.: 10 + +5 => [10, +, +5] - .reduce(function (a, b) { - if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) { - a[a.length - 1] = b; - mergeWithPrevious = true; - return a; - } else if (mergeWithPrevious) { - a[a.length - 1] += b; - mergeWithPrevious = false; - return a; - } else { - return a.concat(b); - } - }, []) - // Here we convert the string values into number values (in px) - .map(function (str) { - return toValue(str, measurement, popperOffsets, referenceOffsets); - }); - }); - - // Loop trough the offsets arrays and execute the operations - ops.forEach(function (op, index) { - op.forEach(function (frag, index2) { - if (isNumeric(frag)) { - offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1); - } - }); - }); - return offsets; - } - - /** - * @function - * @memberof Modifiers - * @argument {Object} data - The data object generated by update method - * @argument {Object} options - Modifiers configuration and options - * @argument {Number|String} options.offset=0 - * The offset value as described in the modifier description - * @returns {Object} The data object, properly modified - */ - function offset(data, _ref) { - var offset = _ref.offset; - var placement = data.placement, - _data$offsets = data.offsets, - popper = _data$offsets.popper, - reference = _data$offsets.reference; - - var basePlacement = placement.split('-')[0]; - - var offsets = void 0; - if (isNumeric(+offset)) { - offsets = [+offset, 0]; - } else { - offsets = parseOffset(offset, popper, reference, basePlacement); - } - - if (basePlacement === 'left') { - popper.top += offsets[0]; - popper.left -= offsets[1]; - } else if (basePlacement === 'right') { - popper.top += offsets[0]; - popper.left += offsets[1]; - } else if (basePlacement === 'top') { - popper.left += offsets[0]; - popper.top -= offsets[1]; - } else if (basePlacement === 'bottom') { - popper.left += offsets[0]; - popper.top += offsets[1]; - } - - data.popper = popper; - return data; - } - - /** - * @function - * @memberof Modifiers - * @argument {Object} data - The data object generated by `update` method - * @argument {Object} options - Modifiers configuration and options - * @returns {Object} The data object, properly modified - */ - function preventOverflow(data, options) { - var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper); - - // If offsetParent is the reference element, we really want to - // go one step up and use the next offsetParent as reference to - // avoid to make this modifier completely useless and look like broken - if (data.instance.reference === boundariesElement) { - boundariesElement = getOffsetParent(boundariesElement); - } - - var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement, data.positionFixed); - options.boundaries = boundaries; - - var order = options.priority; - var popper = data.offsets.popper; - - var check = { - primary: function primary(placement) { - var value = popper[placement]; - if (popper[placement] < boundaries[placement] && !options.escapeWithReference) { - value = Math.max(popper[placement], boundaries[placement]); - } - return defineProperty({}, placement, value); - }, - secondary: function secondary(placement) { - var mainSide = placement === 'right' ? 'left' : 'top'; - var value = popper[mainSide]; - if (popper[placement] > boundaries[placement] && !options.escapeWithReference) { - value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height)); - } - return defineProperty({}, mainSide, value); - } - }; - - order.forEach(function (placement) { - var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary'; - popper = _extends({}, popper, check[side](placement)); - }); - - data.offsets.popper = popper; - - return data; - } - - /** - * @function - * @memberof Modifiers - * @argument {Object} data - The data object generated by `update` method - * @argument {Object} options - Modifiers configuration and options - * @returns {Object} The data object, properly modified - */ - function shift(data) { - var placement = data.placement; - var basePlacement = placement.split('-')[0]; - var shiftvariation = placement.split('-')[1]; - - // if shift shiftvariation is specified, run the modifier - if (shiftvariation) { - var _data$offsets = data.offsets, - reference = _data$offsets.reference, - popper = _data$offsets.popper; - - var isVertical = ['bottom', 'top'].indexOf(basePlacement) !== -1; - var side = isVertical ? 'left' : 'top'; - var measurement = isVertical ? 'width' : 'height'; - - var shiftOffsets = { - start: defineProperty({}, side, reference[side]), - end: defineProperty({}, side, reference[side] + reference[measurement] - popper[measurement]) - }; - - data.offsets.popper = _extends({}, popper, shiftOffsets[shiftvariation]); - } - - return data; - } - - /** - * @function - * @memberof Modifiers - * @argument {Object} data - The data object generated by update method - * @argument {Object} options - Modifiers configuration and options - * @returns {Object} The data object, properly modified - */ - function hide(data) { - if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) { - return data; - } - - var refRect = data.offsets.reference; - var bound = find(data.instance.modifiers, function (modifier) { - return modifier.name === 'preventOverflow'; - }).boundaries; - - if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) { - // Avoid unnecessary DOM access if visibility hasn't changed - if (data.hide === true) { - return data; - } - - data.hide = true; - data.attributes['x-out-of-boundaries'] = ''; - } else { - // Avoid unnecessary DOM access if visibility hasn't changed - if (data.hide === false) { - return data; - } - - data.hide = false; - data.attributes['x-out-of-boundaries'] = false; - } - - return data; - } - - /** - * @function - * @memberof Modifiers - * @argument {Object} data - The data object generated by `update` method - * @argument {Object} options - Modifiers configuration and options - * @returns {Object} The data object, properly modified - */ - function inner(data) { - var placement = data.placement; - var basePlacement = placement.split('-')[0]; - var _data$offsets = data.offsets, - popper = _data$offsets.popper, - reference = _data$offsets.reference; - - var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1; - - var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1; - - popper[isHoriz ? 'left' : 'top'] = reference[basePlacement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0); - - data.placement = getOppositePlacement(placement); - data.offsets.popper = getClientRect(popper); - - return data; - } - - /** - * Modifier function, each modifier can have a function of this type assigned - * to its `fn` property.
    - * These functions will be called on each update, this means that you must - * make sure they are performant enough to avoid performance bottlenecks. - * - * @function ModifierFn - * @argument {dataObject} data - The data object generated by `update` method - * @argument {Object} options - Modifiers configuration and options - * @returns {dataObject} The data object, properly modified - */ - - /** - * Modifiers are plugins used to alter the behavior of your poppers.
    - * Popper.js uses a set of 9 modifiers to provide all the basic functionalities - * needed by the library. - * - * Usually you don't want to override the `order`, `fn` and `onLoad` props. - * All the other properties are configurations that could be tweaked. - * @namespace modifiers - */ - var modifiers = { - /** - * Modifier used to shift the popper on the start or end of its reference - * element.
    - * It will read the variation of the `placement` property.
    - * It can be one either `-end` or `-start`. - * @memberof modifiers - * @inner - */ - shift: { - /** @prop {number} order=100 - Index used to define the order of execution */ - order: 100, - /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ - enabled: true, - /** @prop {ModifierFn} */ - fn: shift - }, - - /** - * The `offset` modifier can shift your popper on both its axis. - * - * It accepts the following units: - * - `px` or unitless, interpreted as pixels - * - `%` or `%r`, percentage relative to the length of the reference element - * - `%p`, percentage relative to the length of the popper element - * - `vw`, CSS viewport width unit - * - `vh`, CSS viewport height unit - * - * For length is intended the main axis relative to the placement of the popper.
    - * This means that if the placement is `top` or `bottom`, the length will be the - * `width`. In case of `left` or `right`, it will be the height. - * - * You can provide a single value (as `Number` or `String`), or a pair of values - * as `String` divided by a comma or one (or more) white spaces.
    - * The latter is a deprecated method because it leads to confusion and will be - * removed in v2.
    - * Additionally, it accepts additions and subtractions between different units. - * Note that multiplications and divisions aren't supported. - * - * Valid examples are: - * ``` - * 10 - * '10%' - * '10, 10' - * '10%, 10' - * '10 + 10%' - * '10 - 5vh + 3%' - * '-10px + 5vh, 5px - 6%' - * ``` - * > **NB**: If you desire to apply offsets to your poppers in a way that may make them overlap - * > with their reference element, unfortunately, you will have to disable the `flip` modifier. - * > More on this [reading this issue](https://github.com/FezVrasta/popper.js/issues/373) - * - * @memberof modifiers - * @inner - */ - offset: { - /** @prop {number} order=200 - Index used to define the order of execution */ - order: 200, - /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ - enabled: true, - /** @prop {ModifierFn} */ - fn: offset, - /** @prop {Number|String} offset=0 - * The offset value as described in the modifier description - */ - offset: 0 - }, - - /** - * Modifier used to prevent the popper from being positioned outside the boundary. - * - * An scenario exists where the reference itself is not within the boundaries.
    - * We can say it has "escaped the boundaries" — or just "escaped".
    - * In this case we need to decide whether the popper should either: - * - * - detach from the reference and remain "trapped" in the boundaries, or - * - if it should ignore the boundary and "escape with its reference" - * - * When `escapeWithReference` is set to`true` and reference is completely - * outside its boundaries, the popper will overflow (or completely leave) - * the boundaries in order to remain attached to the edge of the reference. - * - * @memberof modifiers - * @inner - */ - preventOverflow: { - /** @prop {number} order=300 - Index used to define the order of execution */ - order: 300, - /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ - enabled: true, - /** @prop {ModifierFn} */ - fn: preventOverflow, - /** - * @prop {Array} [priority=['left','right','top','bottom']] - * Popper will try to prevent overflow following these priorities by default, - * then, it could overflow on the left and on top of the `boundariesElement` - */ - priority: ['left', 'right', 'top', 'bottom'], - /** - * @prop {number} padding=5 - * Amount of pixel used to define a minimum distance between the boundaries - * and the popper this makes sure the popper has always a little padding - * between the edges of its container - */ - padding: 5, - /** - * @prop {String|HTMLElement} boundariesElement='scrollParent' - * Boundaries used by the modifier, can be `scrollParent`, `window`, - * `viewport` or any DOM element. - */ - boundariesElement: 'scrollParent' - }, - - /** - * Modifier used to make sure the reference and its popper stay near eachothers - * without leaving any gap between the two. Expecially useful when the arrow is - * enabled and you want to assure it to point to its reference element. - * It cares only about the first axis, you can still have poppers with margin - * between the popper and its reference element. - * @memberof modifiers - * @inner - */ - keepTogether: { - /** @prop {number} order=400 - Index used to define the order of execution */ - order: 400, - /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ - enabled: true, - /** @prop {ModifierFn} */ - fn: keepTogether - }, - - /** - * This modifier is used to move the `arrowElement` of the popper to make - * sure it is positioned between the reference element and its popper element. - * It will read the outer size of the `arrowElement` node to detect how many - * pixels of conjuction are needed. - * - * It has no effect if no `arrowElement` is provided. - * @memberof modifiers - * @inner - */ - arrow: { - /** @prop {number} order=500 - Index used to define the order of execution */ - order: 500, - /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ - enabled: true, - /** @prop {ModifierFn} */ - fn: arrow, - /** @prop {String|HTMLElement} element='[x-arrow]' - Selector or node used as arrow */ - element: '[x-arrow]' - }, - - /** - * Modifier used to flip the popper's placement when it starts to overlap its - * reference element. - * - * Requires the `preventOverflow` modifier before it in order to work. - * - * **NOTE:** this modifier will interrupt the current update cycle and will - * restart it if it detects the need to flip the placement. - * @memberof modifiers - * @inner - */ - flip: { - /** @prop {number} order=600 - Index used to define the order of execution */ - order: 600, - /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ - enabled: true, - /** @prop {ModifierFn} */ - fn: flip, - /** - * @prop {String|Array} behavior='flip' - * The behavior used to change the popper's placement. It can be one of - * `flip`, `clockwise`, `counterclockwise` or an array with a list of valid - * placements (with optional variations). - */ - behavior: 'flip', - /** - * @prop {number} padding=5 - * The popper will flip if it hits the edges of the `boundariesElement` - */ - padding: 5, - /** - * @prop {String|HTMLElement} boundariesElement='viewport' - * The element which will define the boundaries of the popper position, - * the popper will never be placed outside of the defined boundaries - * (except if keepTogether is enabled) - */ - boundariesElement: 'viewport' - }, - - /** - * Modifier used to make the popper flow toward the inner of the reference element. - * By default, when this modifier is disabled, the popper will be placed outside - * the reference element. - * @memberof modifiers - * @inner - */ - inner: { - /** @prop {number} order=700 - Index used to define the order of execution */ - order: 700, - /** @prop {Boolean} enabled=false - Whether the modifier is enabled or not */ - enabled: false, - /** @prop {ModifierFn} */ - fn: inner - }, - - /** - * Modifier used to hide the popper when its reference element is outside of the - * popper boundaries. It will set a `x-out-of-boundaries` attribute which can - * be used to hide with a CSS selector the popper when its reference is - * out of boundaries. - * - * Requires the `preventOverflow` modifier before it in order to work. - * @memberof modifiers - * @inner - */ - hide: { - /** @prop {number} order=800 - Index used to define the order of execution */ - order: 800, - /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ - enabled: true, - /** @prop {ModifierFn} */ - fn: hide - }, - - /** - * Computes the style that will be applied to the popper element to gets - * properly positioned. - * - * Note that this modifier will not touch the DOM, it just prepares the styles - * so that `applyStyle` modifier can apply it. This separation is useful - * in case you need to replace `applyStyle` with a custom implementation. - * - * This modifier has `850` as `order` value to maintain backward compatibility - * with previous versions of Popper.js. Expect the modifiers ordering method - * to change in future major versions of the library. - * - * @memberof modifiers - * @inner - */ - computeStyle: { - /** @prop {number} order=850 - Index used to define the order of execution */ - order: 850, - /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ - enabled: true, - /** @prop {ModifierFn} */ - fn: computeStyle, - /** - * @prop {Boolean} gpuAcceleration=true - * If true, it uses the CSS 3d transformation to position the popper. - * Otherwise, it will use the `top` and `left` properties. - */ - gpuAcceleration: true, - /** - * @prop {string} [x='bottom'] - * Where to anchor the X axis (`bottom` or `top`). AKA X offset origin. - * Change this if your popper should grow in a direction different from `bottom` - */ - x: 'bottom', - /** - * @prop {string} [x='left'] - * Where to anchor the Y axis (`left` or `right`). AKA Y offset origin. - * Change this if your popper should grow in a direction different from `right` - */ - y: 'right' - }, - - /** - * Applies the computed styles to the popper element. - * - * All the DOM manipulations are limited to this modifier. This is useful in case - * you want to integrate Popper.js inside a framework or view library and you - * want to delegate all the DOM manipulations to it. - * - * Note that if you disable this modifier, you must make sure the popper element - * has its position set to `absolute` before Popper.js can do its work! - * - * Just disable this modifier and define you own to achieve the desired effect. - * - * @memberof modifiers - * @inner - */ - applyStyle: { - /** @prop {number} order=900 - Index used to define the order of execution */ - order: 900, - /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ - enabled: true, - /** @prop {ModifierFn} */ - fn: applyStyle, - /** @prop {Function} */ - onLoad: applyStyleOnLoad, - /** - * @deprecated since version 1.10.0, the property moved to `computeStyle` modifier - * @prop {Boolean} gpuAcceleration=true - * If true, it uses the CSS 3d transformation to position the popper. - * Otherwise, it will use the `top` and `left` properties. - */ - gpuAcceleration: undefined - } - }; - - /** - * The `dataObject` is an object containing all the informations used by Popper.js - * this object get passed to modifiers and to the `onCreate` and `onUpdate` callbacks. - * @name dataObject - * @property {Object} data.instance The Popper.js instance - * @property {String} data.placement Placement applied to popper - * @property {String} data.originalPlacement Placement originally defined on init - * @property {Boolean} data.flipped True if popper has been flipped by flip modifier - * @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper. - * @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier - * @property {Object} data.styles Any CSS property defined here will be applied to the popper, it expects the JavaScript nomenclature (eg. `marginBottom`) - * @property {Object} data.arrowStyles Any CSS property defined here will be applied to the popper arrow, it expects the JavaScript nomenclature (eg. `marginBottom`) - * @property {Object} data.boundaries Offsets of the popper boundaries - * @property {Object} data.offsets The measurements of popper, reference and arrow elements. - * @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values - * @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values - * @property {Object} data.offsets.arrow] `top` and `left` offsets, only one of them will be different from 0 - */ - - /** - * Default options provided to Popper.js constructor.
    - * These can be overriden using the `options` argument of Popper.js.
    - * To override an option, simply pass as 3rd argument an object with the same - * structure of this object, example: - * ``` - * new Popper(ref, pop, { - * modifiers: { - * preventOverflow: { enabled: false } - * } - * }) - * ``` - * @type {Object} - * @static - * @memberof Popper - */ - var Defaults = { - /** - * Popper's placement - * @prop {Popper.placements} placement='bottom' - */ - placement: 'bottom', - - /** - * Set this to true if you want popper to position it self in 'fixed' mode - * @prop {Boolean} positionFixed=false - */ - positionFixed: false, - - /** - * Whether events (resize, scroll) are initially enabled - * @prop {Boolean} eventsEnabled=true - */ - eventsEnabled: true, - - /** - * Set to true if you want to automatically remove the popper when - * you call the `destroy` method. - * @prop {Boolean} removeOnDestroy=false - */ - removeOnDestroy: false, - - /** - * Callback called when the popper is created.
    - * By default, is set to no-op.
    - * Access Popper.js instance with `data.instance`. - * @prop {onCreate} - */ - onCreate: function onCreate() {}, - - /** - * Callback called when the popper is updated, this callback is not called - * on the initialization/creation of the popper, but only on subsequent - * updates.
    - * By default, is set to no-op.
    - * Access Popper.js instance with `data.instance`. - * @prop {onUpdate} - */ - onUpdate: function onUpdate() {}, - - /** - * List of modifiers used to modify the offsets before they are applied to the popper. - * They provide most of the functionalities of Popper.js - * @prop {modifiers} - */ - modifiers: modifiers - }; - - /** - * @callback onCreate - * @param {dataObject} data - */ - - /** - * @callback onUpdate - * @param {dataObject} data - */ - - // Utils - // Methods - var Popper = function () { - /** - * Create a new Popper.js instance - * @class Popper - * @param {HTMLElement|referenceObject} reference - The reference element used to position the popper - * @param {HTMLElement} popper - The HTML element used as popper. - * @param {Object} options - Your custom options to override the ones defined in [Defaults](#defaults) - * @return {Object} instance - The generated Popper.js instance - */ - function Popper(reference, popper) { - var _this = this; - - var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - classCallCheck(this, Popper); - - this.scheduleUpdate = function () { - return requestAnimationFrame(_this.update); - }; - - // make update() debounced, so that it only runs at most once-per-tick - this.update = debounce(this.update.bind(this)); - - // with {} we create a new object with the options inside it - this.options = _extends({}, Popper.Defaults, options); - - // init state - this.state = { - isDestroyed: false, - isCreated: false, - scrollParents: [] - }; - - // get reference and popper elements (allow jQuery wrappers) - this.reference = reference && reference.jquery ? reference[0] : reference; - this.popper = popper && popper.jquery ? popper[0] : popper; - - // Deep merge modifiers options - this.options.modifiers = {}; - Object.keys(_extends({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) { - _this.options.modifiers[name] = _extends({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {}); - }); - - // Refactoring modifiers' list (Object => Array) - this.modifiers = Object.keys(this.options.modifiers).map(function (name) { - return _extends({ - name: name - }, _this.options.modifiers[name]); - }) - // sort the modifiers by order - .sort(function (a, b) { - return a.order - b.order; - }); - - // modifiers have the ability to execute arbitrary code when Popper.js get inited - // such code is executed in the same order of its modifier - // they could add new properties to their options configuration - // BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`! - this.modifiers.forEach(function (modifierOptions) { - if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) { - modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state); - } - }); - - // fire the first update to position the popper in the right place - this.update(); - - var eventsEnabled = this.options.eventsEnabled; - if (eventsEnabled) { - // setup event listeners, they will take care of update the position in specific situations - this.enableEventListeners(); - } - - this.state.eventsEnabled = eventsEnabled; - } - - // We can't use class properties because they don't get listed in the - // class prototype and break stuff like Sinon stubs - - - createClass(Popper, [{ - key: 'update', - value: function update$$1() { - return update.call(this); - } - }, { - key: 'destroy', - value: function destroy$$1() { - return destroy.call(this); - } - }, { - key: 'enableEventListeners', - value: function enableEventListeners$$1() { - return enableEventListeners.call(this); - } - }, { - key: 'disableEventListeners', - value: function disableEventListeners$$1() { - return disableEventListeners.call(this); - } - - /** - * Schedule an update, it will run on the next UI update available - * @method scheduleUpdate - * @memberof Popper - */ - - - /** - * Collection of utilities useful when writing custom modifiers. - * Starting from version 1.7, this method is available only if you - * include `popper-utils.js` before `popper.js`. - * - * **DEPRECATION**: This way to access PopperUtils is deprecated - * and will be removed in v2! Use the PopperUtils module directly instead. - * Due to the high instability of the methods contained in Utils, we can't - * guarantee them to follow semver. Use them at your own risk! - * @static - * @private - * @type {Object} - * @deprecated since version 1.8 - * @member Utils - * @memberof Popper - */ - - }]); - return Popper; - }(); - - /** - * The `referenceObject` is an object that provides an interface compatible with Popper.js - * and lets you use it as replacement of a real DOM node.
    - * You can use this method to position a popper relatively to a set of coordinates - * in case you don't have a DOM node to use as reference. - * - * ``` - * new Popper(referenceObject, popperNode); - * ``` - * - * NB: This feature isn't supported in Internet Explorer 10 - * @name referenceObject - * @property {Function} data.getBoundingClientRect - * A function that returns a set of coordinates compatible with the native `getBoundingClientRect` method. - * @property {number} data.clientWidth - * An ES6 getter that will return the width of the virtual reference element. - * @property {number} data.clientHeight - * An ES6 getter that will return the height of the virtual reference element. - */ - - - Popper.Utils = (typeof window !== 'undefined' ? window : global).PopperUtils; - Popper.placements = placements; - Popper.Defaults = Defaults; - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): dropdown.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Dropdown = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'dropdown'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.dropdown'; - var EVENT_KEY = "." + DATA_KEY; - var DATA_API_KEY = '.data-api'; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key - - var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key - - var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key - - var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key - - var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key - - var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse) - - var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + "|" + ARROW_DOWN_KEYCODE + "|" + ESCAPE_KEYCODE); - var Event = { - HIDE: "hide" + EVENT_KEY, - HIDDEN: "hidden" + EVENT_KEY, - SHOW: "show" + EVENT_KEY, - SHOWN: "shown" + EVENT_KEY, - CLICK: "click" + EVENT_KEY, - CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY, - KEYDOWN_DATA_API: "keydown" + EVENT_KEY + DATA_API_KEY, - KEYUP_DATA_API: "keyup" + EVENT_KEY + DATA_API_KEY - }; - var ClassName = { - DISABLED: 'disabled', - SHOW: 'show', - DROPUP: 'dropup', - DROPRIGHT: 'dropright', - DROPLEFT: 'dropleft', - MENURIGHT: 'dropdown-menu-right', - MENULEFT: 'dropdown-menu-left', - POSITION_STATIC: 'position-static' - }; - var Selector = { - DATA_TOGGLE: '[data-toggle="dropdown"]', - FORM_CHILD: '.dropdown form', - MENU: '.dropdown-menu', - NAVBAR_NAV: '.navbar-nav', - VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)' - }; - var AttachmentMap = { - TOP: 'top-start', - TOPEND: 'top-end', - BOTTOM: 'bottom-start', - BOTTOMEND: 'bottom-end', - RIGHT: 'right-start', - RIGHTEND: 'right-end', - LEFT: 'left-start', - LEFTEND: 'left-end' - }; - var Default = { - offset: 0, - flip: true, - boundary: 'scrollParent', - reference: 'toggle', - display: 'dynamic' - }; - var DefaultType = { - offset: '(number|string|function)', - flip: 'boolean', - boundary: '(string|element)', - reference: '(string|element)', - display: 'string' - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Dropdown = - /*#__PURE__*/ - function () { - function Dropdown(element, config) { - this._element = element; - this._popper = null; - this._config = this._getConfig(config); - this._menu = this._getMenuElement(); - this._inNavbar = this._detectNavbar(); - - this._addEventListeners(); - } // Getters - - - var _proto = Dropdown.prototype; - - // Public - _proto.toggle = function toggle() { - if (this._element.disabled || $$$1(this._element).hasClass(ClassName.DISABLED)) { - return; - } - - var parent = Dropdown._getParentFromElement(this._element); - - var isActive = $$$1(this._menu).hasClass(ClassName.SHOW); - - Dropdown._clearMenus(); - - if (isActive) { - return; - } - - var relatedTarget = { - relatedTarget: this._element - }; - var showEvent = $$$1.Event(Event.SHOW, relatedTarget); - $$$1(parent).trigger(showEvent); - - if (showEvent.isDefaultPrevented()) { - return; - } // Disable totally Popper.js for Dropdown in Navbar - - - if (!this._inNavbar) { - /** - * Check for Popper dependency - * Popper - https://popper.js.org - */ - if (typeof Popper === 'undefined') { - throw new TypeError('Bootstrap dropdown require Popper.js (https://popper.js.org)'); - } - - var referenceElement = this._element; - - if (this._config.reference === 'parent') { - referenceElement = parent; - } else if (Util.isElement(this._config.reference)) { - referenceElement = this._config.reference; // Check if it's jQuery element - - if (typeof this._config.reference.jquery !== 'undefined') { - referenceElement = this._config.reference[0]; - } - } // If boundary is not `scrollParent`, then set position to `static` - // to allow the menu to "escape" the scroll parent's boundaries - // https://github.com/twbs/bootstrap/issues/24251 - - - if (this._config.boundary !== 'scrollParent') { - $$$1(parent).addClass(ClassName.POSITION_STATIC); - } - - this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig()); - } // If this is a touch-enabled device we add extra - // empty mouseover listeners to the body's immediate children; - // only needed because of broken event delegation on iOS - // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html - - - if ('ontouchstart' in document.documentElement && $$$1(parent).closest(Selector.NAVBAR_NAV).length === 0) { - $$$1(document.body).children().on('mouseover', null, $$$1.noop); - } - - this._element.focus(); - - this._element.setAttribute('aria-expanded', true); - - $$$1(this._menu).toggleClass(ClassName.SHOW); - $$$1(parent).toggleClass(ClassName.SHOW).trigger($$$1.Event(Event.SHOWN, relatedTarget)); - }; - - _proto.dispose = function dispose() { - $$$1.removeData(this._element, DATA_KEY); - $$$1(this._element).off(EVENT_KEY); - this._element = null; - this._menu = null; - - if (this._popper !== null) { - this._popper.destroy(); - - this._popper = null; - } - }; - - _proto.update = function update() { - this._inNavbar = this._detectNavbar(); - - if (this._popper !== null) { - this._popper.scheduleUpdate(); - } - }; // Private - - - _proto._addEventListeners = function _addEventListeners() { - var _this = this; - - $$$1(this._element).on(Event.CLICK, function (event) { - event.preventDefault(); - event.stopPropagation(); - - _this.toggle(); - }); - }; - - _proto._getConfig = function _getConfig(config) { - config = _objectSpread({}, this.constructor.Default, $$$1(this._element).data(), config); - Util.typeCheckConfig(NAME, config, this.constructor.DefaultType); - return config; - }; - - _proto._getMenuElement = function _getMenuElement() { - if (!this._menu) { - var parent = Dropdown._getParentFromElement(this._element); - - this._menu = $$$1(parent).find(Selector.MENU)[0]; - } - - return this._menu; - }; - - _proto._getPlacement = function _getPlacement() { - var $parentDropdown = $$$1(this._element).parent(); - var placement = AttachmentMap.BOTTOM; // Handle dropup - - if ($parentDropdown.hasClass(ClassName.DROPUP)) { - placement = AttachmentMap.TOP; - - if ($$$1(this._menu).hasClass(ClassName.MENURIGHT)) { - placement = AttachmentMap.TOPEND; - } - } else if ($parentDropdown.hasClass(ClassName.DROPRIGHT)) { - placement = AttachmentMap.RIGHT; - } else if ($parentDropdown.hasClass(ClassName.DROPLEFT)) { - placement = AttachmentMap.LEFT; - } else if ($$$1(this._menu).hasClass(ClassName.MENURIGHT)) { - placement = AttachmentMap.BOTTOMEND; - } - - return placement; - }; - - _proto._detectNavbar = function _detectNavbar() { - return $$$1(this._element).closest('.navbar').length > 0; - }; - - _proto._getPopperConfig = function _getPopperConfig() { - var _this2 = this; - - var offsetConf = {}; - - if (typeof this._config.offset === 'function') { - offsetConf.fn = function (data) { - data.offsets = _objectSpread({}, data.offsets, _this2._config.offset(data.offsets) || {}); - return data; - }; - } else { - offsetConf.offset = this._config.offset; - } - - var popperConfig = { - placement: this._getPlacement(), - modifiers: { - offset: offsetConf, - flip: { - enabled: this._config.flip - }, - preventOverflow: { - boundariesElement: this._config.boundary - } - } // Disable Popper.js if we have a static display - - }; - - if (this._config.display === 'static') { - popperConfig.modifiers.applyStyle = { - enabled: false - }; - } - - return popperConfig; - }; // Static - - - Dropdown._jQueryInterface = function _jQueryInterface(config) { - return this.each(function () { - var data = $$$1(this).data(DATA_KEY); - - var _config = typeof config === 'object' ? config : null; - - if (!data) { - data = new Dropdown(this, _config); - $$$1(this).data(DATA_KEY, data); - } - - if (typeof config === 'string') { - if (typeof data[config] === 'undefined') { - throw new TypeError("No method named \"" + config + "\""); - } - - data[config](); - } - }); - }; - - Dropdown._clearMenus = function _clearMenus(event) { - if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) { - return; - } - - var toggles = $$$1.makeArray($$$1(Selector.DATA_TOGGLE)); - - for (var i = 0; i < toggles.length; i++) { - var parent = Dropdown._getParentFromElement(toggles[i]); - - var context = $$$1(toggles[i]).data(DATA_KEY); - var relatedTarget = { - relatedTarget: toggles[i] - }; - - if (!context) { - continue; - } - - var dropdownMenu = context._menu; - - if (!$$$1(parent).hasClass(ClassName.SHOW)) { - continue; - } - - if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $$$1.contains(parent, event.target)) { - continue; - } - - var hideEvent = $$$1.Event(Event.HIDE, relatedTarget); - $$$1(parent).trigger(hideEvent); - - if (hideEvent.isDefaultPrevented()) { - continue; - } // If this is a touch-enabled device we remove the extra - // empty mouseover listeners we added for iOS support - - - if ('ontouchstart' in document.documentElement) { - $$$1(document.body).children().off('mouseover', null, $$$1.noop); - } - - toggles[i].setAttribute('aria-expanded', 'false'); - $$$1(dropdownMenu).removeClass(ClassName.SHOW); - $$$1(parent).removeClass(ClassName.SHOW).trigger($$$1.Event(Event.HIDDEN, relatedTarget)); - } - }; - - Dropdown._getParentFromElement = function _getParentFromElement(element) { - var parent; - var selector = Util.getSelectorFromElement(element); - - if (selector) { - parent = $$$1(selector)[0]; - } - - return parent || element.parentNode; - }; // eslint-disable-next-line complexity - - - Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) { - // If not input/textarea: - // - And not a key in REGEXP_KEYDOWN => not a dropdown command - // If input/textarea: - // - If space key => not a dropdown command - // - If key is other than escape - // - If key is not up or down => not a dropdown command - // - If trigger inside the menu => not a dropdown command - if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $$$1(event.target).closest(Selector.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) { - return; - } - - event.preventDefault(); - event.stopPropagation(); - - if (this.disabled || $$$1(this).hasClass(ClassName.DISABLED)) { - return; - } - - var parent = Dropdown._getParentFromElement(this); - - var isActive = $$$1(parent).hasClass(ClassName.SHOW); - - if (!isActive && (event.which !== ESCAPE_KEYCODE || event.which !== SPACE_KEYCODE) || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) { - if (event.which === ESCAPE_KEYCODE) { - var toggle = $$$1(parent).find(Selector.DATA_TOGGLE)[0]; - $$$1(toggle).trigger('focus'); - } - - $$$1(this).trigger('click'); - return; - } - - var items = $$$1(parent).find(Selector.VISIBLE_ITEMS).get(); - - if (items.length === 0) { - return; - } - - var index = items.indexOf(event.target); - - if (event.which === ARROW_UP_KEYCODE && index > 0) { - // Up - index--; - } - - if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) { - // Down - index++; - } - - if (index < 0) { - index = 0; - } - - items[index].focus(); - }; - - _createClass(Dropdown, null, [{ - key: "VERSION", - get: function get() { - return VERSION; - } - }, { - key: "Default", - get: function get() { - return Default; - } - }, { - key: "DefaultType", - get: function get() { - return DefaultType; - } - }]); - - return Dropdown; - }(); - /** - * ------------------------------------------------------------------------ - * Data Api implementation - * ------------------------------------------------------------------------ - */ - - - $$$1(document).on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.MENU, Dropdown._dataApiKeydownHandler).on(Event.CLICK_DATA_API + " " + Event.KEYUP_DATA_API, Dropdown._clearMenus).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { - event.preventDefault(); - event.stopPropagation(); - - Dropdown._jQueryInterface.call($$$1(this), 'toggle'); - }).on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function (e) { - e.stopPropagation(); - }); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - $$$1.fn[NAME] = Dropdown._jQueryInterface; - $$$1.fn[NAME].Constructor = Dropdown; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Dropdown._jQueryInterface; - }; - - return Dropdown; - }($, Popper); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): modal.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Modal = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'modal'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.modal'; - var EVENT_KEY = "." + DATA_KEY; - var DATA_API_KEY = '.data-api'; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key - - var Default = { - backdrop: true, - keyboard: true, - focus: true, - show: true - }; - var DefaultType = { - backdrop: '(boolean|string)', - keyboard: 'boolean', - focus: 'boolean', - show: 'boolean' - }; - var Event = { - HIDE: "hide" + EVENT_KEY, - HIDDEN: "hidden" + EVENT_KEY, - SHOW: "show" + EVENT_KEY, - SHOWN: "shown" + EVENT_KEY, - FOCUSIN: "focusin" + EVENT_KEY, - RESIZE: "resize" + EVENT_KEY, - CLICK_DISMISS: "click.dismiss" + EVENT_KEY, - KEYDOWN_DISMISS: "keydown.dismiss" + EVENT_KEY, - MOUSEUP_DISMISS: "mouseup.dismiss" + EVENT_KEY, - MOUSEDOWN_DISMISS: "mousedown.dismiss" + EVENT_KEY, - CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY - }; - var ClassName = { - SCROLLBAR_MEASURER: 'modal-scrollbar-measure', - BACKDROP: 'modal-backdrop', - OPEN: 'modal-open', - FADE: 'fade', - SHOW: 'show' - }; - var Selector = { - DIALOG: '.modal-dialog', - DATA_TOGGLE: '[data-toggle="modal"]', - DATA_DISMISS: '[data-dismiss="modal"]', - FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top', - STICKY_CONTENT: '.sticky-top', - NAVBAR_TOGGLER: '.navbar-toggler' - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Modal = - /*#__PURE__*/ - function () { - function Modal(element, config) { - this._config = this._getConfig(config); - this._element = element; - this._dialog = $$$1(element).find(Selector.DIALOG)[0]; - this._backdrop = null; - this._isShown = false; - this._isBodyOverflowing = false; - this._ignoreBackdropClick = false; - this._scrollbarWidth = 0; - } // Getters - - - var _proto = Modal.prototype; - - // Public - _proto.toggle = function toggle(relatedTarget) { - return this._isShown ? this.hide() : this.show(relatedTarget); - }; - - _proto.show = function show(relatedTarget) { - var _this = this; - - if (this._isTransitioning || this._isShown) { - return; - } - - if ($$$1(this._element).hasClass(ClassName.FADE)) { - this._isTransitioning = true; - } - - var showEvent = $$$1.Event(Event.SHOW, { - relatedTarget: relatedTarget - }); - $$$1(this._element).trigger(showEvent); - - if (this._isShown || showEvent.isDefaultPrevented()) { - return; - } - - this._isShown = true; - - this._checkScrollbar(); - - this._setScrollbar(); - - this._adjustDialog(); - - $$$1(document.body).addClass(ClassName.OPEN); - - this._setEscapeEvent(); - - this._setResizeEvent(); - - $$$1(this._element).on(Event.CLICK_DISMISS, Selector.DATA_DISMISS, function (event) { - return _this.hide(event); - }); - $$$1(this._dialog).on(Event.MOUSEDOWN_DISMISS, function () { - $$$1(_this._element).one(Event.MOUSEUP_DISMISS, function (event) { - if ($$$1(event.target).is(_this._element)) { - _this._ignoreBackdropClick = true; - } - }); - }); - - this._showBackdrop(function () { - return _this._showElement(relatedTarget); - }); - }; - - _proto.hide = function hide(event) { - var _this2 = this; - - if (event) { - event.preventDefault(); - } - - if (this._isTransitioning || !this._isShown) { - return; - } - - var hideEvent = $$$1.Event(Event.HIDE); - $$$1(this._element).trigger(hideEvent); - - if (!this._isShown || hideEvent.isDefaultPrevented()) { - return; - } - - this._isShown = false; - var transition = $$$1(this._element).hasClass(ClassName.FADE); - - if (transition) { - this._isTransitioning = true; - } - - this._setEscapeEvent(); - - this._setResizeEvent(); - - $$$1(document).off(Event.FOCUSIN); - $$$1(this._element).removeClass(ClassName.SHOW); - $$$1(this._element).off(Event.CLICK_DISMISS); - $$$1(this._dialog).off(Event.MOUSEDOWN_DISMISS); - - if (transition) { - var transitionDuration = Util.getTransitionDurationFromElement(this._element); - $$$1(this._element).one(Util.TRANSITION_END, function (event) { - return _this2._hideModal(event); - }).emulateTransitionEnd(transitionDuration); - } else { - this._hideModal(); - } - }; - - _proto.dispose = function dispose() { - $$$1.removeData(this._element, DATA_KEY); - $$$1(window, document, this._element, this._backdrop).off(EVENT_KEY); - this._config = null; - this._element = null; - this._dialog = null; - this._backdrop = null; - this._isShown = null; - this._isBodyOverflowing = null; - this._ignoreBackdropClick = null; - this._scrollbarWidth = null; - }; - - _proto.handleUpdate = function handleUpdate() { - this._adjustDialog(); - }; // Private - - - _proto._getConfig = function _getConfig(config) { - config = _objectSpread({}, Default, config); - Util.typeCheckConfig(NAME, config, DefaultType); - return config; - }; - - _proto._showElement = function _showElement(relatedTarget) { - var _this3 = this; - - var transition = $$$1(this._element).hasClass(ClassName.FADE); - - if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { - // Don't move modal's DOM position - document.body.appendChild(this._element); - } - - this._element.style.display = 'block'; - - this._element.removeAttribute('aria-hidden'); - - this._element.scrollTop = 0; - - if (transition) { - Util.reflow(this._element); - } - - $$$1(this._element).addClass(ClassName.SHOW); - - if (this._config.focus) { - this._enforceFocus(); - } - - var shownEvent = $$$1.Event(Event.SHOWN, { - relatedTarget: relatedTarget - }); - - var transitionComplete = function transitionComplete() { - if (_this3._config.focus) { - _this3._element.focus(); - } - - _this3._isTransitioning = false; - $$$1(_this3._element).trigger(shownEvent); - }; - - if (transition) { - var transitionDuration = Util.getTransitionDurationFromElement(this._element); - $$$1(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(transitionDuration); - } else { - transitionComplete(); - } - }; - - _proto._enforceFocus = function _enforceFocus() { - var _this4 = this; - - $$$1(document).off(Event.FOCUSIN) // Guard against infinite focus loop - .on(Event.FOCUSIN, function (event) { - if (document !== event.target && _this4._element !== event.target && $$$1(_this4._element).has(event.target).length === 0) { - _this4._element.focus(); - } - }); - }; - - _proto._setEscapeEvent = function _setEscapeEvent() { - var _this5 = this; - - if (this._isShown && this._config.keyboard) { - $$$1(this._element).on(Event.KEYDOWN_DISMISS, function (event) { - if (event.which === ESCAPE_KEYCODE) { - event.preventDefault(); - - _this5.hide(); - } - }); - } else if (!this._isShown) { - $$$1(this._element).off(Event.KEYDOWN_DISMISS); - } - }; - - _proto._setResizeEvent = function _setResizeEvent() { - var _this6 = this; - - if (this._isShown) { - $$$1(window).on(Event.RESIZE, function (event) { - return _this6.handleUpdate(event); - }); - } else { - $$$1(window).off(Event.RESIZE); - } - }; - - _proto._hideModal = function _hideModal() { - var _this7 = this; - - this._element.style.display = 'none'; - - this._element.setAttribute('aria-hidden', true); - - this._isTransitioning = false; - - this._showBackdrop(function () { - $$$1(document.body).removeClass(ClassName.OPEN); - - _this7._resetAdjustments(); - - _this7._resetScrollbar(); - - $$$1(_this7._element).trigger(Event.HIDDEN); - }); - }; - - _proto._removeBackdrop = function _removeBackdrop() { - if (this._backdrop) { - $$$1(this._backdrop).remove(); - this._backdrop = null; - } - }; - - _proto._showBackdrop = function _showBackdrop(callback) { - var _this8 = this; - - var animate = $$$1(this._element).hasClass(ClassName.FADE) ? ClassName.FADE : ''; - - if (this._isShown && this._config.backdrop) { - this._backdrop = document.createElement('div'); - this._backdrop.className = ClassName.BACKDROP; - - if (animate) { - $$$1(this._backdrop).addClass(animate); - } - - $$$1(this._backdrop).appendTo(document.body); - $$$1(this._element).on(Event.CLICK_DISMISS, function (event) { - if (_this8._ignoreBackdropClick) { - _this8._ignoreBackdropClick = false; - return; - } - - if (event.target !== event.currentTarget) { - return; - } - - if (_this8._config.backdrop === 'static') { - _this8._element.focus(); - } else { - _this8.hide(); - } - }); - - if (animate) { - Util.reflow(this._backdrop); - } - - $$$1(this._backdrop).addClass(ClassName.SHOW); - - if (!callback) { - return; - } - - if (!animate) { - callback(); - return; - } - - var backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop); - $$$1(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(backdropTransitionDuration); - } else if (!this._isShown && this._backdrop) { - $$$1(this._backdrop).removeClass(ClassName.SHOW); - - var callbackRemove = function callbackRemove() { - _this8._removeBackdrop(); - - if (callback) { - callback(); - } - }; - - if ($$$1(this._element).hasClass(ClassName.FADE)) { - var _backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop); - - $$$1(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(_backdropTransitionDuration); - } else { - callbackRemove(); - } - } else if (callback) { - callback(); - } - }; // ---------------------------------------------------------------------- - // the following methods are used to handle overflowing modals - // todo (fat): these should probably be refactored out of modal.js - // ---------------------------------------------------------------------- - - - _proto._adjustDialog = function _adjustDialog() { - var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; - - if (!this._isBodyOverflowing && isModalOverflowing) { - this._element.style.paddingLeft = this._scrollbarWidth + "px"; - } - - if (this._isBodyOverflowing && !isModalOverflowing) { - this._element.style.paddingRight = this._scrollbarWidth + "px"; - } - }; - - _proto._resetAdjustments = function _resetAdjustments() { - this._element.style.paddingLeft = ''; - this._element.style.paddingRight = ''; - }; - - _proto._checkScrollbar = function _checkScrollbar() { - var rect = document.body.getBoundingClientRect(); - this._isBodyOverflowing = rect.left + rect.right < window.innerWidth; - this._scrollbarWidth = this._getScrollbarWidth(); - }; - - _proto._setScrollbar = function _setScrollbar() { - var _this9 = this; - - if (this._isBodyOverflowing) { - // Note: DOMNode.style.paddingRight returns the actual value or '' if not set - // while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set - // Adjust fixed content padding - $$$1(Selector.FIXED_CONTENT).each(function (index, element) { - var actualPadding = $$$1(element)[0].style.paddingRight; - var calculatedPadding = $$$1(element).css('padding-right'); - $$$1(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this9._scrollbarWidth + "px"); - }); // Adjust sticky content margin - - $$$1(Selector.STICKY_CONTENT).each(function (index, element) { - var actualMargin = $$$1(element)[0].style.marginRight; - var calculatedMargin = $$$1(element).css('margin-right'); - $$$1(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this9._scrollbarWidth + "px"); - }); // Adjust navbar-toggler margin - - $$$1(Selector.NAVBAR_TOGGLER).each(function (index, element) { - var actualMargin = $$$1(element)[0].style.marginRight; - var calculatedMargin = $$$1(element).css('margin-right'); - $$$1(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) + _this9._scrollbarWidth + "px"); - }); // Adjust body padding - - var actualPadding = document.body.style.paddingRight; - var calculatedPadding = $$$1(document.body).css('padding-right'); - $$$1(document.body).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + "px"); - } - }; - - _proto._resetScrollbar = function _resetScrollbar() { - // Restore fixed content padding - $$$1(Selector.FIXED_CONTENT).each(function (index, element) { - var padding = $$$1(element).data('padding-right'); - - if (typeof padding !== 'undefined') { - $$$1(element).css('padding-right', padding).removeData('padding-right'); - } - }); // Restore sticky content and navbar-toggler margin - - $$$1(Selector.STICKY_CONTENT + ", " + Selector.NAVBAR_TOGGLER).each(function (index, element) { - var margin = $$$1(element).data('margin-right'); - - if (typeof margin !== 'undefined') { - $$$1(element).css('margin-right', margin).removeData('margin-right'); - } - }); // Restore body padding - - var padding = $$$1(document.body).data('padding-right'); - - if (typeof padding !== 'undefined') { - $$$1(document.body).css('padding-right', padding).removeData('padding-right'); - } - }; - - _proto._getScrollbarWidth = function _getScrollbarWidth() { - // thx d.walsh - var scrollDiv = document.createElement('div'); - scrollDiv.className = ClassName.SCROLLBAR_MEASURER; - document.body.appendChild(scrollDiv); - var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth; - document.body.removeChild(scrollDiv); - return scrollbarWidth; - }; // Static - - - Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) { - return this.each(function () { - var data = $$$1(this).data(DATA_KEY); - - var _config = _objectSpread({}, Modal.Default, $$$1(this).data(), typeof config === 'object' && config); - - if (!data) { - data = new Modal(this, _config); - $$$1(this).data(DATA_KEY, data); - } - - if (typeof config === 'string') { - if (typeof data[config] === 'undefined') { - throw new TypeError("No method named \"" + config + "\""); - } - - data[config](relatedTarget); - } else if (_config.show) { - data.show(relatedTarget); - } - }); - }; - - _createClass(Modal, null, [{ - key: "VERSION", - get: function get() { - return VERSION; - } - }, { - key: "Default", - get: function get() { - return Default; - } - }]); - - return Modal; - }(); - /** - * ------------------------------------------------------------------------ - * Data Api implementation - * ------------------------------------------------------------------------ - */ - - - $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { - var _this10 = this; - - var target; - var selector = Util.getSelectorFromElement(this); - - if (selector) { - target = $$$1(selector)[0]; - } - - var config = $$$1(target).data(DATA_KEY) ? 'toggle' : _objectSpread({}, $$$1(target).data(), $$$1(this).data()); - - if (this.tagName === 'A' || this.tagName === 'AREA') { - event.preventDefault(); - } - - var $target = $$$1(target).one(Event.SHOW, function (showEvent) { - if (showEvent.isDefaultPrevented()) { - // Only register focus restorer if modal will actually get shown - return; - } - - $target.one(Event.HIDDEN, function () { - if ($$$1(_this10).is(':visible')) { - _this10.focus(); - } - }); - }); - - Modal._jQueryInterface.call($$$1(target), config, this); - }); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - $$$1.fn[NAME] = Modal._jQueryInterface; - $$$1.fn[NAME].Constructor = Modal; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Modal._jQueryInterface; - }; - - return Modal; - }($); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): tooltip.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Tooltip = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'tooltip'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.tooltip'; - var EVENT_KEY = "." + DATA_KEY; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var CLASS_PREFIX = 'bs-tooltip'; - var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g'); - var DefaultType = { - animation: 'boolean', - template: 'string', - title: '(string|element|function)', - trigger: 'string', - delay: '(number|object)', - html: 'boolean', - selector: '(string|boolean)', - placement: '(string|function)', - offset: '(number|string)', - container: '(string|element|boolean)', - fallbackPlacement: '(string|array)', - boundary: '(string|element)' - }; - var AttachmentMap = { - AUTO: 'auto', - TOP: 'top', - RIGHT: 'right', - BOTTOM: 'bottom', - LEFT: 'left' - }; - var Default = { - animation: true, - template: '', - trigger: 'hover focus', - title: '', - delay: 0, - html: false, - selector: false, - placement: 'top', - offset: 0, - container: false, - fallbackPlacement: 'flip', - boundary: 'scrollParent' - }; - var HoverState = { - SHOW: 'show', - OUT: 'out' - }; - var Event = { - HIDE: "hide" + EVENT_KEY, - HIDDEN: "hidden" + EVENT_KEY, - SHOW: "show" + EVENT_KEY, - SHOWN: "shown" + EVENT_KEY, - INSERTED: "inserted" + EVENT_KEY, - CLICK: "click" + EVENT_KEY, - FOCUSIN: "focusin" + EVENT_KEY, - FOCUSOUT: "focusout" + EVENT_KEY, - MOUSEENTER: "mouseenter" + EVENT_KEY, - MOUSELEAVE: "mouseleave" + EVENT_KEY - }; - var ClassName = { - FADE: 'fade', - SHOW: 'show' - }; - var Selector = { - TOOLTIP: '.tooltip', - TOOLTIP_INNER: '.tooltip-inner', - ARROW: '.arrow' - }; - var Trigger = { - HOVER: 'hover', - FOCUS: 'focus', - CLICK: 'click', - MANUAL: 'manual' - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Tooltip = - /*#__PURE__*/ - function () { - function Tooltip(element, config) { - /** - * Check for Popper dependency - * Popper - https://popper.js.org - */ - if (typeof Popper === 'undefined') { - throw new TypeError('Bootstrap tooltips require Popper.js (https://popper.js.org)'); - } // private - - - this._isEnabled = true; - this._timeout = 0; - this._hoverState = ''; - this._activeTrigger = {}; - this._popper = null; // Protected - - this.element = element; - this.config = this._getConfig(config); - this.tip = null; - - this._setListeners(); - } // Getters - - - var _proto = Tooltip.prototype; - - // Public - _proto.enable = function enable() { - this._isEnabled = true; - }; - - _proto.disable = function disable() { - this._isEnabled = false; - }; - - _proto.toggleEnabled = function toggleEnabled() { - this._isEnabled = !this._isEnabled; - }; - - _proto.toggle = function toggle(event) { - if (!this._isEnabled) { - return; - } - - if (event) { - var dataKey = this.constructor.DATA_KEY; - var context = $$$1(event.currentTarget).data(dataKey); - - if (!context) { - context = new this.constructor(event.currentTarget, this._getDelegateConfig()); - $$$1(event.currentTarget).data(dataKey, context); - } - - context._activeTrigger.click = !context._activeTrigger.click; - - if (context._isWithActiveTrigger()) { - context._enter(null, context); - } else { - context._leave(null, context); - } - } else { - if ($$$1(this.getTipElement()).hasClass(ClassName.SHOW)) { - this._leave(null, this); - - return; - } - - this._enter(null, this); - } - }; - - _proto.dispose = function dispose() { - clearTimeout(this._timeout); - $$$1.removeData(this.element, this.constructor.DATA_KEY); - $$$1(this.element).off(this.constructor.EVENT_KEY); - $$$1(this.element).closest('.modal').off('hide.bs.modal'); - - if (this.tip) { - $$$1(this.tip).remove(); - } - - this._isEnabled = null; - this._timeout = null; - this._hoverState = null; - this._activeTrigger = null; - - if (this._popper !== null) { - this._popper.destroy(); - } - - this._popper = null; - this.element = null; - this.config = null; - this.tip = null; - }; - - _proto.show = function show() { - var _this = this; - - if ($$$1(this.element).css('display') === 'none') { - throw new Error('Please use show on visible elements'); - } - - var showEvent = $$$1.Event(this.constructor.Event.SHOW); - - if (this.isWithContent() && this._isEnabled) { - $$$1(this.element).trigger(showEvent); - var isInTheDom = $$$1.contains(this.element.ownerDocument.documentElement, this.element); - - if (showEvent.isDefaultPrevented() || !isInTheDom) { - return; - } - - var tip = this.getTipElement(); - var tipId = Util.getUID(this.constructor.NAME); - tip.setAttribute('id', tipId); - this.element.setAttribute('aria-describedby', tipId); - this.setContent(); - - if (this.config.animation) { - $$$1(tip).addClass(ClassName.FADE); - } - - var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement; - - var attachment = this._getAttachment(placement); - - this.addAttachmentClass(attachment); - var container = this.config.container === false ? document.body : $$$1(this.config.container); - $$$1(tip).data(this.constructor.DATA_KEY, this); - - if (!$$$1.contains(this.element.ownerDocument.documentElement, this.tip)) { - $$$1(tip).appendTo(container); - } - - $$$1(this.element).trigger(this.constructor.Event.INSERTED); - this._popper = new Popper(this.element, tip, { - placement: attachment, - modifiers: { - offset: { - offset: this.config.offset - }, - flip: { - behavior: this.config.fallbackPlacement - }, - arrow: { - element: Selector.ARROW - }, - preventOverflow: { - boundariesElement: this.config.boundary - } - }, - onCreate: function onCreate(data) { - if (data.originalPlacement !== data.placement) { - _this._handlePopperPlacementChange(data); - } - }, - onUpdate: function onUpdate(data) { - _this._handlePopperPlacementChange(data); - } - }); - $$$1(tip).addClass(ClassName.SHOW); // If this is a touch-enabled device we add extra - // empty mouseover listeners to the body's immediate children; - // only needed because of broken event delegation on iOS - // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html - - if ('ontouchstart' in document.documentElement) { - $$$1(document.body).children().on('mouseover', null, $$$1.noop); - } - - var complete = function complete() { - if (_this.config.animation) { - _this._fixTransition(); - } - - var prevHoverState = _this._hoverState; - _this._hoverState = null; - $$$1(_this.element).trigger(_this.constructor.Event.SHOWN); - - if (prevHoverState === HoverState.OUT) { - _this._leave(null, _this); - } - }; - - if ($$$1(this.tip).hasClass(ClassName.FADE)) { - var transitionDuration = Util.getTransitionDurationFromElement(this.tip); - $$$1(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); - } else { - complete(); - } - } - }; - - _proto.hide = function hide(callback) { - var _this2 = this; - - var tip = this.getTipElement(); - var hideEvent = $$$1.Event(this.constructor.Event.HIDE); - - var complete = function complete() { - if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) { - tip.parentNode.removeChild(tip); - } - - _this2._cleanTipClass(); - - _this2.element.removeAttribute('aria-describedby'); - - $$$1(_this2.element).trigger(_this2.constructor.Event.HIDDEN); - - if (_this2._popper !== null) { - _this2._popper.destroy(); - } - - if (callback) { - callback(); - } - }; - - $$$1(this.element).trigger(hideEvent); - - if (hideEvent.isDefaultPrevented()) { - return; - } - - $$$1(tip).removeClass(ClassName.SHOW); // If this is a touch-enabled device we remove the extra - // empty mouseover listeners we added for iOS support - - if ('ontouchstart' in document.documentElement) { - $$$1(document.body).children().off('mouseover', null, $$$1.noop); - } - - this._activeTrigger[Trigger.CLICK] = false; - this._activeTrigger[Trigger.FOCUS] = false; - this._activeTrigger[Trigger.HOVER] = false; - - if ($$$1(this.tip).hasClass(ClassName.FADE)) { - var transitionDuration = Util.getTransitionDurationFromElement(tip); - $$$1(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); - } else { - complete(); - } - - this._hoverState = ''; - }; - - _proto.update = function update() { - if (this._popper !== null) { - this._popper.scheduleUpdate(); - } - }; // Protected - - - _proto.isWithContent = function isWithContent() { - return Boolean(this.getTitle()); - }; - - _proto.addAttachmentClass = function addAttachmentClass(attachment) { - $$$1(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment); - }; - - _proto.getTipElement = function getTipElement() { - this.tip = this.tip || $$$1(this.config.template)[0]; - return this.tip; - }; - - _proto.setContent = function setContent() { - var $tip = $$$1(this.getTipElement()); - this.setElementContent($tip.find(Selector.TOOLTIP_INNER), this.getTitle()); - $tip.removeClass(ClassName.FADE + " " + ClassName.SHOW); - }; - - _proto.setElementContent = function setElementContent($element, content) { - var html = this.config.html; - - if (typeof content === 'object' && (content.nodeType || content.jquery)) { - // Content is a DOM node or a jQuery - if (html) { - if (!$$$1(content).parent().is($element)) { - $element.empty().append(content); - } - } else { - $element.text($$$1(content).text()); - } - } else { - $element[html ? 'html' : 'text'](content); - } - }; - - _proto.getTitle = function getTitle() { - var title = this.element.getAttribute('data-original-title'); - - if (!title) { - title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title; - } - - return title; - }; // Private - - - _proto._getAttachment = function _getAttachment(placement) { - return AttachmentMap[placement.toUpperCase()]; - }; - - _proto._setListeners = function _setListeners() { - var _this3 = this; - - var triggers = this.config.trigger.split(' '); - triggers.forEach(function (trigger) { - if (trigger === 'click') { - $$$1(_this3.element).on(_this3.constructor.Event.CLICK, _this3.config.selector, function (event) { - return _this3.toggle(event); - }); - } else if (trigger !== Trigger.MANUAL) { - var eventIn = trigger === Trigger.HOVER ? _this3.constructor.Event.MOUSEENTER : _this3.constructor.Event.FOCUSIN; - var eventOut = trigger === Trigger.HOVER ? _this3.constructor.Event.MOUSELEAVE : _this3.constructor.Event.FOCUSOUT; - $$$1(_this3.element).on(eventIn, _this3.config.selector, function (event) { - return _this3._enter(event); - }).on(eventOut, _this3.config.selector, function (event) { - return _this3._leave(event); - }); - } - - $$$1(_this3.element).closest('.modal').on('hide.bs.modal', function () { - return _this3.hide(); - }); - }); - - if (this.config.selector) { - this.config = _objectSpread({}, this.config, { - trigger: 'manual', - selector: '' - }); - } else { - this._fixTitle(); - } - }; - - _proto._fixTitle = function _fixTitle() { - var titleType = typeof this.element.getAttribute('data-original-title'); - - if (this.element.getAttribute('title') || titleType !== 'string') { - this.element.setAttribute('data-original-title', this.element.getAttribute('title') || ''); - this.element.setAttribute('title', ''); - } - }; - - _proto._enter = function _enter(event, context) { - var dataKey = this.constructor.DATA_KEY; - context = context || $$$1(event.currentTarget).data(dataKey); - - if (!context) { - context = new this.constructor(event.currentTarget, this._getDelegateConfig()); - $$$1(event.currentTarget).data(dataKey, context); - } - - if (event) { - context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true; - } - - if ($$$1(context.getTipElement()).hasClass(ClassName.SHOW) || context._hoverState === HoverState.SHOW) { - context._hoverState = HoverState.SHOW; - return; - } - - clearTimeout(context._timeout); - context._hoverState = HoverState.SHOW; - - if (!context.config.delay || !context.config.delay.show) { - context.show(); - return; - } - - context._timeout = setTimeout(function () { - if (context._hoverState === HoverState.SHOW) { - context.show(); - } - }, context.config.delay.show); - }; - - _proto._leave = function _leave(event, context) { - var dataKey = this.constructor.DATA_KEY; - context = context || $$$1(event.currentTarget).data(dataKey); - - if (!context) { - context = new this.constructor(event.currentTarget, this._getDelegateConfig()); - $$$1(event.currentTarget).data(dataKey, context); - } - - if (event) { - context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false; - } - - if (context._isWithActiveTrigger()) { - return; - } - - clearTimeout(context._timeout); - context._hoverState = HoverState.OUT; - - if (!context.config.delay || !context.config.delay.hide) { - context.hide(); - return; - } - - context._timeout = setTimeout(function () { - if (context._hoverState === HoverState.OUT) { - context.hide(); - } - }, context.config.delay.hide); - }; - - _proto._isWithActiveTrigger = function _isWithActiveTrigger() { - for (var trigger in this._activeTrigger) { - if (this._activeTrigger[trigger]) { - return true; - } - } - - return false; - }; - - _proto._getConfig = function _getConfig(config) { - config = _objectSpread({}, this.constructor.Default, $$$1(this.element).data(), config); - - if (typeof config.delay === 'number') { - config.delay = { - show: config.delay, - hide: config.delay - }; - } - - if (typeof config.title === 'number') { - config.title = config.title.toString(); - } - - if (typeof config.content === 'number') { - config.content = config.content.toString(); - } - - Util.typeCheckConfig(NAME, config, this.constructor.DefaultType); - return config; - }; - - _proto._getDelegateConfig = function _getDelegateConfig() { - var config = {}; - - if (this.config) { - for (var key in this.config) { - if (this.constructor.Default[key] !== this.config[key]) { - config[key] = this.config[key]; - } - } - } - - return config; - }; - - _proto._cleanTipClass = function _cleanTipClass() { - var $tip = $$$1(this.getTipElement()); - var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX); - - if (tabClass !== null && tabClass.length > 0) { - $tip.removeClass(tabClass.join('')); - } - }; - - _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(data) { - this._cleanTipClass(); - - this.addAttachmentClass(this._getAttachment(data.placement)); - }; - - _proto._fixTransition = function _fixTransition() { - var tip = this.getTipElement(); - var initConfigAnimation = this.config.animation; - - if (tip.getAttribute('x-placement') !== null) { - return; - } - - $$$1(tip).removeClass(ClassName.FADE); - this.config.animation = false; - this.hide(); - this.show(); - this.config.animation = initConfigAnimation; - }; // Static - - - Tooltip._jQueryInterface = function _jQueryInterface(config) { - return this.each(function () { - var data = $$$1(this).data(DATA_KEY); - - var _config = typeof config === 'object' && config; - - if (!data && /dispose|hide/.test(config)) { - return; - } - - if (!data) { - data = new Tooltip(this, _config); - $$$1(this).data(DATA_KEY, data); - } - - if (typeof config === 'string') { - if (typeof data[config] === 'undefined') { - throw new TypeError("No method named \"" + config + "\""); - } - - data[config](); - } - }); - }; - - _createClass(Tooltip, null, [{ - key: "VERSION", - get: function get() { - return VERSION; - } - }, { - key: "Default", - get: function get() { - return Default; - } - }, { - key: "NAME", - get: function get() { - return NAME; - } - }, { - key: "DATA_KEY", - get: function get() { - return DATA_KEY; - } - }, { - key: "Event", - get: function get() { - return Event; - } - }, { - key: "EVENT_KEY", - get: function get() { - return EVENT_KEY; - } - }, { - key: "DefaultType", - get: function get() { - return DefaultType; - } - }]); - - return Tooltip; - }(); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - - $$$1.fn[NAME] = Tooltip._jQueryInterface; - $$$1.fn[NAME].Constructor = Tooltip; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Tooltip._jQueryInterface; - }; - - return Tooltip; - }($, Popper); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): popover.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Popover = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'popover'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.popover'; - var EVENT_KEY = "." + DATA_KEY; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var CLASS_PREFIX = 'bs-popover'; - var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g'); - - var Default = _objectSpread({}, Tooltip.Default, { - placement: 'right', - trigger: 'click', - content: '', - template: '' - }); - - var DefaultType = _objectSpread({}, Tooltip.DefaultType, { - content: '(string|element|function)' - }); - - var ClassName = { - FADE: 'fade', - SHOW: 'show' - }; - var Selector = { - TITLE: '.popover-header', - CONTENT: '.popover-body' - }; - var Event = { - HIDE: "hide" + EVENT_KEY, - HIDDEN: "hidden" + EVENT_KEY, - SHOW: "show" + EVENT_KEY, - SHOWN: "shown" + EVENT_KEY, - INSERTED: "inserted" + EVENT_KEY, - CLICK: "click" + EVENT_KEY, - FOCUSIN: "focusin" + EVENT_KEY, - FOCUSOUT: "focusout" + EVENT_KEY, - MOUSEENTER: "mouseenter" + EVENT_KEY, - MOUSELEAVE: "mouseleave" + EVENT_KEY - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Popover = - /*#__PURE__*/ - function (_Tooltip) { - _inheritsLoose(Popover, _Tooltip); - - function Popover() { - return _Tooltip.apply(this, arguments) || this; - } - - var _proto = Popover.prototype; - - // Overrides - _proto.isWithContent = function isWithContent() { - return this.getTitle() || this._getContent(); - }; - - _proto.addAttachmentClass = function addAttachmentClass(attachment) { - $$$1(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment); - }; - - _proto.getTipElement = function getTipElement() { - this.tip = this.tip || $$$1(this.config.template)[0]; - return this.tip; - }; - - _proto.setContent = function setContent() { - var $tip = $$$1(this.getTipElement()); // We use append for html objects to maintain js events - - this.setElementContent($tip.find(Selector.TITLE), this.getTitle()); - - var content = this._getContent(); - - if (typeof content === 'function') { - content = content.call(this.element); - } - - this.setElementContent($tip.find(Selector.CONTENT), content); - $tip.removeClass(ClassName.FADE + " " + ClassName.SHOW); - }; // Private - - - _proto._getContent = function _getContent() { - return this.element.getAttribute('data-content') || this.config.content; - }; - - _proto._cleanTipClass = function _cleanTipClass() { - var $tip = $$$1(this.getTipElement()); - var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX); - - if (tabClass !== null && tabClass.length > 0) { - $tip.removeClass(tabClass.join('')); - } - }; // Static - - - Popover._jQueryInterface = function _jQueryInterface(config) { - return this.each(function () { - var data = $$$1(this).data(DATA_KEY); - - var _config = typeof config === 'object' ? config : null; - - if (!data && /destroy|hide/.test(config)) { - return; - } - - if (!data) { - data = new Popover(this, _config); - $$$1(this).data(DATA_KEY, data); - } - - if (typeof config === 'string') { - if (typeof data[config] === 'undefined') { - throw new TypeError("No method named \"" + config + "\""); - } - - data[config](); - } - }); - }; - - _createClass(Popover, null, [{ - key: "VERSION", - // Getters - get: function get() { - return VERSION; - } - }, { - key: "Default", - get: function get() { - return Default; - } - }, { - key: "NAME", - get: function get() { - return NAME; - } - }, { - key: "DATA_KEY", - get: function get() { - return DATA_KEY; - } - }, { - key: "Event", - get: function get() { - return Event; - } - }, { - key: "EVENT_KEY", - get: function get() { - return EVENT_KEY; - } - }, { - key: "DefaultType", - get: function get() { - return DefaultType; - } - }]); - - return Popover; - }(Tooltip); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - - $$$1.fn[NAME] = Popover._jQueryInterface; - $$$1.fn[NAME].Constructor = Popover; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Popover._jQueryInterface; - }; - - return Popover; - }($); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): scrollspy.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var ScrollSpy = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'scrollspy'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.scrollspy'; - var EVENT_KEY = "." + DATA_KEY; - var DATA_API_KEY = '.data-api'; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var Default = { - offset: 10, - method: 'auto', - target: '' - }; - var DefaultType = { - offset: 'number', - method: 'string', - target: '(string|element)' - }; - var Event = { - ACTIVATE: "activate" + EVENT_KEY, - SCROLL: "scroll" + EVENT_KEY, - LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY - }; - var ClassName = { - DROPDOWN_ITEM: 'dropdown-item', - DROPDOWN_MENU: 'dropdown-menu', - ACTIVE: 'active' - }; - var Selector = { - DATA_SPY: '[data-spy="scroll"]', - ACTIVE: '.active', - NAV_LIST_GROUP: '.nav, .list-group', - NAV_LINKS: '.nav-link', - NAV_ITEMS: '.nav-item', - LIST_ITEMS: '.list-group-item', - DROPDOWN: '.dropdown', - DROPDOWN_ITEMS: '.dropdown-item', - DROPDOWN_TOGGLE: '.dropdown-toggle' - }; - var OffsetMethod = { - OFFSET: 'offset', - POSITION: 'position' - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var ScrollSpy = - /*#__PURE__*/ - function () { - function ScrollSpy(element, config) { - var _this = this; - - this._element = element; - this._scrollElement = element.tagName === 'BODY' ? window : element; - this._config = this._getConfig(config); - this._selector = this._config.target + " " + Selector.NAV_LINKS + "," + (this._config.target + " " + Selector.LIST_ITEMS + ",") + (this._config.target + " " + Selector.DROPDOWN_ITEMS); - this._offsets = []; - this._targets = []; - this._activeTarget = null; - this._scrollHeight = 0; - $$$1(this._scrollElement).on(Event.SCROLL, function (event) { - return _this._process(event); - }); - this.refresh(); - - this._process(); - } // Getters - - - var _proto = ScrollSpy.prototype; - - // Public - _proto.refresh = function refresh() { - var _this2 = this; - - var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION; - var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method; - var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0; - this._offsets = []; - this._targets = []; - this._scrollHeight = this._getScrollHeight(); - var targets = $$$1.makeArray($$$1(this._selector)); - targets.map(function (element) { - var target; - var targetSelector = Util.getSelectorFromElement(element); - - if (targetSelector) { - target = $$$1(targetSelector)[0]; - } - - if (target) { - var targetBCR = target.getBoundingClientRect(); - - if (targetBCR.width || targetBCR.height) { - // TODO (fat): remove sketch reliance on jQuery position/offset - return [$$$1(target)[offsetMethod]().top + offsetBase, targetSelector]; - } - } - - return null; - }).filter(function (item) { - return item; - }).sort(function (a, b) { - return a[0] - b[0]; - }).forEach(function (item) { - _this2._offsets.push(item[0]); - - _this2._targets.push(item[1]); - }); - }; - - _proto.dispose = function dispose() { - $$$1.removeData(this._element, DATA_KEY); - $$$1(this._scrollElement).off(EVENT_KEY); - this._element = null; - this._scrollElement = null; - this._config = null; - this._selector = null; - this._offsets = null; - this._targets = null; - this._activeTarget = null; - this._scrollHeight = null; - }; // Private - - - _proto._getConfig = function _getConfig(config) { - config = _objectSpread({}, Default, config); - - if (typeof config.target !== 'string') { - var id = $$$1(config.target).attr('id'); - - if (!id) { - id = Util.getUID(NAME); - $$$1(config.target).attr('id', id); - } - - config.target = "#" + id; - } - - Util.typeCheckConfig(NAME, config, DefaultType); - return config; - }; - - _proto._getScrollTop = function _getScrollTop() { - return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop; - }; - - _proto._getScrollHeight = function _getScrollHeight() { - return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight); - }; - - _proto._getOffsetHeight = function _getOffsetHeight() { - return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height; - }; - - _proto._process = function _process() { - var scrollTop = this._getScrollTop() + this._config.offset; - - var scrollHeight = this._getScrollHeight(); - - var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight(); - - if (this._scrollHeight !== scrollHeight) { - this.refresh(); - } - - if (scrollTop >= maxScroll) { - var target = this._targets[this._targets.length - 1]; - - if (this._activeTarget !== target) { - this._activate(target); - } - - return; - } - - if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) { - this._activeTarget = null; - - this._clear(); - - return; - } - - for (var i = this._offsets.length; i--;) { - var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]); - - if (isActiveTarget) { - this._activate(this._targets[i]); - } - } - }; - - _proto._activate = function _activate(target) { - this._activeTarget = target; - - this._clear(); - - var queries = this._selector.split(','); // eslint-disable-next-line arrow-body-style - - - queries = queries.map(function (selector) { - return selector + "[data-target=\"" + target + "\"]," + (selector + "[href=\"" + target + "\"]"); - }); - var $link = $$$1(queries.join(',')); - - if ($link.hasClass(ClassName.DROPDOWN_ITEM)) { - $link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE); - $link.addClass(ClassName.ACTIVE); - } else { - // Set triggered link as active - $link.addClass(ClassName.ACTIVE); // Set triggered links parents as active - // With both
      and
    ',trigger:"hover focus",title:"",delay:0,html:!(pn={AUTO:"auto",TOP:"top",RIGHT:"right",BOTTOM:"bottom",LEFT:"left"}),selector:!(dn={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)"}),placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent"},_n="out",vn={HIDE:"hide"+cn,HIDDEN:"hidden"+cn,SHOW:(mn="show")+cn,SHOWN:"shown"+cn,INSERTED:"inserted"+cn,CLICK:"click"+cn,FOCUSIN:"focusin"+cn,FOCUSOUT:"focusout"+cn,MOUSEENTER:"mouseenter"+cn,MOUSELEAVE:"mouseleave"+cn},En="fade",yn="show",bn=".tooltip-inner",Tn=".arrow",Cn="hover",wn="focus",In="click",Dn="manual",An=function(){function i(t,e){if("undefined"==typeof pe)throw new TypeError("Bootstrap tooltips require Popper.js (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var t=i.prototype;return t.enable=function(){this._isEnabled=!0},t.disable=function(){this._isEnabled=!1},t.toggleEnabled=function(){this._isEnabled=!this._isEnabled},t.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=sn(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),sn(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(sn(this.getTipElement()).hasClass(yn))return void this._leave(null,this);this._enter(null,this)}},t.dispose=function(){clearTimeout(this._timeout),sn.removeData(this.element,this.constructor.DATA_KEY),sn(this.element).off(this.constructor.EVENT_KEY),sn(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&sn(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,(this._activeTrigger=null)!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},t.show=function(){var e=this;if("none"===sn(this.element).css("display"))throw new Error("Please use show on visible elements");var t=sn.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){sn(this.element).trigger(t);var n=sn.contains(this.element.ownerDocument.documentElement,this.element);if(t.isDefaultPrevented()||!n)return;var i=this.getTipElement(),r=gt.getUID(this.constructor.NAME);i.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&sn(i).addClass(En);var o="function"==typeof this.config.placement?this.config.placement.call(this,i,this.element):this.config.placement,s=this._getAttachment(o);this.addAttachmentClass(s);var a=!1===this.config.container?document.body:sn(this.config.container);sn(i).data(this.constructor.DATA_KEY,this),sn.contains(this.element.ownerDocument.documentElement,this.tip)||sn(i).appendTo(a),sn(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new pe(this.element,i,{placement:s,modifiers:{offset:{offset:this.config.offset},flip:{behavior:this.config.fallbackPlacement},arrow:{element:Tn},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){e._handlePopperPlacementChange(t)}}),sn(i).addClass(yn),"ontouchstart"in document.documentElement&&sn(document.body).children().on("mouseover",null,sn.noop);var l=function(){e.config.animation&&e._fixTransition();var t=e._hoverState;e._hoverState=null,sn(e.element).trigger(e.constructor.Event.SHOWN),t===_n&&e._leave(null,e)};if(sn(this.tip).hasClass(En)){var c=gt.getTransitionDurationFromElement(this.tip);sn(this.tip).one(gt.TRANSITION_END,l).emulateTransitionEnd(c)}else l()}},t.hide=function(t){var e=this,n=this.getTipElement(),i=sn.Event(this.constructor.Event.HIDE),r=function(){e._hoverState!==mn&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),sn(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(sn(this.element).trigger(i),!i.isDefaultPrevented()){if(sn(n).removeClass(yn),"ontouchstart"in document.documentElement&&sn(document.body).children().off("mouseover",null,sn.noop),this._activeTrigger[In]=!1,this._activeTrigger[wn]=!1,this._activeTrigger[Cn]=!1,sn(this.tip).hasClass(En)){var o=gt.getTransitionDurationFromElement(n);sn(n).one(gt.TRANSITION_END,r).emulateTransitionEnd(o)}else r();this._hoverState=""}},t.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},t.isWithContent=function(){return Boolean(this.getTitle())},t.addAttachmentClass=function(t){sn(this.getTipElement()).addClass(hn+"-"+t)},t.getTipElement=function(){return this.tip=this.tip||sn(this.config.template)[0],this.tip},t.setContent=function(){var t=sn(this.getTipElement());this.setElementContent(t.find(bn),this.getTitle()),t.removeClass(En+" "+yn)},t.setElementContent=function(t,e){var n=this.config.html;"object"==typeof e&&(e.nodeType||e.jquery)?n?sn(e).parent().is(t)||t.empty().append(e):t.text(sn(e).text()):t[n?"html":"text"](e)},t.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},t._getAttachment=function(t){return pn[t.toUpperCase()]},t._setListeners=function(){var i=this;this.config.trigger.split(" ").forEach(function(t){if("click"===t)sn(i.element).on(i.constructor.Event.CLICK,i.config.selector,function(t){return i.toggle(t)});else if(t!==Dn){var e=t===Cn?i.constructor.Event.MOUSEENTER:i.constructor.Event.FOCUSIN,n=t===Cn?i.constructor.Event.MOUSELEAVE:i.constructor.Event.FOCUSOUT;sn(i.element).on(e,i.config.selector,function(t){return i._enter(t)}).on(n,i.config.selector,function(t){return i._leave(t)})}sn(i.element).closest(".modal").on("hide.bs.modal",function(){return i.hide()})}),this.config.selector?this.config=c({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},t._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},t._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||sn(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),sn(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?wn:Cn]=!0),sn(e.getTipElement()).hasClass(yn)||e._hoverState===mn?e._hoverState=mn:(clearTimeout(e._timeout),e._hoverState=mn,e.config.delay&&e.config.delay.show?e._timeout=setTimeout(function(){e._hoverState===mn&&e.show()},e.config.delay.show):e.show())},t._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||sn(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),sn(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?wn:Cn]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=_n,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout(function(){e._hoverState===_n&&e.hide()},e.config.delay.hide):e.hide())},t._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},t._getConfig=function(t){return"number"==typeof(t=c({},this.constructor.Default,sn(this.element).data(),t)).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),gt.typeCheckConfig(an,t,this.constructor.DefaultType),t},t._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},t._cleanTipClass=function(){var t=sn(this.getTipElement()),e=t.attr("class").match(un);null!==e&&0

    '}),Rn=c({},Ci.DefaultType,{content:"(string|element|function)"}),Mn="fade",Wn=".popover-header",Fn=".popover-body",Un={HIDE:"hide"+kn,HIDDEN:"hidden"+kn,SHOW:(Hn="show")+kn,SHOWN:"shown"+kn,INSERTED:"inserted"+kn,CLICK:"click"+kn,FOCUSIN:"focusin"+kn,FOCUSOUT:"focusout"+kn,MOUSEENTER:"mouseenter"+kn,MOUSELEAVE:"mouseleave"+kn},Bn=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),(e.prototype.constructor=e).__proto__=n;var r=i.prototype;return r.isWithContent=function(){return this.getTitle()||this._getContent()},r.addAttachmentClass=function(t){Sn(this.getTipElement()).addClass(Pn+"-"+t)},r.getTipElement=function(){return this.tip=this.tip||Sn(this.config.template)[0],this.tip},r.setContent=function(){var t=Sn(this.getTipElement());this.setElementContent(t.find(Wn),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(Fn),e),t.removeClass(Mn+" "+Hn)},r._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},r._cleanTipClass=function(){var t=Sn(this.getTipElement()),e=t.attr("class").match(xn);null!==e&&0=this._offsets[r]&&("undefined"==typeof this._offsets[r+1]||t 0 ? selector : null; - } catch (err) { - return null; - } - }, - getTransitionDurationFromElement: function getTransitionDurationFromElement(element) { - if (!element) { - return 0; - } // Get transition-duration of the element - - - var transitionDuration = $$$1(element).css('transition-duration'); - var floatTransitionDuration = parseFloat(transitionDuration); // Return 0 if element or transition duration is not found - - if (!floatTransitionDuration) { - return 0; - } // If multiple durations are defined, take the first - - - transitionDuration = transitionDuration.split(',')[0]; - return parseFloat(transitionDuration) * MILLISECONDS_MULTIPLIER; - }, - reflow: function reflow(element) { - return element.offsetHeight; - }, - triggerTransitionEnd: function triggerTransitionEnd(element) { - $$$1(element).trigger(TRANSITION_END); - }, - // TODO: Remove in v5 - supportsTransitionEnd: function supportsTransitionEnd() { - return Boolean(TRANSITION_END); - }, - isElement: function isElement(obj) { - return (obj[0] || obj).nodeType; - }, - typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) { - for (var property in configTypes) { - if (Object.prototype.hasOwnProperty.call(configTypes, property)) { - var expectedTypes = configTypes[property]; - var value = config[property]; - var valueType = value && Util.isElement(value) ? 'element' : toType(value); - - if (!new RegExp(expectedTypes).test(valueType)) { - throw new Error(componentName.toUpperCase() + ": " + ("Option \"" + property + "\" provided type \"" + valueType + "\" ") + ("but expected type \"" + expectedTypes + "\".")); - } - } - } - } - }; - setTransitionEndSupport(); - return Util; - }($); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): alert.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Alert = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'alert'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.alert'; - var EVENT_KEY = "." + DATA_KEY; - var DATA_API_KEY = '.data-api'; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var Selector = { - DISMISS: '[data-dismiss="alert"]' - }; - var Event = { - CLOSE: "close" + EVENT_KEY, - CLOSED: "closed" + EVENT_KEY, - CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY - }; - var ClassName = { - ALERT: 'alert', - FADE: 'fade', - SHOW: 'show' - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Alert = - /*#__PURE__*/ - function () { - function Alert(element) { - this._element = element; - } // Getters - - - var _proto = Alert.prototype; - - // Public - _proto.close = function close(element) { - element = element || this._element; - - var rootElement = this._getRootElement(element); - - var customEvent = this._triggerCloseEvent(rootElement); - - if (customEvent.isDefaultPrevented()) { - return; - } - - this._removeElement(rootElement); - }; - - _proto.dispose = function dispose() { - $$$1.removeData(this._element, DATA_KEY); - this._element = null; - }; // Private - - - _proto._getRootElement = function _getRootElement(element) { - var selector = Util.getSelectorFromElement(element); - var parent = false; - - if (selector) { - parent = $$$1(selector)[0]; - } - - if (!parent) { - parent = $$$1(element).closest("." + ClassName.ALERT)[0]; - } - - return parent; - }; - - _proto._triggerCloseEvent = function _triggerCloseEvent(element) { - var closeEvent = $$$1.Event(Event.CLOSE); - $$$1(element).trigger(closeEvent); - return closeEvent; - }; - - _proto._removeElement = function _removeElement(element) { - var _this = this; - - $$$1(element).removeClass(ClassName.SHOW); - - if (!$$$1(element).hasClass(ClassName.FADE)) { - this._destroyElement(element); - - return; - } - - var transitionDuration = Util.getTransitionDurationFromElement(element); - $$$1(element).one(Util.TRANSITION_END, function (event) { - return _this._destroyElement(element, event); - }).emulateTransitionEnd(transitionDuration); - }; - - _proto._destroyElement = function _destroyElement(element) { - $$$1(element).detach().trigger(Event.CLOSED).remove(); - }; // Static - - - Alert._jQueryInterface = function _jQueryInterface(config) { - return this.each(function () { - var $element = $$$1(this); - var data = $element.data(DATA_KEY); - - if (!data) { - data = new Alert(this); - $element.data(DATA_KEY, data); - } - - if (config === 'close') { - data[config](this); - } - }); - }; - - Alert._handleDismiss = function _handleDismiss(alertInstance) { - return function (event) { - if (event) { - event.preventDefault(); - } - - alertInstance.close(this); - }; - }; - - _createClass(Alert, null, [{ - key: "VERSION", - get: function get() { - return VERSION; - } - }]); - - return Alert; - }(); - /** - * ------------------------------------------------------------------------ - * Data Api implementation - * ------------------------------------------------------------------------ - */ - - - $$$1(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert())); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - $$$1.fn[NAME] = Alert._jQueryInterface; - $$$1.fn[NAME].Constructor = Alert; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Alert._jQueryInterface; - }; - - return Alert; - }($); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): button.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Button = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'button'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.button'; - var EVENT_KEY = "." + DATA_KEY; - var DATA_API_KEY = '.data-api'; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var ClassName = { - ACTIVE: 'active', - BUTTON: 'btn', - FOCUS: 'focus' - }; - var Selector = { - DATA_TOGGLE_CARROT: '[data-toggle^="button"]', - DATA_TOGGLE: '[data-toggle="buttons"]', - INPUT: 'input', - ACTIVE: '.active', - BUTTON: '.btn' - }; - var Event = { - CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY, - FOCUS_BLUR_DATA_API: "focus" + EVENT_KEY + DATA_API_KEY + " " + ("blur" + EVENT_KEY + DATA_API_KEY) - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Button = - /*#__PURE__*/ - function () { - function Button(element) { - this._element = element; - } // Getters - - - var _proto = Button.prototype; - - // Public - _proto.toggle = function toggle() { - var triggerChangeEvent = true; - var addAriaPressed = true; - var rootElement = $$$1(this._element).closest(Selector.DATA_TOGGLE)[0]; - - if (rootElement) { - var input = $$$1(this._element).find(Selector.INPUT)[0]; - - if (input) { - if (input.type === 'radio') { - if (input.checked && $$$1(this._element).hasClass(ClassName.ACTIVE)) { - triggerChangeEvent = false; - } else { - var activeElement = $$$1(rootElement).find(Selector.ACTIVE)[0]; - - if (activeElement) { - $$$1(activeElement).removeClass(ClassName.ACTIVE); - } - } - } - - if (triggerChangeEvent) { - if (input.hasAttribute('disabled') || rootElement.hasAttribute('disabled') || input.classList.contains('disabled') || rootElement.classList.contains('disabled')) { - return; - } - - input.checked = !$$$1(this._element).hasClass(ClassName.ACTIVE); - $$$1(input).trigger('change'); - } - - input.focus(); - addAriaPressed = false; - } - } - - if (addAriaPressed) { - this._element.setAttribute('aria-pressed', !$$$1(this._element).hasClass(ClassName.ACTIVE)); - } - - if (triggerChangeEvent) { - $$$1(this._element).toggleClass(ClassName.ACTIVE); - } - }; - - _proto.dispose = function dispose() { - $$$1.removeData(this._element, DATA_KEY); - this._element = null; - }; // Static - - - Button._jQueryInterface = function _jQueryInterface(config) { - return this.each(function () { - var data = $$$1(this).data(DATA_KEY); - - if (!data) { - data = new Button(this); - $$$1(this).data(DATA_KEY, data); - } - - if (config === 'toggle') { - data[config](); - } - }); - }; - - _createClass(Button, null, [{ - key: "VERSION", - get: function get() { - return VERSION; - } - }]); - - return Button; - }(); - /** - * ------------------------------------------------------------------------ - * Data Api implementation - * ------------------------------------------------------------------------ - */ - - - $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) { - event.preventDefault(); - var button = event.target; - - if (!$$$1(button).hasClass(ClassName.BUTTON)) { - button = $$$1(button).closest(Selector.BUTTON); - } - - Button._jQueryInterface.call($$$1(button), 'toggle'); - }).on(Event.FOCUS_BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) { - var button = $$$1(event.target).closest(Selector.BUTTON)[0]; - $$$1(button).toggleClass(ClassName.FOCUS, /^focus(in)?$/.test(event.type)); - }); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - $$$1.fn[NAME] = Button._jQueryInterface; - $$$1.fn[NAME].Constructor = Button; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Button._jQueryInterface; - }; - - return Button; - }($); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): carousel.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Carousel = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'carousel'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.carousel'; - var EVENT_KEY = "." + DATA_KEY; - var DATA_API_KEY = '.data-api'; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key - - var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key - - var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch - - var Default = { - interval: 5000, - keyboard: true, - slide: false, - pause: 'hover', - wrap: true - }; - var DefaultType = { - interval: '(number|boolean)', - keyboard: 'boolean', - slide: '(boolean|string)', - pause: '(string|boolean)', - wrap: 'boolean' - }; - var Direction = { - NEXT: 'next', - PREV: 'prev', - LEFT: 'left', - RIGHT: 'right' - }; - var Event = { - SLIDE: "slide" + EVENT_KEY, - SLID: "slid" + EVENT_KEY, - KEYDOWN: "keydown" + EVENT_KEY, - MOUSEENTER: "mouseenter" + EVENT_KEY, - MOUSELEAVE: "mouseleave" + EVENT_KEY, - TOUCHEND: "touchend" + EVENT_KEY, - LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY, - CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY - }; - var ClassName = { - CAROUSEL: 'carousel', - ACTIVE: 'active', - SLIDE: 'slide', - RIGHT: 'carousel-item-right', - LEFT: 'carousel-item-left', - NEXT: 'carousel-item-next', - PREV: 'carousel-item-prev', - ITEM: 'carousel-item' - }; - var Selector = { - ACTIVE: '.active', - ACTIVE_ITEM: '.active.carousel-item', - ITEM: '.carousel-item', - NEXT_PREV: '.carousel-item-next, .carousel-item-prev', - INDICATORS: '.carousel-indicators', - DATA_SLIDE: '[data-slide], [data-slide-to]', - DATA_RIDE: '[data-ride="carousel"]' - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Carousel = - /*#__PURE__*/ - function () { - function Carousel(element, config) { - this._items = null; - this._interval = null; - this._activeElement = null; - this._isPaused = false; - this._isSliding = false; - this.touchTimeout = null; - this._config = this._getConfig(config); - this._element = $$$1(element)[0]; - this._indicatorsElement = $$$1(this._element).find(Selector.INDICATORS)[0]; - - this._addEventListeners(); - } // Getters - - - var _proto = Carousel.prototype; - - // Public - _proto.next = function next() { - if (!this._isSliding) { - this._slide(Direction.NEXT); - } - }; - - _proto.nextWhenVisible = function nextWhenVisible() { - // Don't call next when the page isn't visible - // or the carousel or its parent isn't visible - if (!document.hidden && $$$1(this._element).is(':visible') && $$$1(this._element).css('visibility') !== 'hidden') { - this.next(); - } - }; - - _proto.prev = function prev() { - if (!this._isSliding) { - this._slide(Direction.PREV); - } - }; - - _proto.pause = function pause(event) { - if (!event) { - this._isPaused = true; - } - - if ($$$1(this._element).find(Selector.NEXT_PREV)[0]) { - Util.triggerTransitionEnd(this._element); - this.cycle(true); - } - - clearInterval(this._interval); - this._interval = null; - }; - - _proto.cycle = function cycle(event) { - if (!event) { - this._isPaused = false; - } - - if (this._interval) { - clearInterval(this._interval); - this._interval = null; - } - - if (this._config.interval && !this._isPaused) { - this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval); - } - }; - - _proto.to = function to(index) { - var _this = this; - - this._activeElement = $$$1(this._element).find(Selector.ACTIVE_ITEM)[0]; - - var activeIndex = this._getItemIndex(this._activeElement); - - if (index > this._items.length - 1 || index < 0) { - return; - } - - if (this._isSliding) { - $$$1(this._element).one(Event.SLID, function () { - return _this.to(index); - }); - return; - } - - if (activeIndex === index) { - this.pause(); - this.cycle(); - return; - } - - var direction = index > activeIndex ? Direction.NEXT : Direction.PREV; - - this._slide(direction, this._items[index]); - }; - - _proto.dispose = function dispose() { - $$$1(this._element).off(EVENT_KEY); - $$$1.removeData(this._element, DATA_KEY); - this._items = null; - this._config = null; - this._element = null; - this._interval = null; - this._isPaused = null; - this._isSliding = null; - this._activeElement = null; - this._indicatorsElement = null; - }; // Private - - - _proto._getConfig = function _getConfig(config) { - config = _objectSpread({}, Default, config); - Util.typeCheckConfig(NAME, config, DefaultType); - return config; - }; - - _proto._addEventListeners = function _addEventListeners() { - var _this2 = this; - - if (this._config.keyboard) { - $$$1(this._element).on(Event.KEYDOWN, function (event) { - return _this2._keydown(event); - }); - } - - if (this._config.pause === 'hover') { - $$$1(this._element).on(Event.MOUSEENTER, function (event) { - return _this2.pause(event); - }).on(Event.MOUSELEAVE, function (event) { - return _this2.cycle(event); - }); - - if ('ontouchstart' in document.documentElement) { - // If it's a touch-enabled device, mouseenter/leave are fired as - // part of the mouse compatibility events on first tap - the carousel - // would stop cycling until user tapped out of it; - // here, we listen for touchend, explicitly pause the carousel - // (as if it's the second time we tap on it, mouseenter compat event - // is NOT fired) and after a timeout (to allow for mouse compatibility - // events to fire) we explicitly restart cycling - $$$1(this._element).on(Event.TOUCHEND, function () { - _this2.pause(); - - if (_this2.touchTimeout) { - clearTimeout(_this2.touchTimeout); - } - - _this2.touchTimeout = setTimeout(function (event) { - return _this2.cycle(event); - }, TOUCHEVENT_COMPAT_WAIT + _this2._config.interval); - }); - } - } - }; - - _proto._keydown = function _keydown(event) { - if (/input|textarea/i.test(event.target.tagName)) { - return; - } - - switch (event.which) { - case ARROW_LEFT_KEYCODE: - event.preventDefault(); - this.prev(); - break; - - case ARROW_RIGHT_KEYCODE: - event.preventDefault(); - this.next(); - break; - - default: - } - }; - - _proto._getItemIndex = function _getItemIndex(element) { - this._items = $$$1.makeArray($$$1(element).parent().find(Selector.ITEM)); - return this._items.indexOf(element); - }; - - _proto._getItemByDirection = function _getItemByDirection(direction, activeElement) { - var isNextDirection = direction === Direction.NEXT; - var isPrevDirection = direction === Direction.PREV; - - var activeIndex = this._getItemIndex(activeElement); - - var lastItemIndex = this._items.length - 1; - var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex; - - if (isGoingToWrap && !this._config.wrap) { - return activeElement; - } - - var delta = direction === Direction.PREV ? -1 : 1; - var itemIndex = (activeIndex + delta) % this._items.length; - return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex]; - }; - - _proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) { - var targetIndex = this._getItemIndex(relatedTarget); - - var fromIndex = this._getItemIndex($$$1(this._element).find(Selector.ACTIVE_ITEM)[0]); - - var slideEvent = $$$1.Event(Event.SLIDE, { - relatedTarget: relatedTarget, - direction: eventDirectionName, - from: fromIndex, - to: targetIndex - }); - $$$1(this._element).trigger(slideEvent); - return slideEvent; - }; - - _proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) { - if (this._indicatorsElement) { - $$$1(this._indicatorsElement).find(Selector.ACTIVE).removeClass(ClassName.ACTIVE); - - var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)]; - - if (nextIndicator) { - $$$1(nextIndicator).addClass(ClassName.ACTIVE); - } - } - }; - - _proto._slide = function _slide(direction, element) { - var _this3 = this; - - var activeElement = $$$1(this._element).find(Selector.ACTIVE_ITEM)[0]; - - var activeElementIndex = this._getItemIndex(activeElement); - - var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement); - - var nextElementIndex = this._getItemIndex(nextElement); - - var isCycling = Boolean(this._interval); - var directionalClassName; - var orderClassName; - var eventDirectionName; - - if (direction === Direction.NEXT) { - directionalClassName = ClassName.LEFT; - orderClassName = ClassName.NEXT; - eventDirectionName = Direction.LEFT; - } else { - directionalClassName = ClassName.RIGHT; - orderClassName = ClassName.PREV; - eventDirectionName = Direction.RIGHT; - } - - if (nextElement && $$$1(nextElement).hasClass(ClassName.ACTIVE)) { - this._isSliding = false; - return; - } - - var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName); - - if (slideEvent.isDefaultPrevented()) { - return; - } - - if (!activeElement || !nextElement) { - // Some weirdness is happening, so we bail - return; - } - - this._isSliding = true; - - if (isCycling) { - this.pause(); - } - - this._setActiveIndicatorElement(nextElement); - - var slidEvent = $$$1.Event(Event.SLID, { - relatedTarget: nextElement, - direction: eventDirectionName, - from: activeElementIndex, - to: nextElementIndex - }); - - if ($$$1(this._element).hasClass(ClassName.SLIDE)) { - $$$1(nextElement).addClass(orderClassName); - Util.reflow(nextElement); - $$$1(activeElement).addClass(directionalClassName); - $$$1(nextElement).addClass(directionalClassName); - var transitionDuration = Util.getTransitionDurationFromElement(activeElement); - $$$1(activeElement).one(Util.TRANSITION_END, function () { - $$$1(nextElement).removeClass(directionalClassName + " " + orderClassName).addClass(ClassName.ACTIVE); - $$$1(activeElement).removeClass(ClassName.ACTIVE + " " + orderClassName + " " + directionalClassName); - _this3._isSliding = false; - setTimeout(function () { - return $$$1(_this3._element).trigger(slidEvent); - }, 0); - }).emulateTransitionEnd(transitionDuration); - } else { - $$$1(activeElement).removeClass(ClassName.ACTIVE); - $$$1(nextElement).addClass(ClassName.ACTIVE); - this._isSliding = false; - $$$1(this._element).trigger(slidEvent); - } - - if (isCycling) { - this.cycle(); - } - }; // Static - - - Carousel._jQueryInterface = function _jQueryInterface(config) { - return this.each(function () { - var data = $$$1(this).data(DATA_KEY); - - var _config = _objectSpread({}, Default, $$$1(this).data()); - - if (typeof config === 'object') { - _config = _objectSpread({}, _config, config); - } - - var action = typeof config === 'string' ? config : _config.slide; - - if (!data) { - data = new Carousel(this, _config); - $$$1(this).data(DATA_KEY, data); - } - - if (typeof config === 'number') { - data.to(config); - } else if (typeof action === 'string') { - if (typeof data[action] === 'undefined') { - throw new TypeError("No method named \"" + action + "\""); - } - - data[action](); - } else if (_config.interval) { - data.pause(); - data.cycle(); - } - }); - }; - - Carousel._dataApiClickHandler = function _dataApiClickHandler(event) { - var selector = Util.getSelectorFromElement(this); - - if (!selector) { - return; - } - - var target = $$$1(selector)[0]; - - if (!target || !$$$1(target).hasClass(ClassName.CAROUSEL)) { - return; - } - - var config = _objectSpread({}, $$$1(target).data(), $$$1(this).data()); - - var slideIndex = this.getAttribute('data-slide-to'); - - if (slideIndex) { - config.interval = false; - } - - Carousel._jQueryInterface.call($$$1(target), config); - - if (slideIndex) { - $$$1(target).data(DATA_KEY).to(slideIndex); - } - - event.preventDefault(); - }; - - _createClass(Carousel, null, [{ - key: "VERSION", - get: function get() { - return VERSION; - } - }, { - key: "Default", - get: function get() { - return Default; - } - }]); - - return Carousel; - }(); - /** - * ------------------------------------------------------------------------ - * Data Api implementation - * ------------------------------------------------------------------------ - */ - - - $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler); - $$$1(window).on(Event.LOAD_DATA_API, function () { - $$$1(Selector.DATA_RIDE).each(function () { - var $carousel = $$$1(this); - - Carousel._jQueryInterface.call($carousel, $carousel.data()); - }); - }); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - $$$1.fn[NAME] = Carousel._jQueryInterface; - $$$1.fn[NAME].Constructor = Carousel; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Carousel._jQueryInterface; - }; - - return Carousel; - }($); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): collapse.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Collapse = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'collapse'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.collapse'; - var EVENT_KEY = "." + DATA_KEY; - var DATA_API_KEY = '.data-api'; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var Default = { - toggle: true, - parent: '' - }; - var DefaultType = { - toggle: 'boolean', - parent: '(string|element)' - }; - var Event = { - SHOW: "show" + EVENT_KEY, - SHOWN: "shown" + EVENT_KEY, - HIDE: "hide" + EVENT_KEY, - HIDDEN: "hidden" + EVENT_KEY, - CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY - }; - var ClassName = { - SHOW: 'show', - COLLAPSE: 'collapse', - COLLAPSING: 'collapsing', - COLLAPSED: 'collapsed' - }; - var Dimension = { - WIDTH: 'width', - HEIGHT: 'height' - }; - var Selector = { - ACTIVES: '.show, .collapsing', - DATA_TOGGLE: '[data-toggle="collapse"]' - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Collapse = - /*#__PURE__*/ - function () { - function Collapse(element, config) { - this._isTransitioning = false; - this._element = element; - this._config = this._getConfig(config); - this._triggerArray = $$$1.makeArray($$$1("[data-toggle=\"collapse\"][href=\"#" + element.id + "\"]," + ("[data-toggle=\"collapse\"][data-target=\"#" + element.id + "\"]"))); - var tabToggles = $$$1(Selector.DATA_TOGGLE); - - for (var i = 0; i < tabToggles.length; i++) { - var elem = tabToggles[i]; - var selector = Util.getSelectorFromElement(elem); - - if (selector !== null && $$$1(selector).filter(element).length > 0) { - this._selector = selector; - - this._triggerArray.push(elem); - } - } - - this._parent = this._config.parent ? this._getParent() : null; - - if (!this._config.parent) { - this._addAriaAndCollapsedClass(this._element, this._triggerArray); - } - - if (this._config.toggle) { - this.toggle(); - } - } // Getters - - - var _proto = Collapse.prototype; - - // Public - _proto.toggle = function toggle() { - if ($$$1(this._element).hasClass(ClassName.SHOW)) { - this.hide(); - } else { - this.show(); - } - }; - - _proto.show = function show() { - var _this = this; - - if (this._isTransitioning || $$$1(this._element).hasClass(ClassName.SHOW)) { - return; - } - - var actives; - var activesData; - - if (this._parent) { - actives = $$$1.makeArray($$$1(this._parent).find(Selector.ACTIVES).filter("[data-parent=\"" + this._config.parent + "\"]")); - - if (actives.length === 0) { - actives = null; - } - } - - if (actives) { - activesData = $$$1(actives).not(this._selector).data(DATA_KEY); - - if (activesData && activesData._isTransitioning) { - return; - } - } - - var startEvent = $$$1.Event(Event.SHOW); - $$$1(this._element).trigger(startEvent); - - if (startEvent.isDefaultPrevented()) { - return; - } - - if (actives) { - Collapse._jQueryInterface.call($$$1(actives).not(this._selector), 'hide'); - - if (!activesData) { - $$$1(actives).data(DATA_KEY, null); - } - } - - var dimension = this._getDimension(); - - $$$1(this._element).removeClass(ClassName.COLLAPSE).addClass(ClassName.COLLAPSING); - this._element.style[dimension] = 0; - - if (this._triggerArray.length > 0) { - $$$1(this._triggerArray).removeClass(ClassName.COLLAPSED).attr('aria-expanded', true); - } - - this.setTransitioning(true); - - var complete = function complete() { - $$$1(_this._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).addClass(ClassName.SHOW); - _this._element.style[dimension] = ''; - - _this.setTransitioning(false); - - $$$1(_this._element).trigger(Event.SHOWN); - }; - - var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1); - var scrollSize = "scroll" + capitalizedDimension; - var transitionDuration = Util.getTransitionDurationFromElement(this._element); - $$$1(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); - this._element.style[dimension] = this._element[scrollSize] + "px"; - }; - - _proto.hide = function hide() { - var _this2 = this; - - if (this._isTransitioning || !$$$1(this._element).hasClass(ClassName.SHOW)) { - return; - } - - var startEvent = $$$1.Event(Event.HIDE); - $$$1(this._element).trigger(startEvent); - - if (startEvent.isDefaultPrevented()) { - return; - } - - var dimension = this._getDimension(); - - this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + "px"; - Util.reflow(this._element); - $$$1(this._element).addClass(ClassName.COLLAPSING).removeClass(ClassName.COLLAPSE).removeClass(ClassName.SHOW); - - if (this._triggerArray.length > 0) { - for (var i = 0; i < this._triggerArray.length; i++) { - var trigger = this._triggerArray[i]; - var selector = Util.getSelectorFromElement(trigger); - - if (selector !== null) { - var $elem = $$$1(selector); - - if (!$elem.hasClass(ClassName.SHOW)) { - $$$1(trigger).addClass(ClassName.COLLAPSED).attr('aria-expanded', false); - } - } - } - } - - this.setTransitioning(true); - - var complete = function complete() { - _this2.setTransitioning(false); - - $$$1(_this2._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).trigger(Event.HIDDEN); - }; - - this._element.style[dimension] = ''; - var transitionDuration = Util.getTransitionDurationFromElement(this._element); - $$$1(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); - }; - - _proto.setTransitioning = function setTransitioning(isTransitioning) { - this._isTransitioning = isTransitioning; - }; - - _proto.dispose = function dispose() { - $$$1.removeData(this._element, DATA_KEY); - this._config = null; - this._parent = null; - this._element = null; - this._triggerArray = null; - this._isTransitioning = null; - }; // Private - - - _proto._getConfig = function _getConfig(config) { - config = _objectSpread({}, Default, config); - config.toggle = Boolean(config.toggle); // Coerce string values - - Util.typeCheckConfig(NAME, config, DefaultType); - return config; - }; - - _proto._getDimension = function _getDimension() { - var hasWidth = $$$1(this._element).hasClass(Dimension.WIDTH); - return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT; - }; - - _proto._getParent = function _getParent() { - var _this3 = this; - - var parent = null; - - if (Util.isElement(this._config.parent)) { - parent = this._config.parent; // It's a jQuery object - - if (typeof this._config.parent.jquery !== 'undefined') { - parent = this._config.parent[0]; - } - } else { - parent = $$$1(this._config.parent)[0]; - } - - var selector = "[data-toggle=\"collapse\"][data-parent=\"" + this._config.parent + "\"]"; - $$$1(parent).find(selector).each(function (i, element) { - _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]); - }); - return parent; - }; - - _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) { - if (element) { - var isOpen = $$$1(element).hasClass(ClassName.SHOW); - - if (triggerArray.length > 0) { - $$$1(triggerArray).toggleClass(ClassName.COLLAPSED, !isOpen).attr('aria-expanded', isOpen); - } - } - }; // Static - - - Collapse._getTargetFromElement = function _getTargetFromElement(element) { - var selector = Util.getSelectorFromElement(element); - return selector ? $$$1(selector)[0] : null; - }; - - Collapse._jQueryInterface = function _jQueryInterface(config) { - return this.each(function () { - var $this = $$$1(this); - var data = $this.data(DATA_KEY); - - var _config = _objectSpread({}, Default, $this.data(), typeof config === 'object' && config); - - if (!data && _config.toggle && /show|hide/.test(config)) { - _config.toggle = false; - } - - if (!data) { - data = new Collapse(this, _config); - $this.data(DATA_KEY, data); - } - - if (typeof config === 'string') { - if (typeof data[config] === 'undefined') { - throw new TypeError("No method named \"" + config + "\""); - } - - data[config](); - } - }); - }; - - _createClass(Collapse, null, [{ - key: "VERSION", - get: function get() { - return VERSION; - } - }, { - key: "Default", - get: function get() { - return Default; - } - }]); - - return Collapse; - }(); - /** - * ------------------------------------------------------------------------ - * Data Api implementation - * ------------------------------------------------------------------------ - */ - - - $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { - // preventDefault only for elements (which change the URL) not inside the collapsible element - if (event.currentTarget.tagName === 'A') { - event.preventDefault(); - } - - var $trigger = $$$1(this); - var selector = Util.getSelectorFromElement(this); - $$$1(selector).each(function () { - var $target = $$$1(this); - var data = $target.data(DATA_KEY); - var config = data ? 'toggle' : $trigger.data(); - - Collapse._jQueryInterface.call($target, config); - }); - }); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - $$$1.fn[NAME] = Collapse._jQueryInterface; - $$$1.fn[NAME].Constructor = Collapse; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Collapse._jQueryInterface; - }; - - return Collapse; - }($); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): dropdown.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Dropdown = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'dropdown'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.dropdown'; - var EVENT_KEY = "." + DATA_KEY; - var DATA_API_KEY = '.data-api'; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key - - var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key - - var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key - - var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key - - var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key - - var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse) - - var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + "|" + ARROW_DOWN_KEYCODE + "|" + ESCAPE_KEYCODE); - var Event = { - HIDE: "hide" + EVENT_KEY, - HIDDEN: "hidden" + EVENT_KEY, - SHOW: "show" + EVENT_KEY, - SHOWN: "shown" + EVENT_KEY, - CLICK: "click" + EVENT_KEY, - CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY, - KEYDOWN_DATA_API: "keydown" + EVENT_KEY + DATA_API_KEY, - KEYUP_DATA_API: "keyup" + EVENT_KEY + DATA_API_KEY - }; - var ClassName = { - DISABLED: 'disabled', - SHOW: 'show', - DROPUP: 'dropup', - DROPRIGHT: 'dropright', - DROPLEFT: 'dropleft', - MENURIGHT: 'dropdown-menu-right', - MENULEFT: 'dropdown-menu-left', - POSITION_STATIC: 'position-static' - }; - var Selector = { - DATA_TOGGLE: '[data-toggle="dropdown"]', - FORM_CHILD: '.dropdown form', - MENU: '.dropdown-menu', - NAVBAR_NAV: '.navbar-nav', - VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)' - }; - var AttachmentMap = { - TOP: 'top-start', - TOPEND: 'top-end', - BOTTOM: 'bottom-start', - BOTTOMEND: 'bottom-end', - RIGHT: 'right-start', - RIGHTEND: 'right-end', - LEFT: 'left-start', - LEFTEND: 'left-end' - }; - var Default = { - offset: 0, - flip: true, - boundary: 'scrollParent', - reference: 'toggle', - display: 'dynamic' - }; - var DefaultType = { - offset: '(number|string|function)', - flip: 'boolean', - boundary: '(string|element)', - reference: '(string|element)', - display: 'string' - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Dropdown = - /*#__PURE__*/ - function () { - function Dropdown(element, config) { - this._element = element; - this._popper = null; - this._config = this._getConfig(config); - this._menu = this._getMenuElement(); - this._inNavbar = this._detectNavbar(); - - this._addEventListeners(); - } // Getters - - - var _proto = Dropdown.prototype; - - // Public - _proto.toggle = function toggle() { - if (this._element.disabled || $$$1(this._element).hasClass(ClassName.DISABLED)) { - return; - } - - var parent = Dropdown._getParentFromElement(this._element); - - var isActive = $$$1(this._menu).hasClass(ClassName.SHOW); - - Dropdown._clearMenus(); - - if (isActive) { - return; - } - - var relatedTarget = { - relatedTarget: this._element - }; - var showEvent = $$$1.Event(Event.SHOW, relatedTarget); - $$$1(parent).trigger(showEvent); - - if (showEvent.isDefaultPrevented()) { - return; - } // Disable totally Popper.js for Dropdown in Navbar - - - if (!this._inNavbar) { - /** - * Check for Popper dependency - * Popper - https://popper.js.org - */ - if (typeof Popper === 'undefined') { - throw new TypeError('Bootstrap dropdown require Popper.js (https://popper.js.org)'); - } - - var referenceElement = this._element; - - if (this._config.reference === 'parent') { - referenceElement = parent; - } else if (Util.isElement(this._config.reference)) { - referenceElement = this._config.reference; // Check if it's jQuery element - - if (typeof this._config.reference.jquery !== 'undefined') { - referenceElement = this._config.reference[0]; - } - } // If boundary is not `scrollParent`, then set position to `static` - // to allow the menu to "escape" the scroll parent's boundaries - // https://github.com/twbs/bootstrap/issues/24251 - - - if (this._config.boundary !== 'scrollParent') { - $$$1(parent).addClass(ClassName.POSITION_STATIC); - } - - this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig()); - } // If this is a touch-enabled device we add extra - // empty mouseover listeners to the body's immediate children; - // only needed because of broken event delegation on iOS - // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html - - - if ('ontouchstart' in document.documentElement && $$$1(parent).closest(Selector.NAVBAR_NAV).length === 0) { - $$$1(document.body).children().on('mouseover', null, $$$1.noop); - } - - this._element.focus(); - - this._element.setAttribute('aria-expanded', true); - - $$$1(this._menu).toggleClass(ClassName.SHOW); - $$$1(parent).toggleClass(ClassName.SHOW).trigger($$$1.Event(Event.SHOWN, relatedTarget)); - }; - - _proto.dispose = function dispose() { - $$$1.removeData(this._element, DATA_KEY); - $$$1(this._element).off(EVENT_KEY); - this._element = null; - this._menu = null; - - if (this._popper !== null) { - this._popper.destroy(); - - this._popper = null; - } - }; - - _proto.update = function update() { - this._inNavbar = this._detectNavbar(); - - if (this._popper !== null) { - this._popper.scheduleUpdate(); - } - }; // Private - - - _proto._addEventListeners = function _addEventListeners() { - var _this = this; - - $$$1(this._element).on(Event.CLICK, function (event) { - event.preventDefault(); - event.stopPropagation(); - - _this.toggle(); - }); - }; - - _proto._getConfig = function _getConfig(config) { - config = _objectSpread({}, this.constructor.Default, $$$1(this._element).data(), config); - Util.typeCheckConfig(NAME, config, this.constructor.DefaultType); - return config; - }; - - _proto._getMenuElement = function _getMenuElement() { - if (!this._menu) { - var parent = Dropdown._getParentFromElement(this._element); - - this._menu = $$$1(parent).find(Selector.MENU)[0]; - } - - return this._menu; - }; - - _proto._getPlacement = function _getPlacement() { - var $parentDropdown = $$$1(this._element).parent(); - var placement = AttachmentMap.BOTTOM; // Handle dropup - - if ($parentDropdown.hasClass(ClassName.DROPUP)) { - placement = AttachmentMap.TOP; - - if ($$$1(this._menu).hasClass(ClassName.MENURIGHT)) { - placement = AttachmentMap.TOPEND; - } - } else if ($parentDropdown.hasClass(ClassName.DROPRIGHT)) { - placement = AttachmentMap.RIGHT; - } else if ($parentDropdown.hasClass(ClassName.DROPLEFT)) { - placement = AttachmentMap.LEFT; - } else if ($$$1(this._menu).hasClass(ClassName.MENURIGHT)) { - placement = AttachmentMap.BOTTOMEND; - } - - return placement; - }; - - _proto._detectNavbar = function _detectNavbar() { - return $$$1(this._element).closest('.navbar').length > 0; - }; - - _proto._getPopperConfig = function _getPopperConfig() { - var _this2 = this; - - var offsetConf = {}; - - if (typeof this._config.offset === 'function') { - offsetConf.fn = function (data) { - data.offsets = _objectSpread({}, data.offsets, _this2._config.offset(data.offsets) || {}); - return data; - }; - } else { - offsetConf.offset = this._config.offset; - } - - var popperConfig = { - placement: this._getPlacement(), - modifiers: { - offset: offsetConf, - flip: { - enabled: this._config.flip - }, - preventOverflow: { - boundariesElement: this._config.boundary - } - } // Disable Popper.js if we have a static display - - }; - - if (this._config.display === 'static') { - popperConfig.modifiers.applyStyle = { - enabled: false - }; - } - - return popperConfig; - }; // Static - - - Dropdown._jQueryInterface = function _jQueryInterface(config) { - return this.each(function () { - var data = $$$1(this).data(DATA_KEY); - - var _config = typeof config === 'object' ? config : null; - - if (!data) { - data = new Dropdown(this, _config); - $$$1(this).data(DATA_KEY, data); - } - - if (typeof config === 'string') { - if (typeof data[config] === 'undefined') { - throw new TypeError("No method named \"" + config + "\""); - } - - data[config](); - } - }); - }; - - Dropdown._clearMenus = function _clearMenus(event) { - if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) { - return; - } - - var toggles = $$$1.makeArray($$$1(Selector.DATA_TOGGLE)); - - for (var i = 0; i < toggles.length; i++) { - var parent = Dropdown._getParentFromElement(toggles[i]); - - var context = $$$1(toggles[i]).data(DATA_KEY); - var relatedTarget = { - relatedTarget: toggles[i] - }; - - if (!context) { - continue; - } - - var dropdownMenu = context._menu; - - if (!$$$1(parent).hasClass(ClassName.SHOW)) { - continue; - } - - if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $$$1.contains(parent, event.target)) { - continue; - } - - var hideEvent = $$$1.Event(Event.HIDE, relatedTarget); - $$$1(parent).trigger(hideEvent); - - if (hideEvent.isDefaultPrevented()) { - continue; - } // If this is a touch-enabled device we remove the extra - // empty mouseover listeners we added for iOS support - - - if ('ontouchstart' in document.documentElement) { - $$$1(document.body).children().off('mouseover', null, $$$1.noop); - } - - toggles[i].setAttribute('aria-expanded', 'false'); - $$$1(dropdownMenu).removeClass(ClassName.SHOW); - $$$1(parent).removeClass(ClassName.SHOW).trigger($$$1.Event(Event.HIDDEN, relatedTarget)); - } - }; - - Dropdown._getParentFromElement = function _getParentFromElement(element) { - var parent; - var selector = Util.getSelectorFromElement(element); - - if (selector) { - parent = $$$1(selector)[0]; - } - - return parent || element.parentNode; - }; // eslint-disable-next-line complexity - - - Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) { - // If not input/textarea: - // - And not a key in REGEXP_KEYDOWN => not a dropdown command - // If input/textarea: - // - If space key => not a dropdown command - // - If key is other than escape - // - If key is not up or down => not a dropdown command - // - If trigger inside the menu => not a dropdown command - if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $$$1(event.target).closest(Selector.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) { - return; - } - - event.preventDefault(); - event.stopPropagation(); - - if (this.disabled || $$$1(this).hasClass(ClassName.DISABLED)) { - return; - } - - var parent = Dropdown._getParentFromElement(this); - - var isActive = $$$1(parent).hasClass(ClassName.SHOW); - - if (!isActive && (event.which !== ESCAPE_KEYCODE || event.which !== SPACE_KEYCODE) || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) { - if (event.which === ESCAPE_KEYCODE) { - var toggle = $$$1(parent).find(Selector.DATA_TOGGLE)[0]; - $$$1(toggle).trigger('focus'); - } - - $$$1(this).trigger('click'); - return; - } - - var items = $$$1(parent).find(Selector.VISIBLE_ITEMS).get(); - - if (items.length === 0) { - return; - } - - var index = items.indexOf(event.target); - - if (event.which === ARROW_UP_KEYCODE && index > 0) { - // Up - index--; - } - - if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) { - // Down - index++; - } - - if (index < 0) { - index = 0; - } - - items[index].focus(); - }; - - _createClass(Dropdown, null, [{ - key: "VERSION", - get: function get() { - return VERSION; - } - }, { - key: "Default", - get: function get() { - return Default; - } - }, { - key: "DefaultType", - get: function get() { - return DefaultType; - } - }]); - - return Dropdown; - }(); - /** - * ------------------------------------------------------------------------ - * Data Api implementation - * ------------------------------------------------------------------------ - */ - - - $$$1(document).on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.MENU, Dropdown._dataApiKeydownHandler).on(Event.CLICK_DATA_API + " " + Event.KEYUP_DATA_API, Dropdown._clearMenus).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { - event.preventDefault(); - event.stopPropagation(); - - Dropdown._jQueryInterface.call($$$1(this), 'toggle'); - }).on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function (e) { - e.stopPropagation(); - }); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - $$$1.fn[NAME] = Dropdown._jQueryInterface; - $$$1.fn[NAME].Constructor = Dropdown; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Dropdown._jQueryInterface; - }; - - return Dropdown; - }($, Popper); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): modal.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Modal = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'modal'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.modal'; - var EVENT_KEY = "." + DATA_KEY; - var DATA_API_KEY = '.data-api'; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key - - var Default = { - backdrop: true, - keyboard: true, - focus: true, - show: true - }; - var DefaultType = { - backdrop: '(boolean|string)', - keyboard: 'boolean', - focus: 'boolean', - show: 'boolean' - }; - var Event = { - HIDE: "hide" + EVENT_KEY, - HIDDEN: "hidden" + EVENT_KEY, - SHOW: "show" + EVENT_KEY, - SHOWN: "shown" + EVENT_KEY, - FOCUSIN: "focusin" + EVENT_KEY, - RESIZE: "resize" + EVENT_KEY, - CLICK_DISMISS: "click.dismiss" + EVENT_KEY, - KEYDOWN_DISMISS: "keydown.dismiss" + EVENT_KEY, - MOUSEUP_DISMISS: "mouseup.dismiss" + EVENT_KEY, - MOUSEDOWN_DISMISS: "mousedown.dismiss" + EVENT_KEY, - CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY - }; - var ClassName = { - SCROLLBAR_MEASURER: 'modal-scrollbar-measure', - BACKDROP: 'modal-backdrop', - OPEN: 'modal-open', - FADE: 'fade', - SHOW: 'show' - }; - var Selector = { - DIALOG: '.modal-dialog', - DATA_TOGGLE: '[data-toggle="modal"]', - DATA_DISMISS: '[data-dismiss="modal"]', - FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top', - STICKY_CONTENT: '.sticky-top', - NAVBAR_TOGGLER: '.navbar-toggler' - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Modal = - /*#__PURE__*/ - function () { - function Modal(element, config) { - this._config = this._getConfig(config); - this._element = element; - this._dialog = $$$1(element).find(Selector.DIALOG)[0]; - this._backdrop = null; - this._isShown = false; - this._isBodyOverflowing = false; - this._ignoreBackdropClick = false; - this._scrollbarWidth = 0; - } // Getters - - - var _proto = Modal.prototype; - - // Public - _proto.toggle = function toggle(relatedTarget) { - return this._isShown ? this.hide() : this.show(relatedTarget); - }; - - _proto.show = function show(relatedTarget) { - var _this = this; - - if (this._isTransitioning || this._isShown) { - return; - } - - if ($$$1(this._element).hasClass(ClassName.FADE)) { - this._isTransitioning = true; - } - - var showEvent = $$$1.Event(Event.SHOW, { - relatedTarget: relatedTarget - }); - $$$1(this._element).trigger(showEvent); - - if (this._isShown || showEvent.isDefaultPrevented()) { - return; - } - - this._isShown = true; - - this._checkScrollbar(); - - this._setScrollbar(); - - this._adjustDialog(); - - $$$1(document.body).addClass(ClassName.OPEN); - - this._setEscapeEvent(); - - this._setResizeEvent(); - - $$$1(this._element).on(Event.CLICK_DISMISS, Selector.DATA_DISMISS, function (event) { - return _this.hide(event); - }); - $$$1(this._dialog).on(Event.MOUSEDOWN_DISMISS, function () { - $$$1(_this._element).one(Event.MOUSEUP_DISMISS, function (event) { - if ($$$1(event.target).is(_this._element)) { - _this._ignoreBackdropClick = true; - } - }); - }); - - this._showBackdrop(function () { - return _this._showElement(relatedTarget); - }); - }; - - _proto.hide = function hide(event) { - var _this2 = this; - - if (event) { - event.preventDefault(); - } - - if (this._isTransitioning || !this._isShown) { - return; - } - - var hideEvent = $$$1.Event(Event.HIDE); - $$$1(this._element).trigger(hideEvent); - - if (!this._isShown || hideEvent.isDefaultPrevented()) { - return; - } - - this._isShown = false; - var transition = $$$1(this._element).hasClass(ClassName.FADE); - - if (transition) { - this._isTransitioning = true; - } - - this._setEscapeEvent(); - - this._setResizeEvent(); - - $$$1(document).off(Event.FOCUSIN); - $$$1(this._element).removeClass(ClassName.SHOW); - $$$1(this._element).off(Event.CLICK_DISMISS); - $$$1(this._dialog).off(Event.MOUSEDOWN_DISMISS); - - if (transition) { - var transitionDuration = Util.getTransitionDurationFromElement(this._element); - $$$1(this._element).one(Util.TRANSITION_END, function (event) { - return _this2._hideModal(event); - }).emulateTransitionEnd(transitionDuration); - } else { - this._hideModal(); - } - }; - - _proto.dispose = function dispose() { - $$$1.removeData(this._element, DATA_KEY); - $$$1(window, document, this._element, this._backdrop).off(EVENT_KEY); - this._config = null; - this._element = null; - this._dialog = null; - this._backdrop = null; - this._isShown = null; - this._isBodyOverflowing = null; - this._ignoreBackdropClick = null; - this._scrollbarWidth = null; - }; - - _proto.handleUpdate = function handleUpdate() { - this._adjustDialog(); - }; // Private - - - _proto._getConfig = function _getConfig(config) { - config = _objectSpread({}, Default, config); - Util.typeCheckConfig(NAME, config, DefaultType); - return config; - }; - - _proto._showElement = function _showElement(relatedTarget) { - var _this3 = this; - - var transition = $$$1(this._element).hasClass(ClassName.FADE); - - if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { - // Don't move modal's DOM position - document.body.appendChild(this._element); - } - - this._element.style.display = 'block'; - - this._element.removeAttribute('aria-hidden'); - - this._element.scrollTop = 0; - - if (transition) { - Util.reflow(this._element); - } - - $$$1(this._element).addClass(ClassName.SHOW); - - if (this._config.focus) { - this._enforceFocus(); - } - - var shownEvent = $$$1.Event(Event.SHOWN, { - relatedTarget: relatedTarget - }); - - var transitionComplete = function transitionComplete() { - if (_this3._config.focus) { - _this3._element.focus(); - } - - _this3._isTransitioning = false; - $$$1(_this3._element).trigger(shownEvent); - }; - - if (transition) { - var transitionDuration = Util.getTransitionDurationFromElement(this._element); - $$$1(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(transitionDuration); - } else { - transitionComplete(); - } - }; - - _proto._enforceFocus = function _enforceFocus() { - var _this4 = this; - - $$$1(document).off(Event.FOCUSIN) // Guard against infinite focus loop - .on(Event.FOCUSIN, function (event) { - if (document !== event.target && _this4._element !== event.target && $$$1(_this4._element).has(event.target).length === 0) { - _this4._element.focus(); - } - }); - }; - - _proto._setEscapeEvent = function _setEscapeEvent() { - var _this5 = this; - - if (this._isShown && this._config.keyboard) { - $$$1(this._element).on(Event.KEYDOWN_DISMISS, function (event) { - if (event.which === ESCAPE_KEYCODE) { - event.preventDefault(); - - _this5.hide(); - } - }); - } else if (!this._isShown) { - $$$1(this._element).off(Event.KEYDOWN_DISMISS); - } - }; - - _proto._setResizeEvent = function _setResizeEvent() { - var _this6 = this; - - if (this._isShown) { - $$$1(window).on(Event.RESIZE, function (event) { - return _this6.handleUpdate(event); - }); - } else { - $$$1(window).off(Event.RESIZE); - } - }; - - _proto._hideModal = function _hideModal() { - var _this7 = this; - - this._element.style.display = 'none'; - - this._element.setAttribute('aria-hidden', true); - - this._isTransitioning = false; - - this._showBackdrop(function () { - $$$1(document.body).removeClass(ClassName.OPEN); - - _this7._resetAdjustments(); - - _this7._resetScrollbar(); - - $$$1(_this7._element).trigger(Event.HIDDEN); - }); - }; - - _proto._removeBackdrop = function _removeBackdrop() { - if (this._backdrop) { - $$$1(this._backdrop).remove(); - this._backdrop = null; - } - }; - - _proto._showBackdrop = function _showBackdrop(callback) { - var _this8 = this; - - var animate = $$$1(this._element).hasClass(ClassName.FADE) ? ClassName.FADE : ''; - - if (this._isShown && this._config.backdrop) { - this._backdrop = document.createElement('div'); - this._backdrop.className = ClassName.BACKDROP; - - if (animate) { - $$$1(this._backdrop).addClass(animate); - } - - $$$1(this._backdrop).appendTo(document.body); - $$$1(this._element).on(Event.CLICK_DISMISS, function (event) { - if (_this8._ignoreBackdropClick) { - _this8._ignoreBackdropClick = false; - return; - } - - if (event.target !== event.currentTarget) { - return; - } - - if (_this8._config.backdrop === 'static') { - _this8._element.focus(); - } else { - _this8.hide(); - } - }); - - if (animate) { - Util.reflow(this._backdrop); - } - - $$$1(this._backdrop).addClass(ClassName.SHOW); - - if (!callback) { - return; - } - - if (!animate) { - callback(); - return; - } - - var backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop); - $$$1(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(backdropTransitionDuration); - } else if (!this._isShown && this._backdrop) { - $$$1(this._backdrop).removeClass(ClassName.SHOW); - - var callbackRemove = function callbackRemove() { - _this8._removeBackdrop(); - - if (callback) { - callback(); - } - }; - - if ($$$1(this._element).hasClass(ClassName.FADE)) { - var _backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop); - - $$$1(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(_backdropTransitionDuration); - } else { - callbackRemove(); - } - } else if (callback) { - callback(); - } - }; // ---------------------------------------------------------------------- - // the following methods are used to handle overflowing modals - // todo (fat): these should probably be refactored out of modal.js - // ---------------------------------------------------------------------- - - - _proto._adjustDialog = function _adjustDialog() { - var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; - - if (!this._isBodyOverflowing && isModalOverflowing) { - this._element.style.paddingLeft = this._scrollbarWidth + "px"; - } - - if (this._isBodyOverflowing && !isModalOverflowing) { - this._element.style.paddingRight = this._scrollbarWidth + "px"; - } - }; - - _proto._resetAdjustments = function _resetAdjustments() { - this._element.style.paddingLeft = ''; - this._element.style.paddingRight = ''; - }; - - _proto._checkScrollbar = function _checkScrollbar() { - var rect = document.body.getBoundingClientRect(); - this._isBodyOverflowing = rect.left + rect.right < window.innerWidth; - this._scrollbarWidth = this._getScrollbarWidth(); - }; - - _proto._setScrollbar = function _setScrollbar() { - var _this9 = this; - - if (this._isBodyOverflowing) { - // Note: DOMNode.style.paddingRight returns the actual value or '' if not set - // while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set - // Adjust fixed content padding - $$$1(Selector.FIXED_CONTENT).each(function (index, element) { - var actualPadding = $$$1(element)[0].style.paddingRight; - var calculatedPadding = $$$1(element).css('padding-right'); - $$$1(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this9._scrollbarWidth + "px"); - }); // Adjust sticky content margin - - $$$1(Selector.STICKY_CONTENT).each(function (index, element) { - var actualMargin = $$$1(element)[0].style.marginRight; - var calculatedMargin = $$$1(element).css('margin-right'); - $$$1(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this9._scrollbarWidth + "px"); - }); // Adjust navbar-toggler margin - - $$$1(Selector.NAVBAR_TOGGLER).each(function (index, element) { - var actualMargin = $$$1(element)[0].style.marginRight; - var calculatedMargin = $$$1(element).css('margin-right'); - $$$1(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) + _this9._scrollbarWidth + "px"); - }); // Adjust body padding - - var actualPadding = document.body.style.paddingRight; - var calculatedPadding = $$$1(document.body).css('padding-right'); - $$$1(document.body).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + "px"); - } - }; - - _proto._resetScrollbar = function _resetScrollbar() { - // Restore fixed content padding - $$$1(Selector.FIXED_CONTENT).each(function (index, element) { - var padding = $$$1(element).data('padding-right'); - - if (typeof padding !== 'undefined') { - $$$1(element).css('padding-right', padding).removeData('padding-right'); - } - }); // Restore sticky content and navbar-toggler margin - - $$$1(Selector.STICKY_CONTENT + ", " + Selector.NAVBAR_TOGGLER).each(function (index, element) { - var margin = $$$1(element).data('margin-right'); - - if (typeof margin !== 'undefined') { - $$$1(element).css('margin-right', margin).removeData('margin-right'); - } - }); // Restore body padding - - var padding = $$$1(document.body).data('padding-right'); - - if (typeof padding !== 'undefined') { - $$$1(document.body).css('padding-right', padding).removeData('padding-right'); - } - }; - - _proto._getScrollbarWidth = function _getScrollbarWidth() { - // thx d.walsh - var scrollDiv = document.createElement('div'); - scrollDiv.className = ClassName.SCROLLBAR_MEASURER; - document.body.appendChild(scrollDiv); - var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth; - document.body.removeChild(scrollDiv); - return scrollbarWidth; - }; // Static - - - Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) { - return this.each(function () { - var data = $$$1(this).data(DATA_KEY); - - var _config = _objectSpread({}, Modal.Default, $$$1(this).data(), typeof config === 'object' && config); - - if (!data) { - data = new Modal(this, _config); - $$$1(this).data(DATA_KEY, data); - } - - if (typeof config === 'string') { - if (typeof data[config] === 'undefined') { - throw new TypeError("No method named \"" + config + "\""); - } - - data[config](relatedTarget); - } else if (_config.show) { - data.show(relatedTarget); - } - }); - }; - - _createClass(Modal, null, [{ - key: "VERSION", - get: function get() { - return VERSION; - } - }, { - key: "Default", - get: function get() { - return Default; - } - }]); - - return Modal; - }(); - /** - * ------------------------------------------------------------------------ - * Data Api implementation - * ------------------------------------------------------------------------ - */ - - - $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { - var _this10 = this; - - var target; - var selector = Util.getSelectorFromElement(this); - - if (selector) { - target = $$$1(selector)[0]; - } - - var config = $$$1(target).data(DATA_KEY) ? 'toggle' : _objectSpread({}, $$$1(target).data(), $$$1(this).data()); - - if (this.tagName === 'A' || this.tagName === 'AREA') { - event.preventDefault(); - } - - var $target = $$$1(target).one(Event.SHOW, function (showEvent) { - if (showEvent.isDefaultPrevented()) { - // Only register focus restorer if modal will actually get shown - return; - } - - $target.one(Event.HIDDEN, function () { - if ($$$1(_this10).is(':visible')) { - _this10.focus(); - } - }); - }); - - Modal._jQueryInterface.call($$$1(target), config, this); - }); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - $$$1.fn[NAME] = Modal._jQueryInterface; - $$$1.fn[NAME].Constructor = Modal; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Modal._jQueryInterface; - }; - - return Modal; - }($); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): tooltip.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Tooltip = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'tooltip'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.tooltip'; - var EVENT_KEY = "." + DATA_KEY; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var CLASS_PREFIX = 'bs-tooltip'; - var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g'); - var DefaultType = { - animation: 'boolean', - template: 'string', - title: '(string|element|function)', - trigger: 'string', - delay: '(number|object)', - html: 'boolean', - selector: '(string|boolean)', - placement: '(string|function)', - offset: '(number|string)', - container: '(string|element|boolean)', - fallbackPlacement: '(string|array)', - boundary: '(string|element)' - }; - var AttachmentMap = { - AUTO: 'auto', - TOP: 'top', - RIGHT: 'right', - BOTTOM: 'bottom', - LEFT: 'left' - }; - var Default = { - animation: true, - template: '', - trigger: 'hover focus', - title: '', - delay: 0, - html: false, - selector: false, - placement: 'top', - offset: 0, - container: false, - fallbackPlacement: 'flip', - boundary: 'scrollParent' - }; - var HoverState = { - SHOW: 'show', - OUT: 'out' - }; - var Event = { - HIDE: "hide" + EVENT_KEY, - HIDDEN: "hidden" + EVENT_KEY, - SHOW: "show" + EVENT_KEY, - SHOWN: "shown" + EVENT_KEY, - INSERTED: "inserted" + EVENT_KEY, - CLICK: "click" + EVENT_KEY, - FOCUSIN: "focusin" + EVENT_KEY, - FOCUSOUT: "focusout" + EVENT_KEY, - MOUSEENTER: "mouseenter" + EVENT_KEY, - MOUSELEAVE: "mouseleave" + EVENT_KEY - }; - var ClassName = { - FADE: 'fade', - SHOW: 'show' - }; - var Selector = { - TOOLTIP: '.tooltip', - TOOLTIP_INNER: '.tooltip-inner', - ARROW: '.arrow' - }; - var Trigger = { - HOVER: 'hover', - FOCUS: 'focus', - CLICK: 'click', - MANUAL: 'manual' - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Tooltip = - /*#__PURE__*/ - function () { - function Tooltip(element, config) { - /** - * Check for Popper dependency - * Popper - https://popper.js.org - */ - if (typeof Popper === 'undefined') { - throw new TypeError('Bootstrap tooltips require Popper.js (https://popper.js.org)'); - } // private - - - this._isEnabled = true; - this._timeout = 0; - this._hoverState = ''; - this._activeTrigger = {}; - this._popper = null; // Protected - - this.element = element; - this.config = this._getConfig(config); - this.tip = null; - - this._setListeners(); - } // Getters - - - var _proto = Tooltip.prototype; - - // Public - _proto.enable = function enable() { - this._isEnabled = true; - }; - - _proto.disable = function disable() { - this._isEnabled = false; - }; - - _proto.toggleEnabled = function toggleEnabled() { - this._isEnabled = !this._isEnabled; - }; - - _proto.toggle = function toggle(event) { - if (!this._isEnabled) { - return; - } - - if (event) { - var dataKey = this.constructor.DATA_KEY; - var context = $$$1(event.currentTarget).data(dataKey); - - if (!context) { - context = new this.constructor(event.currentTarget, this._getDelegateConfig()); - $$$1(event.currentTarget).data(dataKey, context); - } - - context._activeTrigger.click = !context._activeTrigger.click; - - if (context._isWithActiveTrigger()) { - context._enter(null, context); - } else { - context._leave(null, context); - } - } else { - if ($$$1(this.getTipElement()).hasClass(ClassName.SHOW)) { - this._leave(null, this); - - return; - } - - this._enter(null, this); - } - }; - - _proto.dispose = function dispose() { - clearTimeout(this._timeout); - $$$1.removeData(this.element, this.constructor.DATA_KEY); - $$$1(this.element).off(this.constructor.EVENT_KEY); - $$$1(this.element).closest('.modal').off('hide.bs.modal'); - - if (this.tip) { - $$$1(this.tip).remove(); - } - - this._isEnabled = null; - this._timeout = null; - this._hoverState = null; - this._activeTrigger = null; - - if (this._popper !== null) { - this._popper.destroy(); - } - - this._popper = null; - this.element = null; - this.config = null; - this.tip = null; - }; - - _proto.show = function show() { - var _this = this; - - if ($$$1(this.element).css('display') === 'none') { - throw new Error('Please use show on visible elements'); - } - - var showEvent = $$$1.Event(this.constructor.Event.SHOW); - - if (this.isWithContent() && this._isEnabled) { - $$$1(this.element).trigger(showEvent); - var isInTheDom = $$$1.contains(this.element.ownerDocument.documentElement, this.element); - - if (showEvent.isDefaultPrevented() || !isInTheDom) { - return; - } - - var tip = this.getTipElement(); - var tipId = Util.getUID(this.constructor.NAME); - tip.setAttribute('id', tipId); - this.element.setAttribute('aria-describedby', tipId); - this.setContent(); - - if (this.config.animation) { - $$$1(tip).addClass(ClassName.FADE); - } - - var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement; - - var attachment = this._getAttachment(placement); - - this.addAttachmentClass(attachment); - var container = this.config.container === false ? document.body : $$$1(this.config.container); - $$$1(tip).data(this.constructor.DATA_KEY, this); - - if (!$$$1.contains(this.element.ownerDocument.documentElement, this.tip)) { - $$$1(tip).appendTo(container); - } - - $$$1(this.element).trigger(this.constructor.Event.INSERTED); - this._popper = new Popper(this.element, tip, { - placement: attachment, - modifiers: { - offset: { - offset: this.config.offset - }, - flip: { - behavior: this.config.fallbackPlacement - }, - arrow: { - element: Selector.ARROW - }, - preventOverflow: { - boundariesElement: this.config.boundary - } - }, - onCreate: function onCreate(data) { - if (data.originalPlacement !== data.placement) { - _this._handlePopperPlacementChange(data); - } - }, - onUpdate: function onUpdate(data) { - _this._handlePopperPlacementChange(data); - } - }); - $$$1(tip).addClass(ClassName.SHOW); // If this is a touch-enabled device we add extra - // empty mouseover listeners to the body's immediate children; - // only needed because of broken event delegation on iOS - // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html - - if ('ontouchstart' in document.documentElement) { - $$$1(document.body).children().on('mouseover', null, $$$1.noop); - } - - var complete = function complete() { - if (_this.config.animation) { - _this._fixTransition(); - } - - var prevHoverState = _this._hoverState; - _this._hoverState = null; - $$$1(_this.element).trigger(_this.constructor.Event.SHOWN); - - if (prevHoverState === HoverState.OUT) { - _this._leave(null, _this); - } - }; - - if ($$$1(this.tip).hasClass(ClassName.FADE)) { - var transitionDuration = Util.getTransitionDurationFromElement(this.tip); - $$$1(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); - } else { - complete(); - } - } - }; - - _proto.hide = function hide(callback) { - var _this2 = this; - - var tip = this.getTipElement(); - var hideEvent = $$$1.Event(this.constructor.Event.HIDE); - - var complete = function complete() { - if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) { - tip.parentNode.removeChild(tip); - } - - _this2._cleanTipClass(); - - _this2.element.removeAttribute('aria-describedby'); - - $$$1(_this2.element).trigger(_this2.constructor.Event.HIDDEN); - - if (_this2._popper !== null) { - _this2._popper.destroy(); - } - - if (callback) { - callback(); - } - }; - - $$$1(this.element).trigger(hideEvent); - - if (hideEvent.isDefaultPrevented()) { - return; - } - - $$$1(tip).removeClass(ClassName.SHOW); // If this is a touch-enabled device we remove the extra - // empty mouseover listeners we added for iOS support - - if ('ontouchstart' in document.documentElement) { - $$$1(document.body).children().off('mouseover', null, $$$1.noop); - } - - this._activeTrigger[Trigger.CLICK] = false; - this._activeTrigger[Trigger.FOCUS] = false; - this._activeTrigger[Trigger.HOVER] = false; - - if ($$$1(this.tip).hasClass(ClassName.FADE)) { - var transitionDuration = Util.getTransitionDurationFromElement(tip); - $$$1(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); - } else { - complete(); - } - - this._hoverState = ''; - }; - - _proto.update = function update() { - if (this._popper !== null) { - this._popper.scheduleUpdate(); - } - }; // Protected - - - _proto.isWithContent = function isWithContent() { - return Boolean(this.getTitle()); - }; - - _proto.addAttachmentClass = function addAttachmentClass(attachment) { - $$$1(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment); - }; - - _proto.getTipElement = function getTipElement() { - this.tip = this.tip || $$$1(this.config.template)[0]; - return this.tip; - }; - - _proto.setContent = function setContent() { - var $tip = $$$1(this.getTipElement()); - this.setElementContent($tip.find(Selector.TOOLTIP_INNER), this.getTitle()); - $tip.removeClass(ClassName.FADE + " " + ClassName.SHOW); - }; - - _proto.setElementContent = function setElementContent($element, content) { - var html = this.config.html; - - if (typeof content === 'object' && (content.nodeType || content.jquery)) { - // Content is a DOM node or a jQuery - if (html) { - if (!$$$1(content).parent().is($element)) { - $element.empty().append(content); - } - } else { - $element.text($$$1(content).text()); - } - } else { - $element[html ? 'html' : 'text'](content); - } - }; - - _proto.getTitle = function getTitle() { - var title = this.element.getAttribute('data-original-title'); - - if (!title) { - title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title; - } - - return title; - }; // Private - - - _proto._getAttachment = function _getAttachment(placement) { - return AttachmentMap[placement.toUpperCase()]; - }; - - _proto._setListeners = function _setListeners() { - var _this3 = this; - - var triggers = this.config.trigger.split(' '); - triggers.forEach(function (trigger) { - if (trigger === 'click') { - $$$1(_this3.element).on(_this3.constructor.Event.CLICK, _this3.config.selector, function (event) { - return _this3.toggle(event); - }); - } else if (trigger !== Trigger.MANUAL) { - var eventIn = trigger === Trigger.HOVER ? _this3.constructor.Event.MOUSEENTER : _this3.constructor.Event.FOCUSIN; - var eventOut = trigger === Trigger.HOVER ? _this3.constructor.Event.MOUSELEAVE : _this3.constructor.Event.FOCUSOUT; - $$$1(_this3.element).on(eventIn, _this3.config.selector, function (event) { - return _this3._enter(event); - }).on(eventOut, _this3.config.selector, function (event) { - return _this3._leave(event); - }); - } - - $$$1(_this3.element).closest('.modal').on('hide.bs.modal', function () { - return _this3.hide(); - }); - }); - - if (this.config.selector) { - this.config = _objectSpread({}, this.config, { - trigger: 'manual', - selector: '' - }); - } else { - this._fixTitle(); - } - }; - - _proto._fixTitle = function _fixTitle() { - var titleType = typeof this.element.getAttribute('data-original-title'); - - if (this.element.getAttribute('title') || titleType !== 'string') { - this.element.setAttribute('data-original-title', this.element.getAttribute('title') || ''); - this.element.setAttribute('title', ''); - } - }; - - _proto._enter = function _enter(event, context) { - var dataKey = this.constructor.DATA_KEY; - context = context || $$$1(event.currentTarget).data(dataKey); - - if (!context) { - context = new this.constructor(event.currentTarget, this._getDelegateConfig()); - $$$1(event.currentTarget).data(dataKey, context); - } - - if (event) { - context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true; - } - - if ($$$1(context.getTipElement()).hasClass(ClassName.SHOW) || context._hoverState === HoverState.SHOW) { - context._hoverState = HoverState.SHOW; - return; - } - - clearTimeout(context._timeout); - context._hoverState = HoverState.SHOW; - - if (!context.config.delay || !context.config.delay.show) { - context.show(); - return; - } - - context._timeout = setTimeout(function () { - if (context._hoverState === HoverState.SHOW) { - context.show(); - } - }, context.config.delay.show); - }; - - _proto._leave = function _leave(event, context) { - var dataKey = this.constructor.DATA_KEY; - context = context || $$$1(event.currentTarget).data(dataKey); - - if (!context) { - context = new this.constructor(event.currentTarget, this._getDelegateConfig()); - $$$1(event.currentTarget).data(dataKey, context); - } - - if (event) { - context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false; - } - - if (context._isWithActiveTrigger()) { - return; - } - - clearTimeout(context._timeout); - context._hoverState = HoverState.OUT; - - if (!context.config.delay || !context.config.delay.hide) { - context.hide(); - return; - } - - context._timeout = setTimeout(function () { - if (context._hoverState === HoverState.OUT) { - context.hide(); - } - }, context.config.delay.hide); - }; - - _proto._isWithActiveTrigger = function _isWithActiveTrigger() { - for (var trigger in this._activeTrigger) { - if (this._activeTrigger[trigger]) { - return true; - } - } - - return false; - }; - - _proto._getConfig = function _getConfig(config) { - config = _objectSpread({}, this.constructor.Default, $$$1(this.element).data(), config); - - if (typeof config.delay === 'number') { - config.delay = { - show: config.delay, - hide: config.delay - }; - } - - if (typeof config.title === 'number') { - config.title = config.title.toString(); - } - - if (typeof config.content === 'number') { - config.content = config.content.toString(); - } - - Util.typeCheckConfig(NAME, config, this.constructor.DefaultType); - return config; - }; - - _proto._getDelegateConfig = function _getDelegateConfig() { - var config = {}; - - if (this.config) { - for (var key in this.config) { - if (this.constructor.Default[key] !== this.config[key]) { - config[key] = this.config[key]; - } - } - } - - return config; - }; - - _proto._cleanTipClass = function _cleanTipClass() { - var $tip = $$$1(this.getTipElement()); - var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX); - - if (tabClass !== null && tabClass.length > 0) { - $tip.removeClass(tabClass.join('')); - } - }; - - _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(data) { - this._cleanTipClass(); - - this.addAttachmentClass(this._getAttachment(data.placement)); - }; - - _proto._fixTransition = function _fixTransition() { - var tip = this.getTipElement(); - var initConfigAnimation = this.config.animation; - - if (tip.getAttribute('x-placement') !== null) { - return; - } - - $$$1(tip).removeClass(ClassName.FADE); - this.config.animation = false; - this.hide(); - this.show(); - this.config.animation = initConfigAnimation; - }; // Static - - - Tooltip._jQueryInterface = function _jQueryInterface(config) { - return this.each(function () { - var data = $$$1(this).data(DATA_KEY); - - var _config = typeof config === 'object' && config; - - if (!data && /dispose|hide/.test(config)) { - return; - } - - if (!data) { - data = new Tooltip(this, _config); - $$$1(this).data(DATA_KEY, data); - } - - if (typeof config === 'string') { - if (typeof data[config] === 'undefined') { - throw new TypeError("No method named \"" + config + "\""); - } - - data[config](); - } - }); - }; - - _createClass(Tooltip, null, [{ - key: "VERSION", - get: function get() { - return VERSION; - } - }, { - key: "Default", - get: function get() { - return Default; - } - }, { - key: "NAME", - get: function get() { - return NAME; - } - }, { - key: "DATA_KEY", - get: function get() { - return DATA_KEY; - } - }, { - key: "Event", - get: function get() { - return Event; - } - }, { - key: "EVENT_KEY", - get: function get() { - return EVENT_KEY; - } - }, { - key: "DefaultType", - get: function get() { - return DefaultType; - } - }]); - - return Tooltip; - }(); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - - $$$1.fn[NAME] = Tooltip._jQueryInterface; - $$$1.fn[NAME].Constructor = Tooltip; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Tooltip._jQueryInterface; - }; - - return Tooltip; - }($, Popper); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): popover.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var Popover = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'popover'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.popover'; - var EVENT_KEY = "." + DATA_KEY; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var CLASS_PREFIX = 'bs-popover'; - var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g'); - - var Default = _objectSpread({}, Tooltip.Default, { - placement: 'right', - trigger: 'click', - content: '', - template: '' - }); - - var DefaultType = _objectSpread({}, Tooltip.DefaultType, { - content: '(string|element|function)' - }); - - var ClassName = { - FADE: 'fade', - SHOW: 'show' - }; - var Selector = { - TITLE: '.popover-header', - CONTENT: '.popover-body' - }; - var Event = { - HIDE: "hide" + EVENT_KEY, - HIDDEN: "hidden" + EVENT_KEY, - SHOW: "show" + EVENT_KEY, - SHOWN: "shown" + EVENT_KEY, - INSERTED: "inserted" + EVENT_KEY, - CLICK: "click" + EVENT_KEY, - FOCUSIN: "focusin" + EVENT_KEY, - FOCUSOUT: "focusout" + EVENT_KEY, - MOUSEENTER: "mouseenter" + EVENT_KEY, - MOUSELEAVE: "mouseleave" + EVENT_KEY - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var Popover = - /*#__PURE__*/ - function (_Tooltip) { - _inheritsLoose(Popover, _Tooltip); - - function Popover() { - return _Tooltip.apply(this, arguments) || this; - } - - var _proto = Popover.prototype; - - // Overrides - _proto.isWithContent = function isWithContent() { - return this.getTitle() || this._getContent(); - }; - - _proto.addAttachmentClass = function addAttachmentClass(attachment) { - $$$1(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment); - }; - - _proto.getTipElement = function getTipElement() { - this.tip = this.tip || $$$1(this.config.template)[0]; - return this.tip; - }; - - _proto.setContent = function setContent() { - var $tip = $$$1(this.getTipElement()); // We use append for html objects to maintain js events - - this.setElementContent($tip.find(Selector.TITLE), this.getTitle()); - - var content = this._getContent(); - - if (typeof content === 'function') { - content = content.call(this.element); - } - - this.setElementContent($tip.find(Selector.CONTENT), content); - $tip.removeClass(ClassName.FADE + " " + ClassName.SHOW); - }; // Private - - - _proto._getContent = function _getContent() { - return this.element.getAttribute('data-content') || this.config.content; - }; - - _proto._cleanTipClass = function _cleanTipClass() { - var $tip = $$$1(this.getTipElement()); - var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX); - - if (tabClass !== null && tabClass.length > 0) { - $tip.removeClass(tabClass.join('')); - } - }; // Static - - - Popover._jQueryInterface = function _jQueryInterface(config) { - return this.each(function () { - var data = $$$1(this).data(DATA_KEY); - - var _config = typeof config === 'object' ? config : null; - - if (!data && /destroy|hide/.test(config)) { - return; - } - - if (!data) { - data = new Popover(this, _config); - $$$1(this).data(DATA_KEY, data); - } - - if (typeof config === 'string') { - if (typeof data[config] === 'undefined') { - throw new TypeError("No method named \"" + config + "\""); - } - - data[config](); - } - }); - }; - - _createClass(Popover, null, [{ - key: "VERSION", - // Getters - get: function get() { - return VERSION; - } - }, { - key: "Default", - get: function get() { - return Default; - } - }, { - key: "NAME", - get: function get() { - return NAME; - } - }, { - key: "DATA_KEY", - get: function get() { - return DATA_KEY; - } - }, { - key: "Event", - get: function get() { - return Event; - } - }, { - key: "EVENT_KEY", - get: function get() { - return EVENT_KEY; - } - }, { - key: "DefaultType", - get: function get() { - return DefaultType; - } - }]); - - return Popover; - }(Tooltip); - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - - $$$1.fn[NAME] = Popover._jQueryInterface; - $$$1.fn[NAME].Constructor = Popover; - - $$$1.fn[NAME].noConflict = function () { - $$$1.fn[NAME] = JQUERY_NO_CONFLICT; - return Popover._jQueryInterface; - }; - - return Popover; - }($); - - /** - * -------------------------------------------------------------------------- - * Bootstrap (v4.1.0): scrollspy.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - - var ScrollSpy = function ($$$1) { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - var NAME = 'scrollspy'; - var VERSION = '4.1.0'; - var DATA_KEY = 'bs.scrollspy'; - var EVENT_KEY = "." + DATA_KEY; - var DATA_API_KEY = '.data-api'; - var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; - var Default = { - offset: 10, - method: 'auto', - target: '' - }; - var DefaultType = { - offset: 'number', - method: 'string', - target: '(string|element)' - }; - var Event = { - ACTIVATE: "activate" + EVENT_KEY, - SCROLL: "scroll" + EVENT_KEY, - LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY - }; - var ClassName = { - DROPDOWN_ITEM: 'dropdown-item', - DROPDOWN_MENU: 'dropdown-menu', - ACTIVE: 'active' - }; - var Selector = { - DATA_SPY: '[data-spy="scroll"]', - ACTIVE: '.active', - NAV_LIST_GROUP: '.nav, .list-group', - NAV_LINKS: '.nav-link', - NAV_ITEMS: '.nav-item', - LIST_ITEMS: '.list-group-item', - DROPDOWN: '.dropdown', - DROPDOWN_ITEMS: '.dropdown-item', - DROPDOWN_TOGGLE: '.dropdown-toggle' - }; - var OffsetMethod = { - OFFSET: 'offset', - POSITION: 'position' - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ - - }; - - var ScrollSpy = - /*#__PURE__*/ - function () { - function ScrollSpy(element, config) { - var _this = this; - - this._element = element; - this._scrollElement = element.tagName === 'BODY' ? window : element; - this._config = this._getConfig(config); - this._selector = this._config.target + " " + Selector.NAV_LINKS + "," + (this._config.target + " " + Selector.LIST_ITEMS + ",") + (this._config.target + " " + Selector.DROPDOWN_ITEMS); - this._offsets = []; - this._targets = []; - this._activeTarget = null; - this._scrollHeight = 0; - $$$1(this._scrollElement).on(Event.SCROLL, function (event) { - return _this._process(event); - }); - this.refresh(); - - this._process(); - } // Getters - - - var _proto = ScrollSpy.prototype; - - // Public - _proto.refresh = function refresh() { - var _this2 = this; - - var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION; - var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method; - var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0; - this._offsets = []; - this._targets = []; - this._scrollHeight = this._getScrollHeight(); - var targets = $$$1.makeArray($$$1(this._selector)); - targets.map(function (element) { - var target; - var targetSelector = Util.getSelectorFromElement(element); - - if (targetSelector) { - target = $$$1(targetSelector)[0]; - } - - if (target) { - var targetBCR = target.getBoundingClientRect(); - - if (targetBCR.width || targetBCR.height) { - // TODO (fat): remove sketch reliance on jQuery position/offset - return [$$$1(target)[offsetMethod]().top + offsetBase, targetSelector]; - } - } - - return null; - }).filter(function (item) { - return item; - }).sort(function (a, b) { - return a[0] - b[0]; - }).forEach(function (item) { - _this2._offsets.push(item[0]); - - _this2._targets.push(item[1]); - }); - }; - - _proto.dispose = function dispose() { - $$$1.removeData(this._element, DATA_KEY); - $$$1(this._scrollElement).off(EVENT_KEY); - this._element = null; - this._scrollElement = null; - this._config = null; - this._selector = null; - this._offsets = null; - this._targets = null; - this._activeTarget = null; - this._scrollHeight = null; - }; // Private - - - _proto._getConfig = function _getConfig(config) { - config = _objectSpread({}, Default, config); - - if (typeof config.target !== 'string') { - var id = $$$1(config.target).attr('id'); - - if (!id) { - id = Util.getUID(NAME); - $$$1(config.target).attr('id', id); - } - - config.target = "#" + id; - } - - Util.typeCheckConfig(NAME, config, DefaultType); - return config; - }; - - _proto._getScrollTop = function _getScrollTop() { - return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop; - }; - - _proto._getScrollHeight = function _getScrollHeight() { - return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight); - }; - - _proto._getOffsetHeight = function _getOffsetHeight() { - return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height; - }; - - _proto._process = function _process() { - var scrollTop = this._getScrollTop() + this._config.offset; - - var scrollHeight = this._getScrollHeight(); - - var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight(); - - if (this._scrollHeight !== scrollHeight) { - this.refresh(); - } - - if (scrollTop >= maxScroll) { - var target = this._targets[this._targets.length - 1]; - - if (this._activeTarget !== target) { - this._activate(target); - } - - return; - } - - if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) { - this._activeTarget = null; - - this._clear(); - - return; - } - - for (var i = this._offsets.length; i--;) { - var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]); - - if (isActiveTarget) { - this._activate(this._targets[i]); - } - } - }; - - _proto._activate = function _activate(target) { - this._activeTarget = target; - - this._clear(); - - var queries = this._selector.split(','); // eslint-disable-next-line arrow-body-style - - - queries = queries.map(function (selector) { - return selector + "[data-target=\"" + target + "\"]," + (selector + "[href=\"" + target + "\"]"); - }); - var $link = $$$1(queries.join(',')); - - if ($link.hasClass(ClassName.DROPDOWN_ITEM)) { - $link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE); - $link.addClass(ClassName.ACTIVE); - } else { - // Set triggered link as active - $link.addClass(ClassName.ACTIVE); // Set triggered links parents as active - // With both
      and