1 <?php
2
3 4 5 6 7 8 9 10
11
12 namespace Icybee\Modules\Pages;
13
14 use ICanBoogie\I18n;
15
16 use Brickrouge\Alert;
17 use Brickrouge\Element;
18 use Brickrouge\Form;
19 use Brickrouge\Text;
20
21 use Icybee\Modules\Nodes\Node;
22 use Icybee\Modules\Editor\EditorElement;
23 use Icybee\Modules\Editor\MultiEditorElement;
24
25 class Module extends \Icybee\Modules\Nodes\Module
26 {
27 28 29
30 protected function lazy_get_views()
31 {
32 return array
33 (
34 'list' => array
35 (
36 'title' => 'Sitemap',
37 'class' => __NAMESPACE__ . '\ListView',
38 'assets' => array(),
39 'renders' => \Icybee\Modules\Views\View::RENDERS_MANY
40 )
41 );
42 }
43
44
45 protected function operation_query_delete(WdOperation $operation)
46 {
47 $entries = array();
48
49 foreach ($operation->params['entries'] as $id)
50 {
51 $record = $this->model[$id];
52
53 if (!$record)
54 {
55 continue;
56 }
57
58 $entries = array_merge(self::get_all_children_ids($record), $entries);
59 }
60
61 $entries = array_unique($entries);
62
63 $operation->params['entries'] = $entries;
64
65 return parent::operation_query_delete($operation);
66 }
67
68 private function get_all_children_ids($record)
69 {
70 $ids = array();
71
72 if ($record->children)
73 {
74
75
76 foreach ($record->children as $child)
77 {
78 $ids = array_merge(self::get_all_children_ids($child), $ids);
79 }
80 }
81
82 $ids[] = $record->nid;
83
84 return $ids;
85 }
86
87
88 protected function operation_query_copy(WdOperation $operation)
89 {
90 $entries = $operation->params['entries'];
91
92 return array
93 (
94 'title' => 'Copy entries',
95 'message' => I18n\t('Are you sure you want to copy the :count selected entries ?', array(':count' => count($entries))),
96 'confirm' => array('Don\'t copy', 'Copy'),
97 'params' => array
98 (
99 'entries' => $entries
100 )
101 );
102 }
103
104 public function get_contents_section($nid, $template=null)
105 {
106 list($template, $template_description, $is_inherited) = $this->resolve_template($nid, $template);
107 list($elements, $hiddens) = $this->get_contents_section_elements($nid, $template);
108
109 if ($elements)
110 {
111 $template_description .= ' ' . I18n\t("The following elements are editable:");
112 }
113 else
114 {
115 $template_description = I18n\t("The <q>:template</q> template does not define any editable element.", array(':template' => $template));
116 }
117
118 $elements = array_merge
119 (
120 array
121 (
122 Page::TEMPLATE => new PopTemplate
123 (
124 array
125 (
126 Element::GROUP => 'contents',
127 Element::DESCRIPTION => $template_description
128 )
129 )
130 ),
131
132 $elements
133 );
134
135 return array
136 (
137 array
138 (
139 Form::HIDDENS => $hiddens,
140
141
142
143
144
145
146 Form::VALUES => array
147 (
148 Page::TEMPLATE => $is_inherited ? null : $template
149 ),
150
151 Element::GROUPS => array
152 (
153 'contents' => array
154 (
155 'title' => 'Template',
156 'weight' => 10
157 ),
158
159 'contents.inherit' => array
160 (
161 'weight' => 11,
162 'description' => 'contents.inherit'
163 )
164 ),
165
166 Element::CHILDREN => $elements
167 ),
168
169 array
170 (
171 'name' => $template,
172 'description' => $template_description,
173 'inherited' => $is_inherited
174 )
175 );
176 }
177
178 protected function get_contents_section_elements($nid, $template)
179 {
180 global $core;
181
182 $info = self::get_template_info($template);
183
184 if (!$info)
185 {
186 return array(array(), array());
187 }
188
189 list($editables, $styles) = $info;
190
191 $elements = array();
192 $hiddens = array();
193
194 $contents_model = $this->model('contents');
195 $context = $core->site->path;
196
197 foreach ($editables as $editable)
198 {
199 $id = $editable['id'];
200 $title = $editable['title'];
201 $title = I18n\t($id, array(), array('scope' => array('content', 'title'), 'default' => $title));
202
203 $does_inherit = !empty($editable['inherit']);
204
205 $value = null;
206
207 $editor_id = $editable['editor'];
208 $editor_config = json_decode($editable['config'], true);
209 $editor_description = $editable['description'];
210
211
212
213
214
215 $contents = $nid ? $contents_model->where('pageid = ? AND contentid = ?', $nid, $id)->one : null;
216
217 if ($contents)
218 {
219 $value = $contents->content;
220
221 if (!$editor_id)
222 {
223 $editor_id = $contents->editor;
224 }
225 }
226
227 if ($does_inherit)
228 {
229 if (!$contents && $nid)
230 {
231 $inherited = null;
232 $node = $this->model[$nid];
233
234 while ($node)
235 {
236 $node_contents = $node->contents;
237
238 if (isset($node_contents[$id]))
239 {
240 $inherited = $node;
241
242 break;
243 }
244
245 $node = $node->parent;
246 }
247
248 if (!$node)
249 {
250 $node = $core->site->home;
251
252 if (isset($node->contents[$id]))
253 {
254 $inherited = $node;
255 }
256 }
257
258
259
260 if ($inherited)
261 {
262 $elements[] = new Element
263 (
264 'div', array
265 (
266 Form::LABEL => $title,
267 Element::GROUP => 'contents.inherit',
268 Element::INNER_HTML => '',
269 Element::DESCRIPTION => I18n\t
270 (
271 'This content is currently inherited from the <q><a href="!url">!title</a></q> parent page. <a href="#edit" class="btn">Edit the content</a>', array
272 (
273 '!url' => $context . '/admin/' . $this->id . '/' . $inherited->nid . '/edit',
274 '!title' => $inherited->title
275 )
276 ),
277
278 \Brickrouge\Section::T_PANEL_CLASS => 'inherit-toggle'
279 )
280 );
281 }
282 else
283 {
284 $editor_description .= I18n\t('No parent page define this content.');
285 }
286 }
287 }
288
289 290 291 292 293 294 295 296
297
298 if (isset($editable['editor']))
299 {
300 if (!isset($core->editors[$editor_id]))
301 {
302 $elements["contents[$id]"] = new Alert
303 (
304 I18n\t('Éditeur inconnu : %editor', array('%editor' => $editable['editor'])), array
305 (
306 Form::LABEL => $title,
307 Element::GROUP => $does_inherit ? 'contents.inherit' : 'contents',
308 Alert::CONTEXT => Alert::CONTEXT_ERROR
309 )
310 );
311
312 continue;
313 }
314
315 $editor = $core->editors[$editor_id];
316
317 $elements["contents[$id]"] = $editor->from
318 (
319 array
320 (
321 Form::LABEL => $title,
322
323 EditorElement::STYLESHEETS => $styles,
324 EditorElement::CONFIG => $editor_config,
325
326 Element::GROUP => $does_inherit ? 'contents.inherit' : 'contents',
327 Element::DESCRIPTION => $editor_description,
328
329 'id' => 'editor-' . $id,
330 'value' => $editor->unserialize($value)
331 )
332 );
333
334
335
336
337
338 $hiddens["editors[$id]"] = $editable['editor'];
339 }
340 else
341 {
342 $elements["contents[$id]"] = new MultiEditorElement
343 (
344 $editor_id, array
345 (
346 Form::LABEL => $title,
347
348 MultiEditorElement::NOT_SWAPPABLE => isset($editable['editor']),
349 MultiEditorElement::SELECTOR_NAME => "editors[$id]",
350 MultiEditorElement::EDITOR_TAGS => array
351 (
352 EditorElement::STYLESHEETS => $styles,
353 EditorElement::CONFIG => $editor_config
354 ),
355
356 Element::GROUP => $does_inherit ? 'contents.inherit' : 'contents',
357 Element::DESCRIPTION => $editor_description,
358
359 'id' => 'editor-' . $id,
360 'value' => $editor_id ? $core->editors[$editor_id]->unserialize($value) : $value
361 )
362 );
363 }
364 }
365
366 return array($elements, $hiddens);
367 }
368
369 370 371 372 373 374 375 376
377 protected function resolve_template($nid, $request_template=null)
378 {
379 global $core;
380
381 $inherited = false;
382 $is_alone = !$this->model->select('nid')->filter_by_siteid($core->site_id)->rc;
383
384 if ($is_alone)
385 {
386 $template = 'home.html';
387 }
388
389 $description = I18n\t("The template defines a page model of which some elements are editable.");
390
391 if (!$nid)
392 {
393 if ($is_alone)
394 {
395 $description .= " Parce que la page est seule elle utilise le gabarit <q>home.html</q>.";
396 }
397 else if (!$request_template)
398 {
399 $template = 'page.html';
400 }
401 else
402 {
403 $template = $request_template;
404 }
405
406 return array($template, $description, $template == 'page.html');
407 }
408
409 $record = $this->model[$nid];
410 $definer = null;
411 $template = $request_template !== null ? $request_template : $record->template;
412
413
414
415 if ($template == 'page.html' && (!$record->parent || ($record->parent && $record->parent->is_home)))
416 {
417
418
419 $inherited = true;
420
421
422
423 $description .= ' ' . "Parce qu'aucun gabarit n'est défini pour la page, elle utilise
424 le gabarit <q>page.html</q>.";
425 }
426 else if ($template == 'home.html' && (!$record->parent && $record->weight == 0))
427 {
428 $inherited = true;
429
430
431 }
432 else if (!$request_template)
433 {
434 $definer = $record->parent;
435
436 if (!$definer)
437 {
438 $template = 'page.html';
439 $inherited = true;
440
441 $description .= ' ' . "Parce qu'aucun gabarit n'est défini pour la page, elle utilise
442 le gabarit <q>page.html</q>.";
443 }
444 }
445 else
446 {
447 $definer = $record;
448 $parent = $record->parent;
449
450
451
452 while ($parent)
453 {
454
455
456 if ($parent->template == $request_template)
457 {
458 break;
459 }
460
461 $parent = $parent->parent;
462 }
463
464
465
466 if ($parent && $parent->template == $request_template)
467 {
468 $definer = $parent;
469 }
470
471
472 }
473
474 if ($definer && $definer != $record)
475 {
476
477
478 $description .= ' ' . I18n\t
479 (
480 'This page uses the <q>:template</q> template, inherited from the parent page <q><a href="!url">!title</a></q>.', array
481 (
482 'template' => $template,
483 'url' => \ICanBoogie\Routing\contextualize("/admin/{$this->id}/{$definer->nid}/edit"),
484 'title' => $definer->title
485 )
486 );
487
488 $inherited = true;
489 }
490
491 return array($template, $description, $inherited);
492 }
493
494 static public function get_template_info($name)
495 {
496 global $core;
497
498 $site = $core->site;
499 $path = $site->resolve_path('templates/' . $name);
500
501 if (!$path)
502 {
503 \ICanBoogie\log_error('Uknown template file %name', array('%name' => $name));
504
505 return array();
506 }
507
508 $html = file_get_contents(\ICanBoogie\DOCUMENT_ROOT . $path);
509 $parser = new \Patron\HTMLParser();
510
511 return self::get_template_info_callback($html, $parser);
512 }
513
514 static protected function get_template_info_callback($html, $parser)
515 {
516 $styles = array();
517 $contents = array();
518
519
520
521
522
523 preg_match_all('#<link.*type="text/css".*>#', $html, $matches);
524
525 foreach ($matches[0] as $match)
526 {
527 preg_match_all('#(\S+)="([^"]+)"#', $match, $attributes_matches, PREG_SET_ORDER);
528
529 $attributes = array();
530
531 foreach ($attributes_matches as $attribute_match)
532 {
533 list(, $attribute, $value) = $attribute_match;
534
535 $attributes[$attribute] = $value;
536 }
537
538 if (isset($attributes['media']) && $attributes['media'] != 'screen')
539 {
540 continue;
541 }
542
543 $styles[] = $attributes['href'];
544 }
545
546
547
548
549
550 $tree = $parser->parse($html, \Patron\Engine::PREFIX);
551
552
553
554
555
556
557
558 $contents_collection = \Patron\HTMLParser::collectMarkup($tree, 'page:content');
559
560
561
562 foreach ($contents_collection as $node)
563 {
564 if (isset($node['children']))
565 {
566 foreach ($node['children'] as $child)
567 {
568 if (!is_array($child))
569 {
570 continue;
571 }
572
573 if ($child['name'] != 'with-param')
574 {
575 continue;
576 }
577
578 $param = $child['args']['name'];
579
580
581
582 $value = '';
583
584 foreach ($child['children'] as $cv)
585 {
586 $value .= $cv;
587 }
588
589 $node['args'][$param] = $value;
590 }
591 }
592
593
594
595 $contents[] = $node['args'] + array
596 (
597 'editor' => null,
598 'config' => null,
599 'description' => null
600 );
601 }
602
603
604
605
606
607 global $core;
608
609 $site = $core->site;
610 $root = $_SERVER['DOCUMENT_ROOT'];
611
612 $call_template_collection = \Patron\HTMLParser::collectMarkup($tree, 'call-template');
613
614 foreach ($call_template_collection as $node)
615 {
616 $template_name = $node['args']['name'];
617
618 $file = $template_name . '.html';
619 $path = $site->resolve_path('templates/partials/' . $file);
620
621 if (!$path)
622 {
623 \ICanBoogie\log_error('Partial template %name not found', array('%name' => $file));
624
625 continue;
626 }
627
628 $template = file_get_contents($root . $path);
629
630 list($partial_contents, $partial_styles) = self::get_template_info_callback($template, $parser);
631
632 $contents = array_merge($contents, $partial_contents);
633
634 if ($partial_styles)
635 {
636 $styles = array_merge($styles, $partial_styles);
637 }
638 }
639
640 return array($contents, $styles);
641 }
642 }