this is working

This commit is contained in:
2025-07-29 11:08:33 +00:00
parent 192094c23a
commit a648a67a0c
287 changed files with 29278 additions and 73 deletions

View File

@@ -73,8 +73,8 @@ $args = array(
//~ }
//~ }
$context['posts'] = new Timber\PostQuery($args);
$context['mainpost'] = new Timber\PostQuery($mainargs);
$context['posts'] = Timber::get_posts($args);
$context['mainpost'] = Timber::get_posts($mainargs);
$context['section_title'] = 'actualidad';

344
assets/css/audioplayer.css Normal file
View File

@@ -0,0 +1,344 @@
.audioplayer
{
height: 2.5em; /* 40 */
color: #fff;
text-shadow: 1px 1px 0 #000;
border: 1px solid #222;
position: relative;
z-index: 1;
background: #333;
background: -webkit-gradient( linear, left top, left bottom, from( #444 ), to( #222 ) );
background: -webkit-linear-gradient( top, #444, #222 );
background: -moz-linear-gradient( top, #444, #222 );
background: -ms-radial-gradient( top, #444, #222 );
background: -o-linear-gradient( top, #444, #222 );
background: linear-gradient( top, #444, #222 );
-webkit-box-shadow: inset 0 1px 0 rgba( 255, 255, 255, .15 ), 0 0 1.25em rgba( 0, 0, 0, .5 ); /* 20 */
-moz-box-shadow: inset 0 1px 0 rgba( 255, 255, 255, .15 ), 0 0 1.25em rgba( 0, 0, 0, .5 ); /* 20 */
box-shadow: inset 0 1px 0 rgba( 255, 255, 255, .15 ), 0 0 1.25em rgba( 0, 0, 0, .5 ); /* 20 */
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
}
.audioplayer-mini
{
width: 2.5em; /* 40 */
margin: 0 auto;
}
.audioplayer > div
{
position: absolute;
}
.audioplayer-playpause
{
width: 2.5em; /* 40 */
height: 100%;
text-align: left;
text-indent: -9999px;
cursor: pointer;
z-index: 2;
top: 0;
left: 0;
}
.audioplayer:not(.audioplayer-mini) .audioplayer-playpause
{
border-right: 1px solid #555;
border-right-color: rgba( 255, 255, 255, .1 );
}
.audioplayer-mini .audioplayer-playpause
{
width: 100%;
}
.audioplayer-playpause:hover,
.audioplayer-playpause:focus
{
background-color: #222;
}
.audioplayer-playpause a
{
display: block;
}
.audioplayer:not(.audioplayer-playing) .audioplayer-playpause a
{
width: 0;
height: 0;
border: 0.5em solid transparent; /* 8 */
border-right: none;
border-left-color: #fff;
content: '';
position: absolute;
top: 50%;
left: 50%;
margin: -0.5em 0 0 -0.25em; /* 8 4 */
}
.audioplayer-playing .audioplayer-playpause a
{
width: 0.75em; /* 12 */
height: 0.75em; /* 12 */
position: absolute;
top: 50%;
left: 50%;
margin: -0.375em 0 0 -0.375em; /* 6 */
}
.audioplayer-playing .audioplayer-playpause a:before,
.audioplayer-playing .audioplayer-playpause a:after
{
width: 40%;
height: 100%;
background-color: #fff;
content: '';
position: absolute;
top: 0;
}
.audioplayer-playing .audioplayer-playpause a:before
{
left: 0;
}
.audioplayer-playing .audioplayer-playpause a:after
{
right: 0;
}
.audioplayer-time
{
width: 4.375em; /* 70 */
height: 100%;
line-height: 2.375em; /* 38 */
text-align: center;
z-index: 2;
top: 0;
}
.audioplayer-time-current
{
border-left: 1px solid #111;
border-left-color: rgba( 0, 0, 0, .25 );
left: 2.5em; /* 40 */
}
.audioplayer-time-duration
{
border-right: 1px solid #555;
border-right-color: rgba( 255, 255, 255, .1 );
right: 2.5em; /* 40 */
}
.audioplayer-novolume .audioplayer-time-duration
{
border-right: 0;
right: 0;
}
.audioplayer-bar
{
height: 0.875em; /* 14 */
background-color: #222;
cursor: pointer;
z-index: 1;
top: 50%;
right: 6.875em; /* 110 */
left: 6.875em; /* 110 */
margin-top: -0.438em; /* 7 */
}
.audioplayer-novolume .audioplayer-bar
{
right: 4.375em; /* 70 */
}
.audioplayer-bar div
{
width: 0;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
.audioplayer-bar-loaded
{
background-color: #333;
z-index: 1;
}
.audioplayer-bar-played
{
background: #007fd1;
background: -webkit-gradient( linear, left top, right top, from( #007fd1 ), to( #c600ff ) );
background: -webkit-linear-gradient( left, #007fd1, #c600ff );
background: -moz-linear-gradient( left, #007fd1, #c600ff );
background: -ms-radial-gradient( left, #007fd1, #c600ff );
background: -o-linear-gradient( left, #007fd1, #c600ff );
background: linear-gradient( left, #007fd1, #c600ff );
z-index: 2;
}
.audioplayer-volume
{
width: 2.5em; /* 40 */
height: 100%;
border-left: 1px solid #111;
border-left-color: rgba( 0, 0, 0, .25 );
text-align: left;
text-indent: -9999px;
cursor: pointer;
z-index: 2;
top: 0;
right: 0;
}
.audioplayer-volume:hover,
.audioplayer-volume:focus
{
background-color: #222;
}
.audioplayer-volume-button
{
width: 100%;
height: 100%;
}
.audioplayer-volume-button a
{
width: 0.313em; /* 5 */
height: 0.375em; /* 6 */
background-color: #fff;
display: block;
position: relative;
z-index: 1;
top: 40%;
left: 35%;
}
.audioplayer-volume-button a:before,
.audioplayer-volume-button a:after
{
content: '';
position: absolute;
}
.audioplayer-volume-button a:before
{
width: 0;
height: 0;
border: 0.5em solid transparent; /* 8 */
border-left: none;
border-right-color: #fff;
z-index: 2;
top: 50%;
right: -0.25em;
margin-top: -0.5em; /* 8 */
}
.audioplayer:not(.audioplayer-mute) .audioplayer-volume-button a:after
{
/* "volume" icon by Nicolas Gallagher, http://nicolasgallagher.com/pure-css-gui-icons */
width: 0.313em; /* 5 */
height: 0.313em; /* 5 */
border: 0.25em double #fff; /* 4 */
border-width: 0.25em 0.25em 0 0; /* 4 */
left: 0.563em; /* 9 */
top: -0.063em; /* 1 */
-webkit-border-radius: 0 0.938em 0 0; /* 15 */
-moz-border-radius: 0 0.938em 0 0; /* 15 */
border-radius: 0 0.938em 0 0; /* 15 */
-webkit-transform: rotate( 45deg );
-moz-transform: rotate( 45deg );
-ms-transform: rotate( 45deg );
-o-transform: rotate( 45deg );
transform: rotate( 45deg );
}
.audioplayer-volume-adjust
{
height: 6.25em; /* 100 */
cursor: default;
position: absolute;
left: 0;
right: -1px;
top: -9999px;
background: #222;
background: -webkit-gradient( linear, left top, left bottom, from( #444 ), to( #222 ) );
background: -webkit-linear-gradient( top, #444, #222 );
background: -moz-linear-gradient( top, #444, #222 );
background: -ms-radial-gradient( top, #444, #222 );
background: -o-linear-gradient( top, #444, #222 );
background: linear-gradient( top, #444, #222 );
-webkit-border-top-left-radius: 2px;
-webkit-border-top-right-radius: 2px;
-moz-border-radius-topleft: 2px;
-moz-border-radius-topright: 2px;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
.audioplayer-volume:not(:hover) .audioplayer-volume-adjust
{
opacity: 0;
}
.audioplayer-volume:hover .audioplayer-volume-adjust
{
top: auto;
bottom: 100%;
}
.audioplayer-volume-adjust > div
{
width: 40%;
height: 80%;
background-color: #222;
cursor: pointer;
position: relative;
z-index: 1;
margin: 30% auto 0;
}
.audioplayer-volume-adjust div div
{
width: 100%;
height: 100%;
position: absolute;
bottom: 0;
left: 0;
background: #007fd1;
background: -webkit-gradient( linear, left bottom, left top, from( #007fd1 ), to( #c600ff ) );
background: -webkit-linear-gradient( bottom, #007fd1, #c600ff );
background: -moz-linear-gradient( bottom, #007fd1, #c600ff );
background: -ms-radial-gradient( bottom, #007fd1, #c600ff );
background: -o-linear-gradient( bottom, #007fd1, #c600ff );
background: linear-gradient( bottom, #007fd1, #c600ff );
}
.audioplayer-novolume .audioplayer-volume
{
display: none;
}
.audioplayer-play,
.audioplayer-pause,
.audioplayer-volume a
{
-webkit-filter: drop-shadow( 1px 1px 0 #000 );
-moz-filter: drop-shadow( 1px 1px 0 #000 );
-ms-filter: drop-shadow( 1px 1px 0 #000 );
-o-filter: drop-shadow( 1px 1px 0 #000 );
filter: drop-shadow( 1px 1px 0 #000 );
}
.audioplayer-bar,
.audioplayer-bar div,
.audioplayer-volume-adjust div
{
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.audioplayer-bar,
.audioplayer-volume-adjust > div
{
-webkit-box-shadow: -1px -1px 0 rgba( 0, 0, 0, .5 ), 1px 1px 0 rgba( 255, 255, 255, .1 );
-moz-box-shadow: -1px -1px 0 rgba( 0, 0, 0, .5 ), 1px 1px 0 rgba( 255, 255, 255, .1 );
box-shadow: -1px -1px 0 rgba( 0, 0, 0, .5 ), 1px 1px 0 rgba( 255, 255, 255, .1 );
}
.audioplayer-volume-adjust div div,
.audioplayer-bar-played
{
-webkit-box-shadow: inset 0 0 5px rgba( 255, 255, 255, .5 );
-moz-box-shadow: inset 0 0 5px rgba( 255, 255, 255, .5 );
box-shadow: inset 0 0 5px rgba( 255, 255, 255, .5 );
}
.audioplayer-volume-adjust
{
-webkit-box-shadow: -2px -2px 2px rgba( 0, 0, 0, .15 ), 2px -2px 2px rgba( 0, 0, 0, .15 );
-moz-box-shadow: -2px -2px 2px rgba( 0, 0, 0, .15 ), 2px -2px 2px rgba( 0, 0, 0, .15 );
box-shadow: -2px -2px 2px rgba( 0, 0, 0, .15 ), 2px -2px 2px rgba( 0, 0, 0, .15 );
}
.audioplayer *,
.audioplayer *:before,
.audioplayer *:after
{
-webkit-transition: color .25s ease, background-color .25s ease, opacity .5s ease;
-moz-transition: color .25s ease, background-color .25s ease, opacity .5s ease;
-ms-transition: color .25s ease, background-color .25s ease, opacity .5s ease;
-o-transition: color .25s ease, background-color .25s ease, opacity .5s ease;
transition: color .25s ease, background-color .25s ease, opacity .5s ease;
}

1
assets/css/blueimp-gallery.min.css vendored Normal file

File diff suppressed because one or more lines are too long

7
assets/css/bootstrap-grid.min.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

8
assets/css/bootstrap-reboot.min.css vendored Normal file
View File

@@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
* Copyright 2011-2019 The Bootstrap Authors
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */

File diff suppressed because one or more lines are too long

7
assets/css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

423
assets/css/custom.css Normal file
View File

@@ -0,0 +1,423 @@
/*-----------------------------------------------------------------------------------
CSS Name: CGTnews over Hashnews - Modern Magazine & Newspaper HTML Template
Description: CGTnews
Author: Estudio Nexos
Author URI: https://www.estudionexos.com/
Version: 1.0
-----------------------------------------------------------------------------------*/
/*----------------------------------------*/
/* 1. Theme default CSS
/*----------------------------------------*/
/*-- Colors --*/
/* maincolor = '#b4061b'
highlight1 = '#b4061b'
highlight1hover = '#8d0801'
highlight2 = '#b4061b'
bgdark = '#001427'
bgdarkhover = '#002548'
/*--
Sections colors
-----------------------------------------*/
/*
dark-red = #d40000 //accion sindical
dark-brown = #986601 //agitacion
light-brown = #ae906d //confederacion
dark-green = #029502 //sin fronteras
light-green = #339900 //cultura libre
violet = #a54bff //eje violeta
dark-blue = #0147d1 //ideas
*/
/*-- Fonts --*/
@font-face {
font-family: "AvenirBold";
src: url(/wp-content/themes/ryn/src/fonts/AvenirNextLTPro-Bold.otf);
font-weight:600;
}
@font-face {
font-family: "AvenirRegular";
src: url(/wp-content/themes/ryn/src/fonts/AvenirNextLTPro-Regular.otf);
font-weight:600;
}
/*-- Google Font --*/
@import url("https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900");
/*-- Common Style --*/
body { font-family: "AvenirRegular", "Roboto", sans-serif; background-color:#f5f5f5; font-weight:400; }
h1, h2, h3, h4, h5, h6 { font-family: "AvenirBold", "Roboto", sans-serif; }
ul { list-style: square outside none; margin: 0px; padding: 0 0 0px 20px; }
ul.sub-menu, ul.sub-menu ul, ul.breaking-news-ticker { list-style: none; margin: 0px; padding: 0px; }
.bg-dark { background-color: #001427 !important; }
.text-danger { color: #b4061b; }
.badge-danger { background-color: #b4061b; }
a { color:#001427; }
a:hover { text-decoration: none; color: #d40000; }
/*-- --
Scroll Up
-----------------------------------------*/
#scrollUp { background-color: #b4061b; }
/*--
Youtube Video PlayList
-----------------------------------------*/
.RYPP { padding: 18px 18px 100px 18px; }
.RYPP .RYPP-playlist { height: 75px; }
.playlist { background-color: #000; }
/*--
Page Banner
-----------------------------------------*/
/*-- Page Banner --*/
.page-banner { padding: 30px 0px 0px; }
@media only screen and (min-width: 992px) and (max-width: 1200px) { .page-banner { padding: 20px 0px 0px; } }
@media only screen and (min-width: 768px) and (max-width: 991px) { .page-banner { padding: 20px 0px 0px; } }
@media only screen and (max-width: 767px) { .page-banner { padding: 20px 0px 0px; } }
.page-banner h2 { color: #000; text-transform: none; }
/*--
Instagram Carousel
-----------------------------------------*/
.instagram-carousel .video.instagram-item::before { content: "\f03d"; }
.instagram-carousel .galeria.instagram-item::before { content: "\f03e"; }
.instagram-carousel .publicacion.instagram-item::before { content: "\f0f6"; color:#666; }
/*--
Blockquote
-----------------------------------------*/
blockquote { text-align: left; background-color: #ccc; color: #000; position: relative; overflow: hidden; width: 100%; float: left; padding: 35px 35px 10px 80px; }
blockquote::before { font-family: 'Fontawesome'; content: "\f10d"; position: absolute; left: -2px; top: 3px; font-size: 60px; color: #ffffff; }
/*--
Background color
-----------------------------------------*/
/*
.bg-red { background-color: #b4061b; }
*/
.bg-red { background-color: #f05555; }
.bg-red .post-block-wrapper { background-color: #f69e9e; }
/*----------------------------------------*/
/* 2. Header
/*----------------------------------------*/
/*----
Header Section
------------------------------------------*/
.header-section { background-color: #ffffff; }
@media only screen and (min-width: 777px) {
.header-logo .logo { float:right; }
.header-section {
background-image: url("/wp-content/themes/ryn/src/img/g4841.png");
background-position: top right;
background-repeat: no-repeat;
background-size: 85px auto;
}
.header-banner { text-align:left; }
}
@media only screen and (min-width: 777px) and (max-width: 1024px) {
.header-section {
padding:10px 0;
background-size: 90px auto;
}
}
@media only screen and (min-width: 741px) and (max-width: 777px) {
.header-section { background-image:none; }
.header-banner { line-height: 20px; }
}
@media only screen and (max-width: 740px) {
.header-top-links ul.header-links { padding:0px; float:none; width:65%; margin:0 auto; text-align:center;}
.header-top-links .header-links li::before { background-color: transparent; }
.header-top-social { text-align:center; }
.header-top-social .header-social { float:none; }
.header-top-social .header-social a { display:inline; float:none; }
.header-section { display:none; }
}
/*-- Header Logo --*/
/*
.header-logo .logo img { height:100px; }
*/
/*-- Header Banner --*/
.header-banner .banner a img { max-width:auto; width:auto; }
/*----
Menu Section
------------------------------------------*/
/*-- Main Menu --*/
.main-menu nav > ul > li.active > a,
.main-menu nav > ul > li:hover > a { color: #b4061b; }
/*-- Sub Menu --*/
.sub-menu li.active a, .sub-menu li:hover a, .sub-menu li a:hover { color: #b4061b; }
.sub-sub-menu { border-top: 1px solid #f1f1f1; }
.sub-sub-menu li { padding-left: 10px }
.sub-menu li:hover .sub-sub-menu li a { color: #666666; }
.sub-menu li:hover .sub-sub-menu li a:hover { color:red; }
/*----
Header Top
------------------------------------------*/
.header-top-links .header-links li.disabled a { background-color: #f05555; }
.header-top-links .header-links li a:hover { color: #b4061b; }
.header-top-social .header-social a:hover {color: #b4061b;}
/*--
Breaking News Section
------------------------------------------*/
.breaking-news-section { background-color: #b4061b; /*-- Breaking News Section Two --*/ /*-- Breaking News Section Three --*/ }
.breaking-news-wrapper .breaking-news-nav button { background-color: red; /*-- Hover --*/ }
/*-- Breaking News Wrapper --*/
.breaking-news-wrapper .breaking-news-ticker li a { font-family: "Roboto", sans-serif; }
/*----------------------------------------*/
/* 3. Post Common Style For Post Block, Carousel & Nav Etc
/*----------------------------------------*/
/*-- Popular Section --*/
.single-publicacion .popular-section { background-color: #1f2024; }
.popular-section .popular-section-title { align-self:center; }
.popular-section h2.title { text-align:center; text-transform:uppercase; font-size:18px; font-weight:600; color:#fff; margin:auto 0px; }
/*-- Post Block Wrapper --*/
.post-block-wrapper { border: 1px solid #f1f1f1; background-color: #ffffff; }
.single-galeria .post-block-wrapper.post-content,
.single-video .post-block-wrapper.post-content,
.single-publicacion .post-block-wrapper.post-content,
.single-audio .post-block-wrapper.post-content { border: none; }
.post-header .teaser,
.single-video .teaser,
.single-publicacion .teaser,
.single-audio .teaser { color:#fff; }
@media only screen and (min-width: 992px) {
.single-video .teaser { position:absolute; bottom:30px; font-size:18px; }
.post-header .teaser,
.single-audio .teaser { font-size:16px; }
.single-publicacion .teaser { font-size:18px; }
}
.post-block-wrapper .head { border-bottom: 3px solid #f1f1f1; }
.post-block-wrapper.dark-red .head { border-bottom: 3px solid #d40000; }
.post-block-wrapper.dark-green .head { border-bottom: 3px solid #029502; }
.post-block-wrapper.light-green .head { border-bottom: 3px solid #339900; }
.post-block-wrapper.dark-brown .head { border-bottom: 3px solid #986601; }
.post-block-wrapper.light-brown .head { border-bottom: 3px solid #ae906d; }
.post-block-wrapper.violet .head { border-bottom: 3px solid #a54bff; }
/*
.post-block-wrapper.violet .head { background: linear-gradient(to left, #fff, #a54bff); border-bottom: 3px solid #fff; }
*/
.post-block-wrapper.dark-blue .head { border-bottom: 3px solid #0147d1; }
.post-block-wrapper.violet { background-color:#a54bff; color:#f5f5f5; }
.post-block-wrapper.violet .head { border-bottom: 3px solid #f1f1f1; }
.post-block-wrapper.violet a { color:#fff; }
.post-block-wrapper.violet a:hover { color:#d40000; }
.post-block-wrapper.bg-dark a { color:#f1f1f1; }
.post-block-wrapper.bg-dark a:hover { color:#d40000; }
.post-block-wrapper .head h2,
.post-block-wrapper .head h3 { font-size: 18px; line-height: 24px; }
.post-block-wrapper .head::before, .post-block-wrapper .head::after { background-color: #b4061b; }
.post-block-wrapper .head .title { color: #b4061b; }
.post-block-wrapper .head .post-block-tab-list > li > a { font-family: "AvenirRegular","Roboto", sans-serif; font-weight: bold; }
.post-block-wrapper .head .post-block-tab-list > li .dropdown-menu li a { font-family: "Roboto", sans-serif; }
.post-block-wrapper .head .post-block-tab-list.feature-post-tab-list > li > a:hover,
.post-block-wrapper .head .post-block-tab-list.feature-post-tab-list > li > a.active { color: #b4061b; }
.post-block-wrapper.dark-red .head .post-block-tab-list.feature-post-tab-list > li > a:hover,
.post-block-wrapper.dark-red .head .post-block-tab-list.feature-post-tab-list > li > a.active { color: #d40000; }
.post-block-wrapper.dark-blue .head .post-block-tab-list.feature-post-tab-list > li > a:hover,
.post-block-wrapper.dark-blue .head .post-block-tab-list.feature-post-tab-list > li > a.active { color: #0147d1; }
.post-block-wrapper .head .post-block-tab-list.feature-post-tab-list > li .dropdown-menu li a:hover,
.post-block-wrapper .head .post-block-tab-list.feature-post-tab-list > li .dropdown-menu li a.active { color: red; }
.post-block-wrapper .body .single-post .content { font-size:18px; line-height: 28px; }
.post-carousel-1 .slick-arrow { background-color: #000; color:#fff; }
/*
.post-block-carousel .slick-arrow:hover { color: #b4061b; border-color: #b4061b; }
*/
.page-pagination ul li a { width:auto; min-width:30px; }
/*----------------------------------------*/
/* 4. Post Styles
/*----------------------------------------*/
.post .post-wrap .category { font-family: "Roboto", sans-serif; }
.post .post-wrap .content .title { font-size: 22px; line-height: 24px; }
@media only screen and (min-width: 992px) and (max-width: 1200px) { .post .post-wrap .content .title { font-size: 20px; } }
@media only screen and (max-width: 479px) { .post .post-wrap .content .title { font-size: 14px; line-height: 18px; } }
.post.post-small .post-wrap .content .title { font-size: 16px; line-height: 18px; }
@media only screen and (min-width: 992px) and (max-width: 1200px) { .post.post-small .post-wrap .content .title { font-size: 12px; line-height: 16px; } }
.post.post-large .post-wrap .content .title { font-size: 32px; line-height: 36px; }
@media only screen and (min-width: 992px) and (max-width: 1200px) { .post.post-large .post-wrap .title { font-size: 28px; line-height: 32px; } }
@media only screen and (max-width: 767px) { .post.post-large .post-wrap .content .title { font-size: 24px; line-height: 30px; } }
@media only screen and (max-width: 479px) { .post.post-large .post-wrap .content .title { font-size: 14px; line-height: 18px; } }
.post .post-wrap .content .title a:hover { color: #b4061b; }
.post .post-wrap .content .meta .meta-item.date { font-size:0.8rem; }
.post .post-wrap .content .meta .meta-item.date.event { font-size:0.9rem; line-height:1.3rem; font-family:"AvenirBold", Roboto, sans-serif; }
.post .post-wrap .content .meta .meta-item i { line-height:18px; }
.post-header .meta .meta-item.author i { color:#17a2b8; }
.post-header .meta .meta-item.category.politic { background-color: #b4061b; }
.post-header .meta .meta-item.category.politic:hover { background-color:#8d0801; }
.post-header .meta .meta-item i { color: /*#b4061b*/#bbb; }
.post.post-overlay.post-large .content { left:50px; right:50px; }
.post.post-overlay .post-wrap .category { position: static; left: auto; top: auto; float:left; margin-right:3px; }
.post.post-overlay .post-wrap .categories { position: absolute; left: 3px; top: 3px; z-index:100; }
/*----------------------------------------*/
/* 5. Single Post Details
/*----------------------------------------*/
/*-- Post Header --*/
.post-header { padding: 50px 30px; background-color: rgba(98, 28, 28, 0.65) }
.post-header .title { font-size: 3rem; line-height: 4rem; font-weight: 700; }
@media only screen and (min-width: 992px) and (max-width: 1200px) { .post-header .title { font-size: 28px; line-height: 32px; } }
@media only screen and (max-width: 767px) { .post-header .title { font-size: 24px; line-height: 30px; } }
@media only screen and (max-width: 479px) { .post-header .title { font-size: 18px; line-height: 24px; } }
.post-header-section { box-shadow: 0 16px 32px 0 rgba(52,58,64,.24); }
@media only screen and (max-width: 767px) { .post-header { padding-bottom: 40px; } }
.post-header .meta .meta-item { font-family: "AvenirRegular","Roboto", sans-serif; }
.post-header .meta .meta-item.category { margin-right:5px; border-radius:0px; }
/*-- Single Post --*/
.single-post .post-wrap .content p { margin-bottom: 30px; display: block; float: none; }
.single-post .post-wrap .content p:first-child { font-family: "AvenirBold", "Roboto"; font-weight:bold; line-height: 24px; font-size: 18px; }
.single-blog .blog-wrap .meta .meta-item.category { margin-right:5px; }
/*-- Single post Publicacion --*/
.single-publicacion .post-content .post-header { padding: 30px 0px 10px; background-color:transparent; }
.single-publicacion .post-header .meta .meta-item { color:#666; }
.single-publicacion .post-header .meta .meta-item.category { color:#fff; }
.single-publicacion .post-header .title { color: #000; }
/*----------------------------------------*/
/* 6. Blog & Blog Details
/*----------------------------------------*/
/*-- Single Post --*/
.single-blog .blog-wrap .meta .meta-item { font-family:"AvenirRegular","Roboto", sans-serif; }
/*----------------------------------------*/
/* 7. Sidebar
/*----------------------------------------*/
/*-- Sidebar Block Wrapper --*/
.sidebar-block-wrapper .head::before, .sidebar-block-wrapper .head::after { background-color: #b4061b; }
.sidebar-block-wrapper .head .title { color: #b4061b; }
/*-- Sidebar Social Follow --*/
.sidebar-social-follow > div { padding: 1px; width: 33%; float: left; }
/*-- Sidebar Tab List For Latest & Popular News --*/
.sidebar-tab-list a { font-family: "AvenirRegular","Roboto", sans-serif; }
.sidebar-tab-list.sidebar-tab-list-3-tabs a { width: 33.33%; }
.sidebar-tab-list.sidebar-tab-list-3-tabs a:last-child::after { right: -1.1px; }
.sidebar-tab-list a::before,
.sidebar-tab-list a::after,
.sidebar-tab-list a.active { background-color: #b4061b; }
/*-- Sidebar Category --*/
.sidebar-category li a { font-family: "AvenirRegular","Roboto", sans-serif; }
/*----------------------------------------*/
/* 8. Contact
/*----------------------------------------*/
/*-- Contact Form --*/
.contact-form input[type="checkbox"] { width: auto; height: auto; border: 1px solid #f1f1f1; line-height: 24px; padding: 7px 15px; }
.contact-form button[type="submit"] { width: auto; border-radius: 5px; background-color: #00c8fa; color: #ffffff; text-transform: capitalize; border: none; padding: 8px 30px; }
.contact-form legend { display: block; line-height: 18px; font-size:14px; font-weight:600; }
.contact-form button[type="submit"]:focus { border: none; }
/*----------------------------------------*/
/* 9. Footer
/*----------------------------------------*/
/*--
Footer Top
----------------------------------------*/
/*-- Footer Widget --*/
.footer-widget .widget-title { border-left: 4px solid #b4061b; }
.footer-widget .widget-title { font-family: "AvenirRegular","Roboto", sans-serif; }
.footer-widget .footer-widget-post .post-wrap .content .meta .meta-item { font-family: "AvenirRegular","Roboto", sans-serif; }
.footer-widget .single-tweet .content .head h5 { font-family: "AvenirRegular","Roboto", sans-serif; }
.footer-top-section a, .footer-bottom-section a {color:#fff; }
.footer-widget .content .footer-social a.rss { background-color: orange; }
.not-front .footer-widget .content .footer-social a { width: 56px; height: 56px; border-radius: 3px; text-align: center; color: #ffffff; text-shadow: 0 2px 2px rgba(0, 0, 0, 0.4); }
.not-front .footer-widget .content .footer-social a i { font-size: 28px; line-height: 58px; }
/*----------------------------------------*/
/* 10. Extra CSS
/*----------------------------------------*/
/*--
Masonry
----------------------------------------*/
.grid-sizer,
.grid-item { float:left; width: 100%; margin-bottom: 10px;}
.grid-item--width2 { width:100%; }
.grid-item img { max-width:100%; }
@media only screen and (min-width: 1501px) {
.grid-sizer,
.grid-item { float:left; width: 16.1%;}
.grid-item--width2 { width: 49.5%; }
.grid-item img { max-width:100%; }
}
@media only screen and (min-width: 1370px) and (max-width: 1500px) {
.grid-sizer,
.grid-item { float:left; width: 16.05%;}
.grid-item--width2 { width: 49.4%; }
}
@media only screen and (min-width: 1274px) and (max-width: 1369px) {
.grid-sizer,
.grid-item { float:left; width: 16%;}
.grid-item--width2 { width: 49.3%; }
}
@media only screen and (min-width: 1185px) and (max-width: 1273px) {
.grid-sizer,
.grid-item { float:left; width: 15.95%;}
.grid-item--width2 { width: 49.3%; }
}
@media only screen and (min-width: 1050px) and (max-width: 1184px) {
.grid-sizer,
.grid-item { float:left; width: 15.85%;}
.grid-item--width2 { width: 49.25%; }
}
@media only screen and (min-width: 955px) and (max-width: 1049px) {
.grid-sizer,
.grid-item { float:left; width: 24.2%;}
.grid-item--width2 { width: 49.3%; }
}
@media only screen and (min-width: 860px) and (max-width: 954px) {
.grid-sizer,
.grid-item { float:left; width: 24.1%;}
.grid-item--width2 { width: 49.3%; }
}
@media only screen and (min-width: 650px) and (max-width: 859px) {
.grid-sizer,
.grid-item { float:left; width: 49%;}
.grid-item--width2 { width: 49%; }
}

4
assets/css/font-awesome.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,16 @@
#!/bin/sh
rm $0
./style
echo "
------------------
(program exited with code: $?)"
echo "Press return to continue"
#to be more compatible with shells like dash
dummy_var=""
read dummy_var

44
assets/css/plugins.css Normal file

File diff suppressed because one or more lines are too long

131
assets/css/rypp.css Normal file
View File

@@ -0,0 +1,131 @@
@charset "UTF-8";
.RYPP {
/* Youtube Player With Playlist */
width: 100%;
position: relative;
padding-right: 250px;
background: #1a1a1a;
overflow: hidden;
font: 400 14px/120% Arial, Helvetica, sans-serif;
color: #999; }
.RYPP .RYPP-video {
width: 100%;
padding-top: 56.25%;
float: left;
position: relative; }
.RYPP .RYPP-video > iframe {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 2; }
.RYPP.r16-9 .RYPP-video {
padding-top: 56.25%; }
.RYPP.r4-3 .RYPP-video {
padding-top: 75%; }
.RYPP.r2-1 .RYPP-video {
padding-top: 50%; }
.RYPP .RYPP-items {
width: 100%;
position: absolute;
left: 0;
top: 64px;
right: 0;
bottom: 0;
overflow-y: auto; }
.RYPP .RYPP-playlist {
width: 250px;
position: absolute;
right: 0;
top: 0;
bottom: 0;
background: #222; }
.RYPP .RYPP-playlist a {
color: #999; }
.RYPP .RYPP-playlist a:hover {
color: #fff; }
.RYPP .RYPP-playlist > header {
width: 100%;
height: 64px;
padding: 16px 0 0 8px;
background: #222;
border-left: 8px solid #222;
border-right: 8px solid #222;
border-bottom: 1px solid #3a3a3a;
z-index: 2; }
.RYPP .RYPP-playlist > header ._h1 {
margin: 0 0 4px 0;
padding: 0;
font-size: 16px;
font-weight: 400;
color: #fff; }
.RYPP .RYPP-playlist > header p {
margin: 0;
padding: 0; }
.RYPP .RYPP-playlist ol {
padding: 0 0 16px 0;
margin: 0;
list-style: none;
counter-reset: item; }
.RYPP .RYPP-playlist ol li {
position: relative;
vertical-align: middle;
overflow: hidden;
padding: 12px 0 12px 12px; }
.RYPP .RYPP-playlist ol li > img {
width: 18%;
display: inline-block;
vertical-align: middle;
border: 2px solid transparent; }
.RYPP .RYPP-playlist ol li > p {
width: 76%;
margin: 0;
padding: 0 16px 0 0;
float: right;
display: inline-block;
vertical-align: middle;
text-align: left;
color: #cacaca; }
.RYPP .RYPP-playlist ol li > p > small {
margin: 0;
padding: 0;
font-size: 80%; }
.RYPP .RYPP-playlist ol li:hover {
background-color: #3a3a3a;
cursor: pointer; }
.RYPP .RYPP-playlist ol li.selected {
background-color: #3a3a3a;
cursor: pointer; }
.RYPP .RYPP-playlist ol li.selected > p {
color: #fff; }
.RYPP .RYPP-playlist ol li.selected > img {
border: 2px solid #c03636; }
.RYPP .RYPP-playlist ol li.selected:before {
content: '▶';
font-size: 10px;
color: #c03636; }
.RYPP .RYPP-playlist ol li:before {
counter-increment: item;
content: counter(item);
font-size: 80%; }
.RYPP-items::-webkit-scrollbar {
width: 6px;
background: #3a3a3a; }
.RYPP-items::-webkit-scrollbar-thumb {
background: #999; }
@media only screen and (max-width: 639px) {
.RYPP {
padding-right: 0; }
.RYPP .RYPP-playlist {
width: 100%;
position: static;
float: left; }
.RYPP .RYPP-playlist .RYPP-items {
position: static;
max-height: 350px;
overflow: auto; } }

2283
assets/css/style.css Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/img/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
assets/img/g4840.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
assets/img/g4841.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
assets/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
assets/img/map/marker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
assets/img/shape/mail-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
assets/img/shape/mail-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
assets/img/tweets/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

48
assets/js/ajax-mail.js Normal file
View File

@@ -0,0 +1,48 @@
$(function() {
// Get the form.
var form = $('#contact-form');
// Get the messages div.
var formMessages = $('.form-messege');
// Set up an event listener for the contact form.
$(form).submit(function(e) {
// Stop the browser from submitting the form.
e.preventDefault();
// Serialize the form data.
var formData = $(form).serialize();
// Submit the form using AJAX.
$.ajax({
type: 'POST',
url: $(form).attr('action'),
data: formData
})
.done(function(response) {
// Make sure that the formMessages div has the 'success' class.
$(formMessages).removeClass('error');
$(formMessages).addClass('success');
// Set the message text.
$(formMessages).text(response);
// Clear the form.
$('#contact-form input,#contact-form textarea').val('');
})
.fail(function(data) {
// Make sure that the formMessages div has the 'error' class.
$(formMessages).removeClass('success');
$(formMessages).addClass('error');
// Set the message text.
if (data.responseText !== '') {
$(formMessages).text(data.responseText);
} else {
$(formMessages).text('Oops! An error occured and your message could not be sent.');
}
});
});
});

5
assets/js/audioplayer.min.js vendored Normal file
View File

@@ -0,0 +1,5 @@
/*
AUTHOR: Osvaldas Valutis, www.osvaldas.info
*/
(function(e,t,n,r){var i="ontouchstart"in t,s=i?"touchstart":"mousedown",o=i?"touchmove":"mousemove",u=i?"touchend":"mouseup",a=i?"touchcancel":"mouseup",f=function(e){var t=Math.floor(e/3600),n=Math.floor(e%3600/60),r=Math.ceil(e%3600%60);return(t==0?"":t>0&&t.toString().length<2?"0"+t+":":t+":")+(n.toString().length<2?"0"+n:n)+":"+(r.toString().length<2?"0"+r:r)},l=function(e){var t=n.createElement("audio");return!!(t.canPlayType&&t.canPlayType("audio/"+e.split(".").pop().toLowerCase()+";").replace(/no/,""))};e.fn.audioPlayer=function(t){var t=e.extend({classPrefix:"audioplayer",strPlay:"Play",strPause:"Pause",strVolume:"Volume"},t),n={},r={playPause:"playpause",playing:"playing",time:"time",timeCurrent:"time-current",timeDuration:"time-duration",bar:"bar",barLoaded:"bar-loaded",barPlayed:"bar-played",volume:"volume",volumeButton:"volume-button",volumeAdjust:"volume-adjust",noVolume:"novolume",mute:"mute",mini:"mini"};for(var u in r)n[u]=t.classPrefix+"-"+r[u];this.each(function(){if(e(this).prop("tagName").toLowerCase()!="audio")return false;var r=e(this),u=r.attr("src"),c=r.get(0).getAttribute("autoplay"),c=c===""||c==="autoplay"?true:false,h=r.get(0).getAttribute("loop"),h=h===""||h==="loop"?true:false,p=false;if(typeof u==="undefined"){r.find("source").each(function(){u=e(this).attr("src");if(typeof u!=="undefined"&&l(u)){p=true;return false}})}else if(l(u))p=true;var d=e('<div class="'+t.classPrefix+'">'+(p?e("<div>").append(r.eq(0).clone()).html():'<embed src="'+u+'" width="0" height="0" volume="100" autostart="'+c.toString()+'" loop="'+h.toString()+'" />')+'<div class="'+n.playPause+'" title="'+t.strPlay+'"><a href="#">'+t.strPlay+"</a></div></div>"),v=p?d.find("audio"):d.find("embed"),v=v.get(0);if(p){d.find("audio").css({width:0,height:0,visibility:"hidden"});d.append('<div class="'+n.time+" "+n.timeCurrent+'"></div><div class="'+n.bar+'"><div class="'+n.barLoaded+'"></div><div class="'+n.barPlayed+'"></div></div><div class="'+n.time+" "+n.timeDuration+'"></div><div class="'+n.volume+'"><div class="'+n.volumeButton+'" title="'+t.strVolume+'"><a href="#">'+t.strVolume+'</a></div><div class="'+n.volumeAdjust+'"><div><div></div></div></div></div>');var m=d.find("."+n.bar),g=d.find("."+n.barPlayed),y=d.find("."+n.barLoaded),b=d.find("."+n.timeCurrent),w=d.find("."+n.timeDuration),E=d.find("."+n.volumeButton),S=d.find("."+n.volumeAdjust+" > div"),x=0,T=function(e){theRealEvent=i?e.originalEvent.touches[0]:e;v.currentTime=Math.round(v.duration*(theRealEvent.pageX-m.offset().left)/m.width())},N=function(e){theRealEvent=i?e.originalEvent.touches[0]:e;v.volume=Math.abs((theRealEvent.pageY-(S.offset().top+S.height()))/S.height())},C=setInterval(function(){y.width(v.buffered.end(0)/v.duration*100+"%");if(v.buffered.end(0)>=v.duration)clearInterval(C)},100);var k=v.volume,L=v.volume=.111;if(Math.round(v.volume*1e3)/1e3==L)v.volume=k;else d.addClass(n.noVolume);w.html("…");b.text(f(0));v.addEventListener("loadeddata",function(){w.text(f(v.duration));S.find("div").height(v.volume*100+"%");x=v.volume});v.addEventListener("timeupdate",function(){b.text(f(v.currentTime));g.width(v.currentTime/v.duration*100+"%")});v.addEventListener("volumechange",function(){S.find("div").height(v.volume*100+"%");if(v.volume>0&&d.hasClass(n.mute))d.removeClass(n.mute);if(v.volume<=0&&!d.hasClass(n.mute))d.addClass(n.mute)});v.addEventListener("ended",function(){d.removeClass(n.playing)});m.on(s,function(e){T(e);m.on(o,function(e){T(e)})}).on(a,function(){m.unbind(o)});E.on("click",function(){if(d.hasClass(n.mute)){d.removeClass(n.mute);v.volume=x}else{d.addClass(n.mute);x=v.volume;v.volume=0}return false});S.on(s,function(e){N(e);S.on(o,function(e){N(e)})}).on(a,function(){S.unbind(o)})}else d.addClass(n.mini);if(c)d.addClass(n.playing);d.find("."+n.playPause).on("click",function(){if(d.hasClass(n.playing)){e(this).attr("title",t.strPlay).find("a").html(t.strPlay);d.removeClass(n.playing);p?v.pause():v.Stop()}else{e(this).attr("title",t.strPause).find("a").html(t.strPause);d.addClass(n.playing);p?v.play():v.Play()}return false});r.replaceWith(d)});return this}})(jQuery,window,document)

1
assets/js/blueimp-gallery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
!function(a){"use strict";"function"==typeof define&&define.amd?define(["jquery","./blueimp-gallery"],a):a(window.jQuery,window.blueimp.Gallery)}(function(a,b){"use strict";a.extend(b.prototype.options,{useBootstrapModal:!0});var c=b.prototype.close,d=b.prototype.imageFactory,e=b.prototype.videoFactory,f=b.prototype.textFactory;a.extend(b.prototype,{modalFactory:function(a,b,c,d){if(!this.options.useBootstrapModal||c)return d.call(this,a,b,c);var e=this,f=this.container.children(".modal"),g=f.clone().show().on("click",function(a){(a.target===g[0]||a.target===g.children()[0])&&(a.preventDefault(),a.stopPropagation(),e.close())}),h=d.call(this,a,function(a){b({type:a.type,target:g[0]}),g.addClass("in")},c);return g.find(".modal-title").text(h.title||String.fromCharCode(160)),g.find(".modal-body").append(h),g[0]},imageFactory:function(a,b,c){return this.modalFactory(a,b,c,d)},videoFactory:function(a,b,c){return this.modalFactory(a,b,c,e)},textFactory:function(a,b,c){return this.modalFactory(a,b,c,f)},close:function(){this.container.find(".modal").removeClass("in"),c.call(this)}})});

7
assets/js/bootstrap.bundle.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

6
assets/js/bootstrap.min-4.0.0.js vendored Normal file

File diff suppressed because one or more lines are too long

7
assets/js/bootstrap.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

23
assets/js/custom.js Normal file
View File

@@ -0,0 +1,23 @@
/* Hero carousel height */
//var rypp_height = $(".RYPP").innerHeight();
//$(".hero-post .image").css( "height" , rypp_height );
/* Video resize */
$(".playlist iframe").attr({
width: $( ".playlist .videoframe" ).width(),
height: Math.floor($( ".playlist .videoframe" ).width()/1.78),
});
//~ var hero_height = $(".playlist").height();
var hero_height = Math.floor($(".playlist .videoframe").height()*2);
$(".hero-post .image").css( "height" , hero_height );
/* Playlist */
//var api_key = 'AIzaSyAsvJPKTArFviBbDntKU4sHxkl8fYrj1uM';
/* Initialize all the player in the page with default options*/
//$('.RYPP').rypp(api_key, {
// //autoplay: false,
//});

7
assets/js/imagesloaded.pkgd.min.js vendored Normal file

File diff suppressed because one or more lines are too long

13
assets/js/jquery-ui.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

362
assets/js/main.js Normal file
View File

@@ -0,0 +1,362 @@
(function ($) {
"use strict";
/*--
Menu Sticky
-----------------------------------*/
var windows = $(window);
var sticky = $('.header-sticky');
/*--
Mobile Menu
------------------------*/
$('.mobile-menu-wrap').meanmenu({
meanScreenWidth: '767',
meanMenuContainer: '.mobile-menu',
meanMenuClose: '<span class="menu-close"></span>',
meanMenuOpen: '<span class="menu-bar"></span>',
meanRevealPosition: 'left',
meanMenuCloseSize: '0',
});
/*--
Header Search
--------------------------------------------*/
var searchToggle = $('.header-search-toggle');
var searchForm = $('.header-search-form');
searchForm.hide();
/*-- Search Toggle --*/
searchToggle.on('click', function(){
if( searchToggle.hasClass('open') ) {
searchForm.animate({
width: "toggle",
});
$(this).removeClass('open').find('i').removeClass('fa-close').addClass('fa-search');
}else{
searchForm.animate({
width: "toggle",
});
$(this).addClass('open').find('i').removeClass('fa-search').addClass('fa-close');
}
});
/*--
Breaking News Ticker
--------------------------------------------*/
$('.breaking-news-ticker').newsTicker({
row_height: 40,
max_rows: 1,
speed: 600,
duration: 5000,
prevButton: $('.news-ticker-prev'),
nextButton: $('.news-ticker-next'),
});
/*--
Slick Slider
-----------------------------------*/
/*-- Post Carousel --*/
$('.post-carousel-1').slick({
autoplay: true,
autoplaySpeed: 5000,
pauseOnFocus: false,
pauseOnHover: false,
infinite: true,
slidesToShow: 1,
prevArrow: '<button type="button" class="slick-prev"><i class="fa fa-angle-left"></i></button>',
nextArrow: '<button type="button" class="slick-next"><i class="fa fa-angle-right"></i></button>',
responsive: [
{
breakpoint: 350,
settings: {
arrows: false,
}
}
]
});
/*-- Popular Post Slider --*/
$('.popular-post-slider').slick({
arrows: false,
autoplay: true,
autoplaySpeed: 5000,
pauseOnFocus: false,
pauseOnHover: false,
infinite: true,
slidesToShow: 3,
responsive: [
{
breakpoint: 1199,
settings: {
slidesToShow: 2,
}
},
{
breakpoint: 991,
settings: {
slidesToShow: 2,
}
},
{
breakpoint: 767,
settings: {
slidesToShow: 1,
}
}
]
});
/*-- Five Row Post Carousel --*/
$('.five-row-post-carousel').slick({
autoplay: false,
autoplaySpeed: 5000,
pauseOnFocus: false,
pauseOnHover: false,
infinite: true,
slidesToShow: 1,
rows: 5,
prevArrow: '<button type="button" class="slick-prev"><i class="fa fa-angle-left"></i></button>',
nextArrow: '<button type="button" class="slick-next"><i class="fa fa-angle-right"></i></button>',
responsive: [
{
breakpoint: 991,
settings: {
slidesToShow: 2,
rows: 4,
}
},
{
breakpoint: 767,
settings: {
slidesToShow: 1,
}
}
]
});
/*-- Four Row Post Carousel --*/
$('.four-row-post-carousel').slick({
autoplay: false,
autoplaySpeed: 5000,
pauseOnFocus: false,
pauseOnHover: false,
infinite: true,
slidesToShow: 1,
rows: 4,
prevArrow: '<button type="button" class="slick-prev"><i class="fa fa-angle-left"></i></button>',
nextArrow: '<button type="button" class="slick-next"><i class="fa fa-angle-right"></i></button>',
});
/*-- Three Row Post Carousel --*/
$('.three-row-post-carousel').slick({
autoplay: false,
autoplaySpeed: 5000,
pauseOnFocus: false,
pauseOnHover: false,
infinite: true,
slidesToShow: 1,
rows: 3,
prevArrow: '<button type="button" class="slick-prev"><i class="fa fa-angle-left"></i></button>',
nextArrow: '<button type="button" class="slick-next"><i class="fa fa-angle-right"></i></button>',
});
/*-- Two Row Post Carousel --*/
$('.two-row-post-carousel').slick({
autoplay: false,
autoplaySpeed: 5000,
pauseOnFocus: false,
pauseOnHover: false,
infinite: true,
slidesToShow: 1,
rows: 2,
prevArrow: '<button type="button" class="slick-prev"><i class="fa fa-angle-left"></i></button>',
nextArrow: '<button type="button" class="slick-next"><i class="fa fa-angle-right"></i></button>',
});
/*-- Sidebar Post Carousel --*/
$('.sidebar-post-carousel').slick({
autoplay: true,
autoplaySpeed: 5000,
pauseOnFocus: false,
pauseOnHover: false,
infinite: true,
slidesToShow: 1,
prevArrow: '<button type="button" class="slick-prev"><i class="fa fa-angle-left"></i></button>',
nextArrow: '<button type="button" class="slick-next"><i class="fa fa-angle-right"></i></button>',
});
/*-- Video Post Slider --*/
$('.video-post-slider').slick({
arrows: true,
autoplay: true,
autoplaySpeed: 5000,
pauseOnFocus: false,
pauseOnHover: false,
infinite: true,
slidesToShow: 3,
prevArrow: '<button type="button" class="slick-prev"><i class="fa fa-angle-left"></i></button>',
nextArrow: '<button type="button" class="slick-next"><i class="fa fa-angle-right"></i></button>',
});
/*-- Four Column Post Carousel --*/
$('.four-column-post-carousel').slick({
arrows: false,
autoplay: true,
autoplaySpeed: 5000,
pauseOnFocus: false,
pauseOnHover: false,
infinite: true,
slidesToShow: 4,
responsive: [
{
breakpoint: 1199,
settings: {
slidesToShow: 3,
}
},
{
breakpoint: 991,
settings: {
slidesToShow: 2,
}
},
{
breakpoint: 767,
settings: {
slidesToShow: 1,
}
}
]
});
/*-- Three Column Post Carousel --*/
$('.three-column-post-carousel').slick({
arrows: true,
autoplay: true,
autoplaySpeed: 5000,
pauseOnFocus: false,
pauseOnHover: false,
infinite: true,
slidesToShow: 3,
prevArrow: '<button type="button" class="slick-prev"><i class="fa fa-angle-left"></i></button>',
nextArrow: '<button type="button" class="slick-next"><i class="fa fa-angle-right"></i></button>',
responsive: [
{
breakpoint: 1199,
settings: {
slidesToShow: 3,
}
},
{
breakpoint: 991,
settings: {
slidesToShow: 2,
}
},
{
breakpoint: 767,
settings: {
slidesToShow: 1,
}
}
]
});
/*-- Two Column Post Carousel --*/
$('.two-column-post-carousel').slick({
arrows: true,
autoplay: true,
autoplaySpeed: 5000,
pauseOnFocus: false,
pauseOnHover: false,
infinite: true,
slidesToShow: 2,
prevArrow: '<button type="button" class="slick-prev"><i class="fa fa-angle-left"></i></button>',
nextArrow: '<button type="button" class="slick-next"><i class="fa fa-angle-right"></i></button>',
responsive: [
{
breakpoint: 767,
settings: {
slidesToShow: 1,
}
}
]
});
/*-- Full Width Instagram Carousel --*/
$('.fullwidth-instagram-carousel').slick({
arrows: false,
autoplay: true,
autoplaySpeed: 5000,
pauseOnFocus: false,
pauseOnHover: false,
infinite: true,
slidesToShow: 5,
responsive: [
{
breakpoint: 1199,
settings: {
slidesToShow: 4,
}
},
{
breakpoint: 991,
settings: {
slidesToShow: 3,
}
},
{
breakpoint: 767,
settings: {
slidesToShow: 2,
}
},
{
breakpoint: 350,
settings: {
slidesToShow: 1,
}
}
]
});
/*--
Custom Scroll
-----------------------------------*/
$(".customScroll").niceScroll();
/*--
Scroll Up
-----------------------------------*/
$.scrollUp({
easingType: 'linear',
scrollSpeed: 900,
animation: 'fade',
scrollText: '<i class="fa fa-angle-up"></i>',
});
/*--
Magnific Video Popup
--------------------------------*/
var imagePopup = $('.image-popup');
imagePopup.magnificPopup({
type: 'image',
tLoading: 'Loading image #%curr%...',
gallery: {
enabled: true,
},
});
var videoPopup = $('.video-popup');
videoPopup.magnificPopup({
type: 'iframe',
mainClass: 'mfp-fade',
removalDelay: 160,
preloader: false,
zoom: {
enabled: true,
}
});
})(jQuery);

9
assets/js/masonry.pkgd.min.js vendored Normal file

File diff suppressed because one or more lines are too long

50
assets/js/plugins.js Normal file

File diff suppressed because one or more lines are too long

4
assets/js/popper.min.js vendored Normal file

File diff suppressed because one or more lines are too long

368
assets/js/rypp.js Normal file
View File

@@ -0,0 +1,368 @@
/*
Youtube Player with Playlist (v2.22)
https://github.com/carloscabo/responsive-youtube-player-with-playlist
by Carlos Cabo (@putuko)
*/
var RYPP = (function($, undefined) {
'use strict';
function Rypp(el, api_key, options) {
if (typeof api_key === 'undefined') {
console.log("Youtube API V3 requires a valid API KEY.\nFollow the instructions at: https://developers.google.com/youtube/v3/getting-started");
return false;
}
// DOM Elements container
this.DOM = {};
// Default settings container
this.options = {};
// Data / urls
this.data = {
// Playlist url
ytapi: {
playlist_info: 'https://www.googleapis.com/youtube/v3/playlists?part=snippet&id={{RESOURCES_ID}}&key={{YOUR_API_KEY}}',
playlist: 'https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId={{RESOURCES_ID}}&key={{YOUR_API_KEY}}',
pl_ID: '',
videolist: 'https://www.googleapis.com/youtube/v3/videos?part=snippet,status&maxResults=50&id={{RESOURCES_ID}}&key={{YOUR_API_KEY}}',
},
temp_vl: [], // Temporary videolist
firsttime: true,
ismobile: (typeof window.orientation !== 'undefined'),
ispopulated: false
};
// Initialize
this.init(el, api_key, options);
}
// Prototype for the instance
Rypp.prototype = {
init: function(el, api_key, options) {
// Api key
this.api_key = api_key;
// Default options
this.options = {
update_title_desc: false,
autoplay: true,
autonext: true,
loop: true,
mute: false,
debug: false
};
// Merge initial options
if (typeof options !== 'undefined') {
$.extend(this.options, options);
}
// DOM elements
this.DOM = {};
this.DOM.$el = $(el);
this.DOM.$playlc = this.DOM.$el.find('.RYPP-playlist');
this.DOM.$items = this.DOM.$el.find('.RYPP-items');
this.DOM.$videoc = this.DOM.$el.find('.RYPP-video');
this.DOM.$title = this.DOM.$el.find('.RYPP-title');
this.DOM.$desc = this.DOM.$el.find('.RYPP-desc');
// YT Player object
this.DOM.$el[0].ytplayer = null;
// Unique player ID
this.data.player_uid = (Math.random().toString(16).substr(2,8));
this.DOM.$el.attr('data-rypp',this.data.player_uid).find('.RYPP-video-player').attr('id','RYPP-vp-'+this.data.player_uid).attr('name','RYPP-vp-'+this.data.player_uid);
if (this.options.debug) console.log('Unique ID: RYPP-vp-'+this.data.player_uid);
// Link JS only once
if (typeof window.YT === 'undefined') {
var
tag = document.createElement('script'),
hID = document.getElementsByTagName('head')[0];
// Add youtube API in HEAD
// tag.src = "https://www.youtube.com/iframe_api";
tag.src = 'https://www.youtube.com/iframe_api?version=3';
hID.appendChild(tag);
} else {
this.addAPIPlayer();
}
},
onYTIframeAPIReadyCallback: function() {
this.addAPIPlayer();
},
updateTitleDesc: function() {
var
that = this,
resources_id = this.DOM.$el.attr('data-playlist'),
url = this.data.ytapi.playlist_info.replace('{{RESOURCES_ID}}', resources_id).replace('{{YOUR_API_KEY}}', this.api_key);
$.ajaxSetup ({cache: false});
$.ajax(url, {
context: this,
dataType: 'json',
crossDomain: true,
error: function(){
// Not successful
},
success: function(data){
// console.log(data);
this.DOM.$title.html( data.items[0].snippet.title );
this.DOM.$desc.html( data.items[0].snippet.description );
}
});
},
populatePlaylist: function() {
if( this.options.update_title_desc ) {
if (this.options.debug) console.log(this.data.player_uid+': Updating playlist title / desc');
this.updateTitleDesc();
}
// Empty playlist
if (this.options.debug) console.log(this.data.player_uid+': Populating playlist');
this.DOM.$items.html('').append($('<ol>'));
// Now we read the video list from playlist data or from IDs...
if (this.DOM.$el.attr('data-playlist')) {
this.data.pl_ID = this.DOM.$el.attr('data-playlist');
this.getVideosFrom(
'playlist',
this.data.pl_ID
);
} else if (this.DOM.$el.attr('data-ids')) {
var vl = this.DOM.$el.attr('data-ids');
// Clean spaces
vl = ($.map(vl.split(','),$.trim)).join(',');
this.getVideosFrom(
'videolist',
vl
);
}
},
addAPIPlayer: function() {
var that = this;
window.YTConfig = { 'host': 'https://www.youtube.com' };
this.DOM.$el[0].ytplayer = new YT.Player('RYPP-vp-'+that.data.player_uid, {
// height: '390',
// width: '640',
playerVars: {
// controls: 0,
// showinfo: 0 ,
// autoplay: 0,
// html5: 1,
enablejsapi: 1,
rel: 0,
modestbranding: 1,
wmode: 'transparent'
},
events: {
'onReady': function(){
if (that.options.debug)console.log(that.data.player_uid+': ytplayer ready');
that.onPlayerReady();
},
'onStateChange': function(e){
that.onPlayerStateChange(e);
},
'onError': function(e) {
console.log(e);
}
}
});
},
// Ready to play
onPlayerReady: function() {
if (this.options.debug) console.log(this.data.player_uid+': ytplayer ready callback');
this.populatePlaylist();
// this.startPlayList();
},
// When video finish
onPlayerStateChange: function(e){
var
that = this;
if (typeof e !== 'undefined') {
// On video loaded?
if(e.data === -1 && this.data.firsttime) {
if(!this.options.autoplay && !this.data.ismobile) { // Is desktop
this.DOM.$el[0].ytplayer.stopVideo();
this.data.firsttime = false;
}
if(this.options.mute) {
this.DOM.$el[0].ytplayer.mute();
}
}
// If mobile and stored in buffer we STOP the video in mobile devices
if(e.data === 3 && this.data.ismobile && this.data.firsttime) {
setTimeout(function(){
that.DOM.$el[0].ytplayer.stopVideo();
that.data.firsttime = false;
}, 500);
}
// Play next only if not mobile
var next = null;
if(e.data === 0 && !this.data.ismobile && this.options.autonext) {
next = this.DOM.$items.find('li.selected').next();
if (next.length === 0 && this.options.loop) {
next = this.DOM.$items.find('li').first();
}
next.trigger('click');
}
}
},
// Get video from data-ids or playlist
// It's impossible to know if a video in a playlist its available or currently deleted. So we do 2 request, first we get all the video IDs an then we ask for info about them.
getVideosFrom: function(kind, resources_id, page_token) {
var
that = this,
url = this.data.ytapi[kind].replace('{{RESOURCES_ID}}', resources_id).replace('{{YOUR_API_KEY}}', this.api_key);
if (typeof page_token !== 'undefined') {
url += '&pageToken=' + page_token;
}
$.ajaxSetup ({cache: false});
$.ajax(url, {
context: this,
dataType: 'json',
crossDomain: true,
error: function(){
// Not successful
},
success: function(data){
// We queried for a playlist
if (data.kind === 'youtube#playlistItemListResponse') {
var video_set = [];
// We get the video IDs and query gain, its the only way to be sure that all the videos are available, and not were deleted :(
$.map(data.items, function(val,idx) {
if (typeof val.snippet.resourceId.videoId !== 'undefined') {
// Add video to temporary list
video_set.push( val.snippet.resourceId.videoId );
// return val.snippet.resourceId.videoId;
}
});
that.data.temp_vl.push( video_set );
// If there are several pages we ask for next
if (typeof data.nextPageToken !== 'undefined' && data.nextPageToken !== '') {
that.getVideosFrom(
'playlist',
that.data.pl_ID,
data.nextPageToken
);
} else {
// No more pages... we process the videos
for (var j = 0, len_pl = that.data.temp_vl.length; j < len_pl; j++) {
video_set = that.data.temp_vl.shift();
that.getVideosFrom('videolist', video_set.join(','));
}
}
} else if (data.kind === 'youtube#videoListResponse') {
// Videos froma Videolist
for (var i = 0, len = data.items.length; i < len; i++) {
var item = data.items[i];
// Videos without thumbnail, deleted or rejected are not included in the player!
if (
$.inArray(item.status.uploadStatus, ['rejected', 'deleted', 'failed']) === -1 &&
typeof item.snippet.thumbnails !== 'undefined'
) {
var
vid = item.id,
tit = item.snippet.title,
aut = item.snippet.channelTitle,
thu = item.snippet.thumbnails.default.url;
that.addVideo2Playlist(vid, tit, aut, thu);
}
if ( $.isEmptyObject( that.data.temp_vl ) ) {
this.startPlayList();
}
}
}
}
});
},
// All videos are supossed to be loaded
// lets start the playlist
startPlayList: function() {
var
D = this.DOM,
vid = null,
that = this;
// Click on playlist elemnts
D.$items.on('click', 'li', function(e) {
e.preventDefault();
D.$items.find('li').removeClass('selected');
$(this).addClass('selected');
vid = $(this).data('video-id');
// Call YT API function
that.DOM.$el[0].ytplayer.loadVideoById(vid);
// If we are in mobile we must stop
if (that.data.ismobile) {
that.data.firsttime = true;
}
});
// Select first if none
if (D.$items.find('li.selected').length === 0) {
if ( this.options.autoplay ) {
D.$items.find('li').first().click();
}
}
},
// Add video block to playlist
addVideo2Playlist: function(vid, tit, aut, thu) {
var
D = this.DOM;
$('<li data-video-id="'+vid+'"><p class="title">'+tit+'<small class="author"><br>'+aut+'</small></p><img src="'+thu+'" class="thumb"></li>').appendTo(D.$items.find('ol'));
},
}; // prototypes
return Rypp;
}(jQuery));
// YOUTUBE API CALLBACK
function onYouTubeIframeAPIReady() {
// console.log( 'Youtube API script loaded. Start players.' );
$('[data-rypp]').each(function(idx, el) {
$(el)[0].rypp_data_obj.onYTIframeAPIReadyCallback();
});
}
// JQuery hook
$.fn.rypp = function(api_key, options) {
return this.each(function() {
// Store object in DOM element
this.rypp_data_obj = new RYPP(this, api_key, options);
});
};

15
assets/js/single-video.js Normal file
View File

@@ -0,0 +1,15 @@
/* Video resize */
$(".post-video iframe").attr({
width : $( ".post-video" ).width(),
height: Math.floor($( ".post-video" ).width()/1.78),
});
/* Video field from iframe in content */
var $isrc = $('.content iframe').attr('src');
var $clean1src = $isrc.replace('https://www.youtube.com/watch?v=','https://www.youtube.com/embed/');
var $clean2src = $clean1src.replace('http://www.youtube.com/v/','https://www.youtube.com/embed/');
var $cleansrc = $clean2src.replace('&hl=es&fs=1&','');
$('iframe.video-content').attr({
src: $cleansrc,
});
$('.content iframe').remove();

5
assets/js/vendor/jquery-1.12.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,7 @@
var api_key = 'AIzaSyAsvJPKTArFviBbDntKU4sHxkl8fYrj1uM';
/* Initialize all the player in the page with default options*/
$('.RYPP').rypp(api_key, {
autoplay: false,
});

102
assets/map/map.js Normal file
View File

@@ -0,0 +1,102 @@
var myCenter=new google.maps.LatLng(40.8654939,-74.0402033);
function initialize()
{
var mapProp = {
center:myCenter,
scrollwheel: false,
zoom:10,
mapTypeId:google.maps.MapTypeId.ROADMAP
};
var map=new google.maps.Map(document.getElementById("contact-map"),mapProp);
var marker=new google.maps.Marker({
position:myCenter,
icon:'img/map/marker.png',
map: map,
});
var styles = [
{
"featureType": "administrative",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#444444"
}
]
},
{
"featureType": "landscape",
"elementType": "all",
"stylers": [
{
"color": "#f2f2f2"
}
]
},
{
"featureType": "poi",
"elementType": "all",
"stylers": [
{
"visibility": "off"
}
]
},
{
"featureType": "road",
"elementType": "all",
"stylers": [
{
"saturation": -100
},
{
"lightness": 45
}
]
},
{
"featureType": "road.highway",
"elementType": "all",
"stylers": [
{
"visibility": "simplified"
}
]
},
{
"featureType": "road.arterial",
"elementType": "labels.icon",
"stylers": [
{
"visibility": "off"
}
]
},
{
"featureType": "transit",
"elementType": "all",
"stylers": [
{
"visibility": "off"
}
]
},
{
"featureType": "water",
"elementType": "all",
"stylers": [
{
"color": "#46bcec"
},
{
"visibility": "on"
}
]
}
];
map.setOptions({styles: styles});
marker.setMap(map);
}
google.maps.event.addDomListener(window, 'load', initialize);

View File

@@ -4,7 +4,8 @@
"rmccue/requests": "^1.7",
"timber/timber": "^2.3",
"illuminate/collections": "^12.21",
"upstatement/routes": "^0.9.2"
"upstatement/routes": "^0.9.2",
"hellonico/timber-dump-extension": "^2.0"
},
"config": {
"allow-plugins": {

391
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "da4f3b212b96744f0677688650913540",
"content-hash": "4b29148fff0eed338088485780c0746c",
"packages": [
{
"name": "altorouter/altorouter",
@@ -312,6 +312,60 @@
],
"time": "2018-05-17T19:22:38+00:00"
},
{
"name": "hellonico/timber-dump-extension",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/nlemoine/timber-dump-extension.git",
"reference": "c1a4269ec4cda8542c068972ee76cee0d5c9d041"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nlemoine/timber-dump-extension/zipball/c1a4269ec4cda8542c068972ee76cee0d5c9d041",
"reference": "c1a4269ec4cda8542c068972ee76cee0d5c9d041",
"shasum": ""
},
"require": {
"symfony/twig-bridge": "^6 || ^7",
"symfony/var-dumper": "^6 || ^7",
"wecodemore/wordpress-early-hook": "^1.2"
},
"type": "library",
"autoload": {
"files": [
"functions.php"
],
"psr-4": {
"HelloNico\\Timber\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-3.0+"
],
"authors": [
{
"name": "Nicolas Lemoine",
"email": "nico@n5s.dev",
"homepage": "https://n5s.dev/"
}
],
"description": "Provides Symfony VarDumper component for Timber",
"homepage": "https://github.com/nlemoine/timber-dump-extension",
"keywords": [
"VarDumper",
"symfony",
"timber",
"twig",
"wordpress"
],
"support": {
"issues": "https://github.com/nlemoine/timber-dump-extension/issues",
"source": "https://github.com/nlemoine/timber-dump-extension/tree/2.0.0"
},
"time": "2024-03-08T12:20:18+00:00"
},
{
"name": "illuminate/collections",
"version": "v12.21.0",
@@ -943,6 +997,279 @@
],
"time": "2018-11-11T11:18:13+00:00"
},
{
"name": "symfony/translation-contracts",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation-contracts.git",
"reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
"reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.6-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Translation\\": ""
},
"exclude-from-classmap": [
"/Test/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to translation",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/translation-contracts/tree/v3.6.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-27T08:32:26+00:00"
},
{
"name": "symfony/twig-bridge",
"version": "v7.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/twig-bridge.git",
"reference": "082eb15d8a4f9afee0acc4709fbe3aaf26d48891"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/twig-bridge/zipball/082eb15d8a4f9afee0acc4709fbe3aaf26d48891",
"reference": "082eb15d8a4f9afee0acc4709fbe3aaf26d48891",
"shasum": ""
},
"require": {
"php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/translation-contracts": "^2.5|^3",
"twig/twig": "^3.21"
},
"conflict": {
"phpdocumentor/reflection-docblock": "<3.2.2",
"phpdocumentor/type-resolver": "<1.4.0",
"symfony/console": "<6.4",
"symfony/form": "<6.4",
"symfony/http-foundation": "<6.4",
"symfony/http-kernel": "<6.4",
"symfony/mime": "<6.4",
"symfony/serializer": "<6.4",
"symfony/translation": "<6.4",
"symfony/workflow": "<6.4"
},
"require-dev": {
"egulias/email-validator": "^2.1.10|^3|^4",
"league/html-to-markdown": "^5.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
"symfony/asset": "^6.4|^7.0",
"symfony/asset-mapper": "^6.4|^7.0",
"symfony/console": "^6.4|^7.0",
"symfony/dependency-injection": "^6.4|^7.0",
"symfony/emoji": "^7.1",
"symfony/expression-language": "^6.4|^7.0",
"symfony/finder": "^6.4|^7.0",
"symfony/form": "^6.4.20|^7.2.5",
"symfony/html-sanitizer": "^6.4|^7.0",
"symfony/http-foundation": "^7.3",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/intl": "^6.4|^7.0",
"symfony/mime": "^6.4|^7.0",
"symfony/polyfill-intl-icu": "~1.0",
"symfony/property-info": "^6.4|^7.0",
"symfony/routing": "^6.4|^7.0",
"symfony/security-acl": "^2.8|^3.0",
"symfony/security-core": "^6.4|^7.0",
"symfony/security-csrf": "^6.4|^7.0",
"symfony/security-http": "^6.4|^7.0",
"symfony/serializer": "^6.4.3|^7.0.3",
"symfony/stopwatch": "^6.4|^7.0",
"symfony/translation": "^6.4|^7.0",
"symfony/validator": "^6.4|^7.0",
"symfony/web-link": "^6.4|^7.0",
"symfony/workflow": "^6.4|^7.0",
"symfony/yaml": "^6.4|^7.0",
"twig/cssinliner-extra": "^3",
"twig/inky-extra": "^3",
"twig/markdown-extra": "^3"
},
"type": "symfony-bridge",
"autoload": {
"psr-4": {
"Symfony\\Bridge\\Twig\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides integration for Twig with various Symfony components",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/twig-bridge/tree/v7.3.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-05-19T13:28:56+00:00"
},
{
"name": "symfony/var-dumper",
"version": "v7.3.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "6e209fbe5f5a7b6043baba46fe5735a4b85d0d42"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/6e209fbe5f5a7b6043baba46fe5735a4b85d0d42",
"reference": "6e209fbe5f5a7b6043baba46fe5735a4b85d0d42",
"shasum": ""
},
"require": {
"php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
"symfony/console": "<6.4"
},
"require-dev": {
"ext-iconv": "*",
"symfony/console": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/process": "^6.4|^7.0",
"symfony/uid": "^6.4|^7.0",
"twig/twig": "^3.12"
},
"bin": [
"Resources/bin/var-dump-server"
],
"type": "library",
"autoload": {
"files": [
"Resources/functions/dump.php"
],
"psr-4": {
"Symfony\\Component\\VarDumper\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides mechanisms for walking through any arbitrary PHP variable",
"homepage": "https://symfony.com",
"keywords": [
"debug",
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v7.3.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-06-27T19:55:54+00:00"
},
{
"name": "timber/timber",
"version": "v2.3.2",
@@ -1179,6 +1506,68 @@
"wiki": "https://github.com/Upstatement/routes/wiki"
},
"time": "2025-02-25T18:07:09+00:00"
},
{
"name": "wecodemore/wordpress-early-hook",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/wecodemore/wordpress-early-hook.git",
"reference": "61affcc3d64d77199bce237341a39a7a01e272e0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/wecodemore/wordpress-early-hook/zipball/61affcc3d64d77199bce237341a39a7a01e272e0",
"reference": "61affcc3d64d77199bce237341a39a7a01e272e0",
"shasum": ""
},
"require": {
"php": ">=7.1 < 8.5"
},
"require-dev": {
"inpsyde/php-coding-standards": "^1.0.0",
"phpunit/phpunit": "^7.5.20 || ^9.6.4",
"roave/security-advisories": "dev-latest",
"roots/wordpress-no-content": ">=6.1.1",
"vimeo/psalm": "^4.30.0"
},
"type": "library",
"autoload": {
"files": [
"wordpress-early-hook.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Giuseppe Mazzapica",
"email": "giuseppe.mazzapica@gmail.com",
"homepage": "https://gmazzap.me",
"role": "Developer"
}
],
"description": "Small library to safely add WordPress hooks before WordPress is loaded.",
"keywords": [
"actions",
"filters",
"hooks",
"wordpress",
"wordpress actions",
"wordpress filters",
"wordpress hooks",
"wp",
"wp actions",
"wp filters",
"wp hooks"
],
"support": {
"issues": "https://github.com/wecodemore/wordpress-early-hook/issues",
"source": "https://github.com/wecodemore/wordpress-early-hook"
},
"time": "2025-04-07T08:58:48+00:00"
}
],
"packages-dev": [],

View File

@@ -10,28 +10,76 @@ include(__DIR__ .'/vendor/autoload.php');
//~ use WeDevs\ORM\WP\Post as Post;
//~ composer require jgrossi/corcel
function create_team_type() {
$obj = new BaseCPT('team','Miembro del equipo');
$obj->menu_icon = 'dashicons-id-alt';
$obj->rewrite = array('slug' => 'equipo');
/*dump($obj->build_cpt());*/
register_post_type( $obj->slug, $obj->build_cpt() );
}
//add_action( 'init', 'create_team_type' );
// function get_posts_by_term_args($taxonomy_slug,$term_slug,$numberposts=8,$post_type='post') {
// $args = array(
// 'post_type' => $post_type,
// 'posts_per_page' => $numberposts,
// 'tax_query' => array(
// array(
// 'taxonomy' => $taxonomy_slug,
// 'field' => 'slug',
// 'terms' => $term_slug,
// ),
// )
// );
// return $args;
// }
// templatetag para rellenar con contenido dinamico la plantilla en desarollo
function frontpage_posts($numberposts=-1,$template_name='frontpage_post.twig') {
$args = [
'numberposts' => $numberposts,
'post_type' => 'post',
];
$ctx = ['posts' => Timber::get_posts( $args )];
return Timber::fetch($template_name, $ctx);
}
add_filter( 'timber/twig', function( \Twig_Environment $twig ) {
$twig->addFunction( new Timber\Twig_Function( 'frontpage_posts', 'frontpage_posts' ) );
// function get_posts_by_term($taxonomy_slug,$term_slug,$numberposts=8,$post_type='post') {
// $args = get_posts_by_term_args($taxonomy_slug, $term_slug, $numberposts, $post_type);
// return Timber::get_posts( $args );
// }
// function posts_by_term($taxonomy_slug, $term_slug, $numberposts=8, $post_type='post', $template_name='posts_by_taxonomy.twig') {
// $ctx = array('posts' => get_posts_by_term($taxonomy_slug,$term_slug,$numberposts,$post_type));
// $ctx['taxonomy'] = get_taxonomy($taxonomy_slug);
// $ctx['term'] = get_term($term_slug, $taxonomy_slug);
// return Timber::fetch($template_name, $ctx);
// }
// function get_posts_by_type($post_type,$numberposts=8) {
// $args = array(
// 'post_type' => $post_type,
// 'posts_per_page' => $numberposts,
// );
// return Timber::get_posts( $args );
// }
// function posts_by_type($post_type,$numberposts=8,$template_name='posts_by_taxonomy.twig') {
// $ctx = array('posts' => get_posts_by_type($post_type,$numberposts));
// return Timber::fetch($template_name, $ctx);
// }
/*
add_filter( 'timber/twig/functions', function( \Twig\Environment $twig ) {
$twig->addFunction( new \Twig\TwigFunction( 'posts_by_term', 'posts_by_term' ) );
return $twig;
} );
add_filter( 'timber/twig/functions', function( \Twig\Environment $twig ) {
$twig->addFunction( new \Twig\TwigFunction( 'posts_by_type', 'posts_by_type' ) );
return $twig;
} );
*/
// templatetag para rellenar con contenido dinamico la plantilla en desarollo
// function frontpage_posts($numberposts=-1,$template_name='frontpage_post.twig') {
// $args = [
// 'posts_per_page' => $numberposts,
// 'post_type' => 'post',
// ];
// $ctx = ['posts' => Timber::get_posts( $args )];
// return Timber::fetch($template_name, $ctx);
// }
// // Añadir al
// add_filter( 'timber/twig', function( \Twig\Environment $twig ) {
// $twig->addFunction( new \Twig\TwigFunction( 'frontpage_posts', 'frontpage_posts' ) );
// return $twig;
// } );
// fin del templatetag para rellenar con contenido dinamico la plantilla en desarollo
// Galeria

View File

@@ -1 +1,19 @@
<?php
if ( ! class_exists( 'Timber' ) ) {
echo 'Timber not activated. Make sure you activate the plugin in >
return;
}
$context = Timber::context();
$context['posts'] = Timber::get_posts(array('post_type' => array('post', 'evento', 'galeria', 'audio', 'video', 'publicacion')));
$templates = array( 'index.twig' );
if ( is_home() ) {
array_unshift( $templates, 'home.twig' );
}
if ( is_front_page() ) {
array_unshift( $templates, 'frontpage.twig' );
}
Timber::render( $templates, $context );

View File

@@ -50,11 +50,12 @@ function posts_by_service($numberposts=-1,$postslug,$slug,$template_name='posts_
return Timber::fetch($template_name, $ctx);
}
add_filter( 'timber/twig', function( \Twig_Environment $twig ) {
$twig->addFunction( new Timber\Twig_Function( 'posts_by_service', 'posts_by_service' ) );
/*
add_filter( 'timber/twig', function( \Twig\Environment $twig ) {
$twig->addFunction( new \Twig\TwigFunction( 'posts_by_service', 'posts_by_service' ) );
return $twig;
} );
*/
// fin del templatetag
Timber::render( $templates, $context );
//var_dump($context);
Timber::render($templates, $context );

View File

@@ -2,7 +2,7 @@
global $params;
$context = Timber::get_context();
$context = Timber::context();
$templates = array('proyectos.twig');
// Areas de proyectos
$areas = get_terms( [
@@ -26,7 +26,7 @@ $context['serviciosterms'] = $serviciosterms;
$projects = array(
'post_type' => 'post',
'post_status' => 'publish',
'numberposts' => -1,
'posts_per_page' => -1,
'orderby' => array(
'date' => 'DESC'
),
@@ -44,7 +44,7 @@ $projects = array(
$projects1 = array(
'post_type' => 'post',
'post_status' => 'publish',
'numberposts' => -1,
'posts_per_page' => -1,
'orderby' => array(
'date' => 'DESC'
),
@@ -57,9 +57,8 @@ $projects1 = array(
),
);
$context['posts'] = new Timber\PostQuery($projects);
$context['projects1'] = new Timber\PostQuery($projects1);
$context['posts'] = Timber::get_posts($projects);
$context['projects1'] = Timber::get_posts($projects1);
$context['section_title'] = 'proyectos';
Timber::render( $templates, $context );

View File

@@ -10,7 +10,7 @@
*/
$context = Timber::get_context();
$post = new TimberPost();
$post = Timber::get_post();
$context['post'] = $post;
// Relacionados -> general
@@ -27,7 +27,7 @@ function get_related_posts($terms) {
$args = array(
'post_type' => 'post',
'numberposts' => 3,
'posts_per_page' => 3,
'tax_query' => array(
array(
'taxonomy' => 'category',
@@ -39,28 +39,12 @@ function get_related_posts($terms) {
'post__not_in' => array( get_the_ID() )
);
return Timber::get_posts($args);
}
//~ $context = Timber::get_context();
//~ $post = Timber::query_post();
//~ $context['post'] = $post;
$context['related'] = get_related_posts($post->get_terms());
if ( post_password_required( $post->ID ) ) {
Timber::render( 'single-password.twig', $context );
} else {
Timber::render( array( 'single-' . $post->ID . '.twig', 'single-' . $post->post_type . '.twig', 'single.twig' ), $context );
}
//~ $timber_post = Timber::query_post();
//~ $context['post'] = $timber_post;
//~ $context['related'] = get_related_posts($timber_post->get_terms());
//~ if ( post_password_required( $timber_post->ID ) ) {
//~ Timber::render( 'single-password.twig', $context );
//~ } else {
//~ Timber::render( array( 'single-' . $timber_post->ID . '.twig', 'single-' . $timber_post->post_type . '.twig', 'single-' . $timber_post->slug . '.twig', 'single.twig' ), $context );
//~ }
}

View File

@@ -25,19 +25,135 @@ use Twig\TwigFilter;
class AndairaSite extends Site {
public $enable_ua = true;
function __construct() {
function __construct() {
add_action('after_setup_theme', array($this, 'theme_supports'));
//$this->recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
//$this->recaptcha_secret = '6Ldp7-cUAAAAALND-F6N211yRaam8jBF_W_jkzg_';
//$this->recaptcha_public = '6Ldp7-cUAAAAANJ68d2DomQJn-TbnUxfVPNHm95K';
//$this->CONTACT_FORM = dirname( __FILE__ ).'/templates/form_contact.html';
add_filter('timber/context', array($this, 'add_to_context'));
add_filter('timber/twig/environment/options', [$this, 'update_twig_environment_options']);
add_filter('timber/twig', array($this, 'add_to_twig'));
add_action('wp_enqueue_scripts', [$this,'load_assets']);
parent::__construct();
$this->recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
$this->recaptcha_secret = '6Ldp7-cUAAAAALND-F6N211yRaam8jBF_W_jkzg_';
$this->recaptcha_public = '6Ldp7-cUAAAAANJ68d2DomQJn-TbnUxfVPNHm95K';
$this->CONTACT_FORM = dirname( __FILE__ ).'/templates/form_contact.html';
}
public function theme_supports()
{
add_theme_support('automatic-feed-links');
add_theme_support( 'disable-layout-styles' );
add_theme_support('title-tag');
add_theme_support('post-thumbnails');
add_theme_support(
'html5',
[
'gallery',
'caption',
]
);
add_theme_support(
'post-formats',
array(
'aside',
'image',
'video',
'quote',
'link',
'gallery',
'audio',
)
);
add_theme_support('menus');
}
function update_twig_environment_options($options)
{
// $options['autoescape'] = true;
return $options;
}
public function add_to_twig($twig)
{
$twig->addFunction(
new \Twig\TwigFunction( 'frontpage_posts', [$this, 'frontpage_posts'] )
);
$twig->addFunction(
new \Twig\TwigFunction( 'posts_by_term', [$this, 'posts_by_term'] )
);
$twig->addFunction(
new \Twig\TwigFunction( 'posts_by_type', [$this, 'posts_by_type'] )
);
$twig->addFunction(
new \Twig\TwigFunction( 'posts_by_service', 'posts_by_service' )
);
return $twig;
}
public function frontpage_posts($numberposts=-1,$template_name='frontpage_post.twig')
{
$args = [
'posts_per_page' => $numberposts,
'post_type' => 'post',
];
$ctx = [
'posts' => Timber::get_posts( $args )
];
return Timber::fetch($template_name, $ctx);
}
public function posts_by_type($post_type, $numberposts=8, $template_name='posts_by_taxonomy.twig')
{
$args = [
'post_type' => $post_type,
'posts_per_page' => $numberposts,
];
$ctx = [
'posts' => Timber::get_posts( $args ),
];
return Timber::fetch($template_name, $ctx);
}
public function posts_by_term($taxonomy_slug, $term_slug, $numberposts=8, $post_type='post', $template_name='posts_by_taxonomy.twig')
{
$args = [
'post_type' => $post_type,
'posts_per_page' => $numberposts,
'tax_query' => [
[
'taxonomy' => $taxonomy_slug,
'field' => 'slug',
'terms' => $term_slug,
],
]
];
$ctx = [
'posts' => Timber::get_posts( $args ),
'taxonomy' => get_taxonomy($taxonomy_slug),
'term' => get_term($term_slug, $taxonomy_slug),
];
return Timber::fetch($template_name, $ctx);
}
function add_to_context( $context ) {
$context = parent::add_to_context($context);
// $context = parent::add_to_context($context);
// Servicios
$svs = array(
'child_of' => 27,
'parent ' => 27,
'parent' => 27,
'hierarchical' => 0,
'sort_column' => 'menu_order',
'sort_order' => 'asc',
@@ -45,7 +161,8 @@ class AndairaSite extends Site {
'post_status' => 'publish',
);
$servicios = get_pages( $svs );
$context['servicios'] = new Timber\PostQuery($servicios);
// dump($servicios);
$context['servicios'] = Timber::get_posts($servicios);
//return $context;
// Areas
@@ -63,5 +180,18 @@ class AndairaSite extends Site {
return $context;
}
function load_assets() {
$version = 4;
// $version_for_app = $version;
$version_for_app = time();
wp_enqueue_style( 'twbsi', get_template_directory_uri() . '/assets/css/bootstrap.min.css', [], $version, 'all');
//wp_enqueue_style( 'lust', get_template_directory_uri() . '/style.css', [], $version, 'all');
// wp_enqueue_script( 'pop', get_template_directory_uri() . '/static/popper.min.js', [], $version, false);
// wp_enqueue_script( 'twbs', get_template_directory_uri() . '/vendor/twbs/bootstrap/dist/js/bootstrap.min.js', [], $version, false);
// wp_enqueue_script( 'lust', get_template_directory_uri() . '/assets/scripts/site.js', [], $version, false);
}
}

119
vendor/bin/var-dump-server vendored Executable file
View File

@@ -0,0 +1,119 @@
#!/usr/bin/env php
<?php
/**
* Proxy PHP file generated by Composer
*
* This file includes the referenced bin path (../symfony/var-dumper/Resources/bin/var-dump-server)
* using a stream wrapper to prevent the shebang from being output on PHP<8
*
* @generated
*/
namespace Composer;
$GLOBALS['_composer_bin_dir'] = __DIR__;
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
if (PHP_VERSION_ID < 80000) {
if (!class_exists('Composer\BinProxyWrapper')) {
/**
* @internal
*/
final class BinProxyWrapper
{
private $handle;
private $position;
private $realpath;
public function stream_open($path, $mode, $options, &$opened_path)
{
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
$opened_path = substr($path, 17);
$this->realpath = realpath($opened_path) ?: $opened_path;
$opened_path = $this->realpath;
$this->handle = fopen($this->realpath, $mode);
$this->position = 0;
return (bool) $this->handle;
}
public function stream_read($count)
{
$data = fread($this->handle, $count);
if ($this->position === 0) {
$data = preg_replace('{^#!.*\r?\n}', '', $data);
}
$this->position += strlen($data);
return $data;
}
public function stream_cast($castAs)
{
return $this->handle;
}
public function stream_close()
{
fclose($this->handle);
}
public function stream_lock($operation)
{
return $operation ? flock($this->handle, $operation) : true;
}
public function stream_seek($offset, $whence)
{
if (0 === fseek($this->handle, $offset, $whence)) {
$this->position = ftell($this->handle);
return true;
}
return false;
}
public function stream_tell()
{
return $this->position;
}
public function stream_eof()
{
return feof($this->handle);
}
public function stream_stat()
{
return array();
}
public function stream_set_option($option, $arg1, $arg2)
{
return true;
}
public function url_stat($path, $flags)
{
$path = substr($path, 17);
if (file_exists($path)) {
return stat($path);
}
return false;
}
}
}
if (
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
) {
return include("phpvfscomposer://" . __DIR__ . '/..'.'/symfony/var-dumper/Resources/bin/var-dump-server');
}
}
return include __DIR__ . '/..'.'/symfony/var-dumper/Resources/bin/var-dump-server';

View File

@@ -6,13 +6,16 @@ $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'89efb1254ef2d1c5d80096acd12c4098' => $vendorDir . '/twig/twig/src/Resources/core.php',
'ffecb95d45175fd40f75be8a23b34f90' => $vendorDir . '/twig/twig/src/Resources/debug.php',
'c7baa00073ee9c61edf148c51917cfb4' => $vendorDir . '/twig/twig/src/Resources/escaper.php',
'f844ccf1d25df8663951193c3fc307c8' => $vendorDir . '/twig/twig/src/Resources/string_loader.php',
'667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
'8c3e128cd1b1ac75ff1847ce2e6ab3ea' => $vendorDir . '/wecodemore/wordpress-early-hook/wordpress-early-hook.php',
'37920fbd6eaeababa873d97ba1c5324c' => $vendorDir . '/hellonico/timber-dump-extension/functions.php',
'23f09fe3194f8c2f70923f90d6702129' => $vendorDir . '/illuminate/collections/functions.php',
'60799491728b879e74601d83e38b2cad' => $vendorDir . '/illuminate/collections/helpers.php',
);

View File

@@ -10,11 +10,15 @@ return array(
'Timber\\' => array($vendorDir . '/timber/timber/src'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
'Symfony\\Contracts\\Translation\\' => array($vendorDir . '/symfony/translation-contracts'),
'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'),
'Symfony\\Component\\PropertyAccess\\' => array($vendorDir . '/symfony/property-access'),
'Symfony\\Bridge\\Twig\\' => array($vendorDir . '/symfony/twig-bridge'),
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
'Illuminate\\Support\\' => array($vendorDir . '/illuminate/collections', $vendorDir . '/illuminate/conditionable', $vendorDir . '/illuminate/macroable'),
'Illuminate\\Contracts\\' => array($vendorDir . '/illuminate/contracts'),
'HelloNico\\Timber\\' => array($vendorDir . '/hellonico/timber-dump-extension/src'),
'Composer\\Installers\\' => array($vendorDir . '/composer/installers/src/Composer/Installers'),
'App\\' => array($baseDir . '/src'),
);

View File

@@ -7,13 +7,16 @@ namespace Composer\Autoload;
class ComposerStaticInite360deab1e3925e3deb6282d6a5a1f68
{
public static $files = array (
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'89efb1254ef2d1c5d80096acd12c4098' => __DIR__ . '/..' . '/twig/twig/src/Resources/core.php',
'ffecb95d45175fd40f75be8a23b34f90' => __DIR__ . '/..' . '/twig/twig/src/Resources/debug.php',
'c7baa00073ee9c61edf148c51917cfb4' => __DIR__ . '/..' . '/twig/twig/src/Resources/escaper.php',
'f844ccf1d25df8663951193c3fc307c8' => __DIR__ . '/..' . '/twig/twig/src/Resources/string_loader.php',
'667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
'8c3e128cd1b1ac75ff1847ce2e6ab3ea' => __DIR__ . '/..' . '/wecodemore/wordpress-early-hook/wordpress-early-hook.php',
'37920fbd6eaeababa873d97ba1c5324c' => __DIR__ . '/..' . '/hellonico/timber-dump-extension/functions.php',
'23f09fe3194f8c2f70923f90d6702129' => __DIR__ . '/..' . '/illuminate/collections/functions.php',
'60799491728b879e74601d83e38b2cad' => __DIR__ . '/..' . '/illuminate/collections/helpers.php',
);
@@ -28,7 +31,10 @@ class ComposerStaticInite360deab1e3925e3deb6282d6a5a1f68
array (
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Polyfill\\Ctype\\' => 23,
'Symfony\\Contracts\\Translation\\' => 30,
'Symfony\\Component\\VarDumper\\' => 28,
'Symfony\\Component\\PropertyAccess\\' => 33,
'Symfony\\Bridge\\Twig\\' => 20,
),
'P' =>
array (
@@ -40,6 +46,10 @@ class ComposerStaticInite360deab1e3925e3deb6282d6a5a1f68
'Illuminate\\Support\\' => 19,
'Illuminate\\Contracts\\' => 21,
),
'H' =>
array (
'HelloNico\\Timber\\' => 17,
),
'C' =>
array (
'Composer\\Installers\\' => 20,
@@ -67,10 +77,22 @@ class ComposerStaticInite360deab1e3925e3deb6282d6a5a1f68
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
),
'Symfony\\Contracts\\Translation\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/translation-contracts',
),
'Symfony\\Component\\VarDumper\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/var-dumper',
),
'Symfony\\Component\\PropertyAccess\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/property-access',
),
'Symfony\\Bridge\\Twig\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/twig-bridge',
),
'Psr\\SimpleCache\\' =>
array (
0 => __DIR__ . '/..' . '/psr/simple-cache/src',
@@ -89,6 +111,10 @@ class ComposerStaticInite360deab1e3925e3deb6282d6a5a1f68
array (
0 => __DIR__ . '/..' . '/illuminate/contracts',
),
'HelloNico\\Timber\\' =>
array (
0 => __DIR__ . '/..' . '/hellonico/timber-dump-extension/src',
),
'Composer\\Installers\\' =>
array (
0 => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers',

View File

@@ -318,6 +318,63 @@
],
"install-path": "../gregwar/formidable/Gregwar/Formidable"
},
{
"name": "hellonico/timber-dump-extension",
"version": "2.0.0",
"version_normalized": "2.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/nlemoine/timber-dump-extension.git",
"reference": "c1a4269ec4cda8542c068972ee76cee0d5c9d041"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nlemoine/timber-dump-extension/zipball/c1a4269ec4cda8542c068972ee76cee0d5c9d041",
"reference": "c1a4269ec4cda8542c068972ee76cee0d5c9d041",
"shasum": ""
},
"require": {
"symfony/twig-bridge": "^6 || ^7",
"symfony/var-dumper": "^6 || ^7",
"wecodemore/wordpress-early-hook": "^1.2"
},
"time": "2024-03-08T12:20:18+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"files": [
"functions.php"
],
"psr-4": {
"HelloNico\\Timber\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-3.0+"
],
"authors": [
{
"name": "Nicolas Lemoine",
"email": "nico@n5s.dev",
"homepage": "https://n5s.dev/"
}
],
"description": "Provides Symfony VarDumper component for Timber",
"homepage": "https://github.com/nlemoine/timber-dump-extension",
"keywords": [
"VarDumper",
"symfony",
"timber",
"twig",
"wordpress"
],
"support": {
"issues": "https://github.com/nlemoine/timber-dump-extension/issues",
"source": "https://github.com/nlemoine/timber-dump-extension/tree/2.0.0"
},
"install-path": "../hellonico/timber-dump-extension"
},
{
"name": "illuminate/collections",
"version": "v12.21.0",
@@ -982,6 +1039,288 @@
],
"install-path": "../symfony/property-access"
},
{
"name": "symfony/translation-contracts",
"version": "v3.6.0",
"version_normalized": "3.6.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation-contracts.git",
"reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
"reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"time": "2024-09-27T08:32:26+00:00",
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.6-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Translation\\": ""
},
"exclude-from-classmap": [
"/Test/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to translation",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/translation-contracts/tree/v3.6.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/translation-contracts"
},
{
"name": "symfony/twig-bridge",
"version": "v7.3.0",
"version_normalized": "7.3.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/twig-bridge.git",
"reference": "082eb15d8a4f9afee0acc4709fbe3aaf26d48891"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/twig-bridge/zipball/082eb15d8a4f9afee0acc4709fbe3aaf26d48891",
"reference": "082eb15d8a4f9afee0acc4709fbe3aaf26d48891",
"shasum": ""
},
"require": {
"php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/translation-contracts": "^2.5|^3",
"twig/twig": "^3.21"
},
"conflict": {
"phpdocumentor/reflection-docblock": "<3.2.2",
"phpdocumentor/type-resolver": "<1.4.0",
"symfony/console": "<6.4",
"symfony/form": "<6.4",
"symfony/http-foundation": "<6.4",
"symfony/http-kernel": "<6.4",
"symfony/mime": "<6.4",
"symfony/serializer": "<6.4",
"symfony/translation": "<6.4",
"symfony/workflow": "<6.4"
},
"require-dev": {
"egulias/email-validator": "^2.1.10|^3|^4",
"league/html-to-markdown": "^5.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
"symfony/asset": "^6.4|^7.0",
"symfony/asset-mapper": "^6.4|^7.0",
"symfony/console": "^6.4|^7.0",
"symfony/dependency-injection": "^6.4|^7.0",
"symfony/emoji": "^7.1",
"symfony/expression-language": "^6.4|^7.0",
"symfony/finder": "^6.4|^7.0",
"symfony/form": "^6.4.20|^7.2.5",
"symfony/html-sanitizer": "^6.4|^7.0",
"symfony/http-foundation": "^7.3",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/intl": "^6.4|^7.0",
"symfony/mime": "^6.4|^7.0",
"symfony/polyfill-intl-icu": "~1.0",
"symfony/property-info": "^6.4|^7.0",
"symfony/routing": "^6.4|^7.0",
"symfony/security-acl": "^2.8|^3.0",
"symfony/security-core": "^6.4|^7.0",
"symfony/security-csrf": "^6.4|^7.0",
"symfony/security-http": "^6.4|^7.0",
"symfony/serializer": "^6.4.3|^7.0.3",
"symfony/stopwatch": "^6.4|^7.0",
"symfony/translation": "^6.4|^7.0",
"symfony/validator": "^6.4|^7.0",
"symfony/web-link": "^6.4|^7.0",
"symfony/workflow": "^6.4|^7.0",
"symfony/yaml": "^6.4|^7.0",
"twig/cssinliner-extra": "^3",
"twig/inky-extra": "^3",
"twig/markdown-extra": "^3"
},
"time": "2025-05-19T13:28:56+00:00",
"type": "symfony-bridge",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Bridge\\Twig\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides integration for Twig with various Symfony components",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/twig-bridge/tree/v7.3.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/twig-bridge"
},
{
"name": "symfony/var-dumper",
"version": "v7.3.1",
"version_normalized": "7.3.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "6e209fbe5f5a7b6043baba46fe5735a4b85d0d42"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/6e209fbe5f5a7b6043baba46fe5735a4b85d0d42",
"reference": "6e209fbe5f5a7b6043baba46fe5735a4b85d0d42",
"shasum": ""
},
"require": {
"php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
"symfony/console": "<6.4"
},
"require-dev": {
"ext-iconv": "*",
"symfony/console": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/process": "^6.4|^7.0",
"symfony/uid": "^6.4|^7.0",
"twig/twig": "^3.12"
},
"time": "2025-06-27T19:55:54+00:00",
"bin": [
"Resources/bin/var-dump-server"
],
"type": "library",
"installation-source": "dist",
"autoload": {
"files": [
"Resources/functions/dump.php"
],
"psr-4": {
"Symfony\\Component\\VarDumper\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides mechanisms for walking through any arbitrary PHP variable",
"homepage": "https://symfony.com",
"keywords": [
"debug",
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v7.3.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/var-dumper"
},
{
"name": "timber/timber",
"version": "v2.3.2",
@@ -1227,6 +1566,71 @@
"wiki": "https://github.com/Upstatement/routes/wiki"
},
"install-path": "../upstatement/routes"
},
{
"name": "wecodemore/wordpress-early-hook",
"version": "1.3.0",
"version_normalized": "1.3.0.0",
"source": {
"type": "git",
"url": "https://github.com/wecodemore/wordpress-early-hook.git",
"reference": "61affcc3d64d77199bce237341a39a7a01e272e0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/wecodemore/wordpress-early-hook/zipball/61affcc3d64d77199bce237341a39a7a01e272e0",
"reference": "61affcc3d64d77199bce237341a39a7a01e272e0",
"shasum": ""
},
"require": {
"php": ">=7.1 < 8.5"
},
"require-dev": {
"inpsyde/php-coding-standards": "^1.0.0",
"phpunit/phpunit": "^7.5.20 || ^9.6.4",
"roave/security-advisories": "dev-latest",
"roots/wordpress-no-content": ">=6.1.1",
"vimeo/psalm": "^4.30.0"
},
"time": "2025-04-07T08:58:48+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"files": [
"wordpress-early-hook.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Giuseppe Mazzapica",
"email": "giuseppe.mazzapica@gmail.com",
"homepage": "https://gmazzap.me",
"role": "Developer"
}
],
"description": "Small library to safely add WordPress hooks before WordPress is loaded.",
"keywords": [
"actions",
"filters",
"hooks",
"wordpress",
"wordpress actions",
"wordpress filters",
"wordpress hooks",
"wp",
"wp actions",
"wp filters",
"wp hooks"
],
"support": {
"issues": "https://github.com/wecodemore/wordpress-early-hook/issues",
"source": "https://github.com/wecodemore/wordpress-early-hook"
},
"install-path": "../wecodemore/wordpress-early-hook"
}
],
"dev": true,

View File

@@ -3,7 +3,7 @@
'name' => '__root__',
'pretty_version' => 'dev-main',
'version' => 'dev-main',
'reference' => 'f4f413ec23c013281b14540789f7c4d74aff121d',
'reference' => '192094c23a9473ff16ed424a7f3ecd8c1d669c70',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -13,7 +13,7 @@
'__root__' => array(
'pretty_version' => 'dev-main',
'version' => 'dev-main',
'reference' => 'f4f413ec23c013281b14540789f7c4d74aff121d',
'reference' => '192094c23a9473ff16ed424a7f3ecd8c1d669c70',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -55,6 +55,15 @@
'aliases' => array(),
'dev_requirement' => false,
),
'hellonico/timber-dump-extension' => array(
'pretty_version' => '2.0.0',
'version' => '2.0.0.0',
'reference' => 'c1a4269ec4cda8542c068972ee76cee0d5c9d041',
'type' => 'library',
'install_path' => __DIR__ . '/../hellonico/timber-dump-extension',
'aliases' => array(),
'dev_requirement' => false,
),
'illuminate/collections' => array(
'pretty_version' => 'v12.21.0',
'version' => '12.21.0.0',
@@ -154,6 +163,33 @@
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/translation-contracts' => array(
'pretty_version' => 'v3.6.0',
'version' => '3.6.0.0',
'reference' => 'df210c7a2573f1913b2d17cc95f90f53a73d8f7d',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation-contracts',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/twig-bridge' => array(
'pretty_version' => 'v7.3.0',
'version' => '7.3.0.0',
'reference' => '082eb15d8a4f9afee0acc4709fbe3aaf26d48891',
'type' => 'symfony-bridge',
'install_path' => __DIR__ . '/../symfony/twig-bridge',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/var-dumper' => array(
'pretty_version' => 'v7.3.1',
'version' => '7.3.1.0',
'reference' => '6e209fbe5f5a7b6043baba46fe5735a4b85d0d42',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/var-dumper',
'aliases' => array(),
'dev_requirement' => false,
),
'timber/timber' => array(
'pretty_version' => 'v2.3.2',
'version' => '2.3.2.0',
@@ -181,5 +217,14 @@
'aliases' => array(),
'dev_requirement' => false,
),
'wecodemore/wordpress-early-hook' => array(
'pretty_version' => '1.3.0',
'version' => '1.3.0.0',
'reference' => '61affcc3d64d77199bce237341a39a7a01e272e0',
'type' => 'library',
'install_path' => __DIR__ . '/../wecodemore/wordpress-early-hook',
'aliases' => array(),
'dev_requirement' => false,
),
),
);

View File

@@ -0,0 +1,19 @@
name: Release
on:
push:
branches:
- main
permissions:
contents: write
pull-requests: write
packages: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: google-github-actions/release-please-action@v4
with:
release-type: "php"

View File

@@ -0,0 +1,2 @@
/vendor
/composer.lock

View File

@@ -0,0 +1,12 @@
# Changelog
## [2.0.0](https://github.com/nlemoine/timber-dump-extension/compare/v1.0.0...v2.0.0) (2024-03-08)
### ⚠ BREAKING CHANGES
* release 2.0
### Features
* release 2.0 ([f3fd31e](https://github.com/nlemoine/timber-dump-extension/commit/f3fd31eb5a10bce468298421e060840a074ee612))

View File

@@ -0,0 +1,17 @@
# Timber Dump Extension
Symfony VarDumper for Timber.
## Install
```bash
composer require hellonico/timber-dump-extension
```
## Usage
```twig
{{ dump(foo) }}
```
Note that this extension will only be enabled if `WP_DEBUG` is set to `true`.

View File

@@ -0,0 +1,34 @@
{
"name": "hellonico/timber-dump-extension",
"description": "Provides Symfony VarDumper component for Timber",
"keywords": [
"timber",
"twig",
"symfony",
"vardumper",
"wordpress"
],
"license": "GPL-3.0+",
"type": "library",
"authors": [
{
"name": "Nicolas Lemoine",
"email": "nico@n5s.dev",
"homepage": "https://n5s.dev/"
}
],
"homepage": "https://github.com/nlemoine/timber-dump-extension",
"require": {
"symfony/twig-bridge": "^6 || ^7",
"symfony/var-dumper": "^6 || ^7",
"wecodemore/wordpress-early-hook": "^1.2"
},
"autoload": {
"psr-4": {
"HelloNico\\Timber\\": "src/"
},
"files": [
"functions.php"
]
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace HelloNico\Timber;
use Symfony\Bridge\Twig\Extension\DumpExtension;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use function WeCodeMore\earlyAddFilter;
function add_dump_extension($twig)
{
if (defined('WP_DEBUG') && WP_DEBUG) {
$twig->addExtension(new DumpExtension(new VarCloner()));
}
return $twig;
}
earlyAddFilter('timber/loader/twig', sprintf('%s\\add_dump_extension', __NAMESPACE__));

View File

@@ -0,0 +1,5 @@
CHANGELOG
=========
The changelog is maintained for all Symfony contracts at the following URL:
https://github.com/symfony/contracts/blob/main/CHANGELOG.md

View File

@@ -0,0 +1,19 @@
Copyright (c) 2018-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,29 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Contracts\Translation;
interface LocaleAwareInterface
{
/**
* Sets the current locale.
*
* @return void
*
* @throws \InvalidArgumentException If the locale contains invalid characters
*/
public function setLocale(string $locale);
/**
* Returns the current locale.
*/
public function getLocale(): string;
}

View File

@@ -0,0 +1,9 @@
Symfony Translation Contracts
=============================
A set of abstractions extracted out of the Symfony components.
Can be used to build on semantics that the Symfony components proved useful and
that already have battle tested implementations.
See https://github.com/symfony/contracts/blob/main/README.md for more information.

View File

@@ -0,0 +1,398 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Contracts\Translation\Test;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use PHPUnit\Framework\TestCase;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Contracts\Translation\TranslatorTrait;
/**
* Test should cover all languages mentioned on http://translate.sourceforge.net/wiki/l10n/pluralforms
* and Plural forms mentioned on http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms.
*
* See also https://developer.mozilla.org/en/Localization_and_Plurals which mentions 15 rules having a maximum of 6 forms.
* The mozilla code is also interesting to check for.
*
* As mentioned by chx http://drupal.org/node/1273968 we can cover all by testing number from 0 to 199
*
* The goal to cover all languages is to far fetched so this test case is smaller.
*
* @author Clemens Tolboom clemens@build2be.nl
*/
class TranslatorTest extends TestCase
{
private string $defaultLocale;
protected function setUp(): void
{
$this->defaultLocale = \Locale::getDefault();
\Locale::setDefault('en');
}
protected function tearDown(): void
{
\Locale::setDefault($this->defaultLocale);
}
public function getTranslator(): TranslatorInterface
{
return new class implements TranslatorInterface {
use TranslatorTrait;
};
}
/**
* @dataProvider getTransTests
*/
#[DataProvider('getTransTests')]
public function testTrans($expected, $id, $parameters)
{
$translator = $this->getTranslator();
$this->assertEquals($expected, $translator->trans($id, $parameters));
}
/**
* @dataProvider getTransChoiceTests
*/
#[DataProvider('getTransChoiceTests')]
public function testTransChoiceWithExplicitLocale($expected, $id, $number)
{
$translator = $this->getTranslator();
$this->assertEquals($expected, $translator->trans($id, ['%count%' => $number]));
}
/**
* @requires extension intl
*
* @dataProvider getTransChoiceTests
*/
#[DataProvider('getTransChoiceTests')]
#[RequiresPhpExtension('intl')]
public function testTransChoiceWithDefaultLocale($expected, $id, $number)
{
$translator = $this->getTranslator();
$this->assertEquals($expected, $translator->trans($id, ['%count%' => $number]));
}
/**
* @dataProvider getTransChoiceTests
*/
#[DataProvider('getTransChoiceTests')]
public function testTransChoiceWithEnUsPosix($expected, $id, $number)
{
$translator = $this->getTranslator();
$translator->setLocale('en_US_POSIX');
$this->assertEquals($expected, $translator->trans($id, ['%count%' => $number]));
}
public function testGetSetLocale()
{
$translator = $this->getTranslator();
$this->assertEquals('en', $translator->getLocale());
}
/**
* @requires extension intl
*/
#[RequiresPhpExtension('intl')]
public function testGetLocaleReturnsDefaultLocaleIfNotSet()
{
$translator = $this->getTranslator();
\Locale::setDefault('pt_BR');
$this->assertEquals('pt_BR', $translator->getLocale());
\Locale::setDefault('en');
$this->assertEquals('en', $translator->getLocale());
}
public static function getTransTests()
{
return [
['Symfony is great!', 'Symfony is great!', []],
['Symfony is awesome!', 'Symfony is %what%!', ['%what%' => 'awesome']],
];
}
public static function getTransChoiceTests()
{
return [
['There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0],
['There is one apple', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 1],
['There are 10 apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10],
['There are 0 apples', 'There is 1 apple|There are %count% apples', 0],
['There is 1 apple', 'There is 1 apple|There are %count% apples', 1],
['There are 10 apples', 'There is 1 apple|There are %count% apples', 10],
// custom validation messages may be coded with a fixed value
['There are 2 apples', 'There are 2 apples', 2],
];
}
/**
* @dataProvider getInterval
*/
#[DataProvider('getInterval')]
public function testInterval($expected, $number, $interval)
{
$translator = $this->getTranslator();
$this->assertEquals($expected, $translator->trans($interval.' foo|[1,Inf[ bar', ['%count%' => $number]));
}
public static function getInterval()
{
return [
['foo', 3, '{1,2, 3 ,4}'],
['bar', 10, '{1,2, 3 ,4}'],
['bar', 3, '[1,2]'],
['foo', 1, '[1,2]'],
['foo', 2, '[1,2]'],
['bar', 1, ']1,2['],
['bar', 2, ']1,2['],
['foo', log(0), '[-Inf,2['],
['foo', -log(0), '[-2,+Inf]'],
];
}
/**
* @dataProvider getChooseTests
*/
#[DataProvider('getChooseTests')]
public function testChoose($expected, $id, $number, $locale = null)
{
$translator = $this->getTranslator();
$this->assertEquals($expected, $translator->trans($id, ['%count%' => $number], null, $locale));
}
public function testReturnMessageIfExactlyOneStandardRuleIsGiven()
{
$translator = $this->getTranslator();
$this->assertEquals('There are two apples', $translator->trans('There are two apples', ['%count%' => 2]));
}
/**
* @dataProvider getNonMatchingMessages
*/
#[DataProvider('getNonMatchingMessages')]
public function testThrowExceptionIfMatchingMessageCannotBeFound($id, $number)
{
$translator = $this->getTranslator();
$this->expectException(\InvalidArgumentException::class);
$translator->trans($id, ['%count%' => $number]);
}
public static function getNonMatchingMessages()
{
return [
['{0} There are no apples|{1} There is one apple', 2],
['{1} There is one apple|]1,Inf] There are %count% apples', 0],
['{1} There is one apple|]2,Inf] There are %count% apples', 2],
['{0} There are no apples|There is one apple', 2],
];
}
public static function getChooseTests()
{
return [
['There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0],
['There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0],
['There are no apples', '{0}There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0],
['There is one apple', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 1],
['There are 10 apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10],
['There are 10 apples', '{0} There are no apples|{1} There is one apple|]1,Inf]There are %count% apples', 10],
['There are 10 apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10],
['There are 0 apples', 'There is one apple|There are %count% apples', 0],
['There is one apple', 'There is one apple|There are %count% apples', 1],
['There are 10 apples', 'There is one apple|There are %count% apples', 10],
['There are 0 apples', 'one: There is one apple|more: There are %count% apples', 0],
['There is one apple', 'one: There is one apple|more: There are %count% apples', 1],
['There are 10 apples', 'one: There is one apple|more: There are %count% apples', 10],
['There are no apples', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 0],
['There is one apple', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 1],
['There are 10 apples', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 10],
['', '{0}|{1} There is one apple|]1,Inf] There are %count% apples', 0],
['', '{0} There are no apples|{1}|]1,Inf] There are %count% apples', 1],
// Indexed only tests which are Gettext PoFile* compatible strings.
['There are 0 apples', 'There is one apple|There are %count% apples', 0],
['There is one apple', 'There is one apple|There are %count% apples', 1],
['There are 2 apples', 'There is one apple|There are %count% apples', 2],
// Tests for float numbers
['There is almost one apple', '{0} There are no apples|]0,1[ There is almost one apple|{1} There is one apple|[1,Inf] There is more than one apple', 0.7],
['There is one apple', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1],
['There is more than one apple', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1.7],
['There are no apples', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0],
['There are no apples', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0.0],
['There are no apples', '{0.0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0],
// Test texts with new-lines
// with double-quotes and \n in id & double-quotes and actual newlines in text
["This is a text with a\n new-line in it. Selector = 0.", '{0}This is a text with a
new-line in it. Selector = 0.|{1}This is a text with a
new-line in it. Selector = 1.|[1,Inf]This is a text with a
new-line in it. Selector > 1.', 0],
// with double-quotes and \n in id and single-quotes and actual newlines in text
["This is a text with a\n new-line in it. Selector = 1.", '{0}This is a text with a
new-line in it. Selector = 0.|{1}This is a text with a
new-line in it. Selector = 1.|[1,Inf]This is a text with a
new-line in it. Selector > 1.', 1],
["This is a text with a\n new-line in it. Selector > 1.", '{0}This is a text with a
new-line in it. Selector = 0.|{1}This is a text with a
new-line in it. Selector = 1.|[1,Inf]This is a text with a
new-line in it. Selector > 1.', 5],
// with double-quotes and id split across lines
['This is a text with a
new-line in it. Selector = 1.', '{0}This is a text with a
new-line in it. Selector = 0.|{1}This is a text with a
new-line in it. Selector = 1.|[1,Inf]This is a text with a
new-line in it. Selector > 1.', 1],
// with single-quotes and id split across lines
['This is a text with a
new-line in it. Selector > 1.', '{0}This is a text with a
new-line in it. Selector = 0.|{1}This is a text with a
new-line in it. Selector = 1.|[1,Inf]This is a text with a
new-line in it. Selector > 1.', 5],
// with single-quotes and \n in text
['This is a text with a\nnew-line in it. Selector = 0.', '{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.', 0],
// with double-quotes and id split across lines
["This is a text with a\nnew-line in it. Selector = 1.", "{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.", 1],
// escape pipe
['This is a text with | in it. Selector = 0.', '{0}This is a text with || in it. Selector = 0.|{1}This is a text with || in it. Selector = 1.', 0],
// Empty plural set (2 plural forms) from a .PO file
['', '|', 1],
// Empty plural set (3 plural forms) from a .PO file
['', '||', 1],
// Floating values
['1.5 liters', '%count% liter|%count% liters', 1.5],
['1.5 litre', '%count% litre|%count% litres', 1.5, 'fr'],
// Negative values
['-1 degree', '%count% degree|%count% degrees', -1],
['-1 degré', '%count% degré|%count% degrés', -1],
['-1.5 degrees', '%count% degree|%count% degrees', -1.5],
['-1.5 degré', '%count% degré|%count% degrés', -1.5, 'fr'],
['-2 degrees', '%count% degree|%count% degrees', -2],
['-2 degrés', '%count% degré|%count% degrés', -2],
];
}
/**
* @dataProvider failingLangcodes
*/
#[DataProvider('failingLangcodes')]
public function testFailedLangcodes($nplural, $langCodes)
{
$matrix = $this->generateTestData($langCodes);
$this->validateMatrix($nplural, $matrix, false);
}
/**
* @dataProvider successLangcodes
*/
#[DataProvider('successLangcodes')]
public function testLangcodes($nplural, $langCodes)
{
$matrix = $this->generateTestData($langCodes);
$this->validateMatrix($nplural, $matrix);
}
/**
* This array should contain all currently known langcodes.
*
* As it is impossible to have this ever complete we should try as hard as possible to have it almost complete.
*/
public static function successLangcodes(): array
{
return [
['1', ['ay', 'bo', 'cgg', 'dz', 'id', 'ja', 'jbo', 'ka', 'kk', 'km', 'ko', 'ky']],
['2', ['nl', 'fr', 'en', 'de', 'de_GE', 'hy', 'hy_AM', 'en_US_POSIX']],
['3', ['be', 'bs', 'cs', 'hr']],
['4', ['cy', 'mt', 'sl']],
['6', ['ar']],
];
}
/**
* This array should be at least empty within the near future.
*
* This both depends on a complete list trying to add above as understanding
* the plural rules of the current failing languages.
*
* @return array with nplural together with langcodes
*/
public static function failingLangcodes(): array
{
return [
['1', ['fa']],
['2', ['jbo']],
['3', ['cbs']],
['4', ['gd', 'kw']],
['5', ['ga']],
];
}
/**
* We validate only on the plural coverage. Thus the real rules is not tested.
*
* @param string $nplural Plural expected
* @param array $matrix Containing langcodes and their plural index values
*/
protected function validateMatrix(string $nplural, array $matrix, bool $expectSuccess = true)
{
foreach ($matrix as $langCode => $data) {
$indexes = array_flip($data);
if ($expectSuccess) {
$this->assertCount($nplural, $indexes, "Langcode '$langCode' has '$nplural' plural forms.");
} else {
$this->assertNotCount($nplural, $indexes, "Langcode '$langCode' has '$nplural' plural forms.");
}
}
}
protected function generateTestData($langCodes)
{
$translator = new class {
use TranslatorTrait {
getPluralizationRule as public;
}
};
$matrix = [];
foreach ($langCodes as $langCode) {
for ($count = 0; $count < 200; ++$count) {
$plural = $translator->getPluralizationRule($count, $langCode);
$matrix[$langCode][$count] = $plural;
}
}
return $matrix;
}
}

View File

@@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Contracts\Translation;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
interface TranslatableInterface
{
public function trans(TranslatorInterface $translator, ?string $locale = null): string;
}

View File

@@ -0,0 +1,68 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Contracts\Translation;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
interface TranslatorInterface
{
/**
* Translates the given message.
*
* When a number is provided as a parameter named "%count%", the message is parsed for plural
* forms and a translation is chosen according to this number using the following rules:
*
* Given a message with different plural translations separated by a
* pipe (|), this method returns the correct portion of the message based
* on the given number, locale and the pluralization rules in the message
* itself.
*
* The message supports two different types of pluralization rules:
*
* interval: {0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples
* indexed: There is one apple|There are %count% apples
*
* The indexed solution can also contain labels (e.g. one: There is one apple).
* This is purely for making the translations more clear - it does not
* affect the functionality.
*
* The two methods can also be mixed:
* {0} There are no apples|one: There is one apple|more: There are %count% apples
*
* An interval can represent a finite set of numbers:
* {1,2,3,4}
*
* An interval can represent numbers between two numbers:
* [1, +Inf]
* ]-1,2[
*
* The left delimiter can be [ (inclusive) or ] (exclusive).
* The right delimiter can be [ (exclusive) or ] (inclusive).
* Beside numbers, you can use -Inf and +Inf for the infinite.
*
* @see https://en.wikipedia.org/wiki/ISO_31-11
*
* @param string $id The message id (may also be an object that can be cast to string)
* @param array $parameters An array of parameters for the message
* @param string|null $domain The domain for the message or null to use the default
* @param string|null $locale The locale or null to use the default
*
* @throws \InvalidArgumentException If the locale contains invalid characters
*/
public function trans(string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string;
/**
* Returns the default locale.
*/
public function getLocale(): string;
}

View File

@@ -0,0 +1,225 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Contracts\Translation;
use Symfony\Component\Translation\Exception\InvalidArgumentException;
/**
* A trait to help implement TranslatorInterface and LocaleAwareInterface.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
trait TranslatorTrait
{
private ?string $locale = null;
/**
* @return void
*/
public function setLocale(string $locale)
{
$this->locale = $locale;
}
public function getLocale(): string
{
return $this->locale ?: (class_exists(\Locale::class) ? \Locale::getDefault() : 'en');
}
public function trans(?string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string
{
if (null === $id || '' === $id) {
return '';
}
if (!isset($parameters['%count%']) || !is_numeric($parameters['%count%'])) {
return strtr($id, $parameters);
}
$number = (float) $parameters['%count%'];
$locale = $locale ?: $this->getLocale();
$parts = [];
if (preg_match('/^\|++$/', $id)) {
$parts = explode('|', $id);
} elseif (preg_match_all('/(?:\|\||[^\|])++/', $id, $matches)) {
$parts = $matches[0];
}
$intervalRegexp = <<<'EOF'
/^(?P<interval>
({\s*
(\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*)
\s*})
|
(?P<left_delimiter>[\[\]])
\s*
(?P<left>-Inf|\-?\d+(\.\d+)?)
\s*,\s*
(?P<right>\+?Inf|\-?\d+(\.\d+)?)
\s*
(?P<right_delimiter>[\[\]])
)\s*(?P<message>.*?)$/xs
EOF;
$standardRules = [];
foreach ($parts as $part) {
$part = trim(str_replace('||', '|', $part));
// try to match an explicit rule, then fallback to the standard ones
if (preg_match($intervalRegexp, $part, $matches)) {
if ($matches[2]) {
foreach (explode(',', $matches[3]) as $n) {
if ($number == $n) {
return strtr($matches['message'], $parameters);
}
}
} else {
$leftNumber = '-Inf' === $matches['left'] ? -\INF : (float) $matches['left'];
$rightNumber = is_numeric($matches['right']) ? (float) $matches['right'] : \INF;
if (('[' === $matches['left_delimiter'] ? $number >= $leftNumber : $number > $leftNumber)
&& (']' === $matches['right_delimiter'] ? $number <= $rightNumber : $number < $rightNumber)
) {
return strtr($matches['message'], $parameters);
}
}
} elseif (preg_match('/^\w+\:\s*(.*?)$/', $part, $matches)) {
$standardRules[] = $matches[1];
} else {
$standardRules[] = $part;
}
}
$position = $this->getPluralizationRule($number, $locale);
if (!isset($standardRules[$position])) {
// when there's exactly one rule given, and that rule is a standard
// rule, use this rule
if (1 === \count($parts) && isset($standardRules[0])) {
return strtr($standardRules[0], $parameters);
}
$message = \sprintf('Unable to choose a translation for "%s" with locale "%s" for value "%d". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $id, $locale, $number);
if (class_exists(InvalidArgumentException::class)) {
throw new InvalidArgumentException($message);
}
throw new \InvalidArgumentException($message);
}
return strtr($standardRules[$position], $parameters);
}
/**
* Returns the plural position to use for the given locale and number.
*
* The plural rules are derived from code of the Zend Framework (2010-09-25),
* which is subject to the new BSD license (http://framework.zend.com/license/new-bsd).
* Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
*/
private function getPluralizationRule(float $number, string $locale): int
{
$number = abs($number);
return match ('pt_BR' !== $locale && 'en_US_POSIX' !== $locale && \strlen($locale) > 3 ? substr($locale, 0, strrpos($locale, '_')) : $locale) {
'af',
'bn',
'bg',
'ca',
'da',
'de',
'el',
'en',
'en_US_POSIX',
'eo',
'es',
'et',
'eu',
'fa',
'fi',
'fo',
'fur',
'fy',
'gl',
'gu',
'ha',
'he',
'hu',
'is',
'it',
'ku',
'lb',
'ml',
'mn',
'mr',
'nah',
'nb',
'ne',
'nl',
'nn',
'no',
'oc',
'om',
'or',
'pa',
'pap',
'ps',
'pt',
'so',
'sq',
'sv',
'sw',
'ta',
'te',
'tk',
'ur',
'zu' => (1 == $number) ? 0 : 1,
'am',
'bh',
'fil',
'fr',
'gun',
'hi',
'hy',
'ln',
'mg',
'nso',
'pt_BR',
'ti',
'wa' => ($number < 2) ? 0 : 1,
'be',
'bs',
'hr',
'ru',
'sh',
'sr',
'uk' => ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2),
'cs',
'sk' => (1 == $number) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2),
'ga' => (1 == $number) ? 0 : ((2 == $number) ? 1 : 2),
'lt' => ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2),
'sl' => (1 == $number % 100) ? 0 : ((2 == $number % 100) ? 1 : (((3 == $number % 100) || (4 == $number % 100)) ? 2 : 3)),
'mk' => (1 == $number % 10) ? 0 : 1,
'mt' => (1 == $number) ? 0 : (((0 == $number) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3)),
'lv' => (0 == $number) ? 0 : (((1 == $number % 10) && (11 != $number % 100)) ? 1 : 2),
'pl' => (1 == $number) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2),
'cy' => (1 == $number) ? 0 : ((2 == $number) ? 1 : (((8 == $number) || (11 == $number)) ? 2 : 3)),
'ro' => (1 == $number) ? 0 : (((0 == $number) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2),
'ar' => (0 == $number) ? 0 : ((1 == $number) ? 1 : ((2 == $number) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : 5)))),
default => 0,
};
}
}

View File

@@ -0,0 +1,37 @@
{
"name": "symfony/translation-contracts",
"type": "library",
"description": "Generic abstractions related to translation",
"keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=8.1"
},
"autoload": {
"psr-4": { "Symfony\\Contracts\\Translation\\": "" },
"exclude-from-classmap": [
"/Test/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "3.6-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
}
}

View File

@@ -0,0 +1,216 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Translation\LocaleSwitcher;
/**
* Exposes some Symfony parameters and services as an "app" global variable.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class AppVariable
{
private TokenStorageInterface $tokenStorage;
private RequestStack $requestStack;
private string $environment;
private bool $debug;
private LocaleSwitcher $localeSwitcher;
private array $enabledLocales;
public function setTokenStorage(TokenStorageInterface $tokenStorage): void
{
$this->tokenStorage = $tokenStorage;
}
public function setRequestStack(RequestStack $requestStack): void
{
$this->requestStack = $requestStack;
}
public function setEnvironment(string $environment): void
{
$this->environment = $environment;
}
public function setDebug(bool $debug): void
{
$this->debug = $debug;
}
public function setLocaleSwitcher(LocaleSwitcher $localeSwitcher): void
{
$this->localeSwitcher = $localeSwitcher;
}
public function setEnabledLocales(array $enabledLocales): void
{
$this->enabledLocales = $enabledLocales;
}
/**
* Returns the current token.
*
* @throws \RuntimeException When the TokenStorage is not available
*/
public function getToken(): ?TokenInterface
{
if (!isset($this->tokenStorage)) {
throw new \RuntimeException('The "app.token" variable is not available.');
}
return $this->tokenStorage->getToken();
}
/**
* Returns the current user.
*
* @see TokenInterface::getUser()
*/
public function getUser(): ?UserInterface
{
if (!isset($this->tokenStorage)) {
throw new \RuntimeException('The "app.user" variable is not available.');
}
return $this->tokenStorage->getToken()?->getUser();
}
/**
* Returns the current request.
*/
public function getRequest(): ?Request
{
if (!isset($this->requestStack)) {
throw new \RuntimeException('The "app.request" variable is not available.');
}
return $this->requestStack->getCurrentRequest();
}
/**
* Returns the current session.
*/
public function getSession(): ?SessionInterface
{
if (!isset($this->requestStack)) {
throw new \RuntimeException('The "app.session" variable is not available.');
}
$request = $this->getRequest();
return $request?->hasSession() ? $request->getSession() : null;
}
/**
* Returns the current app environment.
*/
public function getEnvironment(): string
{
if (!isset($this->environment)) {
throw new \RuntimeException('The "app.environment" variable is not available.');
}
return $this->environment;
}
/**
* Returns the current app debug mode.
*/
public function getDebug(): bool
{
if (!isset($this->debug)) {
throw new \RuntimeException('The "app.debug" variable is not available.');
}
return $this->debug;
}
public function getLocale(): string
{
if (!isset($this->localeSwitcher)) {
throw new \RuntimeException('The "app.locale" variable is not available.');
}
return $this->localeSwitcher->getLocale();
}
public function getEnabled_locales(): array
{
if (!isset($this->enabledLocales)) {
throw new \RuntimeException('The "app.enabled_locales" variable is not available.');
}
return $this->enabledLocales;
}
/**
* Returns some or all the existing flash messages:
* * getFlashes() returns all the flash messages
* * getFlashes('notice') returns a simple array with flash messages of that type
* * getFlashes(['notice', 'error']) returns a nested array of type => messages.
*/
public function getFlashes(string|array|null $types = null): array
{
try {
$session = $this->getSession();
} catch (\RuntimeException) {
return [];
}
if (!$session instanceof FlashBagAwareSessionInterface) {
return [];
}
if (null === $types || '' === $types || [] === $types) {
return $session->getFlashBag()->all();
}
if (\is_string($types)) {
return $session->getFlashBag()->get($types);
}
$result = [];
foreach ($types as $type) {
$result[$type] = $session->getFlashBag()->get($type);
}
return $result;
}
public function getCurrent_route(): ?string
{
if (!isset($this->requestStack)) {
throw new \RuntimeException('The "app.current_route" variable is not available.');
}
return $this->getRequest()?->attributes->get('_route');
}
/**
* @return array<string, mixed>
*/
public function getCurrent_route_parameters(): array
{
if (!isset($this->requestStack)) {
throw new \RuntimeException('The "app.current_route_parameters" variable is not available.');
}
return $this->getRequest()?->attributes->get('_route_params') ?? [];
}
}

View File

@@ -0,0 +1,33 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Attribute;
/**
* Define the template to render in the controller.
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION)]
class Template
{
/**
* @param string $template The name of the template to render
* @param string[]|null $vars The controller method arguments to pass to the template
* @param bool $stream Enables streaming the template
* @param string|null $block The name of the block to use in the template
*/
public function __construct(
public string $template,
public ?array $vars = null,
public bool $stream = false,
public ?string $block = null,
) {
}
}

219
vendor/symfony/twig-bridge/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,219 @@
CHANGELOG
=========
7.3
---
* Add `is_granted_for_user()` Twig function
* Add `field_id()` Twig form helper function
* Add a `Twig` constraint that validates Twig templates
* Make `lint:twig` collect all deprecations instead of stopping at the first one
* Add `name` argument to `email.image` to override the attachment file name being set as the file path
7.2
---
* Deprecate passing a tag to the constructor of `FormThemeNode`
7.1
---
* Add `emojify` Twig filter
7.0
---
* Drop support for Twig 2
6.4
---
* Allow an array to be passed as the first argument to the `importmap()` Twig function
* Add `TemplatedEmail::locale()` to set the locale for the email rendering
* Add `AppVariable::getEnabledLocales()` to retrieve the enabled locales
* Add `impersonation_path()` and `impersonation_url()` Twig functions
6.3
---
* Add `AppVariable::getLocale()` to retrieve the current locale when using the `LocaleSwitcher`
6.2
---
* Add `form_label_content` and `form_help_content` block to form themes
* Add `#[Template()]` to describe how to render arrays returned by controllers
* Add support for toggle buttons in Bootstrap 5 form theme
* Add `app.current_route` and `app.current_route_parameters` variables
6.1
---
* Wrap help messages on form elements in `div` instead of `p`
5.4
---
* Add `github` format & autodetection to render errors as annotations when
running the Twig linter command in a Github Actions environment.
5.3
---
* Add a new `markAsPublic` method on `NotificationEmail` to change the `importance` context option to null after creation
* Add a new `fragment_uri()` helper to generate the URI of a fragment
* Add support of Bootstrap 5 for form theming
* Add a new `serialize` filter to serialize objects using the Serializer component
5.2.0
-----
* added the `impersonation_exit_url()` and `impersonation_exit_path()` functions. They return a URL that allows to switch back to the original user.
* added the `workflow_transition()` function to easily retrieve a specific transition object
* added support for translating `TranslatableInterface` objects
* added the `t()` function to easily create `TranslatableMessage` objects
* Added support for extracting messages from the `t()` function
* Added `field_*` Twig functions to access string values from Form fields
* changed the `importance` context option of `NotificationEmail` to allow `null`
5.0.0
-----
* removed `TwigEngine` class, use `\Twig\Environment` instead.
* removed `transChoice` filter and token
* `HttpFoundationExtension` requires a `UrlHelper` on instantiation
* removed support for implicit STDIN usage in the `lint:twig` command, use `lint:twig -` (append a dash) instead to make it explicit.
* added form theme for Foundation 6
* added support for Foundation 6 switches: add the `switch-input` class to the attributes of a `CheckboxType`
4.4.0
-----
* added a new `TwigErrorRenderer` for `html` format, integrated with the `ErrorHandler` component
* marked all classes extending twig as `@final`
* deprecated to pass `$rootDir` and `$fileLinkFormatter` as 5th and 6th argument respectively to the
`DebugCommand::__construct()` method, swap the variables position.
* the `LintCommand` lints all the templates stored in all configured Twig paths if none argument is provided
* deprecated accepting STDIN implicitly when using the `lint:twig` command, use `lint:twig -` (append a dash) instead to make it explicit.
* added `--show-deprecations` option to the `lint:twig` command
* added support for Bootstrap4 switches: add the `switch-custom` class to the label attributes of a `CheckboxType`
* Marked the `TwigDataCollector` class as `@final`.
4.3.0
-----
* added the `form_parent()` function that allows to reliably retrieve the parent form in Twig templates
* added the `workflow_transition_blockers()` function
* deprecated the `$requestStack` and `$requestContext` arguments of the
`HttpFoundationExtension`, pass a `Symfony\Component\HttpFoundation\UrlHelper`
instance as the only argument instead
4.2.0
-----
* add bundle name suggestion on wrongly overridden templates paths
* added `name` argument in `debug:twig` command and changed `filter` argument as `--filter` option
* deprecated the `transchoice` tag and filter, use the `trans` ones instead with a `%count%` parameter
4.1.0
-----
* add a `workflow_metadata` function
3.4.0
-----
* added an `only` keyword to `form_theme` tag to disable usage of default themes when rendering a form
* deprecated `Symfony\Bridge\Twig\Form\TwigRenderer`
* deprecated `DebugCommand::set/getTwigEnvironment`. Pass an instance of
`Twig\Environment` as first argument of the constructor instead
* deprecated `LintCommand::set/getTwigEnvironment`. Pass an instance of
`Twig\Environment` as first argument of the constructor instead
3.3.0
-----
* added a `workflow_has_marked_place` function
* added a `workflow_marked_places` function
3.2.0
-----
* added `AppVariable::getToken()`
* Deprecated the possibility to inject the Form `TwigRenderer` into the `FormExtension`.
* [BC BREAK] Registering the `FormExtension` without configuring a runtime loader for the `TwigRenderer`
doesn't work anymore.
Before:
```php
use Symfony\Bridge\Twig\Extension\FormExtension;
use Symfony\Bridge\Twig\Form\TwigRenderer;
use Symfony\Bridge\Twig\Form\TwigRendererEngine;
// ...
$rendererEngine = new TwigRendererEngine(['form_div_layout.html.twig']);
$rendererEngine->setEnvironment($twig);
$twig->addExtension(new FormExtension(new TwigRenderer($rendererEngine, $csrfTokenManager)));
```
After:
```php
// ...
$rendererEngine = new TwigRendererEngine(['form_div_layout.html.twig'], $twig);
// require Twig 1.30+
$twig->addRuntimeLoader(new \Twig\RuntimeLoader\FactoryRuntimeLoader([
TwigRenderer::class => function () use ($rendererEngine, $csrfTokenManager) {
return new TwigRenderer($rendererEngine, $csrfTokenManager);
},
]));
$twig->addExtension(new FormExtension());
```
* Deprecated the `TwigRendererEngineInterface` interface.
* added WorkflowExtension (provides `workflow_can` and `workflow_transitions`)
2.7.0
-----
* added LogoutUrlExtension (provides `logout_url` and `logout_path`)
* added an HttpFoundation extension (provides the `absolute_url` and the `relative_path` functions)
* added AssetExtension (provides the `asset` and `asset_version` functions)
* Added possibility to extract translation messages from a file or files besides extracting from a directory
2.5.0
-----
* moved command `twig:lint` from `TwigBundle`
2.4.0
-----
* added stopwatch tag to time templates with the WebProfilerBundle
2.3.0
-----
* added helpers form(), form_start() and form_end()
* deprecated form_enctype() in favor of form_start()
2.2.0
-----
* added a `controller` function to help generating controller references
* added a `render_esi` and a `render_hinclude` function
* [BC BREAK] restricted the `render` tag to only accept URIs or ControllerReference instances (the signature changed)
* added a `render` function to render a request
* The `app` global variable is now injected even when using the twig service directly.
* Added an optional parameter to the `path` and `url` function which allows to generate
relative paths (e.g. "../parent-file") and scheme-relative URLs (e.g. "//example.com/dir/file").
2.1.0
-----
* added global variables access in a form theme
* added TwigEngine
* added TwigExtractor
* added a csrf_token function
* added a way to specify a default domain for a Twig template (via the
'trans_default_domain' tag)

View File

@@ -0,0 +1,593 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter;
use Symfony\Component\Finder\Finder;
use Twig\Environment;
use Twig\Loader\ChainLoader;
use Twig\Loader\FilesystemLoader;
/**
* Lists twig functions, filters, globals and tests present in the current project.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
#[AsCommand(name: 'debug:twig', description: 'Show a list of twig functions, filters, globals and tests')]
class DebugCommand extends Command
{
/**
* @var FilesystemLoader[]
*/
private array $filesystemLoaders;
public function __construct(
private Environment $twig,
private ?string $projectDir = null,
private array $bundlesMetadata = [],
private ?string $twigDefaultPath = null,
private ?FileLinkFormatter $fileLinkFormatter = null,
) {
parent::__construct();
}
protected function configure(): void
{
$this
->setDefinition([
new InputArgument('name', InputArgument::OPTIONAL, 'The template name'),
new InputOption('filter', null, InputOption::VALUE_REQUIRED, 'Show details for all entries matching this filter'),
new InputOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'txt'),
])
->setHelp(<<<'EOF'
The <info>%command.name%</info> command outputs a list of twig functions,
filters, globals and tests.
<info>php %command.full_name%</info>
The command lists all functions, filters, etc.
<info>php %command.full_name% @Twig/Exception/error.html.twig</info>
The command lists all paths that match the given template name.
<info>php %command.full_name% --filter=date</info>
The command lists everything that contains the word date.
<info>php %command.full_name% --format=json</info>
The command lists everything in a machine readable json format.
EOF
)
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$name = $input->getArgument('name');
$filter = $input->getOption('filter');
if (null !== $name && [] === $this->getFilesystemLoaders()) {
throw new InvalidArgumentException(\sprintf('Argument "name" not supported, it requires the Twig loader "%s".', FilesystemLoader::class));
}
$format = $input->getOption('format');
if ('text' === $format) {
trigger_deprecation('symfony/twig-bridge', '7.2', 'The "text" format is deprecated, use "txt" instead.');
$format = 'txt';
}
match ($format) {
'txt' => $name ? $this->displayPathsText($io, $name) : $this->displayGeneralText($io, $filter),
'json' => $name ? $this->displayPathsJson($io, $name) : $this->displayGeneralJson($io, $filter),
default => throw new InvalidArgumentException(\sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))),
};
return 0;
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('name')) {
$suggestions->suggestValues(array_keys($this->getLoaderPaths()));
}
if ($input->mustSuggestOptionValuesFor('format')) {
$suggestions->suggestValues($this->getAvailableFormatOptions());
}
}
private function displayPathsText(SymfonyStyle $io, string $name): void
{
$file = new \ArrayIterator($this->findTemplateFiles($name));
$paths = $this->getLoaderPaths($name);
$io->section('Matched File');
if ($file->valid()) {
if ($fileLink = $this->getFileLink($file->key())) {
$io->block($file->current(), 'OK', \sprintf('fg=black;bg=green;href=%s', $fileLink), ' ', true);
} else {
$io->success($file->current());
}
$file->next();
if ($file->valid()) {
$io->section('Overridden Files');
do {
if ($fileLink = $this->getFileLink($file->key())) {
$io->text(\sprintf('* <href=%s>%s</>', $fileLink, $file->current()));
} else {
$io->text(\sprintf('* %s', $file->current()));
}
$file->next();
} while ($file->valid());
}
} else {
$alternatives = [];
if ($paths) {
$shortnames = [];
$dirs = [];
foreach (current($paths) as $path) {
$dirs[] = $this->isAbsolutePath($path) ? $path : $this->projectDir.'/'.$path;
}
foreach (Finder::create()->files()->followLinks()->in($dirs) as $file) {
$shortnames[] = str_replace('\\', '/', $file->getRelativePathname());
}
[$namespace, $shortname] = $this->parseTemplateName($name);
$alternatives = $this->findAlternatives($shortname, $shortnames);
if (FilesystemLoader::MAIN_NAMESPACE !== $namespace) {
$alternatives = array_map(fn ($shortname) => '@'.$namespace.'/'.$shortname, $alternatives);
}
}
$this->error($io, \sprintf('Template name "%s" not found', $name), $alternatives);
}
$io->section('Configured Paths');
if ($paths) {
$io->table(['Namespace', 'Paths'], $this->buildTableRows($paths));
} else {
$alternatives = [];
$namespace = $this->parseTemplateName($name)[0];
if (FilesystemLoader::MAIN_NAMESPACE === $namespace) {
$message = 'No template paths configured for your application';
} else {
$message = \sprintf('No template paths configured for "@%s" namespace', $namespace);
foreach ($this->getFilesystemLoaders() as $loader) {
$namespaces = $loader->getNamespaces();
foreach ($this->findAlternatives($namespace, $namespaces) as $namespace) {
$alternatives[] = '@'.$namespace;
}
}
}
$this->error($io, $message, $alternatives);
if (!$alternatives && $paths = $this->getLoaderPaths()) {
$io->table(['Namespace', 'Paths'], $this->buildTableRows($paths));
}
}
}
private function displayPathsJson(SymfonyStyle $io, string $name): void
{
$files = $this->findTemplateFiles($name);
$paths = $this->getLoaderPaths($name);
if ($files) {
$data['matched_file'] = array_shift($files);
if ($files) {
$data['overridden_files'] = $files;
}
} else {
$data['matched_file'] = \sprintf('Template name "%s" not found', $name);
}
$data['loader_paths'] = $paths;
$io->writeln(json_encode($data));
}
private function displayGeneralText(SymfonyStyle $io, ?string $filter = null): void
{
$decorated = $io->isDecorated();
$types = ['functions', 'filters', 'tests', 'globals'];
foreach ($types as $index => $type) {
$items = [];
foreach ($this->twig->{'get'.ucfirst($type)}() as $name => $entity) {
if (!$filter || str_contains($name, $filter)) {
$items[$name] = $name.$this->getPrettyMetadata($type, $entity, $decorated);
}
}
if (!$items) {
continue;
}
$io->section(ucfirst($type));
ksort($items);
$io->listing($items);
}
if (!$filter && $paths = $this->getLoaderPaths()) {
$io->section('Loader Paths');
$io->table(['Namespace', 'Paths'], $this->buildTableRows($paths));
}
if ($wrongBundles = $this->findWrongBundleOverrides()) {
foreach ($this->buildWarningMessages($wrongBundles) as $message) {
$io->warning($message);
}
}
}
private function displayGeneralJson(SymfonyStyle $io, ?string $filter): void
{
$decorated = $io->isDecorated();
$types = ['functions', 'filters', 'tests', 'globals'];
$data = [];
foreach ($types as $type) {
foreach ($this->twig->{'get'.ucfirst($type)}() as $name => $entity) {
if (!$filter || str_contains($name, $filter)) {
$data[$type][$name] = $this->getMetadata($type, $entity);
}
}
}
if (isset($data['tests'])) {
$data['tests'] = array_keys($data['tests']);
}
if (!$filter && $paths = $this->getLoaderPaths($filter)) {
$data['loader_paths'] = $paths;
}
if ($wrongBundles = $this->findWrongBundleOverrides()) {
$data['warnings'] = $this->buildWarningMessages($wrongBundles);
}
$data = json_encode($data, \JSON_PRETTY_PRINT);
$io->writeln($decorated ? OutputFormatter::escape($data) : $data);
}
private function getLoaderPaths(?string $name = null): array
{
$loaderPaths = [];
foreach ($this->getFilesystemLoaders() as $loader) {
$namespaces = $loader->getNamespaces();
if (null !== $name) {
$namespace = $this->parseTemplateName($name)[0];
$namespaces = array_intersect([$namespace], $namespaces);
}
foreach ($namespaces as $namespace) {
$paths = array_map($this->getRelativePath(...), $loader->getPaths($namespace));
if (FilesystemLoader::MAIN_NAMESPACE === $namespace) {
$namespace = '(None)';
} else {
$namespace = '@'.$namespace;
}
$loaderPaths[$namespace] = array_merge($loaderPaths[$namespace] ?? [], $paths);
}
}
return $loaderPaths;
}
private function getMetadata(string $type, mixed $entity): mixed
{
if ('globals' === $type) {
return $entity;
}
if ('tests' === $type) {
return null;
}
if ('functions' === $type || 'filters' === $type) {
$cb = $entity->getCallable();
if (null === $cb) {
return null;
}
if (\is_array($cb)) {
if (!method_exists($cb[0], $cb[1])) {
return null;
}
$refl = new \ReflectionMethod($cb[0], $cb[1]);
} elseif (\is_object($cb) && method_exists($cb, '__invoke')) {
$refl = new \ReflectionMethod($cb, '__invoke');
} elseif (\function_exists($cb)) {
$refl = new \ReflectionFunction($cb);
} elseif (\is_string($cb) && preg_match('{^(.+)::(.+)$}', $cb, $m) && method_exists($m[1], $m[2])) {
$refl = new \ReflectionMethod($m[1], $m[2]);
} else {
throw new \UnexpectedValueException('Unsupported callback type.');
}
$args = $refl->getParameters();
// filter out context/environment args
if ($entity->needsEnvironment()) {
array_shift($args);
}
if ($entity->needsContext()) {
array_shift($args);
}
if ('filters' === $type) {
// remove the value the filter is applied on
array_shift($args);
}
// format args
return array_map(function (\ReflectionParameter $param) {
if ($param->isDefaultValueAvailable()) {
return $param->getName().' = '.json_encode($param->getDefaultValue());
}
return $param->getName();
}, $args);
}
return null;
}
private function getPrettyMetadata(string $type, mixed $entity, bool $decorated): ?string
{
if ('tests' === $type) {
return '';
}
try {
$meta = $this->getMetadata($type, $entity);
if (null === $meta) {
return '(unknown?)';
}
} catch (\UnexpectedValueException $e) {
return \sprintf(' <error>%s</error>', $decorated ? OutputFormatter::escape($e->getMessage()) : $e->getMessage());
}
if ('globals' === $type) {
if (\is_object($meta)) {
return ' = object('.$meta::class.')';
}
$description = substr(@json_encode($meta), 0, 50);
return \sprintf(' = %s', $decorated ? OutputFormatter::escape($description) : $description);
}
if ('functions' === $type) {
return '('.implode(', ', $meta).')';
}
if ('filters' === $type) {
return $meta ? '('.implode(', ', $meta).')' : '';
}
return null;
}
private function findWrongBundleOverrides(): array
{
$alternatives = [];
$bundleNames = [];
if ($this->twigDefaultPath && $this->projectDir) {
$folders = glob($this->twigDefaultPath.'/bundles/*', \GLOB_ONLYDIR);
$relativePath = ltrim(substr($this->twigDefaultPath.'/bundles/', \strlen($this->projectDir)), \DIRECTORY_SEPARATOR);
$bundleNames = array_reduce($folders, function ($carry, $absolutePath) use ($relativePath) {
if (str_starts_with($absolutePath, $this->projectDir)) {
$name = basename($absolutePath);
$path = ltrim($relativePath.$name, \DIRECTORY_SEPARATOR);
$carry[$name] = $path;
}
return $carry;
}, $bundleNames);
}
if ($notFoundBundles = array_diff_key($bundleNames, $this->bundlesMetadata)) {
foreach ($notFoundBundles as $notFoundBundle => $path) {
$alternatives[$path] = $this->findAlternatives($notFoundBundle, array_keys($this->bundlesMetadata));
}
}
return $alternatives;
}
private function buildWarningMessages(array $wrongBundles): array
{
$messages = [];
foreach ($wrongBundles as $path => $alternatives) {
$message = \sprintf('Path "%s" not matching any bundle found', $path);
if ($alternatives) {
if (1 === \count($alternatives)) {
$message .= \sprintf(", did you mean \"%s\"?\n", $alternatives[0]);
} else {
$message .= ", did you mean one of these:\n";
foreach ($alternatives as $bundle) {
$message .= \sprintf(" - %s\n", $bundle);
}
}
}
$messages[] = trim($message);
}
return $messages;
}
private function error(SymfonyStyle $io, string $message, array $alternatives = []): void
{
if ($alternatives) {
if (1 === \count($alternatives)) {
$message .= "\n\nDid you mean this?\n ";
} else {
$message .= "\n\nDid you mean one of these?\n ";
}
$message .= implode("\n ", $alternatives);
}
$io->block($message, null, 'fg=white;bg=red', ' ', true);
}
private function findTemplateFiles(string $name): array
{
[$namespace, $shortname] = $this->parseTemplateName($name);
$files = [];
foreach ($this->getFilesystemLoaders() as $loader) {
foreach ($loader->getPaths($namespace) as $path) {
if (!$this->isAbsolutePath($path)) {
$path = $this->projectDir.'/'.$path;
}
$filename = $path.'/'.$shortname;
if (is_file($filename)) {
if (false !== $realpath = realpath($filename)) {
$files[$realpath] = $this->getRelativePath($realpath);
} else {
$files[$filename] = $this->getRelativePath($filename);
}
}
}
}
return $files;
}
private function parseTemplateName(string $name, string $default = FilesystemLoader::MAIN_NAMESPACE): array
{
if (isset($name[0]) && '@' === $name[0]) {
if (false === ($pos = strpos($name, '/')) || $pos === \strlen($name) - 1) {
throw new InvalidArgumentException(\sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
}
$namespace = substr($name, 1, $pos - 1);
$shortname = substr($name, $pos + 1);
return [$namespace, $shortname];
}
return [$default, $name];
}
private function buildTableRows(array $loaderPaths): array
{
$rows = [];
$firstNamespace = true;
$prevHasSeparator = false;
foreach ($loaderPaths as $namespace => $paths) {
if (!$firstNamespace && !$prevHasSeparator && \count($paths) > 1) {
$rows[] = ['', ''];
}
$firstNamespace = false;
foreach ($paths as $path) {
$rows[] = [$namespace, $path.\DIRECTORY_SEPARATOR];
$namespace = '';
}
if (\count($paths) > 1) {
$rows[] = ['', ''];
$prevHasSeparator = true;
} else {
$prevHasSeparator = false;
}
}
if ($prevHasSeparator) {
array_pop($rows);
}
return $rows;
}
private function findAlternatives(string $name, array $collection): array
{
$alternatives = [];
foreach ($collection as $item) {
$lev = levenshtein($name, $item);
if ($lev <= \strlen($name) / 3 || str_contains($item, $name)) {
$alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
}
}
$threshold = 1e3;
$alternatives = array_filter($alternatives, fn ($lev) => $lev < 2 * $threshold);
ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE);
return array_keys($alternatives);
}
private function getRelativePath(string $path): string
{
if (null !== $this->projectDir && str_starts_with($path, $this->projectDir)) {
return ltrim(substr($path, \strlen($this->projectDir)), \DIRECTORY_SEPARATOR);
}
return $path;
}
private function isAbsolutePath(string $file): bool
{
return strspn($file, '/\\', 0, 1) || (\strlen($file) > 3 && ctype_alpha($file[0]) && ':' === $file[1] && strspn($file, '/\\', 2, 1)) || parse_url($file, \PHP_URL_SCHEME);
}
/**
* @return FilesystemLoader[]
*/
private function getFilesystemLoaders(): array
{
if (isset($this->filesystemLoaders)) {
return $this->filesystemLoaders;
}
$this->filesystemLoaders = [];
$loader = $this->twig->getLoader();
if ($loader instanceof FilesystemLoader) {
$this->filesystemLoaders[] = $loader;
} elseif ($loader instanceof ChainLoader) {
foreach ($loader->getLoaders() as $l) {
if ($l instanceof FilesystemLoader) {
$this->filesystemLoaders[] = $l;
}
}
}
return $this->filesystemLoaders;
}
private function getFileLink(string $absolutePath): string
{
return (string) $this->fileLinkFormatter?->format($absolutePath, 1);
}
/** @return string[] */
private function getAvailableFormatOptions(): array
{
return ['txt', 'json'];
}
}

View File

@@ -0,0 +1,307 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\CI\GithubActionReporter;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Finder\Finder;
use Twig\Environment;
use Twig\Error\Error;
use Twig\Loader\ArrayLoader;
use Twig\Loader\FilesystemLoader;
use Twig\Source;
/**
* Command that will validate your template syntax and output encountered errors.
*
* @author Marc Weistroff <marc.weistroff@sensiolabs.com>
* @author Jérôme Tamarelle <jerome@tamarelle.net>
*/
#[AsCommand(name: 'lint:twig', description: 'Lint a Twig template and outputs encountered errors')]
class LintCommand extends Command
{
private array $excludes;
private string $format;
public function __construct(
private Environment $twig,
private array $namePatterns = ['*.twig'],
) {
parent::__construct();
}
protected function configure(): void
{
$this
->addOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())))
->addOption('show-deprecations', null, InputOption::VALUE_NONE, 'Show deprecations as errors')
->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN')
->addOption('excludes', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Excluded directories', [])
->setHelp(<<<'EOF'
The <info>%command.name%</info> command lints a template and outputs to STDOUT
the first encountered syntax error.
You can validate the syntax of contents passed from STDIN:
<info>cat filename | php %command.full_name% -</info>
Or the syntax of a file:
<info>php %command.full_name% filename</info>
Or of a whole directory:
<info>php %command.full_name% dirname</info>
The <info>--format</info> option specifies the format of the command output:
<info>php %command.full_name% dirname --format=json</info>
EOF
)
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$filenames = $input->getArgument('filename');
$showDeprecations = $input->getOption('show-deprecations');
$this->excludes = $input->getOption('excludes');
$this->format = $input->getOption('format') ?? (GithubActionReporter::isGithubActionEnvironment() ? 'github' : 'txt');
if (['-'] === $filenames) {
return $this->display($input, $output, $io, [$this->validate(file_get_contents('php://stdin'), 'Standard Input', $showDeprecations)]);
}
if (!$filenames) {
$loader = $this->twig->getLoader();
if ($loader instanceof FilesystemLoader) {
$paths = [];
foreach ($loader->getNamespaces() as $namespace) {
$paths[] = $loader->getPaths($namespace);
}
$filenames = array_merge(...$paths);
}
if (!$filenames) {
throw new RuntimeException('Please provide a filename or pipe template content to STDIN.');
}
}
return $this->display($input, $output, $io, $this->getFilesInfo($filenames, $showDeprecations));
}
private function getFilesInfo(array $filenames, bool $showDeprecations): array
{
$filesInfo = [];
foreach ($filenames as $filename) {
foreach ($this->findFiles($filename) as $file) {
$filesInfo[] = $this->validate(file_get_contents($file), $file, $showDeprecations);
}
}
return $filesInfo;
}
protected function findFiles(string $filename): iterable
{
if (is_file($filename)) {
return [$filename];
} elseif (is_dir($filename)) {
return Finder::create()->files()->in($filename)->name($this->namePatterns)->exclude($this->excludes);
}
throw new RuntimeException(\sprintf('File or directory "%s" is not readable.', $filename));
}
private function validate(string $template, string $file, bool $collectDeprecation): array
{
$deprecations = [];
if ($collectDeprecation) {
$prevErrorHandler = set_error_handler(static function ($level, $message, $fileName, $line) use (&$prevErrorHandler, &$deprecations, $file) {
if (\E_USER_DEPRECATED === $level) {
$templateLine = 0;
if (preg_match('/ at line (\d+)[ .]/', $message, $matches)) {
$templateLine = $matches[1];
}
$deprecations[] = ['message' => $message, 'file' => $file, 'line' => $templateLine];
return true;
}
return $prevErrorHandler ? $prevErrorHandler($level, $message, $fileName, $line) : false;
});
}
$realLoader = $this->twig->getLoader();
try {
$temporaryLoader = new ArrayLoader([$file => $template]);
$this->twig->setLoader($temporaryLoader);
$nodeTree = $this->twig->parse($this->twig->tokenize(new Source($template, $file)));
$this->twig->compile($nodeTree);
$this->twig->setLoader($realLoader);
} catch (Error $e) {
$this->twig->setLoader($realLoader);
return ['template' => $template, 'file' => $file, 'line' => $e->getTemplateLine(), 'valid' => false, 'exception' => $e];
} finally {
if ($collectDeprecation) {
restore_error_handler();
}
}
return ['template' => $template, 'file' => $file, 'deprecations' => $deprecations, 'valid' => true];
}
private function display(InputInterface $input, OutputInterface $output, SymfonyStyle $io, array $files): int
{
return match ($this->format) {
'txt' => $this->displayTxt($output, $io, $files),
'json' => $this->displayJson($output, $files),
'github' => $this->displayTxt($output, $io, $files, true),
default => throw new InvalidArgumentException(\sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))),
};
}
private function displayTxt(OutputInterface $output, SymfonyStyle $io, array $filesInfo, bool $errorAsGithubAnnotations = false): int
{
$errors = 0;
$githubReporter = $errorAsGithubAnnotations ? new GithubActionReporter($output) : null;
$deprecations = array_merge(...array_column($filesInfo, 'deprecations'));
foreach ($deprecations as $deprecation) {
$this->renderDeprecation($io, $deprecation['line'], $deprecation['message'], $deprecation['file'], $githubReporter);
}
foreach ($filesInfo as $info) {
if ($info['valid'] && $output->isVerbose()) {
$io->comment('<info>OK</info>'.($info['file'] ? \sprintf(' in %s', $info['file']) : ''));
} elseif (!$info['valid']) {
++$errors;
$this->renderException($io, $info['template'], $info['exception'], $info['file'], $githubReporter);
}
}
if (0 === $errors) {
$io->success(\sprintf('All %d Twig files contain valid syntax.', \count($filesInfo)));
} else {
$io->warning(\sprintf('%d Twig files have valid syntax and %d contain errors.', \count($filesInfo) - $errors, $errors));
}
return !$deprecations && !$errors ? 0 : 1;
}
private function displayJson(OutputInterface $output, array $filesInfo): int
{
$errors = 0;
array_walk($filesInfo, function (&$v) use (&$errors) {
$v['file'] = (string) $v['file'];
unset($v['template']);
if (!$v['valid']) {
$v['message'] = $v['exception']->getMessage();
unset($v['exception']);
++$errors;
}
});
$output->writeln(json_encode($filesInfo, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES));
return min($errors, 1);
}
private function renderDeprecation(SymfonyStyle $output, int $line, string $message, string $file, ?GithubActionReporter $githubReporter): void
{
$githubReporter?->error($message, $file, $line <= 0 ? null : $line);
if ($file) {
$output->text(\sprintf('<info> DEPRECATION </info> in %s (line %s)', $file, $line));
} else {
$output->text(\sprintf('<info> DEPRECATION </info> (line %s)', $line));
}
$output->text(\sprintf('<info> >> %s</info> ', $message));
}
private function renderException(SymfonyStyle $output, string $template, Error $exception, ?string $file = null, ?GithubActionReporter $githubReporter = null): void
{
$line = $exception->getTemplateLine();
$githubReporter?->error($exception->getRawMessage(), $file, $line <= 0 ? null : $line);
if ($file) {
$output->text(\sprintf('<error> ERROR </error> in %s (line %s)', $file, $line));
} else {
$output->text(\sprintf('<error> ERROR </error> (line %s)', $line));
}
// If the line is not known (this might happen for deprecations if we fail at detecting the line for instance),
// we render the message without context, to ensure the message is displayed.
if ($line <= 0) {
$output->text(\sprintf('<error> >> %s</error> ', $exception->getRawMessage()));
return;
}
foreach ($this->getContext($template, $line) as $lineNumber => $code) {
$output->text(\sprintf(
'%s %-6s %s',
$lineNumber === $line ? '<error> >> </error>' : ' ',
$lineNumber,
$code
));
if ($lineNumber === $line) {
$output->text(\sprintf('<error> >> %s</error> ', $exception->getRawMessage()));
}
}
}
private function getContext(string $template, int $line, int $context = 3): array
{
$lines = explode("\n", $template);
$position = max(0, $line - $context);
$max = min(\count($lines), $line - 1 + $context);
$result = [];
while ($position < $max) {
$result[$position + 1] = $lines[$position];
++$position;
}
return $result;
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestOptionValuesFor('format')) {
$suggestions->suggestValues($this->getAvailableFormatOptions());
}
}
/** @return string[] */
private function getAvailableFormatOptions(): array
{
return ['txt', 'json', 'github'];
}
}

View File

@@ -0,0 +1,183 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\DataCollector;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Markup;
use Twig\Profiler\Dumper\HtmlDumper;
use Twig\Profiler\Profile;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final
*/
class TwigDataCollector extends DataCollector implements LateDataCollectorInterface
{
private array $computed;
public function __construct(
private Profile $profile,
private ?Environment $twig = null,
) {
}
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
}
public function reset(): void
{
$this->profile->reset();
unset($this->computed);
$this->data = [];
}
public function lateCollect(): void
{
$this->data['profile'] = serialize($this->profile);
$this->data['template_paths'] = [];
if (null === $this->twig) {
return;
}
$templateFinder = function (Profile $profile) use (&$templateFinder) {
if ($profile->isTemplate()) {
try {
$template = $this->twig->load($name = $profile->getName());
} catch (LoaderError) {
$template = null;
}
if (null !== $template && '' !== $path = $template->getSourceContext()->getPath()) {
$this->data['template_paths'][$name] = $path;
}
}
foreach ($profile as $p) {
$templateFinder($p);
}
};
$templateFinder($this->profile);
}
public function getTime(): float
{
return $this->getProfile()->getDuration() * 1000;
}
public function getTemplateCount(): int
{
return $this->getComputedData('template_count');
}
public function getTemplatePaths(): array
{
return $this->data['template_paths'];
}
public function getTemplates(): array
{
return $this->getComputedData('templates');
}
public function getBlockCount(): int
{
return $this->getComputedData('block_count');
}
public function getMacroCount(): int
{
return $this->getComputedData('macro_count');
}
public function getHtmlCallGraph(): Markup
{
$dumper = new HtmlDumper();
$dump = $dumper->dump($this->getProfile());
// needed to remove the hardcoded CSS styles
$dump = str_replace([
'<span style="background-color: #ffd">',
'<span style="color: #d44">',
'<span style="background-color: #dfd">',
'<span style="background-color: #ddf">',
], [
'<span class="status-warning">',
'<span class="status-error">',
'<span class="status-success">',
'<span class="status-info">',
], $dump);
return new Markup($dump, 'UTF-8');
}
public function getProfile(): Profile
{
return $this->profile ??= unserialize($this->data['profile'], ['allowed_classes' => [Profile::class]]);
}
private function getComputedData(string $index): mixed
{
$this->computed ??= $this->computeData($this->getProfile());
return $this->computed[$index];
}
private function computeData(Profile $profile): array
{
$data = [
'template_count' => 0,
'block_count' => 0,
'macro_count' => 0,
];
$templates = [];
foreach ($profile as $p) {
$d = $this->computeData($p);
$data['template_count'] += ($p->isTemplate() ? 1 : 0) + $d['template_count'];
$data['block_count'] += ($p->isBlock() ? 1 : 0) + $d['block_count'];
$data['macro_count'] += ($p->isMacro() ? 1 : 0) + $d['macro_count'];
if ($p->isTemplate()) {
if (!isset($templates[$p->getTemplate()])) {
$templates[$p->getTemplate()] = 1;
} else {
++$templates[$p->getTemplate()];
}
}
foreach ($d['templates'] as $template => $count) {
if (!isset($templates[$template])) {
$templates[$template] = $count;
} else {
$templates[$template] += $count;
}
}
}
$data['templates'] = $templates;
return $data;
}
public function getName(): string
{
return 'twig';
}
}

View File

@@ -0,0 +1,84 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\ErrorRenderer;
use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface;
use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
use Symfony\Component\ErrorHandler\Exception\FlattenException;
use Symfony\Component\HttpFoundation\RequestStack;
use Twig\Environment;
/**
* Provides the ability to render custom Twig-based HTML error pages
* in non-debug mode, otherwise falls back to HtmlErrorRenderer.
*
* @author Yonel Ceruto <yonelceruto@gmail.com>
*/
class TwigErrorRenderer implements ErrorRendererInterface
{
private HtmlErrorRenderer $fallbackErrorRenderer;
private \Closure|bool $debug;
/**
* @param bool|callable $debug The debugging mode as a boolean or a callable that should return it
*/
public function __construct(
private Environment $twig,
?HtmlErrorRenderer $fallbackErrorRenderer = null,
bool|callable $debug = false,
) {
$this->fallbackErrorRenderer = $fallbackErrorRenderer ?? new HtmlErrorRenderer();
$this->debug = \is_bool($debug) ? $debug : $debug(...);
}
public function render(\Throwable $exception): FlattenException
{
$flattenException = FlattenException::createFromThrowable($exception);
$debug = \is_bool($this->debug) ? $this->debug : ($this->debug)($flattenException);
if ($debug || !$template = $this->findTemplate($flattenException->getStatusCode())) {
return $this->fallbackErrorRenderer->render($exception);
}
return $flattenException->setAsString($this->twig->render($template, [
'exception' => $flattenException,
'status_code' => $flattenException->getStatusCode(),
'status_text' => $flattenException->getStatusText(),
]));
}
public static function isDebug(RequestStack $requestStack, bool $debug): \Closure
{
return static function () use ($requestStack, $debug): bool {
if (!$request = $requestStack->getCurrentRequest()) {
return $debug;
}
return $debug && $request->attributes->getBoolean('showException', true);
};
}
private function findTemplate(int $statusCode): ?string
{
$template = \sprintf('@Twig/Exception/error%s.html.twig', $statusCode);
if ($this->twig->getLoader()->exists($template)) {
return $template;
}
$template = '@Twig/Exception/error.html.twig';
if ($this->twig->getLoader()->exists($template)) {
return $template;
}
return null;
}
}

View File

@@ -0,0 +1,92 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\EventListener;
use Symfony\Bridge\Twig\Attribute\Template;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Twig\Environment;
class TemplateAttributeListener implements EventSubscriberInterface
{
public function __construct(
private Environment $twig,
) {
}
public function onKernelView(ViewEvent $event): void
{
$parameters = $event->getControllerResult();
if (!\is_array($parameters ?? [])) {
return;
}
$attribute = $event->getRequest()->attributes->get('_template');
if (!$attribute instanceof Template && !$attribute = $event->controllerArgumentsEvent?->getAttributes()[Template::class][0] ?? null) {
return;
}
$parameters ??= $this->resolveParameters($event->controllerArgumentsEvent, $attribute->vars);
$status = 200;
foreach ($parameters as $k => $v) {
if (!$v instanceof FormInterface) {
continue;
}
if ($v->isSubmitted() && !$v->isValid()) {
$status = 422;
}
$parameters[$k] = $v->createView();
}
$event->setResponse($attribute->stream
? new StreamedResponse(
null !== $attribute->block
? fn () => $this->twig->load($attribute->template)->displayBlock($attribute->block, $parameters)
: fn () => $this->twig->display($attribute->template, $parameters),
$status)
: new Response(
null !== $attribute->block
? $this->twig->load($attribute->template)->renderBlock($attribute->block, $parameters)
: $this->twig->render($attribute->template, $parameters),
$status)
);
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::VIEW => ['onKernelView', -128],
];
}
private function resolveParameters(ControllerArgumentsEvent $event, ?array $vars): array
{
if ([] === $vars) {
return [];
}
$parameters = $event->getNamedArguments();
if (null !== $vars) {
$parameters = array_intersect_key($parameters, array_flip($vars));
}
return $parameters;
}
}

View File

@@ -0,0 +1,56 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Extension;
use Symfony\Component\Asset\Packages;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* Twig extension for the Symfony Asset component.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class AssetExtension extends AbstractExtension
{
public function __construct(
private Packages $packages,
) {
}
public function getFunctions(): array
{
return [
new TwigFunction('asset', $this->getAssetUrl(...)),
new TwigFunction('asset_version', $this->getAssetVersion(...)),
];
}
/**
* Returns the public url/path of an asset.
*
* If the package used to generate the path is an instance of
* UrlPackage, you will always get a URL and not a path.
*/
public function getAssetUrl(string $path, ?string $packageName = null): string
{
return $this->packages->getUrl($path, $packageName);
}
/**
* Returns the version of an asset.
*/
public function getAssetVersion(string $path, ?string $packageName = null): string
{
return $this->packages->getVersion($path, $packageName);
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Extension;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* @author Christian Flothmann <christian.flothmann@sensiolabs.de>
* @author Titouan Galopin <galopintitouan@gmail.com>
*/
final class CsrfExtension extends AbstractExtension
{
public function getFunctions(): array
{
return [
new TwigFunction('csrf_token', [CsrfRuntime::class, 'getCsrfToken']),
];
}
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Extension;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
/**
* @author Christian Flothmann <christian.flothmann@sensiolabs.de>
* @author Titouan Galopin <galopintitouan@gmail.com>
*/
final class CsrfRuntime
{
public function __construct(
private CsrfTokenManagerInterface $csrfTokenManager,
) {
}
public function getCsrfToken(string $tokenId): string
{
return $this->csrfTokenManager->getToken($tokenId)->getValue();
}
}

Some files were not shown because too many files have changed in this diff Show More