Skip to content

Instantly share code, notes, and snippets.

@ikkez
Last active August 29, 2015 14:05
Show Gist options
  • Save ikkez/ef2cfaa3009c439ea484 to your computer and use it in GitHub Desktop.
Save ikkez/ef2cfaa3009c439ea484 to your computer and use it in GitHub Desktop.
F3 Asset Manager
<html>
<head>
<title>F3 Asset Manager</title>
</head>
<body>
<h1>Asset Collector</h1>
<F3:include href="templates/assets_widget.html" />
<F3:asset type="css" src="foo/main.css" key="5" />
</body>
</html>
<?php
/**
Asset manager for the PHP Fat-Free Framework
The contents of this file are subject to the terms of the GNU General
Public License Version 3.0. You may not use this file except in
compliance with the license. Any of the license terms and conditions
can be waived if you get permission from the copyright holder.
Copyright (c) 2014 by ikkez
Christian Knuth <ikkez0n3@gmail.com>
@version 0.3.0
@date: 08.08.2014
**/
class Assets extends Prefab {
/** @var \Template */
protected $template;
/** @var array */
protected $assets;
public function __construct($autoAddMarker=false) {
$this->template = \Template::instance();
$f3 = \Base::instance();
$this->reset();
if($autoAddMarker) {
$this->template->extend('head', 'Assets::render_head');
$this->template->extend('body', 'Assets::render_body');
}
$this->template->extend('asset', 'Assets::add');
$this->template->afterrender(function($data) use ($f3) {
$data=str_replace('{>ASSETS-HEAD<}',$f3->call('\Assets->getAssets','head'),$data);
$data=str_replace('{>ASSETS-FOOTER<}', $f3->call('\Assets->getAssets','footer'),$data);
return $data;
});
}
/**
* reset form handler data
*/
public function reset() {
$this->assets = array();
}
/**
* get asset code from slot
* @param string $slot
* @return string
*/
public function getAssets($slot='head') {
if(!isset($this->assets[$slot]))
return '';
ksort($this->assets[$slot]);
return implode("\n",$this->assets[$slot])."\n";
}
/**
* add asset code to slot
* @param string $code
* @param string $slot
* @param mixed $priority
*/
public function addAsset($code,$slot='head',$priority=null) {
if(!isset($this->assets[$slot]))
$this->assets[$slot]=array();
if($priority)
$this->assets[$slot][$priority] = ($slot=='head'?"\t":'').$code;
else
$this->assets[$slot][] = ($slot=='head'?"\t":'').$code;
}
/**
* parse node data and push new asset code
* @param $node
* @return mixed
*/
public function _asset($node)
{
$node = \Base::instance()->unserialize($node);
$params = $node['@attrib'];
unset($node['@attrib']);
if (array_key_exists('type',$params) && array_key_exists('src',$params)) {
$type = $this->template->resolve($params['type']);
$src = $this->template->resolve($params['src']);
$slot = isset($params['slot']) ? $params['slot'] : 'head';
$prio = isset($params['key']) ? $this->template->resolve($params['key']) : null;
if($type=='css')
$this->addAsset('<link rel="stylesheet" type="text/css" href="'.$src.'" />',
$slot,$prio);
elseif ($type=='js')
$this->addAsset('<script src="'.$src.'"></script>', $slot, $prio);
}
return $this->assets;
}
/**
* auto-append slot marker into <head>
* @param $node
* @return string
*/
public function _head($node)
{
unset($node['@attrib']);
$content = array();
// bypass inner content nodes
foreach ($node as $el)
$content[] = $this->template->build($el);
return '<head>'.implode("\n", $content).'{>ASSETS-HEAD<}</head>';
}
/**
* auto-append footer slot marker into <body>
* @param $node
* @return string
*/
public function _body($node)
{
$params = '';
if (isset($node['@attrib'])) {
$params = $this->resolveAttr($node['@attrib']);
unset($node['@attrib']);
}
$content = array();
// bypass inner content nodes
foreach ($node as $el)
$content[] = $this->template->build($el);
return '<body'.$params.'>'.implode("\n", $content)."\n".'{>ASSETS-FOOTER<}</body>';
}
/**
* general bypass for unhandled tag attributes
* @param array $attr
* @return string
*/
public function resolveAttr(array $attr)
{
$out = '';
foreach ($attr as $key => $value) {
// build dynamic tokens
if (preg_match('/{{(.+?)}}/s', $value))
$value = $this->template->build($value);
if (preg_match('/{{(.+?)}}/s', $key))
$key = $this->template->build($key);
// inline token
if (is_numeric($key))
$out .= ' '.$value;
// value-less parameter
elseif($value==NULL)
$out .= ' '.$key;
// key-value parameter
else
$out .= ' '.$key.'="'.$value.'"';
}
return $out;
}
/**
* handle <asset> template tag
* @param $node
* @return mixed
*/
static public function add(array $node)
{ // dynamic build on final rendering
return '<?php \Assets::instance()->_asset(\''.
\Base::instance()->serialize($node).'\'); ?>';
}
/**
* handle <head> template tag
* @param $node
* @return mixed
*/
static public function render_head(array $node)
{ // static build is enough to insert a marker
$that = \Assets::instance();
return $that->_head($node);
}
/**
* handle <head> template tag
* @param $node
* @return mixed
*/
static public function render_body(array $node)
{ // static build is enough to insert a marker
$that = \Assets::instance();
return $that->_body($node);
}
}
<F3:asset type="{{ @type }}" src="{{ @jq }}" slot="footer" />
<F3:asset type="js" src="js/widget_a.js" slot="footer"/>
<F3:asset type="css" src="js/widget_a.css" key="20" />
<div class="widget_a">
<h3>Widget</h3>
<p>Lorem Ipsun...</p>
</div>
<?php
$f3 = require('lib/base.php');
$f3->route('GET /asset-test', function (Base $f3) {
$f3->set('type','js');
$f3->set('jq','jquery.min.js');
\Assets::instance(true);
echo \Template::instance()->render('templates/assets.html');
});
$f3->run();
@ikkez
Copy link
Author

ikkez commented Aug 13, 2014

This is a draft for an Asset manager plugin for the PHP Fat-Free Framework.

The rendered Output will look like the following:

<html>
<head>
    <title>F3 Asset Manager</title>

    <link rel="stylesheet" type="text/css" href="foo/main.css" />
    <link rel="stylesheet" type="text/css" href="js/widget_a.css" />
</head>
<body>

<h1>Asset Collector</h1>

<div class="widget_a">
    <h3>Widget</h3>
    <p>Lorem Ipsun...</p>
</div>

<script src="jquery.min.js"></script>
<script src="js/widget_a.js"></script>
</body>
</html>

@MINORITYmaN
Copy link

hi ikkez, check my last commit.
https://gist.github.com/MINORITYmaN/57dbc88e4c219f833a9c/revisions
whould leave an html comment if asset file is missing on DEBUG>0 and on DEBUG==0 just skip the insertion.
what do you think about?

regards, Stefano

@ikkez
Copy link
Author

ikkez commented Sep 10, 2014

oh, seems like i have overlook your comment. well nice idea ;)
i'll consider this when i'll come to complete this plugin. there are still some issues with sorting by dependency and the lack of adding remote/external assets from CDNs. and a feature to minify the given files :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment