PluginProbe
iCalendrier / 2.0
iCalendrier v2.0
1.77 1.78 1.79 1.80 1.81 1.82 1.83 2.0 trunk 1.5 1.51 1.52 1.53 1.54 1.6 1.61 1.62 1.7 1.71 1.72 1.73 1.74 1.75 1.76
icalendrier / lib / Icalendrier.php

Icalendrier.php in iCalendrier 2.0, at lib/Icalendrier.php

1,107 lines 31.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /* Copyright 2014 Baptiste Placé
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2, as
6 published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 /**
18 * Class: iCalendrier
19 * Description: Un simple calendrier qui affiche des infos du jour, comme le numéro de semaine, la date, la fête du jour et la phase de lune.
20 * Version: 1.0
21 * Author: Baptiste Placé
22 * Author URI: https://icalendrier.fr/
23 * License: GNU General Public License, version 2
24 */
25
26 require_once dirname(__FILE__) . "/FeteDuJour.php";
27
28
29 class Icalendrier
30 {
31
32 protected $nameDay;
33
34 /** Reference time for everything rendered (injectable for tests). */
35 protected DateTimeImmutable $now;
36
37 protected $lang;
38
39 protected $langs = array(
40 "fr",
41 "en",
42 "en-GB",
43 "es",
44 "pt",
45 "it",
46 "de",
47 "pt-BR",
48 "ro",
49 "sv",
50 "da",
51 );
52
53 /** Languages that write day and month names in lowercase; the modern layout follows that convention like the site does. */
54 protected $lowercaseDates = array('fr', 'es', 'pt', 'pt-BR', 'it', 'ro', 'sv', 'da');
55
56 /** Site-style locale codes (config/websites.php on the iCalendrier sites) mapped to the plugin's short codes. */
57 protected $aliases = array(
58 'fr-FR' => 'fr',
59 'en-US' => 'en',
60 'es-ES' => 'es',
61 'pt-PT' => 'pt',
62 'it-IT' => 'it',
63 'de-DE' => 'de',
64 'ro-RO' => 'ro',
65 'sv-SE' => 'sv',
66 'da-DK' => 'da',
67 );
68
69 protected $siteUrls = array(
70 'fr' => "https://icalendrier.fr/",
71 'en' => "https://icalendars.net/",
72 'es' => "https://icalendario.net/",
73 'pt' => "https://icalendario.pt/",
74 'pt-BR' => "https://icalendario.br.com/",
75 'it' => "https://icalendario.it/",
76 'de' => "https://ikalender.org/",
77 'ro' => "https://www.noutati-ortodoxe.ro/calendar-ortodox/",
78 'en-GB' => "https://icalendar.co.uk/",
79 'sv' => "https://ikalendrar.se/",
80 'da' => "https://ikalender.dk/",
81 );
82
83 /** Site titles (config/websites.php), used as the credit line of the modern layout. */
84 protected $siteLabels = array(
85 'fr' => "iCalendrier",
86 'en' => "iCalendars",
87 'es' => "iCalendario",
88 'pt' => "iCalendário",
89 'pt-BR' => "iCalendario",
90 'it' => "iCalendario",
91 'de' => "iKalender",
92 'ro' => "noutati-ortodoxe.ro",
93 'en-GB' => "iCalendar",
94 'sv' => "iKalendrar",
95 'da' => "iKalender",
96 );
97
98 protected $todayLabels = array(
99 'fr' => "Aujourd'hui",
100 'en' => "Today",
101 'es' => "Hoy en día",
102 'pt' => "Hoje",
103 'pt-BR' => "Hoje",
104 'it' => "Oggi",
105 'de' => "Heute",
106 'ro' => "Astăzi",
107 'en-GB' => "Today",
108 'sv' => "Idag",
109 'da' => "I dag",
110 );
111
112 protected $localDays = array(
113 'fr' => array(
114 'Lundi',
115 'Mardi',
116 'Mercredi',
117 'Jeudi',
118 'Vendredi',
119 'Samedi',
120 'Dimanche',
121 ),
122 'en' => array(
123 'Monday',
124 'Tuesday',
125 'Wednesday',
126 'Thursday',
127 'Friday',
128 'Saturday',
129 'Sunday',
130 ),
131 'es' => array(
132 'Lunes',
133 'Martes',
134 'Miércoles',
135 'Jueves',
136 'Viernes',
137 'Sábado',
138 'Domingo',
139 ),
140 'pt' => array(
141 'Segunda-feira',
142 'Terca-feira',
143 'Quarta-feira',
144 'Quinta-feira',
145 'Sexta-feira',
146 'Sábado',
147 'Domingo',
148 ),
149 'pt-BR' => array(
150 'Segunda-feira',
151 'Terca-feira',
152 'Quarta-feira',
153 'Quinta-feira',
154 'Sexta-feira',
155 'Sábado',
156 'Domingo',
157 ),
158 'it' => array(
159 'Lunedí',
160 'Martedí',
161 'Mercoledí',
162 'Giovedì',
163 'Venerdí',
164 'Sabato',
165 'Domenica',
166 ),
167 'de' => array(
168 'Montag',
169 'Dienstag',
170 'Mittwoch',
171 'Donnerstag',
172 'Freitag',
173 'Samstag',
174 'Sonntag',
175 ),
176 'ro' => array(
177 'Luni',
178 'Marți',
179 'Miercuri',
180 'Joi',
181 'Vineri',
182 'Sâmbătă',
183 'Duminică',
184 ),
185 'en-GB' => array(
186 'Monday',
187 'Tuesday',
188 'Wednesday',
189 'Thursday',
190 'Friday',
191 'Saturday',
192 'Sunday',
193 ),
194 'sv' => array(
195 'Måndag',
196 'Tisdag',
197 'Onsdag',
198 'Torsdag',
199 'Fredag',
200 'Lördag',
201 'Söndag',
202 ),
203 'da' => array(
204 'Mandag',
205 'Tirsdag',
206 'Onsdag',
207 'Torsdag',
208 'Fredag',
209 'Lørdag',
210 'Søndag',
211 ),
212 );
213
214 protected $shortLocalDays = array(
215 'fr' => array(
216 'Lundi',
217 'Mardi',
218 'Mercredi',
219 'Jeudi',
220 'Vendredi',
221 'Samedi',
222 'Dimanche',
223 ),
224 'en' => array(
225 'Monday',
226 'Tuesday',
227 'Wednesday',
228 'Thursday',
229 'Friday',
230 'Saturday',
231 'Sunday',
232 ),
233 'es' => array(
234 'Lunes',
235 'Martes',
236 'Miércoles',
237 'Jueves',
238 'Viernes',
239 'Sábado',
240 'Domingo',
241 ),
242 'pt' => array(
243 'Seg.-feira',
244 'Terca-feira',
245 'Quarta-feira',
246 'Quinta-feira',
247 'Sexta-feira',
248 'Sábado',
249 'Domingo',
250 ),
251 'pt-BR' => array(
252 'Seg.-feira',
253 'Terca-feira',
254 'Quarta-feira',
255 'Quinta-feira',
256 'Sexta-feira',
257 'Sábado',
258 'Domingo',
259 ),
260 'it' => array(
261 'Lunedí',
262 'Martedí',
263 'Mercoledí',
264 'Giovedì',
265 'Venerdí',
266 'Sabato',
267 'Domenica',
268 ),
269 'de' => array(
270 'Montag',
271 'Dienstag',
272 'Mittwoch',
273 'Donnerstag',
274 'Freitag',
275 'Samstag',
276 'Sonntag',
277 ),
278 'ro' => array(
279 'Luni',
280 'Marți',
281 'Miercuri',
282 'Joi',
283 'Vineri',
284 'Sâmbătă',
285 'Duminică',
286 ),
287 'en-GB' => array(
288 'Monday',
289 'Tuesday',
290 'Wednesday',
291 'Thursday',
292 'Friday',
293 'Saturday',
294 'Sunday',
295 ),
296 'sv' => array(
297 'Måndag',
298 'Tisdag',
299 'Onsdag',
300 'Torsdag',
301 'Fredag',
302 'Lördag',
303 'Söndag',
304 ),
305 'da' => array(
306 'Mandag',
307 'Tirsdag',
308 'Onsdag',
309 'Torsdag',
310 'Fredag',
311 'Lørdag',
312 'Søndag',
313 ),
314 );
315
316 protected $weekLabels = array(
317 'fr' => "Semaine",
318 'en' => "Week",
319 'es' => "Semana",
320 'pt' => "Semana",
321 'pt-BR' => "Semana",
322 'it' => "Settimana",
323 'de' => "Woche",
324 'ro' => "Săptămâna",
325 'en-GB' => "Week",
326 'sv' => "Vecka",
327 'da' => "Uge",
328 );
329
330 protected $shortWeekLabels = array(
331 'fr' => "Sem.",
332 'en' => "Week",
333 'es' => "Sem.",
334 'pt' => "Sem.",
335 'pt-BR' => "Sem.",
336 'it' => "Sett.",
337 'de' => "Wo.",
338 'ro' => "Săpt.",
339 'en-GB' => "Week",
340 'sv' => "V.",
341 'da' => "Uge",
342 );
343
344 protected $shortMonthLabels = array(
345 'fr' => array(
346 'Jan.',
347 'Fév.',
348 'Mars',
349 'Avr.',
350 'Mai',
351 'Juin',
352 'Juil.',
353 'Août',
354 'Sep.',
355 'Oct.',
356 'Nov.',
357 'Déc.'
358 ),
359 'en' => array(
360 'Jan.',
361 'Feb.',
362 'Mar.',
363 'Apr.',
364 'May',
365 'June',
366 'July',
367 'Aug.',
368 'Sep.',
369 'Oct.',
370 'Nov.',
371 'Dec.'
372 ),
373 'es' => array(
374 'Ene.',
375 'Feb.',
376 'Mar.',
377 'Abril',
378 'Mayo',
379 'Junio',
380 'Julio',
381 'Ago.',
382 'Sep.',
383 'Oct.',
384 'Nov.',
385 'Dic.'
386 ),
387 'pt' => array(
388 'Jan.',
389 'Fev.',
390 'Mar.',
391 'Abr.',
392 'Maio',
393 'Jun.',
394 'Jul.',
395 'Ago.',
396 'Set.',
397 'Out.',
398 'Nov.',
399 'Dez.'
400 ),
401 'pt-BR' => array(
402 'Jan.',
403 'Fev.',
404 'Mar.',
405 'Abr.',
406 'Maio',
407 'Jun.',
408 'Jul.',
409 'Ago.',
410 'Set.',
411 'Out.',
412 'Nov.',
413 'Dez.'
414 ),
415 'it' => array(
416 'Gen.',
417 'Feb.',
418 'Mar.',
419 'Apr.',
420 'Mag.',
421 'Giu.',
422 'Lug.',
423 'Ago.',
424 'Set.',
425 'Ott.',
426 'Nov.',
427 'Dic.'
428 ),
429 'de' => array(
430 'Jan.',
431 'Feb.',
432 'März',
433 'Apr.',
434 'Mai',
435 'Juni',
436 'Juli',
437 'Aug.',
438 'Sep.',
439 'Okt.',
440 'Nov.',
441 'Dez.'
442 ),
443 'ro' => array(
444 'Ian.',
445 'Feb.',
446 'Mar.',
447 'Apr.',
448 'Mai',
449 'Iun.',
450 'Iul.',
451 'Aug.',
452 'Sep.',
453 'Oct.',
454 'Nov.',
455 'Dec.'
456 ),
457 'en-GB' => array(
458 'Jan.',
459 'Feb.',
460 'Mar.',
461 'Apr.',
462 'May',
463 'June',
464 'July',
465 'Aug.',
466 'Sep.',
467 'Oct.',
468 'Nov.',
469 'Dec.'
470 ),
471 'sv' => array(
472 'Jan.',
473 'Feb.',
474 'Mars',
475 'Apr.',
476 'Maj',
477 'Juni',
478 'Juli',
479 'Aug.',
480 'Sep.',
481 'Okt.',
482 'Nov.',
483 'Dec.',
484 ),
485 'da' => array(
486 'Jan.',
487 'Feb.',
488 'Mar.',
489 'Apr.',
490 'Maj',
491 'Jun.',
492 'Jul.',
493 'Aug.',
494 'Sep.',
495 'Okt.',
496 'Nov.',
497 'Dec.',
498 ),
499 );
500
501 protected $monthLabels = array(
502 'fr' => array(
503 'Janvier',
504 'Février',
505 'Mars',
506 'Avril',
507 'Mai',
508 'Juin',
509 'Juillet',
510 'Août',
511 'Septembre',
512 'Octobre',
513 'Novembre',
514 'Décembre'
515 ),
516 'en' => array(
517 'January',
518 'February',
519 'March',
520 'April',
521 'May',
522 'June',
523 'July',
524 'August',
525 'September',
526 'October',
527 'November',
528 'December'
529 ),
530 'es' => array(
531 'Enero',
532 'Febrero',
533 'Marzo',
534 'Abril',
535 'Mayo',
536 'Junio',
537 'Julio',
538 'Agosto',
539 'Septiembre',
540 'Octubre',
541 'Noviembre',
542 'Diciembre'
543 ),
544 'pt' => array(
545 'Janeiro',
546 'Fevereiro',
547 'Março',
548 'Abril',
549 'Maio',
550 'Junho',
551 'Julho',
552 'Agosto',
553 'Setembro',
554 'Outubro',
555 'Novembro',
556 'Dezembro'
557 ),
558 'pt-BR' => array(
559 'Janeiro',
560 'Fevereiro',
561 'Março',
562 'Abril',
563 'Maio',
564 'Junho',
565 'Julho',
566 'Agosto',
567 'Setembro',
568 'Outubro',
569 'Novembro',
570 'Dezembro'
571 ),
572 'it' => array(
573 'Gennaio',
574 'Febbraio',
575 'Marzo',
576 'Aprile',
577 'Maggio',
578 'Giugno',
579 'Luglio',
580 'Agosto',
581 'Settembre',
582 'Ottobre',
583 'Novembre',
584 'Dicembre'
585 ),
586 'de' => array(
587 'Januar',
588 'Februar',
589 'März',
590 'April',
591 'Mai',
592 'Juni',
593 'Juli',
594 'August',
595 'September',
596 'Oktober',
597 'November',
598 'Dezember'
599 ),
600 'ro' => array(
601 'Ianuarie',
602 'Februarie',
603 'Martie',
604 'Aprilie',
605 'Mai',
606 'Iunie',
607 'Iulie',
608 'August',
609 'Septembrie',
610 'Octombrie',
611 'Noiembrie',
612 'Decembrie'
613 ),
614 'en-GB' => array(
615 'January',
616 'February',
617 'March',
618 'April',
619 'May',
620 'June',
621 'July',
622 'August',
623 'September',
624 'October',
625 'November',
626 'December'
627 ),
628 'sv' => array(
629 'Januari',
630 'Februari',
631 'Mars',
632 'April',
633 'Maj',
634 'Juni',
635 'Juli',
636 'Augusti',
637 'September',
638 'Oktober',
639 'November',
640 'December',
641 ),
642 'da' => array(
643 'Januar',
644 'Februar',
645 'Marts',
646 'April',
647 'Maj',
648 'Juni',
649 'Juli',
650 'August',
651 'September',
652 'Oktober',
653 'November',
654 'December',
655 ),
656 );
657
658 protected $localMoonPhases = array(
659 'fr' => array(
660 'New Moon' => 'Nouvelle lune',
661 'Waxing Crescent' => 'Premier croissant',
662 'First Quarter' => 'Premier quartier',
663 'Waxing Gibbous' => 'Gibbeuse croissante',
664 'Full Moon' => 'Pleine lune',
665 'Waning Gibbous' => 'Gibbeuse décroissante',
666 'Third Quarter' => 'Dernier quartier',
667 'Waning Crescent' => 'Dernier croissant',
668 ),
669 'en' => array(
670 'New Moon' => 'New Moon',
671 'Waxing Crescent' => 'Waxing Crescent',
672 'First Quarter' => 'First Quarter',
673 'Waxing Gibbous' => 'Waxing Gibbous',
674 'Full Moon' => 'Full Moon',
675 'Waning Gibbous' => 'Waning Gibbous',
676 'Third Quarter' => 'Third Quarter',
677 'Waning Crescent' => 'Waning Crescent',
678 ),
679 'es' => array(
680 'New Moon' => 'Luna Nueva',
681 'Waxing Crescent' => 'Luna Nueva Visible',
682 'First Quarter' => 'Cuarto Creciente',
683 'Waxing Gibbous' => 'Luna Gibosa Creciente',
684 'Full Moon' => 'Luna Llena',
685 'Waning Gibbous' => 'Luna Gibosa Menguante',
686 'Third Quarter' => 'Cuarto Menguante',
687 'Waning Crescent' => 'Luna Menguante',
688 ),
689 'pt' => array(
690 'New Moon' => 'Lua nova',
691 'Waxing Crescent' => 'Lua crescente',
692 'First Quarter' => 'Quarto Crescente',
693 'Waxing Gibbous' => 'Lua crescente convexa',
694 'Full Moon' => 'Lua Cheia',
695 'Waning Gibbous' => 'Lua minguante convexa',
696 'Third Quarter' => 'Quarto Minguante',
697 'Waning Crescent' => 'Lua minguante',
698 ),
699 'pt-BR' => array(
700 'New Moon' => 'Lua nova',
701 'Waxing Crescent' => 'Lua crescente',
702 'First Quarter' => 'Quarto Crescente',
703 'Waxing Gibbous' => 'Lua crescente convexa',
704 'Full Moon' => 'Lua Cheia',
705 'Waning Gibbous' => 'Lua minguante convexa',
706 'Third Quarter' => 'Quarto Minguante',
707 'Waning Crescent' => 'Lua minguante',
708 ),
709 'it' => array(
710 'New Moon' => 'Luna nuova',
711 'Waxing Crescent' => 'Luna crescente',
712 'First Quarter' => 'Primo quarto',
713 'Waxing Gibbous' => 'Gibbosa crescente',
714 'Full Moon' => 'Luna piena',
715 'Waning Gibbous' => 'Gibbosa calante',
716 'Third Quarter' => 'Ultimo quarto',
717 'Waning Crescent' => 'Luna calante',
718 ),
719 'de' => array(
720 'New Moon' => 'Neumond',
721 'Waxing Crescent' => 'Erstes Viertel',
722 'First Quarter' => 'Zunehmender Halbmond',
723 'Waxing Gibbous' => 'Zweites Viertel',
724 'Full Moon' => 'Vollmond',
725 'Waning Gibbous' => 'Drittes Viertel',
726 'Third Quarter' => 'Abnehmender Halbmond',
727 'Waning Crescent' => 'Letztes Viertel',
728 ),
729 'ro' => array(
730 'New Moon' => 'Lună nouă',
731 'Waxing Crescent' => 'Prima creștere',
732 'First Quarter' => 'Primul pătrar',
733 'Waxing Gibbous' => 'Lună în creștere',
734 'Full Moon' => 'Lună plină',
735 'Waning Gibbous' => 'Lună în descreștere',
736 'Third Quarter' => 'Al treilea pătrar',
737 'Waning Crescent' => 'Ultima creștere',
738 ),
739 'en-GB' => array(
740 'New Moon' => 'New Moon',
741 'Waxing Crescent' => 'Waxing Crescent',
742 'First Quarter' => 'First Quarter',
743 'Waxing Gibbous' => 'Waxing Gibbous',
744 'Full Moon' => 'Full Moon',
745 'Waning Gibbous' => 'Waning Gibbous',
746 'Third Quarter' => 'Last Quarter',
747 'Waning Crescent' => 'Waning Crescent',
748 ),
749 'sv' => array(
750 'New Moon' => 'Nymåne',
751 'Waxing Crescent' => 'Tilltagande skära',
752 'First Quarter' => 'Första kvarteret',
753 'Waxing Gibbous' => 'Tilltagande gibbeus',
754 'Full Moon' => 'Fullmåne',
755 'Waning Gibbous' => 'Avtagande gibbeus',
756 'Third Quarter' => 'Sista kvarteret',
757 'Waning Crescent' => 'Avtagande skära',
758 ),
759 'da' => array(
760 'New Moon' => 'Nymåne',
761 'Waxing Crescent' => 'Tiltagende månesegl',
762 'First Quarter' => 'Første kvarter',
763 'Waxing Gibbous' => 'Tiltagende måne',
764 'Full Moon' => 'Fuldmåne',
765 'Waning Gibbous' => 'Aftagende måne',
766 'Third Quarter' => 'Sidste kvarter',
767 'Waning Crescent' => 'Aftagende månesegl',
768 ),
769 );
770
771
772 /**
773 * @param string $lang
774 * @param string|int $timezone PHP timezone identifier; 0, '0' or '' keep the server default
775 * @param DateTimeInterface|int|null $now Reference time (tests); defaults to now
776 */
777 public function __construct($lang = 'en', $timezone = 0, DateTimeInterface|int|null $now = null)
778 {
779 $lang = $this->aliases[$lang] ?? $lang;
780 if ( ! in_array($lang, $this->langs, true)) {
781 $lang = "en"; // Default En
782 }
783 $this->lang = $lang;
784
785 // The zone only affects this instance's reference time; global PHP state is left alone.
786 // null means "not requested": an injected $now keeps its own zone, anything else uses the server default.
787 $zone = self::timezone($timezone);
788
789 if ($now instanceof DateTimeInterface) {
790 $this->now = DateTimeImmutable::createFromInterface($now);
791 if (null !== $zone) {
792 $this->now = $this->now->setTimezone($zone);
793 }
794 } elseif (is_int($now)) {
795 $this->now = (new DateTimeImmutable('@' . $now))->setTimezone($zone ?? new DateTimeZone(date_default_timezone_get()));
796 } else {
797 $this->now = new DateTimeImmutable('now', $zone);
798 }
799
800 $this->nameDay = new NameDay();
801 }
802
803 /**
804 * @param string|int $timezone
805 */
806 private static function timezone($timezone): ?DateTimeZone
807 {
808 if ( ! is_string($timezone) || '' === $timezone || '0' === $timezone) {
809 return null;
810 }
811
812 try {
813 return new DateTimeZone($timezone);
814 } catch (Exception $e) {
815 return null; // Unknown identifier: server default.
816 }
817 }
818
819 /**
820 * @param array $parameters showLink, bgColor, style, showNameDay (default on)
821 *
822 * @return string
823 */
824 public function iCalendrierComp($parameters = [])
825 {
826 $html = '';
827
828 $showLink = isset($parameters['showLink']) ? (bool)$parameters['showLink'] : false;
829 $showNameDay = $this->showNameDay($parameters);
830 $bgColor = isset($parameters['bgColor']) ? $this->secureParam($parameters['bgColor']) : false;
831 $styleClassname = isset($parameters['style']) && 'default' !== $parameters['style'] ? ' ' . $this->secureParam($parameters['style']) : '';
832
833 $html .= '<div class="icalComp' . $styleClassname . '">';
834 $html .= '<div class="ccomp">';
835
836 if ($bgColor) {
837 $html .= '<div class="cheight" style="background:' . $bgColor . '!important;">';
838 } else {
839 $html .= '<div class="cheight">';
840 }
841
842 $html .= '<div class="ctitle">';
843 if ($showLink) {
844 $html .= '<a href="' . $this->siteUrls[$this->lang] . '">' . $this->todayLabels[$this->lang] . '</a>';
845 } else {
846 $html .= '<a href="javascript:void(0)">' . $this->todayLabels[$this->lang] . '</a>';
847 }
848 $html .= '</div>';
849
850 $html .= '<div class="cephem">';
851 $html .= '<div class="today">';
852
853 $html .= '<span class="daysem">';
854 $html .= $this->shortLocalDays[$this->lang][$this->now->format('N') - 1];
855 $html .= " - ";
856 $html .= $this->shortWeekLabels[$this->lang] . " " . ltrim($this->now->format('W'), '0');
857 $html .= '</span>';
858
859 $day = $this->now->format('d');
860 $daydig1 = substr($day, 0, 1);
861 $daydig2 = substr($day, 1, 1);
862
863 $html .= '<span class="day">';
864
865 $html .= '<span class="daydig1">';
866 $html .= $daydig1;
867 $html .= '</span>';
868
869 $html .= '<span class="daydig1">';
870 $html .= $daydig2;
871 $html .= '</span>';
872
873 $html .= '</span>';
874
875
876 $html .= '<span class="month">';
877 $html .= $this->shortMonthLabels[$this->lang][$this->now->format('n') - 1];
878 $html .= '</span>';
879
880 if ($showNameDay) {
881 $html .= '<span class="fete">';
882 $html .= $this->nameDay->today($this->lang, (int)$this->now->format('n'), (int)$this->now->format('j'));
883 $html .= '</span>';
884 }
885
886 $html .= '<span class="moon">';
887 $html .= $this->getMoonSide();
888 $html .= '</span>';
889
890 $html .= '</div>';
891 $html .= '</div>';
892 $html .= '</div>';
893 $html .= '</div>';
894 $html .= '</div>';
895
896 return $html;
897 }
898
899 /**
900 * Wide calendar
901 *
902 * @param $parameters
903 *
904 * @return string
905 */
906 public function iCalendrierWide($parameters)
907 {
908 $html = "";
909
910 $showLink = isset($parameters['showLink']) ? (bool)$parameters['showLink'] : false;
911 $showNameDay = $this->showNameDay($parameters);
912 $bgColor = isset($parameters['bgColor']) ? $this->secureParam($parameters['bgColor']) : false;
913 $styleClassname = isset($parameters['style']) && 'default' !== $parameters['style'] ? ' ' . $this->secureParam($parameters['style']) : '';
914
915 if ($bgColor) {
916 $html .= '<div class="icalWide' . $styleClassname . '" style="background:' . $bgColor . ' !important;">';
917 } else {
918 $html .= '<div class="icalWide' . $styleClassname . '">';
919 }
920
921 $html .= '<div class="today">';
922
923 $html .= '<span class="ctitle">';
924 if ($showLink) {
925 $html .= '<a href="' . $this->siteUrls[$this->lang] . '">' . $this->todayLabels[$this->lang] . '</a>';
926 } else {
927 $html .= '<a href="javascript:void(0)">' . $this->todayLabels[$this->lang] . '</a>';
928 }
929 $html .= '</span>';
930
931
932 $html .= '<span class="day">';
933
934 $html .= $this->shortLocalDays[$this->lang][$this->now->format('N') - 1];
935
936 $html .= '</span>';
937
938 $html .= '<span class="num">' . $this->now->format('d') . '</span>';
939
940 $html .= '<span class="month">';
941
942 $html .= $this->monthLabels[$this->lang][$this->now->format('n') - 1];
943 $html .= '</span>';
944
945 $html .= '<span class="more">';
946 $html .= $this->weekLabels[$this->lang] . " " . ltrim($this->now->format('W'), '0');
947
948 if ($showNameDay) {
949 $html .= ' | ';
950 $html .= $this->nameDay->today($this->lang, (int)$this->now->format('n'), (int)$this->now->format('j'));
951 }
952 $html .= '</span>';
953
954 $html .= '<span class="moon">';
955
956 $html .= $this->getMoonSide();
957
958 $html .= '</span>';
959
960 $html .= '</div>';
961 $html .= '</div>';
962
963 return $html;
964 }
965
966 /**
967 * Modern layout (v2), same markup and classes as the widget on the iCalendrier sites.
968 *
969 * @param array $parameters showLink, bgColor, style, showMoon (default on), showNameDay (default on)
970 *
971 * @return string
972 */
973 public function iCalendrierModern($parameters = [])
974 {
975 $showLink = isset($parameters['showLink']) ? (bool)$parameters['showLink'] : false;
976 $showMoon = ! isset($parameters['showMoon']) || (bool)$parameters['showMoon'];
977 $showNameDay = $this->showNameDay($parameters);
978 $bgColor = isset($parameters['bgColor']) ? $this->secureParam($parameters['bgColor']) : false;
979 $styleClassname = isset($parameters['style']) && 'default' !== $parameters['style'] ? ' ' . $this->secureParam($parameters['style']) : '';
980 $lang = $this->lang;
981
982 $html = '<div class="c-ef__widget' . $styleClassname . '">';
983
984 $html .= $bgColor
985 ? '<div class="c-ef__fulldate" style="background:' . $bgColor . '!important;">'
986 : '<div class="c-ef__fulldate">';
987 if ($showLink) {
988 $html .= '<a href="' . $this->siteUrls[$lang] . '">' . $this->siteLabels[$lang] . '</a>';
989 }
990 $html .= '<div class="c-ef__dow">' . $this->dateLabel($this->localDays[$lang][$this->now->format('N') - 1]) . '</div>';
991 $html .= '<div class="c-ef__day">' . $this->now->format('d') . '</div>';
992 $html .= '<div class="c-ef__monthyear">' . $this->dateLabel($this->monthLabels[$lang][$this->now->format('n') - 1]) . ' ' . $this->now->format('Y') . '</div>';
993 $html .= '</div>';
994
995 $html .= '<div class="c-ef__metadata-icons">';
996 $html .= '<span class="c-ef__icon c-ef__icon--cal"></span>';
997 if ($showMoon) {
998 $html .= '<span class="c-ef__icon c-ef__icon--moon"></span>';
999 }
1000 if ($showNameDay) {
1001 $html .= '<span class="c-ef__icon c-ef__icon--cheer"></span>';
1002 }
1003 $html .= '</div>';
1004
1005 $html .= '<div class="c-ef__metadata">';
1006 $html .= '<div class="c-ef__weeknumber">' . $this->weekLabels[$lang] . ' ' . ltrim($this->now->format('W'), '0') . '</div>';
1007 if ($showMoon) {
1008 $moon = $this->moon();
1009 $html .= '<div class="c-ef__moonphase"><div class="c-ef__moonphase-text">';
1010 $html .= $this->localMoonPhases[$lang][$moon->phase_name()];
1011 $html .= ' <span class="c-ef__moonphasechar c-ef__moonphasechar--' . $this->moonFrame($moon) . '"></span>';
1012 $html .= '</div></div>';
1013 }
1014 if ($showNameDay) {
1015 $html .= '<div class="c-ef__saint">' . $this->nameDay->today($lang, (int)$this->now->format('n'), (int)$this->now->format('j')) . '</div>';
1016 }
1017 $html .= '</div>';
1018
1019 $html .= '</div>';
1020
1021 return $html;
1022 }
1023
1024 /** Name days are a Latin-country habit; Northern sites can switch them off. Default on. */
1025 private function showNameDay(array $parameters): bool
1026 {
1027 return ! isset($parameters['showNameDay']) || (bool)$parameters['showNameDay'];
1028 }
1029
1030 /** Day or month name in the casing the current language uses in running text. */
1031 private function dateLabel(string $label): string
1032 {
1033 return in_array($this->lang, $this->lowercaseDates, true) ? mb_strtolower($label) : $label;
1034 }
1035
1036 /**
1037 * Moon for the night that matters: before 7am the night in progress (last midnight),
1038 * from 7am the coming one (next midnight).
1039 */
1040 protected function moon(): Solaris_MoonPhase
1041 {
1042 require_once(dirname(__FILE__) . '/Solaris/MoonPhase.php');
1043
1044 $midnight = $this->now->setTime(0, 0);
1045 if ((int)$this->now->format('G') >= 7) {
1046 $midnight = $midnight->add(new DateInterval('P1D'));
1047 }
1048
1049 return new Solaris_MoonPhase((int)$midnight->format('U'));
1050 }
1051
1052 /**
1053 * Frame 0-7 in the 8-image moon sprite of the modern layout (same formula as the site widget).
1054 */
1055 protected function moonFrame(Solaris_MoonPhase $moon): int
1056 {
1057 return (int)floor(($moon->phase() + 0.0625) * 8) % 8;
1058 }
1059
1060 /**
1061 * Select the moon character
1062 * @return string
1063 */
1064 protected function getMoonSide()
1065 {
1066 $moon = $this->moon();
1067 $phase = $moon->phase();
1068
1069 // Utilisation de la font
1070
1071 // 29 "phases" pour correspondre à la font
1072 $moonCharacters = array(0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', '@', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0);
1073
1074 $totalCharacters = count($moonCharacters);
1075 $step = 1 / ($totalCharacters - 1);
1076
1077 if ($phase < $step / 2) {
1078 $index = 0;
1079 } elseif ($phase > (1 - $step / 2)) {
1080 $index = 28;
1081 } else {
1082 for ($i = 1; $i <= 27; $i++) {
1083 // Passage dans l'interval qui entoure l'illustration
1084 if ($phase >= ($step / 2 + ($i - 1) * $step) && $phase < ($step / 2 + $i * $step)) {
1085 $index = $i;
1086 }
1087 }
1088 }
1089
1090 $html = '<span class="phase">' . $moonCharacters[$index] . '</span>';
1091 $html .= $this->localMoonPhases[$this->lang][$moon->phase_name()];
1092
1093 return $html;
1094 }
1095
1096 /**
1097 * @param string $param
1098 *
1099 * @return string
1100 */
1101 private function secureParam(string $param)
1102 {
1103 return htmlentities(str_replace(["'", '"'], ['', ''], $param));
1104 }
1105
1106 }
1107