├── README.md ├── config ├── autoload.php └── template.php ├── demo ├── controllers │ └── welcome.php ├── views │ ├── hero.php │ ├── news.php │ ├── template.php │ └── widgets │ │ └── navigation.php └── widgets │ └── navigation.php ├── libraries └── Template.php └── spark.info /README.md: -------------------------------------------------------------------------------- 1 | CodeIgniter Template Library 2 | ============================ 3 | 4 | This template library for Codeigniter lets you build complex templates using partial views and widgets. It's built with the same method chaining support that we are seeing so often in Codeigniter so it feels familiar. This library loads a template file that uses partial views. These partial view sections are internally represented by Partial Objects managed by the template library. These objects let you modify their content in a user friendly way through method chaining. 5 | 6 | Installation 7 | ------------ 8 | 9 | Copy the files to the corresponding folder in your application folder (or use spark). 10 | 11 | Configuration 12 | ------------- 13 | 14 | In your template.php config file you can change following configuration parameters (optional): 15 | 16 | /* 17 | | ------------------------------------------------------------------- 18 | | Template configuration 19 | | ------------------------------------------------------------------- 20 | | This file will contain the settings for the template library. 21 | | 22 | | 'parser' = if you want your main template file to be parsed, set to TRUE 23 | | 'template' = the filename of the default template file 24 | | 'cache_ttl' = the time all partials should be cache in seconds, 0 means no global caching 25 | */ 26 | 27 | $config['parser'] = FALSE; 28 | $config['template'] = 'template'; 29 | $config['cache_ttl'] = 0; 30 | 31 | If you prefer, you can autoload the library by adjusting your autoload.php file and add 'template' to the $autoload['libraries'] array. 32 | 33 | Template files 34 | -------------- 35 | 36 | Template files are loaded or parsed by Codeigniter and the partials are passed to them as data. You can easily load them like you would normally use data in your view files: 37 | 38 | 39 | <?php echo $title; ?> 40 | 41 | 42 | 43 | 44 | 45 | 46 | Or when parsing is enabled you can use {content} etc. 47 | 48 | However, I prefer to directly call the library's methods from inside the template file to work around php's Undefined variable errors when you are not setting all partials. Calling these methods well replace non-existing partials with empty one's so you don't get any errors: 49 | 50 | 51 | <?php echo $this->template->title; ?> 52 | template->stylesheet; ?> 53 | 54 | 55 | template->content; ?> 56 | 57 | 58 | These variables are in fact Partial Ojects, so you can still manipulate them from inside the template view file like this: 59 | 60 | prepend('My Website - '); ?> 61 | 62 | Partial manipulation methods will always return the partial object itself for further chaining or for displaying. So this is perfectly possible: 63 | 64 | cache(500)->widget('login')->prepend('Login: '); ?> 65 | 66 | Partial manipulation 67 | -------------------- 68 | 69 | Partials have a few handy methods for manipulating their content such as: 70 | 71 | $partial->set() - overwrites the content 72 | $partial->append() - append something 73 | $partial->add() - same as append (alias) 74 | $partial->prepend() - prepend something 75 | $partial->content() - gets the content 76 | $partial->default() - only set content if empty 77 | 78 | You can also load dynamic content inside partials from view files or widgets. The object named partial used in the method chaining below is the name of the partial you want to load the content into. 79 | 80 | $this->template->partial->view() 81 | 82 | Append or overwrite the partial with a view file with parameters. 83 | 84 | $this->template->partial->view('view-file', array(), $overwrite=FALSE); 85 | 86 | Append or overwrite the partial with a parsed view file with parameters. 87 | 88 | $this->template->partial->parse('view-file', array(), $overwrite=FALSE); 89 | 90 | Append or overwrite the partial with a widget's output. 91 | 92 | $this->template->partial->widget('widget-name', array(), $overwrite=FALSE); 93 | 94 | Publishing 95 | ---------- 96 | 97 | The template class only has a few methods. I chose to do this because almost everything can be managed by using the flexible Partial Object. If you want to publish the entire template with the current partials to the output you can use the publish() method. 98 | 99 | You can pass a custom template file and optional data if wanted: 100 | 101 | $this->template->publish('template', array('title'=>'Title is overwritten!')); 102 | 103 | Most of the time this will be empty using the template file from the config: 104 | 105 | $this->template->publish(); 106 | 107 | If you wish to set the template file before publishing, eg. in a controller's constructor: 108 | 109 | $this->template->set_template('template2'); 110 | 111 | Triggers 112 | -------- 113 | 114 | Some partials have built in triggers: 115 | 116 | stylesheet - you only need to pass the url 117 | javascript - you only need to pass the url 118 | meta - will convert the arguments to the right meta tag 119 | title - converts special characters 120 | description - will convert special characters just like the title 121 | 122 | This is an example of what these built in triggers do: 123 | 124 | $this->template->stylesheet->add('stylesheet.css', array('media' => 'all')); 125 | // 126 | 127 | $this->template->javascript->add('script.js'); 128 | // 129 | 130 | $this->template->meta->add('robots', 'index,follow'); 131 | // 132 | 133 | $this->template->title->set('Dad & Son'); 134 | //Dad & Son 135 | 136 | You can set your own triggers for functions or methods for any partial object like this: 137 | 138 | //function 139 | $this->template->partial->bind('strtoupper'); 140 | 141 | //method 142 | $this->template->partial->bind($this->typography, 'auto_typography'); 143 | 144 | This will trigger the function or method whenever you manipulate the partial's content. 145 | 146 | 147 | Widget 148 | ------ 149 | 150 | Widgets are intelligent partial objects. When their content is asked, their display() method is activated which will fill the content using codeigniter or partial object methods. Widgets classes are found inside the application/widgets folder. They extend the main Widget class which has the same methods as the Partial class. This is an example widget: 151 | 152 | /* File: widgets/hero_widget.php */ 153 | class hero_widget extends Widget { 154 | public function display($args = array()) { 155 | $this->load->model('my_model'); 156 | $data = $this->my_model->all(); 157 | 158 | $this->load->view('widgets/hero', $data); 159 | } 160 | } 161 | 162 | And this is loaded from a controller like this: 163 | 164 | $this->template->partial->widget('hero_widget', $args = array()); 165 | 166 | 167 | Caching 168 | ------- 169 | 170 | I did not want to expand the library in all different ways, therefore I implemented a basic caching function using Codeigniter's caching driver. This might slow your code down on simple websites but allows you to use caching for partials just like you would do yourself with Codeigniter's driver. 171 | 172 | You can cache particular partials: 173 | 174 | $this->template->partial->cache(100); 175 | 176 | Or you can cache all partials: 177 | 178 | $this->template->cache(100); 179 | 180 | Both methods have an extra optional identification parameter that you can use to have multiple cache files for different pages: 181 | 182 | $this->template->cache(100, 'frontpage'); 183 | -------------------------------------------------------------------------------- /config/autoload.php: -------------------------------------------------------------------------------- 1 | template->title = 'Welcome!'; 10 | 11 | // Dynamically add a css stylesheet 12 | $this->template->stylesheet->add('http://twitter.github.com/bootstrap/assets/css/bootstrap.css'); 13 | 14 | // Load a view in the content partial 15 | $this->template->content->view('hero', array('title' => 'Hello, world!')); 16 | 17 | $news = array(); // load from model (but using a dummy array here) 18 | $this->template->content->view('news', $news); 19 | 20 | // Set a partial's content 21 | $this->template->footer = 'Made with Twitter Bootstrap'; 22 | 23 | // Publish the template 24 | $this->template->publish(); 25 | } 26 | } -------------------------------------------------------------------------------- /demo/views/hero.php: -------------------------------------------------------------------------------- 1 |
2 |

3 |

This is a template for a simple marketing or informational website. It includes a large callout called the hero unit and three supporting pieces of content. Use it as a starting point to create something more unique.

4 |

Learn more »

5 |
-------------------------------------------------------------------------------- /demo/views/news.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Heading

4 |

Etiam porta sem malesuada magna mollis euismod. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.

5 |

View details »

6 | 7 |
8 |
9 |

Heading

10 |

Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.

11 |

View details »

12 |
13 |
14 | 15 |

Heading

16 |

Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

17 |

View details »

18 |
19 |
-------------------------------------------------------------------------------- /demo/views/template.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <?php echo $this->template->title->default("Default title"); ?> 5 | 6 | 7 | 8 | template->meta; ?> 9 | template->stylesheet; ?> 10 | 11 | 12 | 13 | template->widget("navigation", array('title' => 'Project name')); 16 | ?> 17 | 18 |
19 | 20 | template->content; 23 | ?> 24 | 25 |
26 | 27 | 35 | 36 |
37 | 38 | 39 | template->javascript; ?> 40 | 41 | 42 | -------------------------------------------------------------------------------- /demo/views/widgets/navigation.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/widgets/navigation.php: -------------------------------------------------------------------------------- 1 | view('widgets/navigation', $data); 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /libraries/Template.php: -------------------------------------------------------------------------------- 1 | _ci = & get_instance(); 47 | 48 | // set the default widget path with APPPATH 49 | $this->_widget_path = APPPATH . 'widgets/'; 50 | 51 | if (!empty($config)) { 52 | $this->initialize($config); 53 | } 54 | 55 | log_message('debug', 'Template library initialized'); 56 | } 57 | 58 | /** 59 | * Initialize with configuration array 60 | * @param array $config 61 | * @return Template 62 | */ 63 | public function initialize($config = array()) { 64 | foreach ($config as $key => $val) { 65 | $this->{'_' . $key} = $val; 66 | } 67 | 68 | if ($this->_widget_path == '') { 69 | $this->_widget_path = APPPATH . 'widgets/'; 70 | } 71 | 72 | if ($this->_parser && !class_exists('CI_Parser')) { 73 | $this->_ci->load->library('parser'); 74 | } 75 | } 76 | 77 | /** 78 | * Set a partial's content. This will create a new partial when not existing 79 | * @param string $index 80 | * @param mixed $value 81 | */ 82 | public function __set($name, $value) { 83 | $this->partial($name)->set($value); 84 | } 85 | 86 | /** 87 | * Access to partials for method chaining 88 | * @param string $name 89 | * @return mixed 90 | */ 91 | public function __get($name) { 92 | return $this->partial($name); 93 | } 94 | 95 | /** 96 | * Check if a partial exists 97 | * @param string $index 98 | * @return boolean 99 | */ 100 | public function exists($index) { 101 | return array_key_exists($index, $this->_partials); 102 | } 103 | 104 | /** 105 | * Set the template file 106 | * @param string $template 107 | */ 108 | public function set_template($template) { 109 | $this->_template = $template; 110 | } 111 | 112 | /** 113 | * Publish the template with the current partials 114 | * You can manually pass a template file with extra data, or use the default template from the config file 115 | * @param string $template 116 | * @param array $data 117 | */ 118 | public function publish($template = FALSE, $data = array()) { 119 | if (is_array($template) || is_object($template)) { 120 | $data = $template; 121 | } else if ($template) { 122 | $this->_template = $template; 123 | } 124 | 125 | if (!$this->_template) { 126 | show_error('There was no template file selected for the current template'); 127 | } 128 | 129 | if (is_array($data) || is_object($data)) { 130 | foreach ($data as $name => $content) { 131 | $this->partial($name)->set($content); 132 | } 133 | } 134 | 135 | unset($data); 136 | 137 | if ($this->_parser) { 138 | $this->_ci->parser->parse($this->_template, $this->_partials); 139 | } else { 140 | $this->_ci->load->view($this->_template, $this->_partials); 141 | } 142 | } 143 | 144 | /** 145 | * Create a partial object with an optional default content 146 | * Can be usefull to use straight from the template file 147 | * @param string $name 148 | * @param string $default 149 | * @return Partial 150 | */ 151 | public function partial($name, $default = FALSE) { 152 | if ($this->exists($name)) { 153 | $partial = $this->_partials[$name]; 154 | } else { 155 | // create new partial 156 | $partial = new Partial($name); 157 | if ($this->_cache_ttl) { 158 | $partial->cache($this->_cache_ttl); 159 | } 160 | 161 | // detect local triggers 162 | if (method_exists($this, 'trigger_' . $name)) { 163 | $partial->bind($this, 'trigger_' . $name); 164 | } 165 | 166 | $this->_partials[$name] = $partial; 167 | } 168 | 169 | if (!$partial->content() && $default) { 170 | $partial->set($default); 171 | } 172 | 173 | return $partial; 174 | } 175 | 176 | /** 177 | * Create a widget object with optional parameters 178 | * Can be usefull to use straight from the template file 179 | * @param string $name 180 | * @param array $data 181 | * @return Widget 182 | */ 183 | public function widget($name, $data = array()) { 184 | $class = str_replace('.php', '', trim($name, '/')); 185 | 186 | // determine path and widget class name 187 | $path = $this->_widget_path; 188 | if (($last_slash = strrpos($class, '/')) !== FALSE) { 189 | $path += substr($class, 0, $last_slash); 190 | $class = substr($class, $last_slash + 1); 191 | } 192 | 193 | // new widget 194 | if(!class_exists($class)) { 195 | // try both lowercase and capitalized versions 196 | foreach (array(ucfirst($class), strtolower($class)) as $class) { 197 | if (file_exists($path . $class . '.php')) { 198 | include_once ($path . $class . '.php'); 199 | 200 | // found the file, stop looking 201 | break; 202 | } 203 | } 204 | } 205 | 206 | if (!class_exists($class)) { 207 | show_error("Widget '" . $class . "' was not found."); 208 | } 209 | 210 | return new $class($class, $data); 211 | } 212 | 213 | /** 214 | * Enable cache for all partials with TTL, default TTL is 60 215 | * @param int $ttl 216 | * @param mixed $identifier 217 | */ 218 | public function cache($ttl = 60, $identifier = '') { 219 | foreach ($this->_partials as $partial) { 220 | $partial->cache($ttl, $identifier); 221 | } 222 | 223 | $this->_cache_ttl = $ttl; 224 | } 225 | 226 | // ---- TRIGGERS ----------------------------------------------------------------- 227 | 228 | /** 229 | * Stylesheet trigger 230 | * @param string $source 231 | */ 232 | public function trigger_stylesheet($url, $attributes = FALSE) { 233 | // array support 234 | if (is_array($url)) { 235 | $return = ''; 236 | foreach ($url as $u) { 237 | $return .= $this->trigger_stylesheet($u, $attributes); 238 | } 239 | return $return; 240 | } 241 | 242 | if (!stristr($url, 'http://') && !stristr($url, 'https://') && substr($url, 0, 2) != '//') { 243 | $url = $this->_ci->config->item('base_url') . $url; 244 | } 245 | 246 | // legacy support for media 247 | if (is_string($attributes)) { 248 | $attributes = array('media' => $attributes); 249 | } 250 | 251 | if (is_array($attributes)) { 252 | $attributeString = ""; 253 | 254 | foreach ($attributes as $key => $value) { 255 | $attributeString .= $key . '="' . $value . '" '; 256 | } 257 | 258 | return '' . "\n\t"; 259 | } else { 260 | return '' . "\n\t"; 261 | } 262 | } 263 | 264 | /** 265 | * Javascript trigger 266 | * @param string $source 267 | */ 268 | public function trigger_javascript($url) { 269 | // array support 270 | if (is_array($url)) { 271 | $return = ''; 272 | foreach ($url as $u) { 273 | $return .= $this->trigger_javascript($u); 274 | } 275 | return $return; 276 | } 277 | 278 | if (!stristr($url, 'http://') && !stristr($url, 'https://') && substr($url, 0, 2) != '//') { 279 | $url = $this->_ci->config->item('base_url') . $url; 280 | } 281 | 282 | return '' . "\n\t"; 283 | } 284 | 285 | /** 286 | * Meta trigger 287 | * @param string $name 288 | * @param mixed $value 289 | * @param enum $type 290 | */ 291 | public function trigger_meta($name, $value, $type = 'meta') { 292 | $name = htmlspecialchars(strip_tags($name)); 293 | $value = htmlspecialchars(strip_tags($value)); 294 | 295 | if ($name == 'keywords' and !strpos($value, ',')) { 296 | $content = preg_replace('/[\s]+/', ', ', trim($value)); 297 | } 298 | 299 | switch ($type) { 300 | case 'meta' : 301 | $content = '' . "\n\t"; 302 | break; 303 | case 'link' : 304 | $content = '' . "\n\t"; 305 | break; 306 | } 307 | 308 | return $content; 309 | } 310 | 311 | /** 312 | * Title trigger, keeps it clean 313 | * @param string $name 314 | * @param mixed $value 315 | * @param enum $type 316 | */ 317 | public function trigger_title($title) { 318 | return htmlspecialchars(strip_tags($title)); 319 | } 320 | 321 | /** 322 | * Title trigger, keeps it clean 323 | * @param string $name 324 | * @param mixed $value 325 | * @param enum $type 326 | */ 327 | public function trigger_description($description) { 328 | return htmlspecialchars(strip_tags($description)); 329 | } 330 | 331 | } 332 | 333 | class Partial { 334 | 335 | protected $_ci, $_content, $_name, $_cache_ttl = 0, $_cached = false, $_identifier, $_trigger; 336 | protected $_args = array(); 337 | 338 | /** 339 | * Construct with optional parameters 340 | * @param array $args 341 | */ 342 | public function __construct($name, $args = array()) { 343 | $this->_ci = &get_instance(); 344 | $this->_args = $args; 345 | $this->_name = $name; 346 | } 347 | 348 | /** 349 | * Gives access to codeigniter's functions from this class if needed 350 | * This will be handy in extending classes 351 | * @param string $index 352 | */ 353 | function __get($name) { 354 | return $this->_ci->$name; 355 | } 356 | 357 | /** 358 | * Alias methods 359 | */ 360 | function __call($name, $args) { 361 | switch ($name) { 362 | case 'default' : 363 | return call_user_func_array(array($this, 'set_default'), $args); 364 | break; 365 | case 'add' : 366 | return call_user_func_array(array($this, 'append'), $args); 367 | break; 368 | } 369 | } 370 | 371 | /** 372 | * Returns the content when converted to a string 373 | * @return string 374 | */ 375 | public function __toString() { 376 | return (string) $this->content(); 377 | } 378 | 379 | /** 380 | * Returns the content 381 | * @return string 382 | */ 383 | public function content() { 384 | if ($this->_cache_ttl && !$this->_cached) { 385 | $this->cache->save($this->cache_id(), $this->_content, $this->_cache_ttl); 386 | } 387 | 388 | return $this->_content; 389 | } 390 | 391 | /** 392 | * Overwrite the content 393 | * @param mixed $content 394 | * @return Partial 395 | */ 396 | public function set() { 397 | if (!$this->_cached) { 398 | $this->_content = (string) $this->trigger(func_get_args()); 399 | } 400 | 401 | return $this; 402 | } 403 | 404 | /** 405 | * Append something to the content 406 | * @param mixed $content 407 | * @return Partial 408 | */ 409 | public function append() { 410 | if (!$this->_cached) { 411 | $this->_content .= (string) $this->trigger(func_get_args()); 412 | } 413 | 414 | return $this; 415 | } 416 | 417 | /** 418 | * Prepend something to the content 419 | * @param mixed $content 420 | * @return Partial 421 | */ 422 | public function prepend() { 423 | if (!$this->_cached) { 424 | $this->_content = (string) $this->trigger(func_get_args()) . $this->_content; 425 | } 426 | 427 | return $this; 428 | } 429 | 430 | /** 431 | * Set content if partial is empty 432 | * @param mixed $default 433 | * @return Partial 434 | */ 435 | public function set_default($default) { 436 | if (!$this->_cached) { 437 | if (!$this->_content) { 438 | $this->_content = $default; 439 | } 440 | } 441 | 442 | return $this; 443 | } 444 | 445 | /** 446 | * Load a view inside this partial, overwrite if wanted 447 | * @param string $view 448 | * @param array $data 449 | * @param bool $overwrite 450 | * @return Partial 451 | */ 452 | public function view($view, $data = array(), $overwrite = false) { 453 | if (!$this->_cached) { 454 | 455 | // better object to array 456 | if (is_object($data)) { 457 | $array = array(); 458 | foreach ($data as $k => $v) { 459 | $array[$k] = $v; 460 | } 461 | $data = $array; 462 | } 463 | 464 | $content = $this->_ci->load->view($view, $data, true); 465 | 466 | if ($overwrite) { 467 | $this->set($content); 468 | } else { 469 | $this->append($content); 470 | } 471 | } 472 | return $this; 473 | } 474 | 475 | /** 476 | * Parses a view inside this partial, overwrite if wanted 477 | * @param string $view 478 | * @param array $data 479 | * @param bool $overwrite 480 | * @return Partial 481 | */ 482 | public function parse($view, $data = array(), $overwrite = false) { 483 | if (!$this->_cached) { 484 | if (!class_exists('CI_Parser')) { 485 | $this->_ci->load->library('parser'); 486 | } 487 | 488 | // better object to array 489 | if (is_object($data)) { 490 | $array = array(); 491 | foreach ($data as $k => $v) { 492 | $array[$k] = $v; 493 | } 494 | $data = $array; 495 | } 496 | 497 | $content = $this->_ci->parser->parse($view, $data, true); 498 | 499 | if ($overwrite) { 500 | $this->set($content); 501 | } else { 502 | $this->append($content); 503 | } 504 | } 505 | 506 | return $this; 507 | } 508 | 509 | /** 510 | * Loads a widget inside this partial, overwrite if wanted 511 | * @param string $name 512 | * @param array $data 513 | * @param bool $overwrite 514 | * @return Partial 515 | */ 516 | public function widget($name, $data = array(), $overwrite = false) { 517 | if (!$this->_cached) { 518 | $widget = $this->template->widget($name, $data); 519 | 520 | if ($overwrite) { 521 | $this->set($widget->content()); 522 | } else { 523 | $this->append($widget->content()); 524 | } 525 | } 526 | return $this; 527 | } 528 | 529 | /** 530 | * Enable cache with TTL, default TTL is 60 531 | * @param int $ttl 532 | * @param mixed $identifier 533 | */ 534 | public function cache($ttl = 60, $identifier = '') { 535 | if (!class_exists('CI_Cache')) { 536 | $this->_ci->load->driver('cache', array('adapter' => 'file')); 537 | } 538 | 539 | $this->_cache_ttl = $ttl; 540 | $this->_identifier = $identifier; 541 | 542 | if ($cached = $this->_ci->cache->get($this->cache_id())) { 543 | $this->_cached = true; 544 | $this->_content = $cached; 545 | } 546 | return $this; 547 | } 548 | 549 | /** 550 | * Used for cache identification 551 | * @return string 552 | */ 553 | private function cache_id() { 554 | if ($this->_identifier) { 555 | return $this->_name . '_' . $this->_identifier . '_' . md5(get_class($this) . implode('', $this->_args)); 556 | } else { 557 | return $this->_name . '_' . md5(get_class($this) . implode('', $this->_args)); 558 | } 559 | } 560 | 561 | /** 562 | * Trigger returns the result if a trigger is set 563 | * @param array $args 564 | * @return string 565 | */ 566 | public function trigger($args) { 567 | if (!$this->_trigger) { 568 | return implode('', $args); 569 | } else { 570 | return call_user_func_array($this->_trigger, $args); 571 | } 572 | } 573 | 574 | /** 575 | * Bind a trigger function 576 | * Can be used like bind($this, "function") or bind("function") 577 | * @param mixed $arg 578 | */ 579 | public function bind() { 580 | if ($count = func_num_args()) { 581 | if ($count >= 2) { 582 | $args = func_get_args(); 583 | $obj = array_shift($args); 584 | $func = array_pop($args); 585 | 586 | foreach ($args as $trigger) { 587 | $obj = $obj->$trigger; 588 | } 589 | 590 | $this->_trigger = array($obj, $func); 591 | } else { 592 | $args = func_get_args(); 593 | $this->_trigger = reset($args); 594 | } 595 | } else { 596 | $this->_trigger = FALSE; 597 | } 598 | } 599 | } 600 | 601 | class Widget extends Partial { 602 | 603 | /* (non-PHPdoc) 604 | * @see Partial::content() 605 | */ 606 | public function content() { 607 | if (!$this->_cached) { 608 | if (method_exists($this, 'display')) { 609 | // capture output 610 | ob_start(); 611 | $this->display($this->_args); 612 | $buffer = ob_get_clean(); 613 | 614 | // if no content is produced but there was direct ouput we set 615 | // that output as content 616 | if (!$this->_content && $buffer) { 617 | $this->set($buffer); 618 | } 619 | } 620 | } 621 | 622 | return parent::content(); 623 | } 624 | } 625 | -------------------------------------------------------------------------------- /spark.info: -------------------------------------------------------------------------------- 1 | # This is the spark-sdk specification. It's in a magical format without a name. 2 | # Use this format while developing your own sparks! 3 | 4 | # This is the spark name. This should be the registered name of the spark. 5 | # It's only used for informational purposes. 6 | name: friendly-template 7 | 8 | # This is the current version of this spark. All sparks should be in 9 | # x.x.x format. Validation will fail otherwise. This is the version 10 | # that will appear on the website. 11 | version: 1.2.1 12 | 13 | # This is the version of CodeIgniter this spark is compatible up to. It should 14 | # be in x.x.x format 15 | compatibility: 2.1.0 16 | 17 | # These are other sparks which this spark needs in order to work correctly. 18 | # Dependencies should be in NAME: VERSION format, where NAME is an existing 19 | # spark name, and VERSION is a version in x.x.x format. 20 | # This is optional, so comment it out if it's unneeded 21 | #dependencies: 22 | # spark-1: 1.0.0 23 | # spark-2: 1.0.0 24 | 25 | # These are tags to associate your spark with 26 | tags: ["template", "parse", "partial", "layout", "chaining", "nesting"] --------------------------------------------------------------------------------