1212namespace MODX \Revolution \Filters ;
1313
1414use Exception ;
15- use MODX \Revolution \Formatter \modManagerDateFormatter ;
15+ use MODX \Revolution \Formatter \modFrontendDateFormatter ;
1616use MODX \Revolution \modElement ;
1717use MODX \Revolution \modTag ;
1818use MODX \Revolution \modTemplateVar ;
@@ -31,15 +31,14 @@ class modOutputFilter
3131 */
3232 public $ modx = null ;
3333
34- private modManagerDateFormatter $ formatter ;
34+ protected modFrontendDateFormatter $ formatter ;
3535
3636 /**
3737 * @param modX $modx A reference to the modX instance
3838 */
3939 public function __construct (modX &$ modx )
4040 {
4141 $ this ->modx = &$ modx ;
42- $ this ->formatter = $ this ->modx ->services ->get (modManagerDateFormatter::class);
4342 }
4443
4544 /**
@@ -55,13 +54,24 @@ public function filter(&$element)
5554 $ output = &$ element ->_output ;
5655 $ inputFilter = $ element ->getInputFilter ();
5756 if ($ inputFilter !== null && $ inputFilter ->hasCommands ()) {
58- $ modifier_cmd = $ inputFilter ->getCommands ();
57+ $ modifier_cmd = array_map ( ' trim ' , $ inputFilter ->getCommands () );
5958 $ modifier_value = $ inputFilter ->getModifiers ();
6059 $ count = count ($ modifier_cmd );
6160 $ condition = [];
6261
62+ // Load lexicon for filters that potentially require translation
63+ if (count (array_intersect ($ modifier_cmd , ['date ' , 'idate ' , 'strftime ' , 'fuzzydate ' , 'ago ' ])) > 0 ) {
64+ $ cultureKey = $ this ->modx ->getOption ('cultureKey ' , null , 'en ' );
65+ $ locale = $ this ->modx ->config ['locale ' ];
66+ $ lang = !empty ($ locale ) && strlen ($ locale ) >= 2 ? substr ($ locale , 0 , 2 ) : $ cultureKey ;
67+ if (empty ($ this ->modx ->lexicon )) {
68+ $ this ->modx ->getService ('lexicon ' , 'modLexicon ' );
69+ }
70+ $ this ->modx ->lexicon ->load ("{$ lang }:core:filters " );
71+ }
72+
6373 for ($ i = 0 ; $ i < $ count ; $ i ++) {
64- $ m_cmd = trim ( $ modifier_cmd [$ i ]) ;
74+ $ m_cmd = $ modifier_cmd [$ i ];
6575 $ m_val = $ modifier_value [$ i ];
6676
6777 $ this ->log ('Processing Modifier: ' . $ m_cmd . ' (parameters: ' . $ m_val . ') ' );
@@ -451,19 +461,27 @@ public function filter(&$element)
451461 /* See PHP's nl2br - http://www.php.net/manual/en/function.nl2br.php */
452462 $ output = nl2br ($ output );
453463 break ;
464+
465+ case 'tabs2spaces ' :
466+ $ spacesPerTab = !empty ($ m_val ) ? (int )$ m_val : 2 ;
467+ if (strpos ($ output , "\t" ) !== false ) {
468+ $ replacement = '' ;
469+ $ i = 0 ;
470+ while ($ i < $ spacesPerTab ) {
471+ $ i ++;
472+ $ replacement .= ' ' ;
473+ }
474+ $ output = str_replace ("\t" , $ replacement , $ output );
475+ }
476+ break ;
454477
455478 case 'strftime ' : /** @deprecated Removal of strftime filter option tbd */
456479 case 'date ' :
457- /* See PHP's datetime - https://www.php.net/manual/en/datetime.format.php */
458- if (empty ($ m_val )) {
459- $ m_val = 'l, d F Y H:i:s ' ;
460- /* @todo this should be modx default date/time format? Lexicon? */
461- }
462- if (($ value = filter_var ($ output , FILTER_VALIDATE_INT )) === false ) {
463- $ value = strtotime ($ output );
464- }
465- $ output = ($ value !== false )
466- ? $ this ->formatter ->format ($ value , $ m_val )
480+ $ format = !empty ($ m_val ) ? $ m_val : '%A, %d %B %Y %H:%M:%S ' ;
481+ $ formatter = new modFrontendDateFormatter ($ this ->modx );
482+ $ formatter ->setSourceFormat ($ m_val );
483+ $ output = ($ output !== false )
484+ ? $ formatter ->format ($ output , $ format )
467485 : ''
468486 ;
469487 break ;
@@ -476,45 +494,42 @@ public function filter(&$element)
476494 $ output = '' ;
477495 }
478496 break ;
497+
479498 case 'fuzzydate ' :
480- /* displays a "fuzzy" date reference */
481- if (empty ($ this ->modx ->lexicon )) {
482- $ this ->modx ->getService ('lexicon ' , 'modLexicon ' );
483- }
484- $ this ->modx ->lexicon ->load ('filters ' );
485499 if (!empty ($ output )) {
486- $ defaultTimeFormat = ' h:i A ' ;
500+ $ relativeFormat = ! empty ( $ m_val ) ? $ m_val : ' %I:%M %p ' ;
487501 $ time = strtotime ($ output );
502+ $ formatter = new modFrontendDateFormatter ($ this ->modx );
503+ $ formatter ->setSourceFormat ($ relativeFormat );
488504 if ($ time >= strtotime ('today ' )) {
489505 $ output = $ this ->modx ->lexicon (
490506 'today_at ' ,
491- ['time ' => $ this ->formatter ->format ($ time , $ defaultTimeFormat )]
507+ ['time ' => $ formatter ->format ($ time , $ relativeFormat )],
508+ $ lang
492509 );
493510 } elseif ($ time >= strtotime ('yesterday ' )) {
494511 $ output = $ this ->modx ->lexicon (
495512 'yesterday_at ' ,
496- ['time ' => $ this ->formatter ->format ($ time , $ defaultTimeFormat )]
513+ ['time ' => $ formatter ->format ($ time , $ relativeFormat )],
514+ $ lang
497515 );
498516 } else {
499517 if (empty ($ m_val )) {
500- $ m_val = 'M j ' ;
518+ $ m_val = '%b %e ' ;
501519 }
502- $ output = $ this ->formatter ->format ($ time , $ m_val );
520+ $ formatter ->setSourceFormat ($ m_val );
521+ $ output = $ formatter ->format ($ time , $ m_val );
503522 }
504523 } else {
505524 $ output = '— ' ;
506525 }
507526 break ;
527+
508528 case 'ago ' :
509529 /* calculates relative time ago from a timestamp */
510530 if (empty ($ output )) {
511531 break ;
512532 }
513- if (empty ($ this ->modx ->lexicon )) {
514- $ this ->modx ->getService ('lexicon ' , 'modLexicon ' );
515- }
516- $ this ->modx ->lexicon ->load ('filters ' );
517-
518533 $ agoTS = [];
519534 $ uts ['start ' ] = strtotime ($ output );
520535 $ uts ['end ' ] = time ();
@@ -569,47 +584,54 @@ public function filter(&$element)
569584 if (!empty ($ agoTS ['years ' ])) {
570585 $ ago [] = $ this ->modx ->lexicon (
571586 ($ agoTS ['years ' ] > 1 ? 'ago_years ' : 'ago_year ' ),
572- ['time ' => $ agoTS ['years ' ]]
587+ ['time ' => $ agoTS ['years ' ]],
588+ $ lang
573589 );
574590 }
575591 if (!empty ($ agoTS ['months ' ])) {
576592 $ ago [] = $ this ->modx ->lexicon (
577593 ($ agoTS ['months ' ] > 1 ? 'ago_months ' : 'ago_month ' ),
578- ['time ' => $ agoTS ['months ' ]]
594+ ['time ' => $ agoTS ['months ' ]],
595+ $ lang
579596 );
580597 }
581598 if (!empty ($ agoTS ['weeks ' ]) && empty ($ agoTS ['years ' ])) {
582599 $ ago [] = $ this ->modx ->lexicon (
583600 ($ agoTS ['weeks ' ] > 1 ? 'ago_weeks ' : 'ago_week ' ),
584- ['time ' => $ agoTS ['weeks ' ]]
601+ ['time ' => $ agoTS ['weeks ' ]],
602+ $ lang
585603 );
586604 }
587605 if (!empty ($ agoTS ['days ' ]) && empty ($ agoTS ['months ' ]) && empty ($ agoTS ['years ' ])) {
588606 $ ago [] = $ this ->modx ->lexicon (
589607 ($ agoTS ['days ' ] > 1 ? 'ago_days ' : 'ago_day ' ),
590- ['time ' => $ agoTS ['days ' ]]
608+ ['time ' => $ agoTS ['days ' ]],
609+ $ lang
591610 );
592611 }
593612 if (!empty ($ agoTS ['hours ' ]) && empty ($ agoTS ['weeks ' ]) && empty ($ agoTS ['months ' ]) && empty ($ agoTS ['years ' ])) {
594613 $ ago [] = $ this ->modx ->lexicon (
595614 ($ agoTS ['hours ' ] > 1 ? 'ago_hours ' : 'ago_hour ' ),
596- ['time ' => $ agoTS ['hours ' ]]
615+ ['time ' => $ agoTS ['hours ' ]],
616+ $ lang
597617 );
598618 }
599619 if (!empty ($ agoTS ['minutes ' ]) && empty ($ agoTS ['days ' ]) && empty ($ agoTS ['weeks ' ]) && empty ($ agoTS ['months ' ]) && empty ($ agoTS ['years ' ])) {
600620 $ ago [] = $ this ->modx ->lexicon (
601621 ($ agoTS ['minutes ' ] == 1 ? 'ago_minute ' : 'ago_minutes ' ),
602- ['time ' => $ agoTS ['minutes ' ]]
622+ ['time ' => $ agoTS ['minutes ' ]],
623+ $ lang
603624 );
604625 }
605626 if (empty ($ ago )) { /* handle <1 min */
606627 $ ago [] = $ this ->modx ->lexicon (
607628 'ago_seconds ' ,
608- ['time ' => !empty ($ agoTS ['seconds ' ]) ? $ agoTS ['seconds ' ] : 0 ]
629+ ['time ' => !empty ($ agoTS ['seconds ' ]) ? $ agoTS ['seconds ' ] : 0 ],
630+ $ lang
609631 );
610632 }
611633 $ output = implode (', ' , $ ago );
612- $ output = $ this ->modx ->lexicon ('ago ' , ['time ' => $ output ]);
634+ $ output = $ this ->modx ->lexicon ('ago ' , ['time ' => $ output ], $ lang );
613635 break ;
614636 case 'md5 ' :
615637 /* See PHP's md5 - http://www.php.net/manual/en/function.md5.php */
0 commit comments