Skip to content

Commit

Permalink
Add {'loading': 'inline'} option for Js and CSS assets (#1377)
Browse files Browse the repository at this point in the history
* Assets.php: Extract common functionaly of addCss() and addJs() into
  addTo(), make css() and js() honor $attributes['loading'],
  make pipelineCss() and pipelineJs() return generated content
  instead of URL depending on new option $returnURL.

* AssetsTest.php: Accept new 'loading' option for CSS, add tests for
  adding and pipelining local and remote assets with inline loading.
  • Loading branch information
OliverO2 authored and rhukster committed Apr 4, 2017
1 parent 4365662 commit f510e13
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 85 deletions.
216 changes: 131 additions & 85 deletions system/src/Grav/Common/Assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,28 +255,32 @@ public function add($asset, $priority = null, $pipeline = true)
}

/**
* Add a CSS asset.
* Add an asset to its assembly.
*
* It checks for duplicates.
* You may add more than one asset passing an array as argument.
* The third argument may alternatively contain an array of options which take precedence over positional
* arguments.
*
* @param mixed $asset
* @param int $priority the priority, bigger comes first
* @param bool $pipeline false if this should not be pipelined
* @param null $group
* @param array $assembly the array assembling the assets
* @param mixed $asset
* @param int $priority the priority, bigger comes first
* @param bool $pipeline false if this should not be pipelined
* @param string $loading how the asset is loaded (async/defer/inline, for CSS: only inline)
* @param string $group name of the group
*
* @return $this
*/
public function addCss($asset, $priority = null, $pipeline = true, $group = null)
public function addTo(&$assembly, $asset, $priority = null, $pipeline = true, $loading = null, $group = null)
{
if (is_array($asset)) {
foreach ($asset as $a) {
$this->addCss($a, $priority, $pipeline, $group);
$this->addTo($assembly, $a, $priority, $pipeline, $loading, $group);
}

return $this;
} elseif (isset($this->collections[$asset])) {
$this->addCss($this->collections[$asset], $priority, $pipeline, $group);
$this->addTo($assembly, $this->collections[$asset], $priority, $pipeline, $loading, $group);

return $this;
}
Expand All @@ -297,33 +301,57 @@ public function addCss($asset, $priority = null, $pipeline = true, $group = null
'asset' => $asset,
'remote' => $remote,
'priority' => intval($priority ?: 10),
'order' => count($this->css),
'order' => count($assembly),
'pipeline' => (bool) $pipeline,
'loading' => $loading ?: '',
'group' => $group ?: 'head',
'modified' => $modified
];

// check for dynamic array and merge with defaults
if (func_num_args() > 1) {
$dynamic_arg = func_get_arg(1);
if (func_num_args() > 2) {
$dynamic_arg = func_get_arg(2);
if (is_array($dynamic_arg)) {
$data = array_merge($data, $dynamic_arg);
}
}

$key = md5($asset);
if ($asset) {
$this->css[$key] = $data;
$assembly[$key] = $data;
}

return $this;
}

/**
* Add a CSS asset.
*
* It checks for duplicates.
* You may add more than one asset passing an array as argument.
* The second argument may alternatively contain an array of options which take precedence over positional
* arguments.
*
* @param mixed $asset
* @param int $priority the priority, bigger comes first
* @param bool $pipeline false if this should not be pipelined
* @param string $group
* @param string $loading how the asset is loaded (async/defer/inline, for CSS: only inline)
*
* @return $this
*/
public function addCss($asset, $priority = null, $pipeline = true, $group = null, $loading = null)
{
return $this->addTo($this->css, $asset, $priority, $pipeline, $loading, $group);
}

/**
* Add a JavaScript asset.
*
* It checks for duplicates.
* You may add more than one asset passing an array as argument.
* The second argument may alternatively contain an array of options which take precedence over positional
* arguments.
*
* @param mixed $asset
* @param int $priority the priority, bigger comes first
Expand All @@ -335,55 +363,7 @@ public function addCss($asset, $priority = null, $pipeline = true, $group = null
*/
public function addJs($asset, $priority = null, $pipeline = true, $loading = null, $group = null)
{
if (is_array($asset)) {
foreach ($asset as $a) {
$this->addJs($a, $priority, $pipeline, $loading, $group);
}

return $this;
} elseif (isset($this->collections[$asset])) {
$this->addJs($this->collections[$asset], $priority, $pipeline, $loading, $group);

return $this;
}

$modified = false;
$remote = $this->isRemoteLink($asset);
if (!$remote) {
$modified = $this->getLastModificationTime($asset);
$asset = $this->buildLocalLink($asset);
}

// Check for existence
if ($asset === false) {
return $this;
}

$data = [
'asset' => $asset,
'remote' => $remote ,
'priority' => intval($priority ?: 10),
'order' => count($this->js),
'pipeline' => (bool) $pipeline,
'loading' => $loading ?: '',
'group' => $group ?: 'head',
'modified' => $modified
];

// check for dynamic array and merge with defaults
if (func_num_args() > 1) {
$dynamic_arg = func_get_arg(1);
if (is_array($dynamic_arg)) {
$data = array_merge($data, $dynamic_arg);
}
}

$key = md5($asset);
if ($asset) {
$this->js[$key] = $data;
}

return $this;
return $this->addTo($this->js, $asset, $priority, $pipeline, $loading, $group);
}

/**
Expand Down Expand Up @@ -547,32 +527,54 @@ public function css($group = 'head', $attributes = [])
$this->css = array_reverse($this->css);
$this->inline_css = array_reverse($this->inline_css);

$inlineGroup = array_key_exists('loading', $attributes) && $attributes['loading'] === 'inline';

$attributes = $this->attributes(array_merge(['type' => 'text/css', 'rel' => 'stylesheet'], $attributes));

$output = '';
$inline_css = '';

if ($this->css_pipeline) {
$pipeline_result = $this->pipelineCss($group);
$pipeline_html = '<link href="' . $pipeline_result . '"' . $attributes . ' />' . "\n";
$pipeline_result = $this->pipelineCss($group, !$inlineGroup);
$pipeline_html = ($inlineGroup ? '' : '<link href="' . $pipeline_result . '"' . $attributes . ' />' . "\n");

if ($this->css_pipeline_before_excludes && $pipeline_result) {
$output .= $pipeline_html;
if ($inlineGroup) {
$inline_css .= $pipeline_result;
}
else {
$output .= $pipeline_html;
}
}
foreach ($this->css_no_pipeline as $file) {
if ($group && $file['group'] == $group) {
$media = isset($file['media']) ? sprintf(' media="%s"', $file['media']) : '';
$output .= '<link href="' . $file['asset'] . $this->getTimestamp($file) . '"' . $attributes . $media . ' />' . "\n";
if ($file['loading'] === 'inline') {
$inline_css .= $this->gatherLinks([$file], CSS_ASSET) . "\n";
}
else {
$media = isset($file['media']) ? sprintf(' media="%s"', $file['media']) : '';
$output .= '<link href="' . $file['asset'] . $this->getTimestamp($file) . '"' . $attributes . $media . ' />' . "\n";
}
}
}
if (!$this->css_pipeline_before_excludes && $pipeline_result) {
$output .= $pipeline_html;
if ($inlineGroup) {
$inline_css .= $pipeline_result;
}
else {
$output .= $pipeline_html;
}
}
} else {
foreach ($this->css as $file) {
if ($group && $file['group'] == $group) {
$media = isset($file['media']) ? sprintf(' media="%s"', $file['media']) : '';
$output .= '<link href="' . $file['asset'] . $this->getTimestamp($file) . '"' . $attributes . $media . ' />' . "\n";
if ($inlineGroup || $file['loading'] === 'inline') {
$inline_css .= $this->gatherLinks([$file], CSS_ASSET) . "\n";
}
else {
$media = isset($file['media']) ? sprintf(' media="%s"', $file['media']) : '';
$output .= '<link href="' . $file['asset'] . $this->getTimestamp($file) . '"' . $attributes . $media . ' />' . "\n";
}
}
}
}
Expand Down Expand Up @@ -626,30 +628,52 @@ public function js($group = 'head', $attributes = [])
$this->js = array_reverse($this->js);
$this->inline_js = array_reverse($this->inline_js);

$inlineGroup = array_key_exists('loading', $attributes) && $attributes['loading'] === 'inline';

$attributes = $this->attributes(array_merge(['type' => 'text/javascript'], $attributes));

$output = '';
$inline_js = '';

if ($this->js_pipeline) {
$pipeline_result = $this->pipelineJs($group);
$pipeline_html = '<script src="' . $pipeline_result . '"' . $attributes . ' ></script>' . "\n";
$pipeline_result = $this->pipelineJs($group, !$inlineGroup);
$pipeline_html = ($inlineGroup ? '' : '<script src="' . $pipeline_result . '"' . $attributes . ' ></script>' . "\n");

if ($this->js_pipeline_before_excludes && $pipeline_result) {
$output .= $pipeline_html;
if ($inlineGroup) {
$inline_js .= $pipeline_result;
}
else {
$output .= $pipeline_html;
}
}
foreach ($this->js_no_pipeline as $file) {
if ($group && $file['group'] == $group) {
$output .= '<script src="' . $file['asset'] . $this->getTimestamp($file) . '"' . $attributes . ' ' . $file['loading'] . '></script>' . "\n";
if ($file['loading'] === 'inline') {
$inline_js .= $this->gatherLinks([$file], JS_ASSET) . "\n";
}
else {
$output .= '<script src="' . $file['asset'] . $this->getTimestamp($file) . '"' . $attributes . ' ' . $file['loading'] . '></script>' . "\n";
}
}
}
if (!$this->js_pipeline_before_excludes && $pipeline_result) {
$output .= $pipeline_html;
if ($inlineGroup) {
$inline_js .= $pipeline_result;
}
else {
$output .= $pipeline_html;
}
}
} else {
foreach ($this->js as $file) {
if ($group && $file['group'] == $group) {
$output .= '<script src="' . $file['asset'] . $this->getTimestamp($file) . '"' . $attributes . ' ' . $file['loading'] . '></script>' . "\n";
if ($inlineGroup || $file['loading'] === 'inline') {
$inline_js .= $this->gatherLinks([$file], JS_ASSET) . "\n";
}
else {
$output .= '<script src="' . $file['asset'] . $this->getTimestamp($file) . '"' . $attributes . ' ' . $file['loading'] . '></script>' . "\n";
}
}
}
}
Expand All @@ -672,10 +696,11 @@ public function js($group = 'head', $attributes = [])
* Minify and concatenate CSS
*
* @param string $group
* @param bool $returnURL true if pipeline should return the URL, otherwise the content
*
* @return bool|string
* @return bool|string URL or generated content if available, else false
*/
protected function pipelineCss($group = 'head')
protected function pipelineCss($group = 'head', $returnURL = true)
{
// temporary list of assets to pipeline
$temp_css = [];
Expand All @@ -695,9 +720,14 @@ protected function pipelineCss($group = 'head')
$this->css_no_pipeline = json_decode(file_get_contents($this->assets_dir . $inline_file), true);
}

// If pipeline exist return it
// If pipeline exist return its URL or content
if (file_exists($this->assets_dir . $file)) {
return $relative_path . $this->getTimestamp();
if ($returnURL) {
return $relative_path . $this->getTimestamp();
}
else {
return file_get_contents($this->assets_dir . $file) . "\n";
}
}

// Remove any non-pipeline files
Expand Down Expand Up @@ -744,7 +774,12 @@ protected function pipelineCss($group = 'head')
if (strlen(trim($buffer)) > 0) {
file_put_contents($this->assets_dir . $file, $buffer);

return $relative_path . $this->getTimestamp();
if ($returnURL) {
return $relative_path . $this->getTimestamp();
}
else {
return $buffer . "\n";
}
} else {
return false;
}
Expand All @@ -754,10 +789,11 @@ protected function pipelineCss($group = 'head')
* Minify and concatenate JS files.
*
* @param string $group
* @param bool $returnURL true if pipeline should return the URL, otherwise the content
*
* @return string
* @return bool|string URL or generated content if available, else false
*/
protected function pipelineJs($group = 'head')
protected function pipelineJs($group = 'head', $returnURL = true)
{
// temporary list of assets to pipeline
$temp_js = [];
Expand All @@ -777,9 +813,14 @@ protected function pipelineJs($group = 'head')
$this->js_no_pipeline = json_decode(file_get_contents($this->assets_dir . $inline_file), true);
}

// If pipeline exist return it
// If pipeline exist return its URL or content
if (file_exists($this->assets_dir . $file)) {
return $relative_path . $this->getTimestamp();
if ($returnURL) {
return $relative_path . $this->getTimestamp();
}
else {
return file_get_contents($this->assets_dir . $file) . "\n";
}
}

// Remove any non-pipeline files
Expand Down Expand Up @@ -816,7 +857,12 @@ protected function pipelineJs($group = 'head')
if (strlen(trim($buffer)) > 0) {
file_put_contents($this->assets_dir . $file, $buffer);

return $relative_path . $this->getTimestamp();
if ($returnURL) {
return $relative_path . $this->getTimestamp();
}
else {
return $buffer . "\n";
}
} else {
return false;
}
Expand Down
Loading

0 comments on commit f510e13

Please sign in to comment.