Skip to content

Instantly share code, notes, and snippets.

@fprochazka
Created December 9, 2010 21:10
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fprochazka/735345 to your computer and use it in GitHub Desktop.
Save fprochazka/735345 to your computer and use it in GitHub Desktop.
Inteligent Head JS (http://headjs.com/) loading component
<?php
namespace Kdyby\Component;
use Nette;
use Nette\String;
use Nette\Web\Html;
use Kdyby;
/**
* @author Filip Procházka <hosiplan@kdyby.org>
*/
class Headjs extends Kdyby\Control\LookoutControl
{
const PACKAGE_FULL = 'head';
const PACKAGE_MIN = 'head.min';
const PACKAGE_LOAD = 'head.load.min';
const EXECUTE_SEQUENCE = 'sequence';
const EXECUTE_PARALEL = 'paralel';
/** @var string */
private $dir;
/** @var array */
private $files = array();
/** @var array */
private $printed = array();
/** @var bool */
private $loaded = FALSE;
/** @var string */
private $package;
/** @var Nette\Caching\Cache */
private $cache;
/**
* @param Nette\Caching\Cache $cache
*/
public function setCache(Nette\Caching\Cache $cache)
{
$this->cache = $cache;
}
/**
* @return Nette\Caching\Cache
*/
public function getCache()
{
return $this->cache;
}
/**
* @param string $package
*/
public function setPackage($package)
{
$this->package = $package;
}
/**
* @return string
*/
public function getPackage()
{
return $this->package;
}
/**
* @param string $dir
*/
public function setJavascriptDir($dir)
{
$this->dir = $dir;
}
/**
* @return string
*/
public function getJavascriptDir()
{
return $this->dir;
}
/**
* @param string $file
*/
public function addScript($file)
{
$this->files[] = $file;
}
public function viewDefault($file1 = NULL, $file2 = NULL, $file3 = NULL)
{
$files = func_get_args();
$package = $this->package ?: self::PACKAGE_MIN;
$this->renderHtml($this->dir . '/' . $package . ".js", $files);
}
public function viewLoad($file1 = NULL, $file2 = NULL, $file3 = NULL)
{
$files = func_get_args();
$package = $this->package ?: self::PACKAGE_MIN;
$this->renderHtml($this->dir . '/' . $package . ".js", $files);
}
/**
* @param string $file
* @return boolean
*/
protected function isRelative($file)
{
return !String::match($file, '~^[a-z0-9]{1,5}:\/\/.+~i');
}
/**
* @param string $string
* @return boolean
*/
protected function isClosure($string)
{
return String::match($string, '~^\s*?function\s*?\(\s*?\)\s*?\{.*?\}\s*?$~i');
}
/**
* @param string $src
* @param array $files
*/
protected function renderHtml($src, $files)
{
if (!$this->loaded) {
echo $this->renderLoad($src), "\n";
$this->loaded = TRUE;
}
$files = array_diff(array_merge($this->files, $files), $this->printed);
if ($files) {
if (count($files) === 1 && $this->isClosure(reset($files))) {
trigger_error(__CLASS__.": won't process function when have no files to load!", E_USER_WARNING);
}
if (!$this->cache || !isset($this->cache[$files])) {
$init = $this->renderInit($files)."\n";
if ($this->cache && !isset($this->cache[$files])) {
$this->cache[$files] = $init;
}
} else {
$init = $this->cache[$files];
}
$this->printed = array_merge($this->printed, $files);
echo $init;
}
}
/**
* @param string $src
* @return string
*/
protected function renderLoad($src)
{
$script = Html::el('script');
$script->type = 'text/javascript';
$script->src = $src;
return (string)$script;
}
/**
* @param array $files
* @param string $execute
* @return string
*/
protected function renderInit(array $files, $execute = self::EXECUTE_SEQUENCE)
{
$script = Html::el('script');
$script->type = 'text/javascript';
$script->src = NULL;
if ($execute === self::EXECUTE_SEQUENCE) {
$chain = array();
foreach ($files as $file) {
if ($this->isClosure($file)) {
$chain[] = trim($file);
} else {
$chain[] = '"'. ($this->isRelative($file) ? $this->dir.'/'.$file : $file) .'"';
}
}
$script->setHtml("\n\thead.js(".implode(', ', $chain).");\n");
} else {
$chain = NULL;
foreach ($files as $file) {
$file = $this->isRelative($file) ? $this->dir . '/' . $file : $file;
$chain .= '.js("'.$file.'")';
}
$script->setHtml("\n\thead".$chain.";\n");
}
return (string)$script;
}
}
<?php
// this class is required for smooth run of Headjs component
namespace Kdyby\Control;
use Nette;
use Nette\String;
class LookoutControl extends Nette\Application\Control
{
/** @var string */
private $view;
/** @var array */
private $renderParams = array();
/** @var array */
private static $methods = array();
/**
* @return array
*/
public function getRenderParams()
{
return $this->renderParams;
}
/**
* @return string
*/
public function getView()
{
return $this->view;
}
/**
* @param string $type
* @param mixed $param
* @return string
*/
final public function render($type = NULL, $param = NULL)
{
$class = get_class($this);
if (!isset(self::$methods[$class])) {
self::$methods[$class] = get_class_methods($this);
}
$this->view = $this->view ?: 'default';
$this->renderParams = $this->renderParams ?: func_get_args();
$viewMethod = 'view' . ucfirst($this->view);
if (in_array('beforeRender', self::$methods[$class])) {
call_user_func_array(array($this, 'beforeRender'), $this->renderParams);
}
$dir = dirname($this->reflection->fileName);
$view = lcfirst($this->view);
$templates = array(
$dir . '/' . $view . '.latte',
$dir . '/' . $view . '.phtml'
);
foreach ($templates as $file){
if (file_exists($file)) {
$this->template->setFile($file);
break;
}
}
ob_start();
call_user_func_array(array($this, $viewMethod), $this->renderParams);
$output = ob_get_clean();
if (!$output && file_exists($file)) { // raw output from function
$output = (string)$this->template;
}
echo $output;
if (in_array('afterRender', self::$methods[$class])) {
call_user_func_array(array($this, 'afterRender'), $this->renderParams);
}
$this->view = NULL;
$this->renderParams = array();
}
/**
* Calls self::render($view, $args) instead of nonexisting render<view>($args) methods
* @param string $method
* @param array $args
* @return mixed
*/
public function __call($method, $args)
{
if (String::startsWith($method, 'render')) {
$this->view = substr($method, 6);
$this->renderParams = $args;
return call_user_func(array($this, 'render'));
}
return parent::__call($method, $args);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment