diff --git a/CHANGELOG.md b/CHANGELOG.md index e19f64f01..24489165c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,19 @@ +# v1.1.0 +## XX/XX/2016 + +1. [](#new) + * +1. [](#improved) + * Now supporting hostnames with localhost environments for better vhost support/development +1. [](#bugfix) + * + # v1.0.10 ## 02/11/2016 1. [](#new) * Added new `Page::contentMeta()` mechanism to store content-level meta data alongside content - * Added Japanese language translation + * Added Japanese language translation 1. [](#improved) * Updated some vendor libraries 1. [](#bugfix) @@ -18,7 +28,7 @@ * New **page-level SSL** functionality when using `absolute_urls` * Added `reverse_proxy` config option for issues with non-standard ports * Added `proxy_url` config option to support GPM behind proxy servers #639 - * New `Pages::parentsRawRoutes()` method + * New `Pages::parentsRawRoutes()` method * Enhanced `bin/gpm info` CLI command with Changelog support #559 * Ability to add empty *Folder* via admin plugin * Added latest `jQuery 2.2.0` library to core diff --git a/bin/grav b/bin/grav index 7c44efd2e..550767f9d 100755 --- a/bin/grav +++ b/bin/grav @@ -32,15 +32,17 @@ if (!file_exists(ROOT_DIR . 'index.php')) { exit('FATAL: Must be run from ROOT directory of Grav!'); } -$app = new Application('Grav CLI Application', '0.1.0'); +$app = new Application('Grav CLI Application', GRAV_VERSION); $app->addCommands(array( - new Grav\Console\Cli\InstallCommand(), - new Grav\Console\Cli\ComposerCommand(), - new Grav\Console\Cli\SandboxCommand(), - new Grav\Console\Cli\CleanCommand(), - new Grav\Console\Cli\ClearCacheCommand(), - new Grav\Console\Cli\BackupCommand(), - new Grav\Console\Cli\NewProjectCommand(), - new Grav\Console\Cli\NewUserCommand(), + new \Grav\Console\Cli\InstallCommand(), + new \Grav\Console\Cli\ComposerCommand(), + new \Grav\Console\Cli\SandboxCommand(), + new \Grav\Console\Cli\CleanCommand(), + new \Grav\Console\Cli\ClearCacheCommand(), + new \Grav\Console\Cli\BackupCommand(), + new \Grav\Console\Cli\NewProjectCommand(), + new \Grav\Console\Cli\NewUserCommand(), + new \Grav\Console\Cli\DevTools\NewPluginCommand(), + new \Grav\Console\Cli\DevTools\NewThemeCommand(), )); $app->run(); diff --git a/composer.json b/composer.json index 016c37c95..5730daa5a 100644 --- a/composer.json +++ b/composer.json @@ -26,10 +26,12 @@ "maximebf/debugbar": "~1.10", "ext-mbstring": "*", "ext-openssl": "*", - "ext-curl": "*" + "ext-curl": "*", + "twig/extensions": "^1.3" }, "require-dev": { "codeception/codeception": "^2.1", + "phpunit/php-code-coverage": "~2.0", "fzaninotto/faker": "^1.5" }, "autoload": { diff --git a/composer.lock b/composer.lock index bcf3ef2c9..221d490f4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "dafb943040964731630ab4992b1ea540", - "content-hash": "93e9fc9ecc82e91296f8a21aa9756123", + "hash": "ff44cbc35ded0b6491ab74b32f62cd9f", + "content-hash": "5d8b4ff937850c8b1cd333f5855369a6", "packages": [ { "name": "doctrine/cache", @@ -216,16 +216,16 @@ }, { "name": "filp/whoops", - "version": "2.0.0", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "a327942c50cbd62b25c6fbe08f173031ce25fbff" + "reference": "d13505b240a6f580bc75ba591da30299d6cb0eec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/a327942c50cbd62b25c6fbe08f173031ce25fbff", - "reference": "a327942c50cbd62b25c6fbe08f173031ce25fbff", + "url": "https://api.github.com/repos/filp/whoops/zipball/d13505b240a6f580bc75ba591da30299d6cb0eec", + "reference": "d13505b240a6f580bc75ba591da30299d6cb0eec", "shasum": "" }, "require": { @@ -233,7 +233,8 @@ }, "require-dev": { "mockery/mockery": "0.9.*", - "phpunit/phpunit": "^4.8 || ^5.0" + "phpunit/phpunit": "^4.8 || ^5.0", + "symfony/var-dumper": "~3.0" }, "suggest": { "symfony/var-dumper": "Pretty print complex values better with var-dumper available", @@ -271,7 +272,7 @@ "whoops", "zf2" ], - "time": "2016-01-06 17:51:21" + "time": "2016-04-07 06:16:25" }, { "name": "gregwar/cache", @@ -427,16 +428,16 @@ }, { "name": "monolog/monolog", - "version": "1.18.0", + "version": "1.18.2", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "e19b764b5c855580e8ffa7e615f72c10fd2f99cc" + "reference": "064b38c16790249488e7a8b987acf1c9d7383c09" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/e19b764b5c855580e8ffa7e615f72c10fd2f99cc", - "reference": "e19b764b5c855580e8ffa7e615f72c10fd2f99cc", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/064b38c16790249488e7a8b987acf1c9d7383c09", + "reference": "064b38c16790249488e7a8b987acf1c9d7383c09", "shasum": "" }, "require": { @@ -451,13 +452,13 @@ "doctrine/couchdb": "~1.0@dev", "graylog2/gelf-php": "~1.0", "jakub-onderka/php-parallel-lint": "0.9", + "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", "phpunit/phpunit": "~4.5", "phpunit/phpunit-mock-objects": "2.3.0", "raven/raven": "^0.13", "ruflin/elastica": ">=0.90 <3.0", - "swiftmailer/swiftmailer": "~5.3", - "videlalvaro/php-amqplib": "~2.4" + "swiftmailer/swiftmailer": "~5.3" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", @@ -466,11 +467,11 @@ "ext-mongo": "Allow sending log messages to a MongoDB server", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", "php-console/php-console": "Allow sending log messages to Google Chrome", "raven/raven": "Allow sending log messages to a Sentry server", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib" + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, "type": "library", "extra": { @@ -501,20 +502,20 @@ "logging", "psr-3" ], - "time": "2016-03-01 18:00:40" + "time": "2016-04-02 13:12:58" }, { "name": "mrclay/minify", - "version": "2.2.1", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/mrclay/minify.git", - "reference": "3c11ba8232a2155a1a29552aafc528be5fb0a662" + "reference": "f4cb31135d288f951bb0af1f23a03d4c00ba9446" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mrclay/minify/zipball/3c11ba8232a2155a1a29552aafc528be5fb0a662", - "reference": "3c11ba8232a2155a1a29552aafc528be5fb0a662", + "url": "https://api.github.com/repos/mrclay/minify/zipball/f4cb31135d288f951bb0af1f23a03d4c00ba9446", + "reference": "f4cb31135d288f951bb0af1f23a03d4c00ba9446", "shasum": "" }, "require": { @@ -546,7 +547,7 @@ ], "description": "Minify is a PHP5 app that helps you follow several rules for client-side performance. It combines multiple CSS or Javascript files, removes unnecessary whitespace and comments, and serves them with gzip encoding and optimal client-side cache headers", "homepage": "http://code.google.com/p/minify/", - "time": "2014-10-30 22:58:02" + "time": "2016-03-08 11:49:57" }, { "name": "pimple/pimple", @@ -638,12 +639,12 @@ "source": { "type": "git", "url": "https://github.com/rockettheme/toolbox.git", - "reference": "bb8902cf4ec25ece14d89efc743f3732244e18a8" + "reference": "c1da8d97b11e5a341d085bdbc83ca1b6721477a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rockettheme/toolbox/zipball/bb8902cf4ec25ece14d89efc743f3732244e18a8", - "reference": "bb8902cf4ec25ece14d89efc743f3732244e18a8", + "url": "https://api.github.com/repos/rockettheme/toolbox/zipball/c1da8d97b11e5a341d085bdbc83ca1b6721477a5", + "reference": "c1da8d97b11e5a341d085bdbc83ca1b6721477a5", "shasum": "" }, "require": { @@ -678,20 +679,20 @@ "php", "rockettheme" ], - "time": "2016-03-15 12:06:40" + "time": "2016-03-21 06:47:31" }, { "name": "symfony/console", - "version": "v2.8.3", + "version": "v2.8.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "56cc5caf051189720b8de974e4746090aaa10d44" + "reference": "9a5aef5fc0d4eff86853d44202b02be8d5a20154" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/56cc5caf051189720b8de974e4746090aaa10d44", - "reference": "56cc5caf051189720b8de974e4746090aaa10d44", + "url": "https://api.github.com/repos/symfony/console/zipball/9a5aef5fc0d4eff86853d44202b02be8d5a20154", + "reference": "9a5aef5fc0d4eff86853d44202b02be8d5a20154", "shasum": "" }, "require": { @@ -738,20 +739,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-02-28 16:20:50" + "time": "2016-03-17 09:19:04" }, { "name": "symfony/event-dispatcher", - "version": "v2.8.3", + "version": "v2.8.4", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "78c468665c9568c3faaa9c416a7134308f2d85c3" + "reference": "47d2d8cade9b1c3987573d2943bb9352536cdb87" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/78c468665c9568c3faaa9c416a7134308f2d85c3", - "reference": "78c468665c9568c3faaa9c416a7134308f2d85c3", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/47d2d8cade9b1c3987573d2943bb9352536cdb87", + "reference": "47d2d8cade9b1c3987573d2943bb9352536cdb87", "shasum": "" }, "require": { @@ -798,7 +799,7 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2016-01-27 05:14:19" + "time": "2016-03-07 14:04:32" }, { "name": "symfony/polyfill-iconv", @@ -920,16 +921,16 @@ }, { "name": "symfony/var-dumper", - "version": "v2.8.3", + "version": "v2.8.4", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "19b697abe08833ddf38c3ab0cb1bfad236b13bde" + "reference": "1f840df081f59cbe25140742bbe94a0dfac0222a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/19b697abe08833ddf38c3ab0cb1bfad236b13bde", - "reference": "19b697abe08833ddf38c3ab0cb1bfad236b13bde", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1f840df081f59cbe25140742bbe94a0dfac0222a", + "reference": "1f840df081f59cbe25140742bbe94a0dfac0222a", "shasum": "" }, "require": { @@ -979,20 +980,20 @@ "debug", "dump" ], - "time": "2016-02-13 09:21:29" + "time": "2016-03-07 14:04:32" }, { "name": "symfony/yaml", - "version": "v2.8.3", + "version": "v2.8.4", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "2a4ee40acb880c56f29fb1b8886e7ffe94f3b995" + "reference": "584e52cb8f788a887553ba82db6caacb1d6260bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/2a4ee40acb880c56f29fb1b8886e7ffe94f3b995", - "reference": "2a4ee40acb880c56f29fb1b8886e7ffe94f3b995", + "url": "https://api.github.com/repos/symfony/yaml/zipball/584e52cb8f788a887553ba82db6caacb1d6260bb", + "reference": "584e52cb8f788a887553ba82db6caacb1d6260bb", "shasum": "" }, "require": { @@ -1028,7 +1029,59 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-02-23 07:41:20" + "time": "2016-03-04 07:54:35" + }, + { + "name": "twig/extensions", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig-extensions.git", + "reference": "449e3c8a9ffad7c2479c7864557275a32b037499" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig-extensions/zipball/449e3c8a9ffad7c2479c7864557275a32b037499", + "reference": "449e3c8a9ffad7c2479c7864557275a32b037499", + "shasum": "" + }, + "require": { + "twig/twig": "~1.20|~2.0" + }, + "require-dev": { + "symfony/translation": "~2.3" + }, + "suggest": { + "symfony/translation": "Allow the time_diff output to be translated" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-0": { + "Twig_Extensions_": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Common additional features for Twig that do not directly belong in core", + "homepage": "http://twig.sensiolabs.org/doc/extensions/index.html", + "keywords": [ + "i18n", + "text" + ], + "time": "2015-08-22 16:38:35" }, { "name": "twig/twig", @@ -1095,41 +1148,42 @@ "packages-dev": [ { "name": "codeception/codeception", - "version": "2.1.6", + "version": "2.1.7", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "b199941f5e59d1e7fd32d78296c8ab98db873d89" + "reference": "65971b0dee4972710365b6102154cd412a9bf7b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/b199941f5e59d1e7fd32d78296c8ab98db873d89", - "reference": "b199941f5e59d1e7fd32d78296c8ab98db873d89", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/65971b0dee4972710365b6102154cd412a9bf7b1", + "reference": "65971b0dee4972710365b6102154cd412a9bf7b1", "shasum": "" }, "require": { "ext-json": "*", "ext-mbstring": "*", - "facebook/webdriver": ">=1.0.1", + "facebook/webdriver": ">=1.0.1 <2.0", "guzzlehttp/guzzle": ">=4.1.4 <7.0", "guzzlehttp/psr7": "~1.0", - "php": ">=5.4.0", - "phpunit/phpunit": "~4.8.0", - "symfony/browser-kit": ">=2.4|<3.1", - "symfony/console": ">=2.4|<3.1", - "symfony/css-selector": ">=2.4|<3.1", - "symfony/dom-crawler": ">=2.4|<3.1", - "symfony/event-dispatcher": ">=2.4|<3.1", - "symfony/finder": ">=2.4|<3.1", - "symfony/yaml": ">=2.4|<3.1" + "php": ">=5.4.0 <8.0", + "phpunit/php-code-coverage": ">=2.1.3", + "phpunit/phpunit": ">4.8.20 <6.0", + "symfony/browser-kit": ">=2.5 <3.1", + "symfony/console": ">=2.5 <3.1", + "symfony/css-selector": ">=2.5 <3.1", + "symfony/dom-crawler": ">=2.5 <3.1", + "symfony/event-dispatcher": ">=2.5 <3.1", + "symfony/finder": ">=2.5 <3.1", + "symfony/yaml": ">=2.5 <3.1" }, "require-dev": { "codeception/specify": "~0.3", - "facebook/php-sdk-v4": "~4.0", + "facebook/php-sdk-v4": "~5.0", "flow/jsonpath": "~0.2", "monolog/monolog": "~1.8", "pda/pheanstalk": "~2.0", - "videlalvaro/php-amqplib": "~2.4" + "php-amqplib/php-amqplib": "~2.4" }, "suggest": { "codeception/phpbuiltinserver": "Extension to start and stop PHP built-in web server for your tests", @@ -1171,7 +1225,7 @@ "functional testing", "unit testing" ], - "time": "2016-02-09 22:27:48" + "time": "2016-03-12 01:15:25" }, { "name": "doctrine/instantiator", @@ -1324,16 +1378,16 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.1.1", + "version": "6.2.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "c6851d6e48f63b69357cbfa55bca116448140e0c" + "reference": "d094e337976dff9d8e2424e8485872194e768662" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/c6851d6e48f63b69357cbfa55bca116448140e0c", - "reference": "c6851d6e48f63b69357cbfa55bca116448140e0c", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d094e337976dff9d8e2424e8485872194e768662", + "reference": "d094e337976dff9d8e2424e8485872194e768662", "shasum": "" }, "require": { @@ -1349,7 +1403,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.1-dev" + "dev-master": "6.2-dev" } }, "autoload": { @@ -1382,7 +1436,7 @@ "rest", "web service" ], - "time": "2015-11-23 00:47:50" + "time": "2016-03-21 20:02:09" }, { "name": "guzzlehttp/promises", @@ -1846,16 +1900,16 @@ }, { "name": "phpunit/phpunit", - "version": "4.8.23", + "version": "4.8.24", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "6e351261f9cd33daf205a131a1ba61c6d33bd483" + "reference": "a1066c562c52900a142a0e2bbf0582994671385e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6e351261f9cd33daf205a131a1ba61c6d33bd483", - "reference": "6e351261f9cd33daf205a131a1ba61c6d33bd483", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1066c562c52900a142a0e2bbf0582994671385e", + "reference": "a1066c562c52900a142a0e2bbf0582994671385e", "shasum": "" }, "require": { @@ -1914,7 +1968,7 @@ "testing", "xunit" ], - "time": "2016-02-11 14:56:33" + "time": "2016-03-14 06:16:08" }, { "name": "phpunit/phpunit-mock-objects", @@ -2394,16 +2448,16 @@ }, { "name": "symfony/browser-kit", - "version": "v3.0.3", + "version": "v3.0.4", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "dde849a0485b70a24b36f826ed3fb95b904d80c3" + "reference": "e07127ac31230b30887c2dddf3708d883d239b14" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/dde849a0485b70a24b36f826ed3fb95b904d80c3", - "reference": "dde849a0485b70a24b36f826ed3fb95b904d80c3", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/e07127ac31230b30887c2dddf3708d883d239b14", + "reference": "e07127ac31230b30887c2dddf3708d883d239b14", "shasum": "" }, "require": { @@ -2447,20 +2501,20 @@ ], "description": "Symfony BrowserKit Component", "homepage": "https://symfony.com", - "time": "2016-01-27 11:34:55" + "time": "2016-03-04 07:55:57" }, { "name": "symfony/css-selector", - "version": "v3.0.3", + "version": "v3.0.4", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "6605602690578496091ac20ec7a5cbd160d4dff4" + "reference": "65e764f404685f2dc20c057e889b3ad04b2e2db0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/6605602690578496091ac20ec7a5cbd160d4dff4", - "reference": "6605602690578496091ac20ec7a5cbd160d4dff4", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/65e764f404685f2dc20c057e889b3ad04b2e2db0", + "reference": "65e764f404685f2dc20c057e889b3ad04b2e2db0", "shasum": "" }, "require": { @@ -2500,20 +2554,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2016-01-27 05:14:46" + "time": "2016-03-04 07:55:57" }, { "name": "symfony/dom-crawler", - "version": "v3.0.3", + "version": "v3.0.4", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "981c8edb4538f88ba976ed44bdcaa683fce3d6c6" + "reference": "18a06d7a9af41718c20764a674a0ebba3bc40d1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/981c8edb4538f88ba976ed44bdcaa683fce3d6c6", - "reference": "981c8edb4538f88ba976ed44bdcaa683fce3d6c6", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/18a06d7a9af41718c20764a674a0ebba3bc40d1f", + "reference": "18a06d7a9af41718c20764a674a0ebba3bc40d1f", "shasum": "" }, "require": { @@ -2556,20 +2610,20 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2016-02-28 16:24:34" + "time": "2016-03-23 13:23:25" }, { "name": "symfony/finder", - "version": "v3.0.3", + "version": "v3.0.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "623bda0abd9aa29e529c8e9c08b3b84171914723" + "reference": "c54e407b35bc098916704e9fd090da21da4c4f52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/623bda0abd9aa29e529c8e9c08b3b84171914723", - "reference": "623bda0abd9aa29e529c8e9c08b3b84171914723", + "url": "https://api.github.com/repos/symfony/finder/zipball/c54e407b35bc098916704e9fd090da21da4c4f52", + "reference": "c54e407b35bc098916704e9fd090da21da4c4f52", "shasum": "" }, "require": { @@ -2605,7 +2659,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-01-27 05:14:46" + "time": "2016-03-10 11:13:05" } ], "aliases": [ diff --git a/system/blueprints/config/system.yaml b/system/blueprints/config/system.yaml index 6059d7fde..73d4af5af 100644 --- a/system/blueprints/config/system.yaml +++ b/system/blueprints/config/system.yaml @@ -567,6 +567,28 @@ form: validate: type: bool + assets.css_pipeline_include_externals: + type: toggle + label: PLUGIN_ADMIN.CSS_PIPELINE_INCLUDE_EXTERNALS + help: PLUGIN_ADMIN.CSS_PIPELINE_INCLUDE_EXTERNALS_HELP + highlight: 1 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + + assets.css_pipeline_before_excludes: + type: toggle + label: PLUGIN_ADMIN.CSS_PIPELINE_BEFORE_EXCLUDES + help: PLUGIN_ADMIN.CSS_PIPELINE_BEFORE_EXCLUDES_HELP + highlight: 1 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + assets.css_minify: type: toggle label: PLUGIN_ADMIN.CSS_MINIFY @@ -611,6 +633,28 @@ form: validate: type: bool + assets.js_pipeline_include_externals: + type: toggle + label: PLUGIN_ADMIN.JAVASCRIPT_PIPELINE_INCLUDE_EXTERNALS + help: PLUGIN_ADMIN.JAVASCRIPT_PIPELINE_INCLUDE_EXTERNALS_HELP + highlight: 1 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + + assets.js_pipeline_before_excludes: + type: toggle + label: PLUGIN_ADMIN.JAVASCRIPT_PIPELINE_BEFORE_EXCLUDES + help: PLUGIN_ADMIN.JAVASCRIPT_PIPELINE_BEFORE_EXCLUDES_HELP + highlight: 1 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + assets.js_minify: type: toggle label: PLUGIN_ADMIN.JAVASCRIPT_MINIFY diff --git a/system/config/system.yaml b/system/config/system.yaml index 1d21cea23..534c9b09c 100644 --- a/system/config/system.yaml +++ b/system/config/system.yaml @@ -80,10 +80,14 @@ twig: assets: # Configuration for Assets Manager (JS, CSS) css_pipeline: false # The CSS pipeline is the unification of multiple CSS resources into one file + css_pipeline_include_externals: true # Include external URLs in the pipeline by default + css_pipeline_before_excludes: true # Render the pipeline before any excluded files css_minify: true # Minify the CSS during pipelining css_minify_windows: false # Minify Override for Windows platforms. False by default due to ThreadStackSize css_rewrite: true # Rewrite any CSS relative URLs during pipelining js_pipeline: false # The JS pipeline is the unification of multiple JS resources into one file + js_pipeline_include_externals: true # Include external URLs in the pipeline by default + js_pipeline_before_excludes: true # Render the pipeline before any excluded files js_minify: true # Minify the JS during pipelining enable_asset_timestamp: false # Enable asset timestamps collections: diff --git a/system/defines.php b/system/defines.php index 7d1ce424a..e81c95143 100644 --- a/system/defines.php +++ b/system/defines.php @@ -13,9 +13,7 @@ if (!defined('GRAV_ROOT')) { define('ROOT_DIR', GRAV_ROOT . '/'); define('USER_PATH', 'user/'); define('USER_DIR', ROOT_DIR . USER_PATH); -define('SYSTEM_DIR', ROOT_DIR .'system/'); define('CACHE_DIR', ROOT_DIR . 'cache/'); -define('LOG_DIR', ROOT_DIR .'logs/'); // DEPRECATED: Do not use! define('ASSETS_DIR', ROOT_DIR . 'assets/'); @@ -23,10 +21,12 @@ define('IMAGES_DIR', ROOT_DIR . 'images/'); define('ACCOUNTS_DIR', USER_DIR .'accounts/'); define('PAGES_DIR', USER_DIR .'pages/'); define('DATA_DIR', USER_DIR .'data/'); +define('SYSTEM_DIR', ROOT_DIR .'system/'); define('LIB_DIR', SYSTEM_DIR .'src/'); define('PLUGINS_DIR', USER_DIR .'plugins/'); define('THEMES_DIR', USER_DIR .'themes/'); define('VENDOR_DIR', ROOT_DIR .'vendor/'); +define('LOG_DIR', ROOT_DIR .'logs/'); // END DEPRECATED // Some extensions diff --git a/system/src/Grav/Common/Assets.php b/system/src/Grav/Common/Assets.php index 3a9a19d17..ebdce1b7b 100644 --- a/system/src/Grav/Common/Assets.php +++ b/system/src/Grav/Common/Assets.php @@ -61,7 +61,11 @@ class Assets // Configuration toggles to enable/disable the pipelining feature protected $css_pipeline = false; + protected $css_pipeline_include_externals = true; + protected $css_pipeline_before_excludes = true; protected $js_pipeline = false; + protected $js_pipeline_include_externals = true; + protected $js_pipeline_before_excludes = true; // The asset holding arrays protected $collections = []; @@ -120,10 +124,26 @@ class Assets $this->css_pipeline = $config['css_pipeline']; } + if (isset($config['css_pipeline_include_externals'])) { + $this->css_pipeline_include_externals = $config['css_pipeline_include_externals']; + } + + if (isset($config['css_pipeline_before_excludes'])) { + $this->css_pipeline_before_excludes = $config['css_pipeline_before_excludes']; + } + if (isset($config['js_pipeline'])) { $this->js_pipeline = $config['js_pipeline']; } + if (isset($config['js_pipeline_include_externals'])) { + $this->js_pipeline_include_externals = $config['js_pipeline_include_externals']; + } + + if (isset($config['js_pipeline_before_excludes'])) { + $this->js_pipeline_before_excludes = $config['js_pipeline_before_excludes']; + } + // Pipeline requires public dir if (($this->js_pipeline || $this->css_pipeline) && !is_dir($this->assets_dir)) { throw new \Exception('Assets: Public dir not found'); @@ -526,8 +546,10 @@ class Assets if ($this->css_pipeline) { $pipeline_result = $this->pipelineCss($group); - if ($pipeline_result) { - $output .= '' . "\n"; + $pipeline_html = '' . "\n"; + + if ($this->css_pipeline_before_excludes && $pipeline_result) { + $output .= $pipeline_html; } foreach ($this->css_no_pipeline as $file) { if ($group && $file['group'] == $group) { @@ -535,6 +557,9 @@ class Assets $output .= '' . "\n"; } } + if (!$this->css_pipeline_before_excludes && $pipeline_result) { + $output .= $pipeline_html; + } } else { foreach ($this->css as $file) { if ($group && $file['group'] == $group) { @@ -600,14 +625,19 @@ class Assets if ($this->js_pipeline) { $pipeline_result = $this->pipelineJs($group); - if ($pipeline_result) { - $output .= '' . "\n"; + $pipeline_html = '' . "\n"; + + if ($this->js_pipeline_before_excludes && $pipeline_result) { + $output .= $pipeline_html; } foreach ($this->js_no_pipeline as $file) { if ($group && $file['group'] == $group) { $output .= '' . "\n"; } } + if (!$this->js_pipeline_before_excludes && $pipeline_result) { + $output .= $pipeline_html; + } } else { foreach ($this->js as $file) { if ($group && $file['group'] == $group) { @@ -649,20 +679,27 @@ class Assets // clear no-pipeline assets lists $this->css_no_pipeline = []; - $file = md5(json_encode($this->css) . $this->css_minify . $this->css_rewrite . $group) . '.css'; + $uid = md5(json_encode($this->css) . $this->css_minify . $this->css_rewrite . $group); + $file = $uid . '.css'; + $inline_file = $uid . '-inline.css'; $relative_path = "{$this->base_url}{$this->assets_url}/{$file}"; - $absolute_path = $this->assets_dir . $file; + + // If inline files exist set them on object + if (file_exists($this->assets_dir . $inline_file)) { + $this->css_no_pipeline = json_decode(file_get_contents($this->assets_dir . $inline_file), true); + } // If pipeline exist return it - if (file_exists($absolute_path)) { + if (file_exists($this->assets_dir . $file)) { return $relative_path . $key; } // Remove any non-pipeline files foreach ($this->css as $id => $asset) { if ($asset['group'] == $group) { - if (!$asset['pipeline']) { + if (!$asset['pipeline'] || + ($this->isRemoteLink($asset['asset']) && $this->css_pipeline_include_externals === false)) { $this->css_no_pipeline[$id] = $asset; } else { $temp_css[$id] = $asset; @@ -675,6 +712,12 @@ class Assets return false; } + // Write non-pipeline files out + if (!empty($this->css_no_pipeline)) { + file_put_contents($this->assets_dir . $inline_file, json_encode($this->css_no_pipeline)); + } + + $css_minify = $this->css_minify; // If this is a Windows server, and minify_windows is false (default value) skip the @@ -693,7 +736,7 @@ class Assets // Write file if (strlen(trim($buffer)) > 0) { - file_put_contents($absolute_path, $buffer); + file_put_contents($this->assets_dir . $file, $buffer); return $relative_path . $key; } else { @@ -720,20 +763,27 @@ class Assets // clear no-pipeline assets lists $this->js_no_pipeline = []; - $file = md5(json_encode($this->js) . $this->js_minify . $group) . '.js'; + $uid = md5(json_encode($this->js) . $this->js_minify . $group); + $file = $uid . '.js'; + $inline_file = $uid . '-inline.js'; $relative_path = "{$this->base_url}{$this->assets_url}/{$file}"; - $absolute_path = $this->assets_dir . $file; + + // If inline files exist set them on object + if (file_exists($this->assets_dir . $inline_file)) { + $this->js_no_pipeline = json_decode(file_get_contents($this->assets_dir . $inline_file), true); + } // If pipeline exist return it - if (file_exists($absolute_path)) { + if (file_exists($this->assets_dir . $file)) { return $relative_path . $key; } // Remove any non-pipeline files foreach ($this->js as $id => $asset) { if ($asset['group'] == $group) { - if (!$asset['pipeline']) { + if (!$asset['pipeline'] || + ($this->isRemoteLink($asset['asset']) && $this->js_pipeline_include_externals === false)) { $this->js_no_pipeline[] = $asset; } else { $temp_js[$id] = $asset; @@ -746,6 +796,11 @@ class Assets return false; } + // Write non-pipeline files out + if (!empty($this->js_no_pipeline)) { + file_put_contents($this->assets_dir . $inline_file, json_encode($this->js_no_pipeline)); + } + // Concatenate files $buffer = $this->gatherLinks($temp_js, JS_ASSET); if ($this->js_minify) { @@ -754,7 +809,7 @@ class Assets // Write file if (strlen(trim($buffer)) > 0) { - file_put_contents($absolute_path, $buffer); + file_put_contents($this->assets_dir . $file, $buffer); return $relative_path . $key; } else { @@ -1010,10 +1065,11 @@ class Assets protected function gatherLinks(array $links, $css = true) { $buffer = ''; - $local = true; + foreach ($links as $asset) { $relative_dir = ''; + $local = true; $link = $asset['asset']; $relative_path = $link; diff --git a/system/src/Grav/Common/Data/BlueprintSchema.php b/system/src/Grav/Common/Data/BlueprintSchema.php index 659c18ba3..b2f41adaf 100644 --- a/system/src/Grav/Common/Data/BlueprintSchema.php +++ b/system/src/Grav/Common/Data/BlueprintSchema.php @@ -136,7 +136,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface && !isset($data[$name])) { $value = isset($field['label']) ? $field['label'] : $field['name']; $language = Grav::instance()['language']; - $message = sprintf($language->translate('FORM.MISSING_REQUIRED_FIELD', null, true) . ' %s', $value); + $message = sprintf($language->translate('FORM.MISSING_REQUIRED_FIELD', null, true) . ' %s', $language->translate($value)); $messages[$field['name']][] = $message; } } diff --git a/system/src/Grav/Common/GPM/GPM.php b/system/src/Grav/Common/GPM/GPM.php index a71f82884..c4577547f 100644 --- a/system/src/Grav/Common/GPM/GPM.php +++ b/system/src/Grav/Common/GPM/GPM.php @@ -194,7 +194,7 @@ class GPM extends Iterator } foreach ($this->installed['plugins'] as $slug => $plugin) { - if (!isset($repository[$slug]) || $plugin->symlink) { + if (!isset($repository[$slug]) || $plugin->symlink || !$plugin->version || $plugin->gpm === false) { continue; } @@ -272,7 +272,7 @@ class GPM extends Iterator } foreach ($this->installed['themes'] as $slug => $plugin) { - if (!isset($repository[$slug]) || $plugin->symlink) { + if (!isset($repository[$slug]) || $plugin->symlink || !$plugin->version || $plugin->gpm === false) { continue; } diff --git a/system/src/Grav/Common/GPM/Response.php b/system/src/Grav/Common/GPM/Response.php index 50e89677e..f8c8ed307 100644 --- a/system/src/Grav/Common/GPM/Response.php +++ b/system/src/Grav/Common/GPM/Response.php @@ -199,7 +199,15 @@ class Response // if proxy set add that $proxy_url = Grav::instance()['config']->get('system.proxy_url'); if ($proxy_url) { - $options['fopen']['proxy'] = $proxy_url; + $parsed_url = parse_url($proxy_url); + + $options['fopen']['proxy'] = ($parsed_url['scheme'] ?: 'http') . '://' . $parsed_url['host'] . (isset($parsed_url['port']) ? ':' . $parsed_url['port'] : ''); + $options['fopen']['request_fulluri'] = true; + + if (isset($parsed_url['user']) && isset($parsed_url['pass'])) { + $auth = base64_encode($parsed_url['user'] . ':' . $parsed_url['pass']); + $options['fopen']['header'] = "Proxy-Authorization: Basic $auth"; + } } if ($callback) { @@ -267,7 +275,18 @@ class Response // if proxy set add that $proxy_url = Grav::instance()['config']->get('system.proxy_url'); if ($proxy_url) { - $options['curl'][CURLOPT_PROXY] = $proxy_url; + $parsed_url = parse_url($proxy_url); + + $options['curl'][CURLOPT_PROXY] = $parsed_url['host']; + $options['curl'][CURLOPT_PROXYTYPE] = 'HTTP'; + + if (isset($parsed_url['port'])) { + $options['curl'][CURLOPT_PROXYPORT] = $parsed_url['port']; + } + + if (isset($parsed_url['user']) && isset($parsed_url['pass'])) { + $options['curl'][CURLOPT_PROXYUSERPWD] = $parsed_url['user'] . ':' . $parsed_url['pass']; + } } // no open_basedir set, we can proceed normally @@ -276,7 +295,7 @@ class Response return curl_exec($ch); } - $max_redirects = isset($options['curl'][CURLOPT_MAXREDIRS]) ? $options['curl'][CURLOPT_MAXREDIRS] : 3; + $max_redirects = isset($options['curl'][CURLOPT_MAXREDIRS]) ? $options['curl'][CURLOPT_MAXREDIRS] : 3; $options['curl'][CURLOPT_FOLLOWLOCATION] = false; // open_basedir set but no redirects to follow, we can disable followlocation and proceed normally diff --git a/system/src/Grav/Common/Grav.php b/system/src/Grav/Common/Grav.php index 4917da357..b761cda2a 100644 --- a/system/src/Grav/Common/Grav.php +++ b/system/src/Grav/Common/Grav.php @@ -84,8 +84,6 @@ class Grav extends Container $container['debugger'] = new Debugger(); $container['debugger']->startTimer('_services', 'Services'); - $container->register(new LoggerServiceProvider); - $container->register(new ErrorServiceProvider); $container['uri'] = function ($c) { @@ -154,18 +152,35 @@ class Grav extends Container // Redirection tests if ($page) { + $url = $page->route(); + + if ($uri->params()) { + if ($url == '/') { //Avoid double slash + $url = $uri->params(); + } else { + $url .= $uri->params(); + } + } + if ($uri->query()) { + $url .= '?' . $uri->query(); + } + if ($uri->fragment()) { + $url .= '#' . $uri->fragment(); + } + // Language-specific redirection scenarios if ($language->enabled()) { if ($language->isLanguageInUrl() && !$language->isIncludeDefaultLanguage()) { - $c->redirect($page->route()); + $c->redirect($url); } if (!$language->isLanguageInUrl() && $language->isIncludeDefaultLanguage()) { - $c->redirectLangSafe($page->route()); + $c->redirectLangSafe($url); } } + // Default route test and redirect if ($c['config']->get('system.pages.redirect_default_route') && $page->route() != $path) { - $c->redirectLangSafe($page->route()); + $c->redirectLangSafe($url); } } @@ -199,6 +214,7 @@ class Grav extends Container $container->register(new StreamsServiceProvider); $container->register(new ConfigServiceProvider); + $container->register(new LoggerServiceProvider); $container['inflector'] = new Inflector(); diff --git a/system/src/Grav/Common/Markdown/ParsedownGravTrait.php b/system/src/Grav/Common/Markdown/ParsedownGravTrait.php index 6610e056b..9b99c0587 100644 --- a/system/src/Grav/Common/Markdown/ParsedownGravTrait.php +++ b/system/src/Grav/Common/Markdown/ParsedownGravTrait.php @@ -63,9 +63,13 @@ trait ParsedownGravTrait * @param $type * @param $tag */ - public function addBlockType($type, $tag, $continuable = false, $completable = false) + public function addBlockType($type, $tag, $continuable = false, $completable = false, $index = null) { - $this->BlockTypes[$type] [] = $tag; + if (!isset($index)) { + $this->BlockTypes[$type] [] = $tag; + } else { + array_splice($this->BlockTypes[$type], $index, 0, $tag); + } if ($continuable) { $this->continuable_blocks[] = $tag; @@ -82,10 +86,17 @@ trait ParsedownGravTrait * @param $type * @param $tag */ - public function addInlineType($type, $tag) + public function addInlineType($type, $tag, $index = null) { - $this->InlineTypes[$type] [] = $tag; - $this->inlineMarkerList .= $type; + if (!isset($index)) { + $this->InlineTypes[$type] [] = $tag; + } else { + array_splice($this->InlineTypes[$type], $index, 0, $tag); + } + + if (strpos($this->inlineMarkerList, $type) === false) { + $this->inlineMarkerList .= $type; + } } /** @@ -229,6 +240,7 @@ trait ParsedownGravTrait // if there is a query, then parse it and build action calls if (isset($url['query'])) { + $url['query'] = htmlspecialchars_decode(urldecode($url['query'])); $actions = array_reduce(explode('&', $url['query']), function ($carry, $item) { $parts = explode('=', $item, 2); $value = isset($parts[1]) ? $parts[1] : null; diff --git a/system/src/Grav/Common/Page/Page.php b/system/src/Grav/Common/Page/Page.php index c8ecf7d22..64acb7671 100644 --- a/system/src/Grav/Common/Page/Page.php +++ b/system/src/Grav/Common/Page/Page.php @@ -2134,7 +2134,7 @@ class Page /** @var Pages $pages */ $pages = Grav::instance()['pages']; - return $pages->dispatch($url, $all); + return $pages->find($url, $all); } /** diff --git a/system/src/Grav/Common/Page/Pages.php b/system/src/Grav/Common/Page/Pages.php index fb98932db..1cb97592d 100644 --- a/system/src/Grav/Common/Page/Pages.php +++ b/system/src/Grav/Common/Page/Pages.php @@ -287,6 +287,19 @@ class Pages return new Collection($children, [], $this); } + /** + * alias method to return find a page. + * + * @param string $url The relative URL of the page + * @param bool $all + * + * @return Page|null + */ + public function find($url, $all = false) + { + return $this->dispatch($url, $all); + } + /** * Dispatch URI to a page. * @@ -704,7 +717,7 @@ class Pages $last_modified = Folder::lastModifiedFile($pages_dir); } - $page_cache_id = md5(USER_DIR . $last_modified . $language->getActive() . $config->checksum()); + $page_cache_id = md5($pages_dir . $last_modified . $language->getActive() . $config->checksum()); list($this->instances, $this->routes, $this->children, $taxonomy_map, $this->sort) = $cache->fetch($page_cache_id); if (!$this->instances) { diff --git a/system/src/Grav/Common/Service/LoggerServiceProvider.php b/system/src/Grav/Common/Service/LoggerServiceProvider.php index edaf92178..75affc985 100644 --- a/system/src/Grav/Common/Service/LoggerServiceProvider.php +++ b/system/src/Grav/Common/Service/LoggerServiceProvider.php @@ -5,16 +5,23 @@ use Pimple\Container; use Pimple\ServiceProviderInterface; use \Monolog\Logger; use \Monolog\Handler\StreamHandler; +use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class LoggerServiceProvider implements ServiceProviderInterface { public function register(Container $container) { - $log = new Logger('grav'); - $log_file = LOG_DIR.'grav.log'; + $container['log'] = function ($c) { + $log = new Logger('grav'); - $log->pushHandler(new StreamHandler($log_file, Logger::DEBUG)); + /** @var UniformResourceLocator $locator */ + $locator = $c['locator']; - $container['log'] = $log; + $log_file = $locator->findResource('log://grav.log', true, true); + + $log->pushHandler(new StreamHandler($log_file, Logger::DEBUG)); + + return $log; + }; } } diff --git a/system/src/Grav/Common/Themes.php b/system/src/Grav/Common/Themes.php index e3497f542..1ed46d44a 100644 --- a/system/src/Grav/Common/Themes.php +++ b/system/src/Grav/Common/Themes.php @@ -278,15 +278,23 @@ class Themes extends Iterator $locator = $this->grav['locator']; if ($config->get('system.languages.translations', true)) { - $languageFiles = array_reverse($locator->findResources("theme://languages" . YAML_EXT)); - - $languages = []; - foreach ($languageFiles as $language) { - $languages[] = CompiledYamlFile::instance($language)->content(); + $language_file = $locator->findResource("theme://languages" . YAML_EXT); + if ($language_file) { + $language = CompiledYamlFile::instance($language_file)->content(); + $this->grav['languages']->mergeRecursive($language); } + $languages_folder = $locator->findResource("theme://languages/"); + if (file_exists($languages_folder)) { + $languages = []; + $iterator = new \DirectoryIterator($languages_folder); - if ($languages) { - $languages = call_user_func_array('array_replace_recursive', $languages); + /** @var \DirectoryIterator $directory */ + foreach ($iterator as $file) { + if ($file->getExtension() != 'yaml') { + continue; + } + $languages[$file->getBasename('.yaml')] = CompiledYamlFile::instance($file->getPathname())->content(); + } $this->grav['languages']->mergeRecursive($languages); } } diff --git a/system/src/Grav/Common/Twig/Twig.php b/system/src/Grav/Common/Twig/Twig.php index e36b5372f..502c2c542 100644 --- a/system/src/Grav/Common/Twig/Twig.php +++ b/system/src/Grav/Common/Twig/Twig.php @@ -150,6 +150,13 @@ class Twig } $this->twig->addExtension(new TwigExtension()); + // enable the Intl Twig extension if translations are enabled + if (count($config->get('system.languages.supported', [])) > 0) { + if (class_exists('\Twig_Extensions_Extension_Intl')) { + $this->twig->addExtension(new \Twig_Extensions_Extension_Intl()); + } + } + $this->grav->fireEvent('onTwigExtensions'); // Set some standard variables for twig diff --git a/system/src/Grav/Common/Twig/TwigExtension.php b/system/src/Grav/Common/Twig/TwigExtension.php index 2fc18b9d9..fb37f934c 100644 --- a/system/src/Grav/Common/Twig/TwigExtension.php +++ b/system/src/Grav/Common/Twig/TwigExtension.php @@ -63,7 +63,6 @@ class TwigExtension extends \Twig_Extension new \Twig_SimpleFilter('*ize', [$this, 'inflectorFilter']), new \Twig_SimpleFilter('absolute_url', [$this, 'absoluteUrlFilter']), new \Twig_SimpleFilter('contains', [$this, 'containsFilter']), - new \Twig_SimpleFilter('date', [$this, 'dateFilter'], array('needs_environment' => true)), new \Twig_SimpleFilter('defined', [$this, 'definedDefaultFilter']), new \Twig_SimpleFilter('ends_with', [$this, 'endsWithFilter']), new \Twig_SimpleFilter('fieldName', [$this, 'fieldNameFilter']), @@ -318,67 +317,6 @@ class TwigExtension extends \Twig_Extension return (strpos($haystack, $needle) !== false); } - /** - * Overrides the built-in date filter to output dates in the set locale - * - * @param TwigEnvironment $env A Twig_Environment instance - * @param DateTime|DateTimeInterface|DateInterval|string $date A date - * @param string|null $format The target format, null to use the default - * @param DateTimeZone|string|null|false $timezone The target timezone, null to use the default, false to leave unchanged - * - * @return string The formatted date - */ - function dateFilter(TwigEnvironment $env, $date, $format = null, $timezone = null) - { - $this->grav->setLocale(); - - if (null === $format) { - $formats = $env->getExtension('core')->getDateFormat(); - $format = $date instanceof DateInterval ? $formats[1] : $formats[0]; - } - - if ($date instanceof DateInterval) { - return strftime($this->dateFormatToStrftime($format), $date->getTimestamp()); - } - - return strftime($this->dateFormatToStrftime($format), \twig_date_converter($env, $date, $timezone)->getTimestamp()); - } - - /** - * Convert a date format to a strftime format - * - * Timezone conversion is done for unix. Windows users must exchange %z and %Z. - * - * Unsupported date formats : S, n, t, L, B, G, u, e, I, P, Z, c, r - * Unsupported strftime formats : %U, %W, %C, %g, %r, %R, %T, %X, %c, %D, %F, %x - * - * @param string $dateFormat a date format - * @return string - * - * @author https://secure.php.net/manual/it/function.strftime.php#96424 - */ - public function dateFormatToStrftime($dateFormat) - { - $caracs = array( - // Day - no strf eq : S - 'd' => '%d', 'D' => '%a', 'j' => '%e', 'l' => '%A', 'N' => '%u', 'w' => '%w', 'z' => '%j', - // Week - no date eq : %U, %W - 'W' => '%V', - // Month - no strf eq : n, t - 'F' => '%B', 'm' => '%m', 'M' => '%b', - // Year - no strf eq : L; no date eq : %C, %g - 'o' => '%G', 'Y' => '%Y', 'y' => '%y', - // Time - no strf eq : B, G, u; no date eq : %r, %R, %T, %X - 'a' => '%P', 'A' => '%p', 'g' => '%l', 'h' => '%I', 'H' => '%H', 'i' => '%M', 's' => '%S', - // Timezone - no strf eq : e, I, P, Z - 'O' => '%z', 'T' => '%Z', - // Full Date / Time - no strf eq : c, r; no date eq : %c, %D, %F, %x - 'U' => '%s' - ); - - return strtr((string)$dateFormat, $caracs); - } - /** * displays a facebook style 'time ago' formatted date/time * diff --git a/system/src/Grav/Common/Uri.php b/system/src/Grav/Common/Uri.php index 0c708ca85..7a9e536e7 100644 --- a/system/src/Grav/Common/Uri.php +++ b/system/src/Grav/Common/Uri.php @@ -159,17 +159,12 @@ class Uri private function buildEnvironment() { - // set hostname - $address = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '::1'; - // check for localhost variations - if ($this->name == 'localhost' || $address == '::1' || $address == '127.0.0.1') { - $env = 'localhost'; + if ($this->name == '127.0.0.1' || $this->name== '::1') { + return 'localhost'; } else { - $env = $this->name; + return $this->name; } - - return $env; } /** @@ -479,7 +474,7 @@ class Uri * Gets the Fragment portion of a URI (eg #target) * * @param null $fragment - * + * * @return null */ public function fragment($fragment = null) @@ -601,6 +596,27 @@ class Uri return $this->base; } + /** + * Return the base relative URL including the language prefix + * or the base relative url if multilanguage is not enabled + * + * @return String The base of the URI + */ + public function baseIncludingLanguage() + { + $grav = Grav::instance(); + + // Link processing should prepend language + $language = $grav['language']; + $language_append = ''; + if ($language->enabled()) { + $language_append = $language->getLanguageURLPrefix(); + } + + $base = $grav['base_url_relative']; + return rtrim($base . $grav['pages']->base(), '/') . $language_append; + } + /** * Return root URL to the site. * diff --git a/system/src/Grav/Console/Cli/DevTools/DevToolsCommand.php b/system/src/Grav/Console/Cli/DevTools/DevToolsCommand.php new file mode 100644 index 000000000..dbdf1c8ff --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/DevToolsCommand.php @@ -0,0 +1,192 @@ +grav = Grav::instance(array('loader' => $autoload)); + $this->grav['config']->init(); + $this->grav['uri']->init(); + $this->grav['streams']; + $this->inflector = $this->grav['inflector']; + $this->locator = $this->grav['locator']; + $this->twig = new Twig($this->grav); + $this->gpm = new GPM(true); + + //Add `theme://` to prevent fail + $this->locator->addPath('theme', '', []); + } + + /** + * Copies the component type and renames accordingly + */ + protected function createComponent() + { + $name = $this->component['name']; + $folderName = strtolower($this->inflector->hyphenize($name)); + $type = $this->component['type']; + + $template = $this->component['template']; + $templateFolder = __DIR__ . '/components/' . $type . DS . $template; + $componentFolder = $this->locator->findResource($type . 's://') . DS . $folderName; + + //Copy All files to component folder + try { + Folder::copy($templateFolder, $componentFolder); + } catch (\Exception $e) { + $this->output->writeln("" . $e->getMessage() . ""); + return false; + } + + //Add Twig vars and templates then initialize + $this->twig->twig_vars['component'] = $this->component; + $this->twig->twig_paths[] = $templateFolder; + $this->twig->init(); + + //Get all templates of component then process each with twig and save + $templates = Folder::all($componentFolder); + + try { + foreach($templates as $templateFile) { + if (Utils::endsWith($templateFile, '.twig') && !Utils::endsWith($templateFile, '.html.twig')) { + $content = $this->twig->processTemplate($templateFile); + $file = File::instance($componentFolder . DS . str_replace('.twig', '', $templateFile)); + $file->content($content); + $file->save(); + + //Delete twig template + $file = File::instance($componentFolder . DS . $templateFile); + $file->delete(); + } + } + } catch (\Exception $e) { + $this->output->writeln("" . $e->getMessage() . ""); + $this->output->writeln("Rolling back..."); + Folder::delete($componentFolder); + $this->output->writeln($type . "creation failed!"); + return false; + } + + rename($componentFolder . DS . $type . '.php', $componentFolder . DS . $this->inflector->hyphenize($name) . '.php'); + rename($componentFolder . DS . $type . '.yaml', $componentFolder . DS . $this->inflector->hyphenize($name) . '.yaml'); + + $this->output->writeln(''); + $this->output->writeln('SUCCESS ' . $type . ' ' . $name . ' -> Created Successfully'); + $this->output->writeln(''); + $this->output->writeln('Path: ' . $componentFolder . ''); + $this->output->writeln(''); + } + + /** + * Iterate through all options and validate + */ + protected function validateOptions() + { + foreach (array_filter($this->options) as $type => $value) { + $this->validate($type, $value); + } + } + + /** + * @param $type + * @param $value + * @param string $extra + * + * @return mixed + */ + protected function validate($type, $value, $extra = '') + { + switch ($type) { + case 'name': + //Check If name + if ($value == null || trim($value) == '') { + throw new \RuntimeException('Name cannot be empty'); + } + if (false != $this->gpm->findPackage($value)) { + throw new \RuntimeException('Package name exists in GPM'); + } + + break; + + case 'description': + if($value == null || trim($value) == '') { + throw new \RuntimeException('Description cannot be empty'); + } + + break; + + case 'developer': + if ($value === null || trim($value) == '') { + throw new \RuntimeException('Developer\'s Name cannot be empty'); + } + + break; + + case 'email': + if (!preg_match('/^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/', $value)) { + throw new \RuntimeException('Not a valid email address'); + } + + break; + } + + return $value; + } +} diff --git a/system/src/Grav/Console/Cli/DevTools/NewPluginCommand.php b/system/src/Grav/Console/Cli/DevTools/NewPluginCommand.php new file mode 100644 index 000000000..8a0a47510 --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/NewPluginCommand.php @@ -0,0 +1,129 @@ +setName('new-plugin') + ->setAliases(['newplugin']) + ->addOption( + 'name', + 'pn', + InputOption::VALUE_OPTIONAL, + 'The name of your new Grav plugin' + ) + ->addOption( + 'description', + 'd', + InputOption::VALUE_OPTIONAL, + 'A description of your new Grav plugin' + ) + ->addOption( + 'developer', + 'dv', + InputOption::VALUE_OPTIONAL, + 'The name/username of the developer' + ) + ->addOption( + 'email', + 'e', + InputOption::VALUE_OPTIONAL, + 'The developer\'s email' + ) + ->setDescription('Creates a new Grav plugin with the basic required files') + ->setHelp('The new-plugin command creates a new Grav instance and performs the creation of a plugin.'); + } + + /** + * @return int|null|void + */ + protected function serve() + { + $this->init(); + + /** + * @var array DevToolsCommand $component + */ + $this->component['type'] = 'plugin'; + $this->component['template'] = 'blank'; + $this->component['version'] = '0.1.0'; // @todo add optional non prompting version argument + + $this->options = [ + 'name' => $this->input->getOption('name'), + 'description' => $this->input->getOption('description'), + 'author' => [ + 'name' => $this->input->getOption('developer'), + 'email' => $this->input->getOption('email') + ] + ]; + + $this->validateOptions(); + + $this->component = array_replace($this->component, $this->options); + + $helper = $this->getHelper('question'); + + if (!$this->options['name']) { + $question = new Question('Enter Plugin Name: '); + $question->setValidator(function ($value) { + return $this->validate('name', $value); + }); + + $this->component['name'] = $helper->ask($this->input, $this->output, $question); + } + + if (!$this->options['description']) { + $question = new Question('Enter Plugin Description: '); + $question->setValidator(function ($value) { + return $this->validate('description', $value); + }); + + $this->component['description'] = $helper->ask($this->input, $this->output, $question); + } + + if (!$this->options['author']['name']) { + $question = new Question('Enter Developer Name: '); + $question->setValidator(function ($value) { + return $this->validate('developer', $value); + }); + + $this->component['author']['name'] = $helper->ask($this->input, $this->output, $question); + } + + if (!$this->options['author']['email']) { + $question = new Question('Enter Developer Email: '); + $question->setValidator(function ($value) { + return $this->validate('email', $value); + }); + + $this->component['author']['email'] = $helper->ask($this->input, $this->output, $question); + } + + $this->component['template'] = 'blank'; + + $this->createComponent(); + } + +} diff --git a/system/src/Grav/Console/Cli/DevTools/NewThemeCommand.php b/system/src/Grav/Console/Cli/DevTools/NewThemeCommand.php new file mode 100644 index 000000000..10e76ad73 --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/NewThemeCommand.php @@ -0,0 +1,145 @@ +setName('new-theme') + ->setAliases(['newtheme']) + ->addOption( + 'name', + 'pn', + InputOption::VALUE_OPTIONAL, + 'The name of your new Grav theme' + ) + ->addOption( + 'description', + 'd', + InputOption::VALUE_OPTIONAL, + 'A description of your new Grav theme' + ) + ->addOption( + 'developer', + 'dv', + InputOption::VALUE_OPTIONAL, + 'The name/username of the developer' + ) + ->addOption( + 'email', + 'e', + InputOption::VALUE_OPTIONAL, + 'The developer\'s email' + ) + ->setDescription('Creates a new Grav theme with the basic required files') + ->setHelp('The new-theme command creates a new Grav instance and performs the creation of a theme.'); + } + + /** + * @return int|null|void + */ + protected function serve() + { + $this->init(); + + /** + * @var array DevToolsCommand $component + */ + $this->component['type'] = 'theme'; + $this->component['template'] = 'blank'; + $this->component['version'] = '0.1.0'; // @todo add optional non prompting version argument + + $this->options = [ + 'name' => $this->input->getOption('name'), + 'description' => $this->input->getOption('description'), + 'author' => [ + 'name' => $this->input->getOption('developer'), + 'email' => $this->input->getOption('email') + ] + ]; + + $this->validateOptions(); + + $this->component = array_replace($this->component, $this->options); + + $helper = $this->getHelper('question'); + + if (!$this->options['name']) { + $question = new Question('Enter Theme Name: '); + $question->setValidator(function ($value) { + return $this->validate('name', $value); + }); + + $this->component['name'] = $helper->ask($this->input, $this->output, $question); + } + + if (!$this->options['description']) { + $question = new Question('Enter Theme Description: '); + $question->setValidator(function ($value) { + return $this->validate('description', $value); + }); + + $this->component['description'] = $helper->ask($this->input, $this->output, $question); + } + + if (!$this->options['author']['name']) { + $question = new Question('Enter Developer Name: '); + $question->setValidator(function ($value) { + return $this->validate('developer', $value); + }); + + $this->component['author']['name'] = $helper->ask($this->input, $this->output, $question); + } + + if (!$this->options['author']['email']) { + $question = new Question('Enter Developer Email: '); + $question->setValidator(function ($value) { + return $this->validate('email', $value); + }); + + $this->component['author']['email'] = $helper->ask($this->input, $this->output, $question); + } + + $question = new ChoiceQuestion( + 'Please choose a template type', + array('pure-blank', 'inheritence') + ); + $this->component['template'] = $helper->ask($this->input, $this->output, $question); + + if ($this->component['template'] == 'inheritence') { + $themes = $this->gpm->getInstalledThemes(); + $installedThemes = []; + foreach($themes as $key => $theme) { + array_push($installedThemes, $key); + } + $question = new ChoiceQuestion( + 'Please choose a theme to extend: ', + $installedThemes + ); + $this->component['extends'] = $helper->ask($this->input, $this->output, $question); + } + $this->createComponent(); + } + +} diff --git a/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/CHANGELOG.md.twig b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/CHANGELOG.md.twig new file mode 100644 index 000000000..973fb2766 --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/CHANGELOG.md.twig @@ -0,0 +1,5 @@ +# v0.1.0 +## {{ "now"|date("m/d/Y") }} + +1. [](#new) + * ChangeLog started... diff --git a/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/LICENSE.twig b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/LICENSE.twig new file mode 100644 index 000000000..6f88097cd --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/LICENSE.twig @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) {{ "now"|date("Y") }} {{ component.author.name }} + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/README.md.twig b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/README.md.twig new file mode 100644 index 000000000..56a02db62 --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/README.md.twig @@ -0,0 +1,7 @@ +# {{ component.name|titleize }} Plugin + +The **{{ component.name|titleize }}** Plugin is for [Grav CMS](http://github.com/getgrav/grav). This README.md file should be modified to describe the features, installation, configuration, and general usage of this plugin. + +## Description + +{{ component.description }} diff --git a/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/blueprints.yaml.twig b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/blueprints.yaml.twig new file mode 100644 index 000000000..ff985869e --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/blueprints.yaml.twig @@ -0,0 +1,31 @@ +name: {{ component.name|titleize }} +version: 0.1.0 +description: {{ component.description }} +icon: plug +author: + name: {{ component.author.name }} + email: {{ component.author.email }} +homepage: https://github.com/{{ component.author.name|hyphenize }}/grav-plugin-{{ component.name|hyphenize }} +demo: http://demo.yoursite.com +keywords: grav, plugin, etc +bugs: https://github.com/{{ component.author.name|hyphenize }}/grav-plugin-{{ component.name|hyphenize }}/issues +readme: https://github.com/{{ component.author.name|hyphenize }}/grav-plugin-{{ component.name|hyphenize }}/blob/develop/README.md +license: MIT + +form: + validation: strict + fields: + enabled: + type: toggle + label: Plugin status + highlight: 1 + default: 0 + options: + 1: Enabled + 0: Disabled + validate: + type: bool + text_var: + type: text + label: Text Variable + help: Text to add to the top of a page diff --git a/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/plugin.php.twig b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/plugin.php.twig new file mode 100644 index 000000000..662724518 --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/plugin.php.twig @@ -0,0 +1,63 @@ + ['onPluginsInitialized', 0] + ]; + } + + /** + * Initialize the plugin + */ + public function onPluginsInitialized() + { + // Don't proceed if we are in the admin plugin + if ($this->isAdmin()) { + return; + } + + // Enable the main event we are interested in + $this->enable([ + 'onPageContentRaw' => ['onPageContentRaw', 0] + ]); + } + + /** + * Do some work for this event, full details of events can be found + * on the learn site: http://learn.getgrav.org/plugins/event-hooks + * + * @param Event $e + */ + public function onPageContentRaw(Event $e) + { + // Get a variable from the plugin configuration + $text = $this->grav['config']->get('plugins.{{ component.name|hyphenize }}.text_var'); + + // Get the current raw content + $content = $e['page']->getRawContent(); + + // Prepend the output with the custom text and set back on the page + $e['page']->setRawContent($text . "\n\n" . $content); + } +} diff --git a/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/plugin.yaml.twig b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/plugin.yaml.twig new file mode 100644 index 000000000..55e2f2ed7 --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/plugin.yaml.twig @@ -0,0 +1,2 @@ +enabled: true +text_var: Custom Text added by the **{{ component.name|titleize }}** plugin (disable plugin to remove) diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/CHANGELOG.md.twig b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/CHANGELOG.md.twig new file mode 100644 index 000000000..973fb2766 --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/CHANGELOG.md.twig @@ -0,0 +1,5 @@ +# v0.1.0 +## {{ "now"|date("m/d/Y") }} + +1. [](#new) + * ChangeLog started... diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/LICENSE.twig b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/LICENSE.twig new file mode 100644 index 000000000..6f88097cd --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/LICENSE.twig @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) {{ "now"|date("Y") }} {{ component.author.name }} + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/README.md.twig b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/README.md.twig new file mode 100644 index 000000000..e4ff0fd9a --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/README.md.twig @@ -0,0 +1,7 @@ +# {{ component.name|titleize }} Plugin + +The **{{ component.name|titleize }}** Theme is for [Grav CMS](http://github.com/getgrav/grav). This README.md file should be modified to describe the features, installation, configuration, and general usage of this theme. + +## Description + +{{ component.description }} diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/blueprints.yaml.twig b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/blueprints.yaml.twig new file mode 100644 index 000000000..78c58b11c --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/blueprints.yaml.twig @@ -0,0 +1,13 @@ +name: {{ component.name|titleize }} +version: 0.1.0 +description: {{ component.description }} +icon: rebel +author: + name: {{ component.author.name }} + email: {{ component.author.email }} +homepage: https://github.com/{{ component.author.name|hyphenize }}/grav-theme-{{ component.name|hyphenize }} +demo: http://demo.yoursite.com +keywords: grav, theme, etc +bugs: https://github.com/{{ component.author.name|hyphenize }}/grav-theme-{{ component.name|hyphenize }}/issues +readme: https://github.com/{{ component.author.name|hyphenize }}/grav-theme-{{ component.name|hyphenize }}/blob/develop/README.md +license: MIT diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/css/.gitkeep b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/css/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/js/.gitkeep b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/js/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/screenshot.jpg b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/screenshot.jpg new file mode 100644 index 000000000..e37871b43 Binary files /dev/null and b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/screenshot.jpg differ diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/templates/.gitkeep b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/templates/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/theme.php.twig b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/theme.php.twig new file mode 100644 index 000000000..9bdfe8a59 --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/theme/inheritence/theme.php.twig @@ -0,0 +1,9 @@ + ul > li > a { + border-radius: 2px; +} + +/*Active dropdown nav item */ +.main-nav ul li:hover > a { + background-color: #175E91; +} + +/* Selected Dropdown nav item */ +.main-nav ul li.selected > a { + background-color: #fff; + color: #175E91; +} + +/* Dropdown CSS */ +.main-nav ul li {position: relative;} + +.main-nav ul li ul { + position: absolute; + background-color: #1F8DD6; + min-width: 100%; + text-align: left; + z-index: 999; + + display: none; +} +.main-nav ul li ul li { + display: block; +} + +/* Dropdown CSS */ +.main-nav ul li ul ul { + left: 100%; + top: 0; +} + +/* Active on Hover */ +.main-nav li:hover > ul { + display: block; +} + +/* Child Indicator */ +.main-nav .has-children > a { + padding-right: 30px; +} +.main-nav .has-children > a:after { + font-family: FontAwesome; + content: '\f107'; + position: absolute; + display: inline-block; + right: 8px; + top: 0; +} + +.main-nav .has-children .has-children > a:after { + content: '\f105'; +} diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/fonts/.gitkeep b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/fonts/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/images/logo.png b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/images/logo.png new file mode 100644 index 000000000..64be1a963 Binary files /dev/null and b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/images/logo.png differ diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/js/.gitkeep b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/js/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/screenshot.jpg b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/screenshot.jpg new file mode 100644 index 000000000..e37871b43 Binary files /dev/null and b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/screenshot.jpg differ diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/default.html.twig b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/default.html.twig new file mode 100644 index 000000000..4dd67b693 --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/default.html.twig @@ -0,0 +1,5 @@ +{% extends 'partials/base.html.twig' %} + +{% block content %} + {{ page.content }} +{% endblock %} diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/error.html.twig b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/error.html.twig new file mode 100644 index 000000000..31117fe41 --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/error.html.twig @@ -0,0 +1,8 @@ +{% extends 'partials/base.html.twig' %} + +{% block content %} +
+

Errror!

+ {{ page.content }} +
+{% endblock %} diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/partials/base.html.twig b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/partials/base.html.twig new file mode 100644 index 000000000..858ad9b7e --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/partials/base.html.twig @@ -0,0 +1,68 @@ +{% set theme_config = attribute(config.themes, config.system.pages.theme) %} + + + +{% block head %} + + {% if header.title %}{{ header.title|e('html') }} | {% endif %}{{ site.title|e('html') }} + + + + {% include 'partials/metadata.html.twig' %} + + + + + {% block stylesheets %} + {% do assets.addCss('http://yui.yahooapis.com/pure/0.6.0/pure-min.css', 100) %} + {% do assets.addCss('https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css', 99) %} + {% do assets.addCss('theme://css/custom.css', 98) %} + {% endblock %} + {{ assets.css() }} + + {% block javascripts %} + {% do assets.addJs('jquery', 100) %} + {% endblock %} + {{ assets.js() }} + +{% endblock head%} + + + +{% block header %} +
+
+ + {% block header_navigation %} + + {% endblock %} +
+
+{% endblock %} + +{% block body %} +
+
+ {% block content %}{% endblock %} +
+
+{% endblock %} + +{% block footer %} + +{% endblock %} + +{% block bottom %} + {{ assets.js('bottom') }} +{% endblock %} + + diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/partials/header.html.twig b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/partials/header.html.twig new file mode 100644 index 000000000..3ea12975a --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/partials/header.html.twig @@ -0,0 +1,23 @@ + diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/partials/metadata.html.twig b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/partials/metadata.html.twig new file mode 100644 index 000000000..2f08a0e5a --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/partials/metadata.html.twig @@ -0,0 +1,3 @@ +{% for meta in page.metadata %} + +{% endfor %} diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/partials/navigation.html.twig b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/partials/navigation.html.twig new file mode 100644 index 000000000..fa4b71fd4 --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/templates/partials/navigation.html.twig @@ -0,0 +1,48 @@ +{% macro loop(page) %} + {% for p in page.children.visible %} + {% set current_page = (p.active or p.activeChild) ? 'selected' : '' %} + {% if p.children.visible.count > 0 %} +
  • + + {% if p.header.icon %}{% endif %} + {{ p.menu }} + + +
  • + {% else %} +
  • + + {% if p.header.icon %}{% endif %} + {{ p.menu }} + +
  • + {% endif %} + {% endfor %} +{% endmacro %} + + + diff --git a/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/theme.php.twig b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/theme.php.twig new file mode 100644 index 000000000..9bdfe8a59 --- /dev/null +++ b/system/src/Grav/Console/Cli/DevTools/components/theme/pure-blank/theme.php.twig @@ -0,0 +1,9 @@ +findResource('plugins://' . $package . DS . 'blueprints.yaml'); + if (!file_exists($blueprints_path)) { // theme? + $blueprints_path = $locator->findResource('themes://' . $package . DS . 'blueprints.yaml'); + if (!file_exists($blueprints_path)) { + continue; + } + } + + $package_yaml = Yaml::parse(file_get_contents($blueprints_path)); + $currentlyInstalledVersion = $package_yaml['version']; + + if (!$currentlyInstalledVersion) { + continue; + } + $installed = $this->gpm->findPackage($package); if ($installed) { $name = $installed->name; - $version = $installed->version; if ($this->gpm->isUpdatable($package)) { $updatable = ' [updatable: v' . $installed->available . ']'; @@ -84,7 +101,7 @@ class VersionCommand extends ConsoleCommand $updatable = $updatable ?: ''; if ($installed || $package == 'grav') { - $this->output->writeln('You are running ' . $name . ' v' . $version . '' . $updatable); + $this->output->writeln('You are running ' . $name . ' v' . $currentlyInstalledVersion . '' . $updatable); } else { $this->output->writeln('Package ' . $package . ' not found'); } diff --git a/tests/unit/Grav/Common/AssetsTest.php b/tests/unit/Grav/Common/AssetsTest.php index 4d0cfb533..3e4aa905b 100644 --- a/tests/unit/Grav/Common/AssetsTest.php +++ b/tests/unit/Grav/Common/AssetsTest.php @@ -71,6 +71,12 @@ class AssetsTest extends \Codeception\TestCase\Test 'group' => 'head' ], reset($array)); + //test addCss() adding asset to a separate group, and with an alternate rel attribute + $this->assets->reset(); + $this->assets->addCSS('test.css', ['group' => 'alternate']); + $css = $this->assets->css('alternate', ['rel' => 'alternate']); + $this->assertSame('' . PHP_EOL, $css); + //test addJs() $this->assets->reset(); $this->assets->addJs('test.js'); diff --git a/tests/unit/Grav/Common/UriTest.php b/tests/unit/Grav/Common/UriTest.php index 70887da46..d2299ac06 100644 --- a/tests/unit/Grav/Common/UriTest.php +++ b/tests/unit/Grav/Common/UriTest.php @@ -273,19 +273,16 @@ class UriTest extends \Codeception\TestCase\Test public function testEnvironment() { - $address = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '::1'; - if ($this->uri->host() == 'localhost' || $address == '::1' || $address == '127.0.0.1') { - $address = 'localhost'; - } - $this->uri->initializeWithURL('http://localhost/a-page')->init(); - $this->assertSame($address, $this->uri->environment()); + $this->assertSame('localhost', $this->uri->environment()); + $this->uri->initializeWithURL('http://127.0.0.1/a-page')->init(); + $this->assertSame('localhost', $this->uri->environment()); $this->uri->initializeWithURL('http://localhost:8080/a-page')->init(); - $this->assertSame($address, $this->uri->environment()); + $this->assertSame('localhost', $this->uri->environment()); $this->uri->initializeWithURL('http://foobar.it:443/a-page')->init(); - $this->assertSame($address, $this->uri->environment()); + $this->assertSame('foobar.it', $this->uri->environment()); $this->uri->initializeWithURL('https://google.com/a-page')->init(); - $this->assertSame($address, $this->uri->environment()); + $this->assertSame('google.com', $this->uri->environment()); } public function testBasename() diff --git a/webserver-configs/Caddyfile b/webserver-configs/Caddyfile index 014017c93..682947087 100644 --- a/webserver-configs/Caddyfile +++ b/webserver-configs/Caddyfile @@ -1,8 +1,31 @@ :8080 gzip fastcgi / 127.0.0.1:9000 php + +# Begin - Security +# deny all direct access for these folders rewrite { - regexp .* - ext / - to /index.php?_url={uri} + r /(.git|cache|bin|logs|backups|tests)/.*$ + status 403 +} +# deny running scripts inside core system folders +rewrite { + r /(system|vendor)/.*\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$ + status 403 +} +# deny running scripts inside user folder +rewrite { + r /user/.*\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ + status 403 +} +# deny access to specific files in the root folder +rewrite { + r /(LICENSE.txt|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess) + status 403 +} +## End - Security + +# global rewrite should come last. +rewrite { + to {path} {path}/ /index.php?_url={uri} }