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;
13
14 use ICanBoogie\Debug;
15 use ICanBoogie\Event;
16 use ICanBoogie\Events;
17 use ICanBoogie\Exception;
18 use ICanBoogie\Operation;
19 use ICanBoogie\Route;
20
21 use Brickrouge\A;
22 use Brickrouge\Alert;
23 use Brickrouge\DropdownMenu;
24 use Brickrouge\Element;
25
26 use Icybee\Modules\Pages\PageController;
27 use Icybee\Modules\Users\Users\Role;
28
29 class Document extends \Brickrouge\Document
30 {
31 /**
32 * Getter hook for the use ICanBoogie\Core::$document property.
33 *
34 * @return Document
35 */
36 static public function get()
37 {
38 global $document;
39
40 return $document = new static;
41 }
42
43 /*
44 * Markups
45 */
46
47 static public function markup_document_title(array $args, \Patron\Engine $patron, $template)
48 {
49 global $core;
50
51 $document = $core->document;
52
53 $title = isset($document->title) ? $document->title : null;
54
55 new Document\BeforeRenderTitleEvent($document, array('title' => &$title));
56
57 $rc = '<title>' . \ICanBoogie\escape($title) . '</title>';
58
59 new Document\RenderTitleEvent($document, array('html' => &$rc));
60
61 return $rc;
62 }
63
64 /**
65 * Returns the rendered metas of the document.
66 *
67 * {@link Document\BeforeRenderMetasEvent} is fired to collect HTTP equiv tags and meta tags.
68 * {@link Document\RenderMetasEvent} is fired once the metas have been rendered into a HTML
69 * string.
70 *
71 * @return string
72 */
73 static public function markup_document_metas()
74 {
75 global $core;
76
77 $document = $core->document;
78
79 $http_equiv = array
80 (
81 'Content-Type' => 'text/html; charset=' . \ICanBoogie\CHARSET
82 );
83
84 $metas = array
85 (
86 'og' => array()
87 );
88
89 new Document\BeforeRenderMetasEvent($document, array('http_equiv' => &$http_equiv, 'metas' => &$metas));
90
91 $html = '';
92
93 foreach ($http_equiv as $name => $content)
94 {
95 $html .= '<meta http-equiv="' . \ICanBoogie\escape($name) . '" content="' . \ICanBoogie\escape($content) . '" />' . PHP_EOL;
96 }
97
98 foreach ($metas as $name => $content)
99 {
100 if (is_array($content))
101 {
102 continue;
103 }
104
105 $html .= '<meta name="' . \ICanBoogie\escape($name) . '" content="' . \ICanBoogie\escape($content) . '" />' . PHP_EOL;
106 }
107
108 foreach ($metas as $name => $properties)
109 {
110 if (!is_array($properties))
111 {
112 continue;
113 }
114
115 foreach ($properties as $property => $content)
116 {
117 $html .= '<meta property="' . $name . ':' . \ICanBoogie\escape($property) . '" content="' . \ICanBoogie\escape($content) . '" />' . PHP_EOL;
118 }
119 }
120
121 new Document\RenderMetasEvent($document, array('html' => &$html));
122
123 return $html;
124 }
125
126 /**
127 * CSS assets can be collected and rendered into `LINK` elements with the `p:document:css`
128 * element. The `href` attribute is used to add an asset to the collection. The `weight`
129 * attribute specifies the weight of that asset. If the `weight` attribute is not specified,
130 * the weight of the asset is defaulted to 100. If the `href` attribute is not specified,
131 * the assets are rendered. If a template is specified the collection is passed as `this`,
132 * otherwise the collection is rendered into an HTML string of `LINK` elements.
133 *
134 * Note: Currently, the element is not rendered right away, a placeholder is inserted instead
135 * and is replaced when the `Icybee\Modules\Pages\PageController::render` event is fired.
136 *
137 * <pre>
138 * <p:document:css
139 * href = string
140 * weight = int>
141 * <!-- Content: p:with-params, template? -->
142 * </p:document:css>
143 * </pre>
144 *
145 * Example:
146 *
147 * <pre>
148 * <p:document:css href="/public/page.css" />
149 * <p:document:css href="/public/reset.css" weight="-100" />
150 *
151 * <p:document:css />
152 * </pre>
153 *
154 * Produces:
155 *
156 * <pre>
157 * <link href="/public/reset.css" type="text/css" rel="stylesheet" />
158 * <link href="/public/page.css" type="text/css" rel="stylesheet" />
159 * </pre>
160 *
161 * @param array $args
162 * @param Patron\Engine $engine
163 * @param mixed $template
164 *
165 * @return void|string
166 */
167 static public function markup_document_css(array $args, \Patron\Engine $engine, $template)
168 {
169 global $core;
170
171 if (isset($args['href']))
172 {
173 $core->document->css->add($args['href'], $args['weight'], dirname($engine->get_file()));
174
175 return;
176 }
177
178 $key = '<!-- document-css-placeholder-' . md5(uniqid()) . ' -->';
179
180 $core->events->attach(function(PageController\RenderEvent $event, PageController $target) use($engine, $template, $key)
181 {
182 #
183 # The event is chained so that it gets executed once the event chain has been
184 # processed.
185 #
186
187 $event->chain(function(PageController\RenderEvent $event) use($engine, $template, $key)
188 {
189 global $core;
190
191 $document = $core->document;
192
193 $html = $template ? $engine($template, $document->css) : (string) $document->css;
194
195 $event->html = str_replace($key, $html, $event->html);
196 });
197 });
198
199 return PHP_EOL . $key;
200 }
201
202 /**
203 * JavaScript assets can be collected and rendered into `SCRIPT` elements with the `p:document:js`
204 * element. The `href` attribute is used to add an asset to the collection. The `weight`
205 * attribute specifies the weight of that asset. If the `weight` attribute is not specified,
206 * the weight of the asset is defaulted to 100. If the `href` attribute is not specified,
207 * the assets are rendered. If a template is specified the collection is passed as `this`,
208 * otherwise the collection is rendered into an HTML string of `SCRIPT` elements.
209 *
210 * <pre>
211 * <p:document:js
212 * href = string
213 * weight = int>
214 * <!-- Content: p:with-params, template? -->
215 * </p:document:js>
216 * </pre>
217 *
218 * Example:
219 *
220 * <pre>
221 * <p:document:js href="/public/page.js" />
222 * <p:document:js href="/public/reset.js" weight="-100" />
223 *
224 * <p:document:js />
225 * </pre>
226 *
227 * Produces:
228 *
229 * <pre>
230 * <script src="/public/reset.css" type="text/javascript"></script>
231 * <script src="/public/page.css" type="text/javascript"></script>
232 * </pre>
233 *
234 * @param array $args
235 * @param Patron\Engine $engine
236 * @param mixed $template
237 *
238 * @return void|string
239 */
240 static public function markup_document_js(array $args, \Patron\Engine $engine, $template)
241 {
242 global $core;
243
244 $document = $core->document;
245
246 if (isset($args['href']))
247 {
248 $document->js->add($args['href'], $args['weight'], dirname($engine->get_file()));
249
250 return;
251 }
252
253 return $template ? $engine($template, $document->js) : (string) $document->js;
254 }
255
256 /*
257 * Object
258 */
259
260 public $title;
261 public $page_title;
262
263 public function __construct()
264 {
265 global $core;
266
267 parent::__construct();
268
269 $cache_assets = $core->config['cache assets'];
270
271 $this->css->use_cache = $cache_assets;
272 $this->js->use_cache = $cache_assets;
273 }
274
275 public function __get($property)
276 {
277 $value = parent::__get($property);
278
279 if ($property === 'css_class_names')
280 {
281 new \Brickrouge\AlterCSSClassNamesEvent($this, $value);
282 }
283
284 return $value;
285 }
286
287 /**
288 * Returns the CSS class of the node.
289 *
290 * @return string
291 */
292 protected function get_css_class()
293 {
294 return $this->css_class();
295 }
296
297 /**
298 * Returns the CSS class names of the node.
299 *
300 * @return array[string]mixed
301 */
302 protected function get_css_class_names()
303 {
304 global $core;
305
306 $names = $core->request->context->page->css_class_names;
307
308 unset($names['active']);
309
310 return $names;
311 }
312
313 /**
314 * Return the CSS class of the node.
315 *
316 * @param string|array $modifiers CSS class names modifiers
317 *
318 * @return string
319 */
320 public function css_class($modifiers=null)
321 {
322 return \Brickrouge\render_css_class($this->css_class_names, $modifiers);
323 }
324 }
325
326 namespace Icybee\Document;
327
328 /**
329 * Event class for the `Brickrouge\Document::render_metas:before` event.
330 */
331 class BeforeRenderMetasEvent extends \ICanBoogie\Event
332 {
333 /**
334 * Reference to the HTTP equivalent array.
335 *
336 * @var array[string]string
337 */
338 public $http_equiv;
339
340 /**
341 * Reference to the metas array.
342 *
343 * The `og` array is used to define OpenGraph metas.
344 *
345 * @var array[string]string
346 */
347 public $metas;
348
349 /**
350 * The event is constructed with the type `render_metas:before`.
351 *
352 * @param \Brickrouge\Document $target
353 * @param array $payload
354 */
355 public function __construct(\Brickrouge\Document $target, array $payload)
356 {
357 parent::__construct($target, 'render_metas:before', $payload);
358 }
359 }
360
361 /**
362 * Event class for the `Brickrouge\Document::render_metas` event.
363 */
364 class RenderMetasEvent extends \ICanBoogie\Event
365 {
366 /**
367 * Reference to the rendered HTML.
368 *
369 * @var string
370 */
371 public $html;
372
373 /**
374 * The event is constructed with the type `render_metas`.
375 *
376 * @param \Brickrouge\Document $target
377 * @param array $payload
378 */
379 public function __construct(\Brickrouge\Document $target, array $payload)
380 {
381 parent::__construct($target, 'render_metas', $payload);
382 }
383 }
384
385 /**
386 * Event class for the `Brickrouge\Document::render_title:before` event.
387 *
388 * @todo-20130318: is `title` the only property of the payload ? there should be `page_title`,
389 * `site_title` and `separator`. Or an array of parts with the `page` and `site` key.
390 */
391 class BeforeRenderTitleEvent extends \ICanBoogie\Event
392 {
393 /**
394 * Reference of the title to render.
395 *
396 * @var string
397 */
398 public $title;
399
400 /**
401 * The event is constructed with the type `render_title:before`.
402 *
403 * @param \Brickrouge\Document $target
404 * @param array $payload
405 */
406 public function __construct(\Brickrouge\Document $target, array $payload)
407 {
408 parent::__construct($target, 'render_title:before', $payload);
409 }
410 }
411
412 /**
413 * Event class for the `Brickrouge\Document::render_title` event.
414 */
415 class RenderTitleEvent extends \ICanBoogie\Event
416 {
417 /**
418 * HTML of the `TITLE` markup.
419 *
420 * @var string
421 */
422 public $html;
423
424 /**
425 * The event is constructed with the type `render_title`.
426 *
427 * @param \Brickrouge\Document $target
428 * @param array $payload
429 */
430 public function __construct(\Brickrouge\Document $target, array $payload)
431 {
432 parent::__construct($target, 'render_title', $payload);
433 }
434 }