Skip to content

Commit cada178

Browse files
committed
Allow panel with headings without title.
1 parent ea2361f commit cada178

File tree

1 file changed

+133
-20
lines changed

1 file changed

+133
-20
lines changed

src/View/Helper/BootstrapPanelHelper.php

Lines changed: 133 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,56 @@ class BootstrapPanelHelper extends Helper {
3232

3333
public $current = NULL ;
3434

35+
/* Protected attributes used to generate ID for collapsible panels. */
36+
protected $_panelCount = 0;
37+
protected $_bodyId = null;
38+
protected $_headId = null;
39+
40+
/* Default value for "collapsible" option. */
41+
protected $_defaultCollapsible = false;
42+
43+
/* Protected attribute used to generate group ID. */
44+
protected $_groupCount = 0;
45+
protected $_groupId = false;
46+
47+
protected $_groupPanelCount = 0;
48+
protected $_groupPanelOpen = 0;
49+
50+
protected $_lastPanelClosed = true;
51+
protected $_autoCloseOnCreate = false;
52+
53+
protected $_collapsible = false;
54+
55+
public function startGroup($options = []) {
56+
$options += [
57+
'class' => '',
58+
'role' => 'tablist',
59+
'aria-multiselectable' => true,
60+
'id' => 'panelGroup-'.(++$this->_groupCount),
61+
'collapsible' => true,
62+
'open' => 0
63+
];
64+
$this->_defaultCollapsible = $options['collapsible'];
65+
$this->_autoCloseOnCreate = true;
66+
$this->_lastPanelClosed = true;
67+
$this->_groupPanelCount = -1;
68+
$this->_groupPanelOpen = $options['open'];
69+
$this->_groupId = $options['id'];
70+
$options = $this->addClass($options, 'panel-group');
71+
$class = $options['class'];
72+
unset($options['class'], $options['open'], $options['collapsible']);
73+
return $this->Html->div($class, null, $options);
74+
}
75+
76+
public function endGroup() {
77+
$this->_defaultCollapsible = false;
78+
$out = '';
79+
if (!$this->_lastPanelClosed) {
80+
$out = $this->end();
81+
}
82+
return $out.'</div>';
83+
}
84+
3585
/**
3686
*
3787
* Create a Twitter Bootstrap like panel.
@@ -45,28 +95,52 @@ class BootstrapPanelHelper extends Helper {
4595
public function create($title = null, $options = []) {
4696

4797
if (is_array($title)) {
48-
$options = $title ;
98+
$options = $title;
4999
}
50100

51-
$nobody = $this->_extractOption('no-body', $options, false);
52-
unset ($options['no-body']);
53-
$type = $this->_extractOption('type', $options, 'default');
54-
unset ($options['type']);
101+
$options += [
102+
'no-body' => false,
103+
'type' => 'default',
104+
'collapsible' => $this->_defaultCollapsible
105+
];
106+
107+
$nobody = $options['no-body'];
108+
$type = $options['type'];
109+
$this->_collapsible = $options['collapsible'];
110+
unset ($options['no-body'], $options['collapsible'], $options['type']);
55111

56112
$options = $this->addClass($options, ['panel', 'panel-'.$type]);
113+
114+
if ($this->_collapsible) {
115+
$this->_headId = 'heading-'.($this->_panelCount);
116+
$this->_bodyId = 'collapse-'.($this->_panelCount);
117+
$this->_panelCount++;
118+
}
119+
57120
$class = $options['class'];
58121
unset ($options['class']);
59122

60-
$res = $this->Html->div($class, null, $options);
123+
$out = '';
124+
125+
if ($this->_autoCloseOnCreate && !$this->_lastPanelClosed) {
126+
$out .= $this->end();
127+
}
128+
$this->_lastPanelClosed = false;
129+
130+
/* Increment panel counter for the current group. */
131+
$this->_groupPanelCount++;
132+
133+
$out .= $this->Html->div($class, null, $options);
61134
if (is_string($title) && $title) {
62-
$res .= $this->_createHeader($title, [
135+
$out .= $this->_createHeader($title, [
63136
'title' => isset($options['title']) ? $options['title'] : true
64137
]) ;
65138
if (!$nobody) {
66-
$res .= $this->_startPart('body');
139+
$out .= $this->_startPart('body');
67140
}
68141
}
69-
return $res ;
142+
143+
return $out ;
70144
}
71145

72146
/**
@@ -79,11 +153,9 @@ public function create($title = null, $options = []) {
79153
*
80154
**/
81155
public function end ($title = null, $options = []) {
156+
$this->_lastPanelClosed = true;
82157
$res = '' ;
83-
if ($this->current != null) {
84-
$this->current = null ;
85-
$res .= $this->_endPart();
86-
}
158+
$res .= $this->_cleanCurrent();
87159
if ($title !== null) {
88160
$res .= $this->footer($title, $options) ;
89161
}
@@ -92,36 +164,64 @@ public function end ($title = null, $options = []) {
92164
}
93165

94166
protected function _cleanCurrent () {
167+
$res = '';
95168
if ($this->current) {
169+
$res = $this->_endPart();
96170
$this->current = NULL ;
97-
return $this->_endPart();
98171
}
99-
return '' ;
172+
return $res;
100173
}
101174

102175
protected function _createHeader ($title, $options = [], $titleOptions = []) {
103176
if (empty($titleOptions)) {
104177
$titleOptions = $options['title'] ;
105178
}
106179
unset ($options['title']);
180+
$options = $this->addClass($options, 'panel-heading');
181+
$class = $options['class'];
182+
unset ($options['class']);
183+
if ($this->_collapsible) {
184+
$options += [
185+
'role' => 'tab',
186+
'id' => $this->_headId
187+
];
188+
$this->_headId = $options['id'];
189+
$title = $this->Html->link($title, '#'.$this->_bodyId, [
190+
'data-toggle' => 'collapse',
191+
'data-parent' => $this->_groupId ? '#'.$this->_groupId : false,
192+
'aria-expanded' => true,
193+
'aria-controls' => '#'.$this->_bodyId
194+
]);
195+
}
107196
if ($titleOptions !== false) {
108197
if (!is_array($titleOptions)) {
109198
$titleOptions = [];
110199
}
200+
$titleOptions += ['tag' => 'h4'];
111201
$titleOptions = $this->addClass($titleOptions, 'panel-title');
112-
$title = $titleOptions ? $this->Html->tag('h3', $title, $titleOptions) : $title;
202+
$tag = $titleOptions['tag'];
203+
unset($titleOptions['tag']);
204+
$title = $titleOptions ? $this->Html->tag($tag, $title, $titleOptions) : $title;
113205
}
114-
$options = $this->addClass($options, 'panel-heading');
115-
$class = $options['class'];
116-
unset ($options['class']);
117206
return $this->_cleanCurrent().$this->Html->div($class, $title, $options);
118207
}
119208

120209
protected function _createBody ($text, $options = []) {
121210
$options = $this->addClass($options, 'panel-body');
122211
$class = $options['class'];
123212
unset ($options['class']);
124-
return $this->_cleanCurrent().$this->Html->div($class, $text, $options) ;
213+
$body = $this->Html->div($class, $text, $options);
214+
if ($this->_collapsible) {
215+
$open = ((is_int($this->_groupPanelOpen)
216+
&& $this->_groupPanelOpen == $this->_groupPanelCount)
217+
|| $this->_groupPanelOpen == $this->_bodyId) ? ' in' : '';
218+
$body = $this->Html->div('panel-collapse collapse'.$open, $body, [
219+
'role' => 'tabpanel',
220+
'aria-labelledby' => $this->_headId,
221+
'id' => $this->_bodyId
222+
]);
223+
}
224+
return $this->_cleanCurrent().$body ;
125225
}
126226

127227
protected function _createFooter ($text = null, $options = []) {
@@ -137,12 +237,25 @@ protected function _startPart ($part, $options = []) {
137237
$res = $this->_endPart () ;
138238
}
139239
$this->current = $part ;
240+
if ($this->_collapsible && $this->current == 'body') {
241+
$open = ((is_int($this->_groupPanelOpen)
242+
&& $this->_groupPanelOpen === $this->_groupPanelCount)
243+
|| $this->_groupPanelOpen === $this->_bodyId) ? ' in' : '';
244+
$res .= $this->Html->div('panel-collapse collapse'.$open, null, [
245+
'role' => 'tabpanel',
246+
'aria-labelledby' => $this->_headId,
247+
'id' => $this->_bodyId
248+
]);
249+
}
140250
return $res.$this->Html->div('panel-'.$part.' '.$this->_extractOption('class',
141251
$options, ''),
142252
null, $options) ;
143253
}
144254

145255
protected function _endPart () {
256+
if ($this->_collapsible && $this->current == 'body') {
257+
return '</div></div>';
258+
}
146259
return '</div>' ;
147260
}
148261

0 commit comments

Comments
 (0)