diff --git a/.travis.yml b/.travis.yml index 2a2b5d695..578da9f7f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,11 @@ script: FILES="$RT_DEVTOOLS/grav-dist/*.zip"; for file in ${FILES[@]}; do NAME=${file##*/}; - REPO="$(echo ${NAME} | rev | cut -f 2- -d "-" | rev)"; + if [[ "$NAME" == *"-rc"* ]]; then + REPO="$(echo ${NAME} | rev | cut -f 3- -d "-" | rev)"; + else + REPO="$(echo ${NAME} | rev | cut -f 2- -d "-" | rev)"; + fi; if [[ $REPO == 'grav' || $REPO == 'grav-admin' || $REPO == 'grav-update' ]]; then REPO="grav"; fi; @@ -60,7 +64,7 @@ script: ASSETS="$(echo "${API}" | node gh-assets.js)"; TAG="$(echo "${API}" | grep tag_name | head -n 1 | cut -d '"' -f 4)"; if [ $REPO == "grav" ]; then - TAG=$TRAVIS_TAG; + TAG="$TRAVIS_TAG"; fi; if [ ! -z "$ASSETS" ]; then for asset in ${ASSETS[@]}; do diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cb97d31d..fa91a22cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,23 @@ +# v1.0.0-rc.2 +## 10/27/2015 + +1. [](#new) + * Added support for CSS Asset groups + * Added a `wrapped_site` system option for themes/plugins to use + * Pass `Page` object as event to `onTwigPageVariables()` event hook + * New `Data.items()` method to get all items +1. [](#improved) + * Missing pipelined remote asset will now fail quietly + * More reliably handle inline JS and CSS to remove only surrounding HTML tags + * `Medium.meta` returns new Data object so null checks are possible + * Improved Medium metadata merging to allow for automatic title/alt/class attributes + * Moved Grav object to global variable rather than template variable (useful for macros) + * German language improvements + * Updated bundled composer +1. [](#bugfix) + * Accept variety of `true` values in `User.authorize()` method + * Fix for `Validation` throwing an error if no label set + # v1.0.0-rc.1 ## 10/23/2015 @@ -18,7 +38,7 @@ 1. [](#improved) * Moved hardcoded mimetypes to `media.yaml` to be treated as Page media files * Set `errors: display: false` by default in `system.yaml` - * Strip out extra slashes in the URI + * Strip out extra slashes in the URI * Validate hostname to ensure it is valid * Ignore more SCM folders in Backups * Removed `home_redirect` settings from `system.yaml` @@ -29,7 +49,7 @@ * Debugbar vendor library update * Always fallback to english if other translations are not available 1. [](#bugfix) - * Fix for redirecting external URL with multi-language + * Fix for redirecting external URL with multi-language * Fix for Asset pipeline not respecting asset groups * Fix language files with child/parent theme relationships * Fixed a regression issue resulting in incorrect default language diff --git a/bin/composer.phar b/bin/composer.phar index deead1618..72b1546b2 100755 Binary files a/bin/composer.phar and b/bin/composer.phar differ diff --git a/system/blueprints/config/system.yaml b/system/blueprints/config/system.yaml index fca66cd30..b17fc3605 100644 --- a/system/blueprints/config/system.yaml +++ b/system/blueprints/config/system.yaml @@ -750,6 +750,17 @@ form: underline: true fields: + wrapped_site: + type: toggle + label: PLUGIN_ADMIN.WRAPPED_SITE + highlight: 0 + help: PLUGIN_ADMIN.WRAPPED_SITE_HELP + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + absolute_urls: type: toggle label: PLUGIN_ADMIN.ABSOLUTE_URLS diff --git a/system/config/system.yaml b/system/config/system.yaml index 366d1e549..443788d67 100644 --- a/system/config/system.yaml +++ b/system/config/system.yaml @@ -2,6 +2,7 @@ absolute_urls: false # Absolute or relative URLs for `base_url timezone: '' # Valid values: http://php.net/manual/en/timezones.php default_locale: # Default locale (defaults to system) param_sep: ':' # Parameter separator, use ';' for Apache on windows +wrapped_site: false # For themes/plugins to know if Grav is wrapped by another platform languages: supported: [] # List of languages supported. eg: [en, fr, de] diff --git a/system/defines.php b/system/defines.php index 2adc2b99e..b3d9c06e4 100644 --- a/system/defines.php +++ b/system/defines.php @@ -2,7 +2,7 @@ // Some standard defines define('GRAV', true); -define('GRAV_VERSION', '1.0.0-rc.1'); +define('GRAV_VERSION', '1.0.0-rc.2'); define('DS', '/'); // Directories and Paths diff --git a/system/languages/de.yaml b/system/languages/de.yaml index 7cdc5d8e8..798e14d10 100644 --- a/system/languages/de.yaml +++ b/system/languages/de.yaml @@ -1,43 +1,43 @@ INFLECTOR_IRREGULAR: - 'person': 'personen' - 'man': 'menschen' - 'child': 'kinder' - 'sex': 'geschlecht' - 'move': 'züge' + 'person': 'Personen' + 'man': 'Menschen' + 'child': 'Kinder' + 'sex': 'Geschlecht' + 'move': 'Züge' NICETIME: NO_DATE_PROVIDED: Keine Daten vorhanden BAD_DATE: Falsches Datum AGO: her FROM_NOW: ab jetzt - SECOND: sekunde - MINUTE: minute - HOUR: stunde - DAY: tag - WEEK: woche - MONTH: monat - YEAR: jahr - DECADE: dekade + SECOND: Sekunde + MINUTE: Minute + HOUR: Stunde + DAY: Tag + WEEK: Woche + MONTH: Monat + YEAR: Jahr + DECADE: Dekade SEC: sek MIN: min HR: std - DAY: tag + DAY: Tag WK: wo MO: mo YR: yh DEC: dec - SECOND_PLURAL: sekunden - MINUTE_PLURAL: minuten - HOUR_PLURAL: stunden - DAY_PLURAL: tage - WEEK_PLURAL: wochen - MONTH_PLURAL: monate - YEAR_PLURAL: jahre - DECADE_PLURAL: dekaden - SEC_PLURAL: sekunden - MIN_PLURAL: minuten - HR_PLURAL: stunden - DAY_PLURAL: tage - WK_PLURAL: wochen - MO_PLURAL: monate - YR_PLURAL: jahre - DEC_PLURAL: dekaden + SECOND_PLURAL: Sekunden + MINUTE_PLURAL: Minuten + HOUR_PLURAL: Stunden + DAY_PLURAL: Tage + WEEK_PLURAL: Wochen + MONTH_PLURAL: Monate + YEAR_PLURAL: Jahre + DECADE_PLURAL: Dekaden + SEC_PLURAL: Sekunden + MIN_PLURAL: Minuten + HR_PLURAL: Stunden + DAY_PLURAL: Tage + WK_PLURAL: Wochen + MO_PLURAL: Monate + YR_PLURAL: Jahre + DEC_PLURAL: Dekaden diff --git a/system/src/Grav/Common/Assets.php b/system/src/Grav/Common/Assets.php index 14a9161ef..f1a61b349 100644 --- a/system/src/Grav/Common/Assets.php +++ b/system/src/Grav/Common/Assets.php @@ -42,6 +42,8 @@ class Assets /** @const Regex to match CSS import content */ const CSS_IMPORT_REGEX = '{@import(.*);}'; + const HTML_TAG_REGEX = '#(<([A-Z][A-Z0-9]*)>)+(.*)(<\/\2>)#is'; + /** * Closure used by the pipeline to fetch assets. @@ -227,21 +229,22 @@ class Assets * It checks for duplicates. * You may add more than one asset passing an array as argument. * - * @param mixed $asset - * @param int $priority the priority, bigger comes first - * @param bool $pipeline false if this should not be pipelined + * @param mixed $asset + * @param int $priority the priority, bigger comes first + * @param bool $pipeline false if this should not be pipelined + * @param null $group * * @return $this */ - public function addCss($asset, $priority = null, $pipeline = null) + public function addCss($asset, $priority = null, $pipeline = null, $group = null) { if (is_array($asset)) { foreach ($asset as $a) { - $this->addCss($a, $priority, $pipeline); + $this->addCss($a, $priority, $pipeline, $group); } return $this; } elseif (isset($this->collections[$asset])) { - $this->add($this->collections[$asset], $priority, $pipeline); + $this->add($this->collections[$asset], $priority, $pipeline, $group); return $this; } @@ -253,7 +256,8 @@ class Assets 'asset' => $asset, 'priority' => intval($priority ?: 10), 'order' => count($this->css), - 'pipeline' => $pipeline ?: true + 'pipeline' => $pipeline ?: true, + 'group' => $group ?: 'head' ]; // check for dynamic array and merge with defaults @@ -369,20 +373,27 @@ class Assets * For adding chunks of string-based inline CSS * * @param mixed $asset - * @param int $priority the priority, bigger comes first + * @param int $priority the priority, bigger comes first + * @param null $group * * @return $this */ - public function addInlineCss($asset, $priority = null) + public function addInlineCss($asset, $priority = null, $group = null) { + $asset = trim($asset); + if (is_a($asset, 'Twig_Markup')) { - $asset = strip_tags((string)$asset); + preg_match(self::HTML_TAG_REGEX, $asset, $matches ); + if (isset($matches[3])) { + $asset = $matches[3]; + } } $data = [ 'priority' => intval($priority ?: 10), 'order' => count($this->inline_css), - 'asset' => $asset + 'asset' => $asset, + 'group' => $group ?: 'head' ]; // check for dynamic array and merge with defaults @@ -416,8 +427,13 @@ class Assets */ public function addInlineJs($asset, $priority = null, $group = null) { + $asset = trim($asset); + if (is_a($asset, 'Twig_Markup')) { - $asset = strip_tags((string)$asset); + preg_match(self::HTML_TAG_REGEX, $asset, $matches ); + if (isset($matches[3])) { + $asset = $matches[3]; + } } $data = [ @@ -447,11 +463,12 @@ class Assets /** * Build the CSS link tags. * + * @param string $group name of the group * @param array $attributes * * @return string */ - public function css($attributes = []) + public function css($group = 'head', $attributes = []) { if (!$this->css) { return null; @@ -479,29 +496,37 @@ class Assets $attributes = $this->attributes(array_merge(['type' => 'text/css', 'rel' => 'stylesheet'], $attributes)); $output = ''; + $inline_css = ''; + if ($this->css_pipeline) { - $pipeline_result = $this->pipelineCss(); + $pipeline_result = $this->pipelineCss($group); if ($pipeline_result) { $output .= '' . "\n"; } foreach ($this->css_no_pipeline as $file) { - $media = isset($file['media']) ? sprintf(' media="%s"', $file['media']) : ''; - $output .= '' . "\n"; + if ($group && $file['group'] == $group) { + $media = isset($file['media']) ? sprintf(' media="%s"', $file['media']) : ''; + $output .= '' . "\n"; + } } } else { foreach ($this->css as $file) { - $media = isset($file['media']) ? sprintf(' media="%s"', $file['media']) : ''; - $output .= '' . "\n"; + if ($group && $file['group'] == $group) { + $media = isset($file['media']) ? sprintf(' media="%s"', $file['media']) : ''; + $output .= '' . "\n"; + } } } // Render Inline CSS - if (count($this->inline_css) > 0) { - $output .= "\n"; + } + + if ($inline_css) { + $output .= "\n\n"; } @@ -582,7 +607,7 @@ class Assets * * @return string */ - protected function pipelineCss() + protected function pipelineCss($group = 'head') { /** @var Cache $cache */ $cache = self::getGrav()['cache']; @@ -594,7 +619,7 @@ class Assets // clear no-pipeline assets lists $this->css_no_pipeline = []; - $file = md5(json_encode($this->css) . $this->css_minify . $this->css_rewrite) . '.css'; + $file = md5(json_encode($this->css) . $this->css_minify . $this->css_rewrite . $group) . '.css'; $relative_path = "{$this->base_url}" . basename(ASSETS_DIR) . "/{$file}"; $absolute_path = ASSETS_DIR . $file; @@ -606,10 +631,12 @@ class Assets // Remove any non-pipeline files foreach ($this->css as $id => $asset) { - if (!$asset['pipeline']) { - $this->css_no_pipeline[$id] = $asset; - } else { - $temp_css[$id] = $asset; + if ($asset['group'] == $group) { + if (!$asset['pipeline']) { + $this->css_no_pipeline[$id] = $asset; + } else { + $temp_css[$id] = $asset; + } } } @@ -930,6 +957,7 @@ class Assets * Download and concatenate the content of several links. * * @param array $links + * @param bool $css * * @return string */ @@ -960,7 +988,12 @@ class Assets $link = ROOT_DIR . $relative_path; } - $file = ($this->fetch_command instanceof Closure) ? $this->fetch_command->__invoke($link) : file_get_contents($link); + $file = ($this->fetch_command instanceof Closure) ? @$this->fetch_command->__invoke($link) : @file_get_contents($link); + + // No file found, skip it... + if ($file === false) { + continue; + } // Double check last character being if (!$css) { diff --git a/system/src/Grav/Common/Data/Data.php b/system/src/Grav/Common/Data/Data.php index 6a35fbc9e..2a12eb22d 100644 --- a/system/src/Grav/Common/Data/Data.php +++ b/system/src/Grav/Common/Data/Data.php @@ -224,6 +224,16 @@ class Data implements DataInterface return $this->file()->raw(); } + /** + * Return the data items. + * + * @return array + */ + public function items() + { + return $this->items; + } + /** * Set or get the data storage. * diff --git a/system/src/Grav/Common/Data/Validation.php b/system/src/Grav/Common/Data/Validation.php index 1ad2f22a4..8bdc064af 100644 --- a/system/src/Grav/Common/Data/Validation.php +++ b/system/src/Grav/Common/Data/Validation.php @@ -36,7 +36,7 @@ class Validation // Validate type with fallback type text. $type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type']; $method = 'type'.strtr($type, '-', '_'); - $name = ucfirst($field['label'] ? $field['label'] : $field['name']); + $name = ucfirst(isset($field['label']) ? $field['label'] : $field['name']); $message = (string) isset($field['validate']['message']) ? $field['validate']['message'] : 'Invalid input in "' . $language->translate($name) . '""'; if (method_exists(__CLASS__, $method)) { diff --git a/system/src/Grav/Common/Page/Medium/Medium.php b/system/src/Grav/Common/Page/Medium/Medium.php index cf15863cf..d3d3e6298 100644 --- a/system/src/Grav/Common/Page/Medium/Medium.php +++ b/system/src/Grav/Common/Page/Medium/Medium.php @@ -68,6 +68,16 @@ class Medium extends Data implements RenderableInterface $this->reset(); } + /** + * Return just metadata from the Medium object + * + * @return $this + */ + public function meta() + { + return new Data($this->items); + } + /** * Add meta file for the medium. * @@ -203,9 +213,29 @@ class Medium extends Data implements RenderableInterface } $attributes['style'] = $style; - !empty($title) && empty($attributes['title']) && $attributes['title'] = $title; - !empty($alt) && empty($attributes['alt']) && $attributes['alt'] = $alt; - !empty($class) && empty($attributes['class']) && $attributes['class'] = $class; + if (empty($attributes['title'])) { + if (!empty($title)) { + $attributes['title'] = $title; + } elseif (!empty($this->items['title'])) { + $attributes['title'] = $this->items['title']; + } + } + + if (empty($attributes['alt'])) { + if (!empty($alt)) { + $attributes['alt'] = $alt; + } elseif (!empty($this->items['alt'])) { + $attributes['alt'] = $this->items['alt']; + } + } + + if (empty($attributes['class'])) { + if (!empty($class)) { + $attributes['class'] = $class; + } elseif (!empty($this->items['class'])) { + $attributes['class'] = $this->items['class']; + } + } switch ($this->mode) { case 'text': @@ -376,8 +406,6 @@ class Medium extends Data implements RenderableInterface $this->querystring($this->querystring(null, false) . '&' . $qs); } - self::$grav['debugger']->addMessage($this->querystring()); - return $this; } diff --git a/system/src/Grav/Common/Twig/Twig.php b/system/src/Grav/Common/Twig/Twig.php index 5b2319561..381efe56f 100644 --- a/system/src/Grav/Common/Twig/Twig.php +++ b/system/src/Grav/Common/Twig/Twig.php @@ -7,6 +7,7 @@ use Grav\Common\Page\Page; use Grav\Common\Inflector; use Grav\Common\Utils; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; +use RocketTheme\Toolbox\Event\Event; /** * The Twig object handles all the Twig template rendering for Grav. It's a singleton object @@ -142,7 +143,6 @@ class Twig // Set some standard variables for twig $this->twig_vars = array( - 'grav' => $this->grav, 'config' => $config, 'uri' => $this->grav['uri'], 'base_dir' => rtrim(ROOT_DIR, '/'), @@ -202,7 +202,7 @@ class Twig $content = $content !== null ? $content : $item->content(); // override the twig header vars for local resolution - $this->grav->fireEvent('onTwigPageVariables'); + $this->grav->fireEvent('onTwigPageVariables', new Event(['page' => $item])); $twig_vars = $this->twig_vars; $twig_vars['page'] = $item; diff --git a/system/src/Grav/Common/Twig/TwigExtension.php b/system/src/Grav/Common/Twig/TwigExtension.php index 9424e8f87..2da411210 100644 --- a/system/src/Grav/Common/Twig/TwigExtension.php +++ b/system/src/Grav/Common/Twig/TwigExtension.php @@ -36,6 +36,18 @@ class TwigExtension extends \Twig_Extension return 'GravTwigExtension'; } + /** + * Register some standard globals + * + * @return array + */ + public function getGlobals() + { + return array( + 'grav' => $this->grav, + ); + } + /** * Return a list of all filters. * diff --git a/system/src/Grav/Common/User/User.php b/system/src/Grav/Common/User/User.php index 21cd61c38..e11be723a 100644 --- a/system/src/Grav/Common/User/User.php +++ b/system/src/Grav/Common/User/User.php @@ -5,6 +5,7 @@ use Grav\Common\Data\Blueprints; use Grav\Common\Data\Data; use Grav\Common\File\CompiledYamlFile; use Grav\Common\GravTrait; +use Grav\Common\Utils; /** * User object @@ -138,7 +139,7 @@ class User extends Data return false; } - return $this->get("access.{$action}") === true; + return Utils::isPositive($this->get("access.{$action}")); } /** diff --git a/system/src/Grav/Common/Utils.php b/system/src/Grav/Common/Utils.php index c0b15af44..8c55669a2 100644 --- a/system/src/Grav/Common/Utils.php +++ b/system/src/Grav/Common/Utils.php @@ -377,4 +377,14 @@ abstract class Utils } } + /** + * Checks if a value is positive + * + * @param string $value + * + * @return boolean + */ + public static function isPositive($value) { + return in_array($value, [true, 1, '1', 'yes', 'on', 'true'], true); + } }