Skip to content

Commit dc41609

Browse files
committed
Add support for list tag helpers, and convert other helpers to use them
Also add support for pill-style navigation in tabs helper Add method hook for creating unknown tags by default, removes need for p() and h4() Add note about Font Awesome version dependency
1 parent bef5813 commit dc41609

File tree

1 file changed

+68
-18
lines changed

1 file changed

+68
-18
lines changed

bootstrap.phphelper.php

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
* TwitterBootstrapPHPHelper Class
44
*
55
* Helper class to create HTML that's nicely compliant with Twitter Bootstrap v2.3.2 -- http://twitter.github.io/bootstrap/
6-
* Intended to work with Font Awesome -- http://fortawesome.github.io/Font-Awesome/
6+
* Intended to work with Font Awesome v3.2.1 -- http://fortawesome.github.io/Font-Awesome/
77
*
88
* @author Leith Caldwell
99
* @copyright Copyright (c) 2013, Leith Caldwell
1010
* @license http://creativecommons.org/licenses/by-sa/3.0/deed.en_US CC BY-SA 3.0
11-
* @version 0.6.8
11+
* @version 0.7.0
1212
*/
1313
class TwitterBootstrapPHPHelper {
1414
public $content;
@@ -77,6 +77,27 @@ private static function check_id($opts = array()) {
7777
if (!empty($opts->name) && empty($opts->id)) $opts->id = self::id_for_name($opts->name, $opts->value);
7878
return $opts;
7979
}
80+
81+
/**
82+
* Method hook for when called method is undefined, assume a regular tag
83+
*
84+
* @param string $name The tag name
85+
* @param array $arguments The content and options passed to the tag; ignores any other parameters
86+
* @return string $html
87+
*/
88+
public function __call($name, $arguments) {
89+
// intentionally fall through and add defaults as we go
90+
switch (count($arguments)) {
91+
case 0: $arguments = array("");
92+
case 1: $arguments += array(1 => array());
93+
case 2:
94+
default: list($text, $opts) = $arguments;
95+
}
96+
$html = self::tag($name, $text, $opts);
97+
$this->store($html, $opts);
98+
return $html;
99+
}
100+
80101
/* explain() isn't strictly Bootstrap, but provides a nice (?) icon for use with JS .popover() */
81102
public static function explain($content, $opts = array()) {
82103
$html = '';
@@ -146,11 +167,33 @@ public function heading($text, $opts = array()) { return self::_heading('h2
146167
public function subheading($text, $opts = array()) { return self::_heading('h3', $text, array('class' => 'subheading'.(isset($opts['class']) ? ' '.$opts['class'] : '')) + $opts); }
147168

148169

149-
/* standard tags */
150-
public function p($text, $opts = array()) { $html = self::tag('p', $text, $opts); $this->store($html, $opts); return $html; }
151-
public function h4($text, $opts = array()) { $html = self::tag('h4', $text, $opts); $this->store($html, $opts); return $html; }
170+
/* standard tags not covered by method hook */
152171
public function img($src, $opts = array()) { $html = self::tag_open('img', $opts + array('src' => $src)); $this->store($html, $opts); return $html; }
153172

173+
/**
174+
* @param string $tag
175+
* @param array $items List of items, either HTML string, or ['content' => "HTML", 'opts' => []]
176+
*/
177+
private function _list($tag, $items = array(), $opts = array()) {
178+
$opts = self::apply_defaults($opts, array(
179+
'class' => '',
180+
'item_opts' => array(),
181+
));
182+
183+
$html = self::tag_open($tag, array('class' => $opts->class));
184+
foreach ($items as $key => $item) {
185+
if (is_array($item)) $item = (object)$item;
186+
$content = is_object($item) ? $item->content : $item;
187+
$item_opts = self::apply_defaults(is_object($item) ? $item->opts : array(), $opts->item_opts);
188+
$html .= self::tag('li', $content, $item_opts);
189+
}
190+
$html .= "</$tag>";
191+
$this->store($html, $opts);
192+
return $html;
193+
}
194+
public function ol($items, $opts = array()) { return self::_list('ol', $items, $opts); }
195+
public function ul($items, $opts = array()) { return self::_list('ul', $items, $opts); }
196+
154197
public function gap($opts = array()) { $html = '<br>'; $this->store($html, $opts); return $html; }
155198
public function clear($opts = array()) {
156199
$opts = self::apply_defaults($opts, array(
@@ -203,18 +246,19 @@ public function thumbnails($thumbs, $opts = array()) {
203246
// TODO : convert to generic validation call
204247
if (!in_array($opts->active, $thumb_ids)) $opts->active = reset($thumb_ids);
205248

206-
$html = self::tag_open('ul', array('class' => 'thumbnails clearfix'));
207-
$html .= $this->hidden($opts->name, $opts->active, array('return_only' => true));
249+
$html = $this->hidden($opts->name, $opts->active, array('return_only' => true));
250+
$items = array();
208251
foreach ($thumbs as $thumb_id => $thumb) {
209-
$html .= self::tag_open('li', array(
210-
'class' => 'span3 selectable'.($thumb_id == $opts->active ? ' selected' : '').(empty($thumb->disabled) ? '' : ' muted'),
211-
'data-value' => $thumb_id,
212-
'data-input' => self::id_for_name($opts->name),
213-
));
214-
$html .= $this->thumbnail((array)$thumb + array('size' => $opts->size, 'alt' => $thumb->name, 'return_only' => true));
215-
$html .= "</li>";
252+
$items[] = array(
253+
'content' => $this->thumbnail((array)$thumb + array('size' => $opts->size, 'alt' => $thumb->name, 'return_only' => true)),
254+
'opts' => array(
255+
'class' => 'span3 selectable'.($thumb_id == $opts->active ? ' selected' : '').(empty($thumb->disabled) ? '' : ' muted'),
256+
'data-value' => $thumb_id,
257+
'data-input' => self::id_for_name($opts->name),
258+
)
259+
);
216260
}
217-
$html .= '</ul>';
261+
$html .= self::ul($items, array('class' => 'thumbnails clearfix', 'return_only' => true));
218262

219263
$this->store($html, $opts);
220264
return $html;
@@ -225,6 +269,7 @@ public function tabs_open($tabs, $opts = array()) {
225269
if (!empty($tab_ids)) array_walk($tabs, function(&$v,&$k) { $k = 'tab_'.$k; });
226270

227271
$opts = self::apply_defaults($opts, array(
272+
'type' => 'tabs',
228273
'direction' => 'above',
229274
'active' => reset($tab_ids), // first id -- TODO : somehow store active tab?
230275
));
@@ -233,13 +278,18 @@ public function tabs_open($tabs, $opts = array()) {
233278

234279
// TODO : convert to generic validation call
235280
if (!in_array($opts->direction, array('','above','left','right','below'))) $opts->direction = 'above';
281+
if (!in_array($opts->type, array('tabs','pills'))) $opts->type = 'tabs';
236282

237283
$html = "<div class='tabbable".($opts->direction == 'above' || $opts->direction == '' ? '' : 'tabs-'.$opts->direction)."'>";
238-
$html .= self::tag_open('ul', array('class' => 'nav nav-tabs'));
284+
285+
$items = array();
239286
foreach ($tabs as $key => $title) {
240-
$html .= self::tag('li', self::tag('a', $title, array('href' => '#tab_'.$key, 'data-toggle' => 'tab')), $key == $opts->active ? array('class' => 'active') : array());
287+
$items[] = array(
288+
'content' => self::tag('a', $title, array('href' => '#tab_'.$key, 'data-toggle' => substr($opts->type, 0, -1))),
289+
'opts' => $key == $opts->active ? array('class' => 'active') : array()
290+
);
241291
}
242-
$html .= "</ul>";
292+
$html .= self::ul($items, array('class' => 'nav nav-'.$opts->type, 'return_only' => true));
243293
$html .= self::tag_open('div', array('class' => 'tab-content'));
244294

245295
$this->store($html, $opts);

0 commit comments

Comments
 (0)