1 <?php
2
3 /*
4 * This file is part of the Icybee package.
5 *
6 * (c) Olivier Laviale <olivier.laviale@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Icybee\Modules\Pages;
13
14 use ICanBoogie\Event;
15 use Brickrouge\Element;
16
17 /**
18 * BreadcrumbElement
19 * =================
20 *
21 * Renders a _location_ breadcumb, showing where the page is located in the website hierarchy.
22 *
23 * A breadcrumb is a navigation aid. It allows users to keep track of their locations within the
24 * website. A breadcrumb typically appears horizontally across the top of a web page, usually
25 * below title bars or headers. It provides links to the parent pages of the current one. The
26 * SINGLE RIGHT-POINTING ANGLE QUOTATION MARK character (›) serves as hierarchy separator.
27 *
28 * The breadcrumb element is made of slices. In each slice there is a link to the page of the slice
29 * unless the slice if the last one in which case the in a strong element.
30 *
31 * The breadcrumb is an OL element and each of its slice is a LI element.
32 *
33 *
34 * Event: render_inner_html:before
35 * -------------------------------
36 *
37 * Fired before the inner HTML of the element is rendered.
38 *
39 * ### Signature
40 *
41 * before_render_inner_html($event, $sender);
42 *
43 * ### Arguments
44 *
45 * * event - (ICanBoogie\Event) An event object with the following properties:
46 * * slices - (&array) The slices of the breadcrumb
47 * * separator - (&string) The separator for the slices.
48 * * page - (Icybee\Modules\Pages\Page) The current page object.
49 *
50 * * target - {@link BreadcrumbElement} The breadcrumb element that fired the event.
51 *
52 *
53 * Event: render_inner_html
54 * ------------------------
55 *
56 * Fired when the inner HTML of the element has been rendered.
57 *
58 * ### Signature
59 *
60 * on_render_inner_html($event, $sender);
61 *
62 * ### Arguments
63 *
64 * * event - (ICanBoogie\Event) An event object with the following properties:
65 * * rc - (&string) The rendered inner HTML.
66 * * page - (Icybee\Modules\Pages\Page) The current page object.
67 *
68 * * sender - {@link BreadcrumbElement} The breadcrumb element that fired the event.
69 *
70 */
71 class BreadcrumbElement extends Element
72 {
73 const PAGE = '#breadcrumb-page';
74 const DIVIDER = '#breadcrumb-divider';
75
76 const DEFAULT_DIVIDER = '›';
77
78 /**
79 * Returns the breadcrumb for the current page.
80 *
81 * The breadcrumb is build and rendered using the #{@link \Brickrouge\Element\Breadcrumb}
82 * element.
83 *
84 * @param array $args
85 * @param \Patron\Engine $patron
86 * @param array|string $template
87 *
88 * @return string
89 */
90 static public function markup()
91 {
92 global $core;
93
94 return new static
95 (
96 array
97 (
98 self::PAGE => $core->request->context->page
99 )
100 );
101 }
102
103 public function __construct($tags)
104 {
105 parent::__construct
106 (
107 'ol', $tags + array
108 (
109 self::DIVIDER => self::DEFAULT_DIVIDER,
110
111 'class' => 'breadcrumb'
112 )
113 );
114 }
115
116 protected function render_inner_html()
117 {
118 $page = $node = $this[self::PAGE];
119 $slices = array();
120
121 while ($node)
122 {
123 $url = $node->url;
124 $label = $node->label;
125 $label = \ICanBoogie\shorten($label, 48);
126 $label = \Brickrouge\escape($label);
127
128 $slices[] = array
129 (
130 'url' => $url,
131 'label' => $label,
132 'class' => $node->css_class('-type -slug -template -constructor -node-id -node-constructor'),
133 'page' => $node
134 );
135
136 if (!$node->parent && !$node->is_home)
137 {
138 $node = $node->home;
139 }
140 else
141 {
142 $node = $node->parent;
143 }
144 }
145
146 $slices = array_reverse($slices);
147 $divider = $this[self::DIVIDER] ?: self::DEFAULT_DIVIDER;
148
149 new BreadcrumbElement\BeforeRenderInnerHTMLEvent
150 (
151 $this, array
152 (
153 'slices' => &$slices,
154 'divider' => &$divider,
155 'page' => $page
156 )
157 );
158
159 $html = '';
160 $slices = array_values($slices);
161 $last = count($slices) - 1;
162
163 foreach ($slices as $i => $slice)
164 {
165 $html .= '<li class="' . $slice['class'] . '">';
166
167 if ($i)
168 {
169 $html .= '<span class="divider">' . $divider . '</span>';
170 }
171
172 $class = \Brickrouge\escape($slice['class']);
173 $label = \Brickrouge\escape($slice['label']);
174
175 if ($i != $last)
176 {
177 $html .= '<a href="' . \Brickrouge\escape($slice['url']) . '" class="' . $class . '">' . $label . '</a>';
178 }
179 else
180 {
181 $html .= '<strong class="' . $class . '">' . $label . '</strong>';
182 }
183
184 $html .= '</li>';
185 }
186
187 new BreadcrumbElement\RenderInnerHTMLEvent
188 (
189 $this, array
190 (
191 'html' => &$html,
192 'page' => $page
193 )
194 );
195
196 return $html;
197 }
198 }
199
200 namespace Icybee\Modules\Pages\BreadcrumbElement;
201
202 /**
203 * Event class for the `Icybee\Modules\Pages\BreadcrumbElement::render_inner_html:before`
204 * event.
205 */
206 class BeforeRenderInnerHTMLEvent extends \ICanBoogie\Event
207 {
208 /**
209 * Reference to the slices array.
210 *
211 * @var array
212 */
213 public $slices;
214
215 /**
216 * Reference to the divider.
217 *
218 * @var string
219 */
220 public $divider;
221
222 /**
223 * The page for which the breadcrumb is computed.
224 *
225 * @var \Icybee\Modules\Pages\Page.
226 */
227 public $page;
228
229 /**
230 * The event is constructed with the type `render_inner_html:before`.
231 *
232 * @param \Icybee\Modules\Pages\BreadcrumbElement $target
233 * @param array $payload
234 */
235 public function __construct(\Icybee\Modules\Pages\BreadcrumbElement $target, array $payload)
236 {
237 parent::__construct($target, 'render_inner_html:before', $payload);
238 }
239 }
240
241 /**
242 * Event class for the `Icybee\Modules\Pages\BreadcrumbElement::render_inner_html`
243 * event.
244 */
245 class RenderInnerHTMLEvent extends \ICanBoogie\Event
246 {
247 /**
248 * Reference to the inner HTML.
249 *
250 * @var string
251 */
252 public $html;
253
254 /**
255 * The page for which the breadcrumb is computed.
256 *
257 * @var \Icybee\Modules\Pages\Page.
258 */
259 public $page;
260
261 /**
262 * The event is constructed with the type `render_inner_html`.
263 *
264 * @param \Icybee\Modules\Pages\BreadcrumbElement $target
265 * @param array $payload
266 */
267 public function __construct(\Icybee\Modules\Pages\BreadcrumbElement $target, array $payload)
268 {
269 parent::__construct($target, 'render_inner_html', $payload);
270 }
271 }