Initial commit: CloudOps infrastructure platform

This commit is contained in:
root
2026-04-09 19:58:57 +02:00
commit 1166a52f26
7762 changed files with 839452 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
.barAnimate() {
-webkit-transition-property: margin;
transition-property: margin;
-webkit-transition-duration: .5s;
transition-duration: .5s;
transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
-webkit-transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
}

View File

@@ -0,0 +1,65 @@
.mf-bar-collapser {
position: absolute;
right: 3px;
width: 24px;
height: 24px;
text-align: center;
z-index: 21000;
&.mf-bar-collapser-top {
top: 0;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
.mf-bar-collapser-icon svg {
margin: 2px 0 0 0;
}
}
&.mf-bar-collapser-bottom {
bottom: 0;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
.mf-bar-collapser-icon svg {
margin: -2px 0 0 0;
}
}
&.mf-bar-collapser-large {
width: 40px;
height: 40px;
&.mf-bar-collapser-top .mf-bar-collapser-icon svg {
margin: 4px 0 0 0;
}
&.mf-bar-collapser-bottom .mf-bar-collapser-icon svg {
margin: -4px 0 0 0;
}
}
&.mf-bar-collapser-sticky {
position: fixed;
}
&.mf-bar-collapser-top, &.mf-bar-collapser-bottom {
&.mf-bar-collapsed .mf-bar-collapser-icon svg {
margin: 0;
}
}
a.mf-bar-collapser-icon {
position: relative;
display: inline-block;
&:after {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
}
}

View File

@@ -0,0 +1,65 @@
{% set props = focus.properties %}
{% set color = (props.colors.primary is not empty and props.colors.primary is color light) ? '000000' : 'ffffff' %}
{% set animate = preview is not empty and props.animate is not empty ? ' mf-animate' : '' %}
<div class="mautic-focus mf-bar mf-bar-{{ props.bar.size }} mf-bar-{{ props.bar.placement }} {% if props.bar.sticky %}mf-bar-sticky{% endif %} {{ animate }}" style="background-color: #{{ props.colors.primary|replace({'#': ''}) }};">
<div class="mf-content">
{% if htmlMode in ['editor', 'html'] %}
{{ focus[htmlMode]|raw }}
{% else %}
<div class="mf-headline">{{ props.content.headline }}</div>
{% if 'form' == focus.type %}
{focus_form}
{% elseif 'link' == focus.type %}
<a href="{% if preview is empty %}{{ clickUrl }}{% else %}#{% endif %}" class="mf-link" target="{% if props.content.link_new_window %}_new{% else %}_parent{% endif %}">
{{ props.content.link_text }}
</a>
{% endif %}
{% endif %}
</div>
<div class="mf-bar-collapse"></div>
</div>
{% if props.bar.allow_hide %}
<div class="mf-copy-to-parent mf-bar-collapser mf-bar-collapser-{{ props.bar.placement }} mf-bar-collapser-{{ props.bar.size }} {% if props.bar.sticky %}mf-bar-collapser-sticky{% endif %} mf-bar-collapser-{{ focus.id }}"
style="background-color: #{{ props.colors.primary|replace({'#': ''}) }}; color: #{{ props.colors.text|replace({'#': ''}) }};">
<style scoped>
.mf-bar-collapser-icon {
color: #{{ color }};
}
.mf-bar-collapser-icon:hover {
color: #{{ color }};
}
</style>
<a class="mf-bar-collapser-icon" href="javascript:void(0)" {% if preview is not empty %}onclick="Mautic.toggleBarCollapse()"{% endif %}>
{% set size = 'large' == props.bar.size ? 40 : 24 %}
{% set transformSize = 20 %}
{% set scale = 'large' == props.bar.size ? 1 : 0.6 %}
{% set direction = 'top' == props.bar.placement ? '-90' : '90' %}
<svg style="overflow: hidden;" xmlns="http://www.w3.org/2000/svg" width="{{ size }}" version="1.1"
height="{{ size }}" data-transform-size="{{ transformSize }}" data-transform-direction="{{ direction }}" data-transform-scale="{{ scale }}">
<g transform="scale({{ scale }}) rotate({{ direction }} {{ transformSize }} {{ transformSize }})">
<desc>Created with Raphaël 2.1.2</desc>
<defs>
<linearGradient gradientTransform="matrix(1,0,0,1,-4,-4)" y2="0" x2="6.123233995736766e-17" y1="1" x1="0" id="1390-_0050af-_002c62">
<stop stop-color="#{{ color }}" offset="0%"></stop>
<stop stop-color="#{{ color }}" offset="100%"></stop>
</linearGradient>
</defs>
<path transform="matrix(1,0,0,1,4,4)" opacity="0" stroke-linejoin="round" stroke-width="3"
d="M16,1.466C7.973,1.466,1.466,7.973,1.466,16C1.466,24.027,7.973,30.534,16,30.534C24.027,30.534,30.534,24.027,30.534,15.999999999999998C30.534,7.973,24.027,1.466,16,1.466ZM13.665,25.725L10.129,22.186L16.316,15.998999999999999L10.128999999999998,9.811999999999998L13.664999999999997,6.275999999999998L23.388999999999996,15.998999999999999L13.665,25.725Z"
stroke="#ffffff" fill="none" style="stroke-linejoin: round; opacity: 0;"></path>
<path fill-opacity="1" opacity="1" transform="matrix(1,0,0,1,4,4)"
d="M16,1.466C7.973,1.466,1.466,7.973,1.466,16C1.466,24.027,7.973,30.534,16,30.534C24.027,30.534,30.534,24.027,30.534,15.999999999999998C30.534,7.973,24.027,1.466,16,1.466ZM13.665,25.725L10.129,22.186L16.316,15.998999999999999L10.128999999999998,9.811999999999998L13.664999999999997,6.275999999999998L23.388999999999996,15.998999999999999L13.665,25.725Z"
stroke="none" fill="url(#1390-_0050af-_002c62)" style="opacity: 1; fill-opacity: 1;"></path>
<rect opacity="0" style="opacity: 0;" stroke="#000" fill="#000000" ry="0" rx="0" r="0" y="0" x="0"></rect>
</g>
</svg>
</a>
</div>
{% endif %}
{% if props.bar.push_page and 'top' == props.bar.placement %}
<div class="mf-move-to-parent mf-bar-spacer mf-bar-spacer-{{ props.bar.size }} mf-bar-spacer-{{ focus.id }}"></div>
{% endif %}

View File

@@ -0,0 +1,64 @@
{{ include('@MauticFocus/Builder/Bar/animations.less.twig', with_context=false) }}
.mf-bar-iframe {
width: 100%;
position: static;
z-index: 20000;
left: 0;
right: 0;
&.mf-animate {
.barAnimate();
}
&.mf-bar-iframe-top {
top: 0;
margin-top: -100px;
}
&.mf-bar-iframe-bottom {
bottom: 0;
margin-bottom: -100px;
}
&.mf-bar-iframe-regular {
body, html {
min-height: 30px;
}
&.mf-bar-iframe-top {
margin-top: -30px;
}
&.mf-bar-iframe-bottom {
margin-bottom: -30px;
}
}
&.mf-bar-iframe-large {
body, html {
min-height: 50px;
}
&.mf-bar-iframe-top {
margin-top: -50px;
}
&.mf-bar-iframe-bottom {
margin-bottom: -50px;
}
}
&.mf-bar-iframe-sticky {
position: fixed;
}
}
{{ include('@MauticFocus/Builder/Bar/shared.less.twig', with_context=false) }}
{{ include('@MauticFocus/Builder/Bar/collapser.less.twig', with_context=false) }}
@media only screen and (max-width: 667px) {
.mf-bar-collapser {
display: none !important;
}
}

View File

@@ -0,0 +1,26 @@
.mf-bar-spacer {
display: block;
overflow: hidden;
position: relative;
&.mf-bar-spacer-regular {
height: 30px;
}
&.mf-bar-spacer-large {
height: 50px;
}
}
.mf-bar-collapser-icon {
opacity: 0.3;
text-decoration: none;
transition-property: all;
transition-duration: .5s;
transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
&:hover {
opacity: 0.7;
text-decoration: none;
}
}

View File

@@ -0,0 +1,122 @@
.mf-bar {
width: 100%;
position: fixed;
left: 0;
right: 0;
display: table;
padding-left: 5px;
padding-right: 5px;
z-index: 20000;
&.mf-bar-top {
top: 0;
}
&.mf-bar-bottom {
bottom: 0;
}
.mf-bar-collapse {
width: 100px;
display: table-cell;
vertical-align: middle;
line-height: 13px;
}
.mf-content {
display: table-cell;
vertical-align: middle;
text-align: center;
.mf-link {
margin-left: 10px;
padding: 2px 15px;
}
.mf-headline {
display: inline-block;
}
}
&.mf-bar-regular {
height: 30px;
font-size: 14px;
&.mf-bar-top .mf-bar-collapser-icon svg {
margin: 3px 0 0 0;
}
&.mf-bar-bottom .mf-bar-collapser-icon svg {
margin: -3px 0 0 0;
}
.mauticform-input, select, .mauticform-button, .mauticform-pagebreak {
padding: 3px 6px;
font-size: 0.9em;
}
}
&.mf-bar-large {
height: 50px;
font-size: 17px;
&.mf-bar-top .mf-bar-collapser-icon svg {
margin: 5px 0 0 0;
}
&.mf-bar-bottom .mf-bar-collapser-icon svg {
margin: -5px 0 0 0;
}
.mf-link {
font-size: 1em;
}
.mauticform-input, select, .mauticform-button, .mauticform-pagebreak {
font-size: 1em;
}
}
.mauticform-row, .mauticform-checkboxgrp-row, .mauticform-radiogrp-row {
display: inline-block;
margin-right: 3px;
}
.mauticform-row .mauticform-input, .mauticform-row select {
color: #000000;
}
.mauticform-label {
display: none;
}
.mauticform_wrapper {
display: inline-block;
}
.mf-responsive {
.mf-bar-collapse, .mf-bar-collapser {
display: none !important;
}
}
}
{{ include('@MauticFocus/Builder/Bar/collapser.less.twig', with_context=false) }}
@media only screen and (max-width: 667px) {
& .mf-bar-collapse, & .mf-bar-collapser {
display: none !important;
}
}
{% if preview is not empty %}
{{ include('@MauticFocus/Builder/Bar/animations.less.twig', with_context=false) }}
{{ include('@MauticFocus/Builder/Bar/shared.less.twig', with_context=false) }}
.mf-bar {
&.mf-animate {
.barAnimate();
}
}
.mf-bar, .mf-bar-collapser, .mf-bar-collapser-sticky {
position: absolute !important;
}
{% endif %}

View File

@@ -0,0 +1,76 @@
.modalTranslate(@x; @y) {
-webkit-transform: translate(@x, @y);
-ms-transform: translate(@x, @y);
transform: translate(@x, @y);
}
.modalAnimate() {
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
-webkit-animation-duration: 0.3s;
animation-duration: 0.3s;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
.modalAnimateName(@name) {
-webkit-animation-name: @name;
animation-name: @name;
}
.modalSlideDownTop() {
0% {
margin-top: -100%;
.modalTranslate(-50%, -150%);
}
100% {
margin-top: 0;
.modalTranslate(-50%, 0);
}
}
@-webkit-keyframes mf-modal-slide-down-top {
.modalSlideDownTop;
}
@keyframes mf-modal-slide-down-top {
.modalSlideDownTop;
}
.modalSlideDownMiddle() {
0% {
margin-top: -100%;
.modalTranslate(-50%, -150%);
}
100% {
margin-top: 0;
.modalTranslate(-50%, -50%);
}
}
@-webkit-keyframes mf-modal-slide-down-middle {
.modalSlideDownMiddle;
}
@keyframes mf-modal-slide-down-middle {
.modalSlideDownMiddle;
}
.modalSlideUpBottom() {
0% {
margin-bottom: -100%;
.modalTranslate(-50%, 150%);
}
100% {
margin-bottom: 0;
.modalTranslate(-50%, 0);
}
}
@-webkit-keyframes mf-modal-slide-up-bottom {
.modalSlideUpBottom;
}
@keyframes mf-modal-slide-up-bottom {
.modalSlideUpBottom;
}

View File

@@ -0,0 +1,40 @@
{%- set props = focus.properties -%}
{%- set style = focus.style -%}
{%- set placement = props[style].placement is defined ? props[style].placement|replace({'_': '-'}) : false -%}
{%- set animate = not preview and props.animate is defined and props.animate == 1 -%}
<style scoped>
.mf-{{ style }} {
border-color: #{{ props.colors.primary }};
}
</style>
<div class="mautic-focus mf-{{ style }} {% if placement %}mf-{{ style }}-{{ placement }}{% endif %} {% if animate %}mf-animate{% endif %}">
<div class="mf-{{ style }}-container">
<div class="mf-{{ style }}-close">
<a href="javascript:void(0)" {% if not preview %}onclick="Mautic.closeFocusModal('{{ style }}')"{% endif %}>x</a>
</div>
<div class="mf-content">
{% if htmlMode in ['editor', 'html'] %}
{{ focus[htmlMode]|raw }}
{% else %}
<div class="mf-headline">{{ props['content']['headline'] }}</div>
{% if props['content']['tagline'] is defined %}
<div class="mf-tagline">{{ props['content']['tagline'] }}</div>
{% endif %}
<div class="mf-inner-container">
{% if 'form' == focus.type %}
{focus_form}
{% elseif 'link' == focus.type %}
<a href="{% if not preview %}{{ clickUrl }}{% else %}#{% endif %}"
class="mf-link"
target="{% if props.content.link_new_window %}_new{% else %}_parent{% endif %}">
{{ props['content']['link_text'] }}
</a>
{% endif %}
</div>
{% endif %}
</div>
</div>
</div>
{% if 'modal' == style %}
<div class="mf-move-to-parent mf-{{ style }}-overlay mf-{{ style }}-overlay-{{ focus['id'] }}"></div>
{% endif %}

View File

@@ -0,0 +1,11 @@
.mf-modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
background: #000000;
z-index: 21002;
width: 100%;
height: 100%;
opacity: .7;
}

View File

@@ -0,0 +1,46 @@
{{ include('@MauticFocus/Builder/Modal/animations.less.twig', with_context=false) }}
{{ include('@MauticFocus/Builder/Modal/overlay.less.twig', with_context=false) }}
.mf-modal-iframe {
position: fixed;
z-index: 21003;
left: 50%;
&.mf-animate {
.modalAnimate();
}
&.mf-modal-iframe-top {
top: 10px;
margin-top: -100%;
.modalTranslate(-50%, 0);
&.mf-animate {
.modalAnimateName(mf-modal-slide-down-top);
}
}
&.mf-modal-iframe-middle {
top: 50%;
margin-top: -100%;
.modalTranslate(-50%, -50%);
&.mf-animate {
.modalAnimateName(mf-modal-slide-down-middle);
}
}
&.mf-modal-iframe-bottom {
bottom: 10px;
margin-bottom: -100%;
.modalTranslate(-50%, 0);
&.mf-animate {
.modalAnimateName(mf-modal-slide-up-bottom);
}
}
&.mf-loaded {
margin-top: 0;
margin-bottom: 0;
}
}

View File

@@ -0,0 +1,114 @@
.mf-modal {
position: relative;
opacity: 1;
z-index: 2000;
margin: auto;
padding: 45px;
border-radius: 4px;
border-width: 6px 1px 1px 1px;
border-style: solid;
background: #fff;
max-width: 40em;
text-align: center;
.mf-content {
margin-bottom: 30px;
.mf-headline {
font-size: 1.6em;
font-weight: 600;
}
.mf-tagline {
font-size: 1.2em;
font-weight: normal;
margin-top: 4px;
}
a.mf-link {
display: block;
max-width: 70%;
padding: 10px;
margin: auto;
font-size: 1.2em;
}
}
.mf-modal-close {
position: fixed;
top: 5px;
right: 8px;
a {
font-size: 1.4em;
color: #757575;
opacity: .4;
text-decoration: none;
}
a:hover {
opacity: .8;
text-decoration: none;
}
}
.mauticform-input, .mauticform-row select, .mauticform-button, .mauticform-pagebreak {
width: 75%;
height: 35px;
margin-bottom: 5px;
}
}
.mf-responsive.mf-modal, .mf-responsive .mf-modal {
width: 90%;
padding: 10px;
}
{% if preview is not empty %}
{{ include('@MauticFocus/Builder/Modal/animations.less.twig', with_context=false) }}
{{ include('@MauticFocus/Builder/Modal/overlay.less.twig', with_context=false) }}
.mf-modal, .mf-modal-overlay {
position: absolute !important;
}
.mf-modal {
z-index: 1023;
left: 50%;
&.mf-animate {
.modalAnimate();
}
&.mf-modal-top {
top: 10px;
.modalTranslate(-50%, 0);
&.mf-animate {
.modalAnimateName(mf-modal-slide-down-top);
}
}
&.mf-modal-middle {
top: 50%;
.modalTranslate(-50%, -50%);
&.mf-animate {
.modalAnimateName(mf-modal-slide-down-middle);
}
}
&.mf-modal-bottom {
bottom: 10px;
.modalTranslate(-50%, 0);
&.mf-animate {
.modalAnimateName(mf-modal-slide-up-bottom);
}
}
}
.mf-modal-overlay {
z-index: 1022;
}
{% endif %}

View File

@@ -0,0 +1,75 @@
.notificationTranslate(@percent) {
-webkit-transform: translateX(@percent);
-ms-transform: translateX(@percent);
transform: translateX(@percent);
}
.notificationAnimate() {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
.notificationName(@name) {
-webkit-animation-name: @name;
animation-name: @name;
}
.notificationSlideLeft() {
0% {
.notificationTranslate(150%);
}
50% {
.notificationTranslate(-8%);
}
65% {
.notificationTranslate(4%);
}
80% {
.notificationTranslate(-4%);
}
95% {
.notificationTranslate(2%);
}
100% {
.notificationTranslate(0%);
}
}
@-webkit-keyframes mf-notification-slide-left {
.notificationSlideLeft;
}
@keyframes mf-notification-slide-left {
.notificationSlideLeft;
}
.notificationSlideRight() {
0% {
.notificationTranslate(-150%);
}
50% {
.notificationTranslate(8%);
}
65% {
.notificationTranslate(-4%);
}
80% {
.notificationTranslate(4%);
}
95% {
.notificationTranslate(-2%);
}
100% {
.notificationTranslate(0%);
}
}
@-webkit-keyframes mf-notification-slide-right {
.notificationSlideRight;
}
@keyframes mf-notification-slide-right {
.notificationSlideRight;
}

View File

@@ -0,0 +1,6 @@
{{- include('@MauticFocus/Builder/Modal/index.html.twig', {
'focus': focus,
'preview': preview,
'clickUrl': clickUrl,
'htmlMode': htmlMode,
}) -}}

View File

@@ -0,0 +1,58 @@
{{ include('@MauticFocus/Builder/Notification/animations.less.twig', with_context=false) }}
.mf-notification-iframe {
position: fixed;
z-index: 21001;
margin-top: -100%;
&.mf-loaded {
margin-top: 0;
margin-bottom: 0;
&.mf-animate {
.notificationAnimate();
}
&.mf-notification-iframe-top-left {
top: 5px;
left: 5px;
&.mf-animate {
.notificationName(mf-notification-slide-right);
}
}
&.mf-notification-iframe-top-right {
top: 5px;
right: 5px;
&.mf-animate {
.notificationName(mf-notification-slide-left);
}
}
&.mf-notification-iframe-bottom-left {
bottom: 5px;
left: 5px;
&.mf-animate {
.notificationName(mf-notification-slide-right);
}
}
&.mf-notification-iframe-bottom-right {
bottom: 5px;
right: 5px;
&.mf-animate {
.notificationName(mf-notification-slide-left);
}
}
&.mf-responsive {
left: 0 !important;
right: 0 !important;
}
}
}

View File

@@ -0,0 +1,107 @@
.mf-notification {
position: relative;
opacity: 1;
z-index: 2000;
margin: auto;
background: #fff;
border-radius: 4px;
border-width: 6px 1px 1px 1px;
border-style: solid;
min-height: 8em;
padding: 10px 20px;
width: 350px;
.mf-content {
margin-bottom: 30px;
.mf-headline {
font-size: 1.2em;
font-weight: 600;
}
.mf-tagline {
font-size: 1em;
font-weight: normal;
margin-top: 4px;
}
}
.mf-notification-close {
position: fixed;
top: 5px;
right: 8px;
a {
font-size: 1em;
color: #757575;
opacity: .4;
text-decoration: none;
&:hover {
opacity: .8;
text-decoration: none;
}
}
}
.mauticform-input, .mauticform-row select, .mauticform-button, .mauticform-pagebreak {
width: 100%;
height: 28px;
margin-bottom: 2px;
}
}
.mf-responsive.mf-notification, .mf-responsive .mf-notification {
width: 90%;
padding: 10px;
left: 0;
right: 0;
}
{% if preview is not empty %}
.mf-notification {
position: absolute !important;
&.mf-animate {
.notificationAnimate();
}
&.mf-notification-top-left {
top: 5px;
left: 5px;
&.mf-animate {
.notificationName(mf-notification-slide-right);
}
}
&.mf-notification-top-right {
top: 5px;
right: 5px;
&.mf-animate {
.notificationName(mf-notification-slide-left);
}
}
&.mf-notification-bottom-left {
bottom: 5px;
left: 5px;
&.mf-animate {
.notificationName(mf-notification-slide-right);
}
}
&.mf-notification-bottom-right {
bottom: 5px;
right: 5px;
&.mf-animate {
.notificationName(mf-notification-slide-left);
}
}
}
{{ include('@MauticFocus/Builder/Notification/animations.less.twig', with_context=false) }}
{% endif %}

View File

@@ -0,0 +1,6 @@
{{- include('@MauticFocus/Builder/Modal/index.html.twig', {
'focus': focus,
'preview': preview,
'clickUrl': clickUrl,
'htmlMode': htmlMode,
}, with_context=false) -}}

View File

@@ -0,0 +1,19 @@
.mf-page-iframe {
position: fixed;
z-index: 21005;
top: 1px;
right: 1px;
left: 1px;
bottom: 1px;
width: 100%;
height: 100%;
}
@media only screen and (max-width: 667px) {
.mf-page-iframe {
top: 0;
right: 0;
left: 0;
bottom: 0;
}
}

View File

@@ -0,0 +1,78 @@
.mf-page {
position: fixed;
opacity: 1;
z-index: 20000;
margin: auto;
padding: 45px;
background: #fff;
border-radius: 2px;
border-width: 6px 1px 1px 1px;
border-style: solid;
top: 1px;
right: 1px;
left: 1px;
bottom: 1px;
text-align: center;
.mf-content {
position: absolute;
min-width: 75%;
top: 50%;
left: 50%;
right: 0;
transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
margin-bottom: 30px;
.mf-headline {
font-size: 2.5em;
font-weight: 600;
}
.mf-tagline {
font-size: 1.8em;
font-weight: normal;
margin-top: 4px;
}
a.mf-link {
padding: 10px 15px;
display: block;
max-width: 50%;
margin: auto;
font-size: 1.8em;
}
}
.mf-page-close {
position: absolute;
top: 0;
right: 8px;
a {
font-size: 1.8em;
color: #757575;
opacity: .4;
text-decoration: none;
&:hover {
opacity: .8;
text-decoration: none;
}
}
}
.mauticform-input, .mauticform-row select, .mauticform-button, .mauticform-pagebreak {
width: 75%;
height: 40px;
font-size: 1.6em;
margin-bottom: 8px;
}
}
{% if preview is not empty %}
.mf-page {
position: absolute !important;
}
{% endif %}

View File

@@ -0,0 +1,59 @@
{#
Variables
- focus (MauticPlugin\MauticFocusBundle\Entity\Focus)
- preview (optional)
- clickUrl
- htmlMode
Notes
- focus.htmlMode === htmlMode? is this always true?
#}
{% set templateBase = '@MauticFocus/Builder/' ~ focus.style|capitalize ~ '/index.html.twig' %}
{% set preview = preview|default(false) %}
{% set clickUrl = clickUrl|default('#') %}
{% set props = focus.properties %}
<div>
<style scoped>
.mautic-focus * {
all: revert;
box-sizing: border-box;
}
.mautic-focus {
font-family: {{ props.content.font }};
color: #{{ props.colors.text|replace({'#': ''}) }};
}
{% if props.colors is defined and props.colors is not empty %}
.mf-content a.mf-link, .mf-content .mauticform-button, .mf-content .mauticform-pagebreak {
background-color: #{{ props.colors.button|replace({'#': ''}) }};
color: #{{ props.colors.button_text }};
}
.mauticform-input:focus, select:focus {
border: 1px solid #{{ props.colors.button|replace({'#': ''}) }};
}
{% endif %}
{% if preview %}
{{ include('@MauticFocus/Builder/style.less.twig', {
'preview': true,
'focus': focus,
}, with_context=false) }}
{% endif %}
</style>
{{ include(templateBase, {
'focus': focus,
'preview': preview,
'clickUrl': clickUrl,
'htmlMode': htmlMode,
}, with_context=false) }}
{% if focus.properties.content.css is defined and focus.properties.content.css is not empty %}
<style scoped>
{{ focus.properties.content.css|raw }}
</style>
{% endif %}
{# Add view tracking image #}
{% if not preview %}
<img src="{{ url('mautic_focus_pixel', {'id': focus.id}, true) }}" alt="Mautic Focus" style="display: none;"/>
{% endif %}
</div>

View File

@@ -0,0 +1,118 @@
{#
Variables
- form
- pages
- lastPage
- style
- focusId
- preview
- contactFields
- companyFields
- viewOnlyFields
- displayManager
#}
{% set formName = '_' ~ inputAlphanum(inputTransliterate(form.name))|lower ~ '_focus' %}
{% set jsFormName = formName|trim('_', 'left') %}
{% set fields = form.fields %}
{% set required = [] %}
<!-- START FOCUS FORM -->
{{ include('@MauticForm/Builder/_script.html.twig', {'form': form, 'formName': formName}, with_context=false) }}
<script>
var MauticFocusHandler = function (messageType, message) {
var wrapper = document.getElementById('mauticform_wrapper{{ formName }}');
var innerForm = wrapper.getElementsByClassName('mauticform-innerform');
innerForm[0].style.display = "none";
{% if 'page' == style %}
document.getElementById('mauticform{{ formName }}_' + messageType).style.fontSize = "2em";
{% elseif 'bar' == style %}
document.getElementById('mauticform{{ formName }}_' + messageType).style.fontSize = "1.1em";
{% endif %}
var headline = document.getElementsByClassName('mf-headline');
if (headline.length) {
headline[0].style.display = "none";
}
var tagline = document.getElementsByClassName('mf-tagline');
if (tagline.length) {
tagline[0].style.display = "none";
}
if (message) {
document.getElementById('mauticform{{ formName }}_' + messageType).innerHTML = message;
}
if (messageType == 'error') {
setTimeout(function () {
if (headline.length) {
{% if 'bar' == style %}
headline[0].style.display = "inline-block";
{% else %}
headline[0].style.display = "block";
{% endif %}
}
if (tagline.length) {
tagline[0].style.display = "inherit";
}
innerForm[0].style.display = "inherit";
document.getElementById('mauticform{{ formName }}_' + messageType).innerHTML = '';
}, 1500);
}
};
if (typeof MauticFormCallback == 'undefined') {
var MauticFormCallback = {};
}
MauticFormCallback["{{ jsFormName }}"] = {
onMessageSet: function (data) {
if (data.message) {
MauticFocusHandler(data.type);
}
},
onErrorMark: function (data) {
if (data.validationMessage) {
MauticFocusHandler('error', data.validationMessage);
return true;
}
},
onResponse: function (data) {
if (data.download) {
document.getElementById('mauticiframe{{ formName }}').src = data.download;
if (data.redirect) {
setTimeout(function () {
window.top.location = data.redirect;
}, 2000);
}
return true;
} else if (data.redirect) {
window.top.location = data.redirect;
return true;
}
return false;
}
}
</script>
{% set formExtra %}
<input type="hidden" name="mauticform[focusId]" id="mauticform{{ formName }}_focus_id" value="{{ focusId }}"/>
{% endset %}
{{ include('@MauticForm/Builder/form.html.twig', {
'form': form,
'formPages': pages,
'lastFormPage': lastPage,
'formExtra': formExtra,
'action': preview ? '#' : null,
'suffix': '_focus',
'contactFields': contactFields,
'companyFields': companyFields,
'viewOnlyFields': viewOnlyFields,
'displayManager': displayManager,
}, with_context=false) }}
<!-- END FOCUS FORM -->

View File

@@ -0,0 +1,750 @@
{#
Variables
- focus (MauticPlugin\MauticFocusBundle\Entity\Focus)
- preview (bool, default: false)
- clickUrl (string)
#}
{%- set style = focus.style -%}
{%- set props = focus.properties -%}
{%- set useScrollEvent = (props.when in ['scroll_slight', 'scroll_middle', 'scroll_bottom']) -%}
{%- set useUnloadEvent = ('leave' == props.when) -%}
{%- set useTimeout = props.timeout|default(0) -%}
{%- set animate = props.animate is not defined or (props.animate is defined and props.animate is not empty) -%}
{%- set linkActivation = props.link_activation is not defined or (props.link_activation is defined and props.link_activation is not empty) -%}
{%- set clickUrl = clickUrl|default(props.content.link_url) -%}
{%- if '5seconds' == props.when -%}
{%- set useTimeout = 5 -%}
{%- elseif 'minute' == props.when -%}
{%- set useTimeout = 60 -%}
{%- endif -%}
{%- if useTimeout > 0 -%}
{%- set timeout = useTimeout * 1000 -%}
{%- endif -%}
{%- set cssContent = include('@MauticFocus/Builder/style.less.twig', {
'preview': preview,
'focus': focus,
}, with_context=false) -%}
{%- set parentCssContent = include('@MauticFocus/Builder/parent.less.twig', {
'preview': preview,
}, with_context=false) -%}
{%- if 'bar' is same as style -%}
{%- set iframeClass = 'mf-bar-iframe mf-bar-iframe-' ~ props.bar.placement ~ ' mf-bar-iframe-' ~ props.bar.size -%}
{%- if props.bar.sticky -%}
{% set iframeClass = iframeClass ~ ' mf-bar-iframe-sticky' -%}
{%- endif -%}
{%- elseif 'modal' is same as style or 'notification' is same as style -%}
{%- set iframeClass = 'mf-' ~ style ~ '-iframe mf-' ~ style ~ '-iframe-' ~ props[style].placement|replace({'_': '-'}) -%}
{%- else -%}
{%- set iframeClass = 'mf-' ~ style ~ '-iframe' -%}
{%- endif -%}
(function (window) {
if (typeof window.MauticFocusParentHeadStyleInserted == 'undefined') {
window.MauticFocusParentHeadStyleInserted = false;
}
window.MauticFocus{{ focus.id }} = function () {
var Focus = {
debug: {{ ('dev' == app.environment) ? 'true' : 'false' }},
modalsDismissed: {},
ignoreConverted: {% if 'notification' is not same as focus.type and props.stop_after_conversion is defined and props.stop_after_conversion is not empty %}true{% else %}false{% endif %},
ignoreClosed: {% if props.stop_after_close is defined and props.stop_after_close is not empty %}true{% else %}false{% endif %},
// Initialize the focus
initialize: function () {
if (Focus.debug)
console.log('initialize()');
Focus.insertStyleIntoHead();
Focus.registerFocusEvent();
// Add class to body
Focus.addClass(document.getElementsByTagName('body')[0], 'MauticFocus{{ style|capitalize }}');
},
// Register click events for toggling bar, closing windows, etc
registerClickEvents: function () {
{% if 'bar' == style %}
var isTop = Focus.hasClass(Focus.iframeFocus, 'mf-bar-top');
Focus.setDefaultBarPosition(isTop);
var collapser = document.getElementsByClassName('mf-bar-collapser-{{ focus.id }}');
if (collapser[0]) {
collapser[0].addEventListener('click', function () {
Focus.toggleBarCollapse(collapser[0], false);
});
}
{% else %}
var closer = Focus.iframeDoc.getElementsByClassName('mf-{{ style }}-close');
var aTag = closer[0].getElementsByTagName('a');
var container = Focus.iframeDoc.getElementsByClassName('mf-{{ style }}');
container.onclick = function(e) {
if (e) { e.stopPropagation(); }
else { window.event.cancelBubble = true; }
};
aTag[0].addEventListener('click', function (event) {
if (typeof Focus.modalsDismissed["{{ focus.id }}"] == 'undefined') {
Focus.incrementCloseCount();
}
document.dispatchEvent(new CustomEvent("focus_{{ focus.id }}_close"));
});
document.addEventListener("focus_{{ focus.id }}_close", function (event) {
// Prevent multiple engagements for link clicks on exit intent
Focus.modalsDismissed["{{ focus.id }}"] = true;
// Remove iframe
if (Focus.iframe.parentNode) {
Focus.iframe.parentNode.removeChild(Focus.iframe);
}
var overlays = document.getElementsByClassName('mf-modal-overlay-{{ focus.id }}');
if (overlays.length) {
overlays[0].parentNode.removeChild(overlays[0]);
}
});
{% endif %}
{% if 'link' == focus.type %}
var links = Focus.iframeDoc.getElementsByClassName('mf-link');
if (links.length) {
links[0].addEventListener('click', function (event) {
Focus.convertVisitor();
});
}
{% elseif 'form' == focus.type %}
var buttons = Focus.iframeDoc.getElementsByClassName('mauticform-button');
if (buttons.length) {
buttons[0].addEventListener('click', function (event) {
Focus.convertVisitor();
});
}
{% endif %}
},
setDefaultBarPosition: function (isTop) {
if (isTop) {
Focus.iframe.style.marginTop = 0;
}else {
Focus.iframe.style.marginBottom = 0;
}
},
toggleBarCollapse: function (collapser, useCookie) {
var svg = collapser.getElementsByTagName('svg');
var g = svg[0].getElementsByTagName('g');
var currentSize = svg[0].getAttribute('data-transform-size');
var currentDirection = svg[0].getAttribute('data-transform-direction');
var currentScale = svg[0].getAttribute('data-transform-scale');
if (useCookie) {
if (Focus.cookies.hasItem('mf-bar-collapser-{{ focus.id }}')) {
var newDirection = Focus.cookies.getItem('mf-bar-collapser-{{ focus.id }}');
if (isNaN(newDirection)) {
var newDirection = currentDirection;
}
} else {
// Set cookie with current direction
var newDirection = currentDirection;
}
} else {
var newDirection = (parseInt(currentDirection) * -1);
Focus.cookies.setItem('mf-bar-collapser-{{ focus.id }}', newDirection);
}
setTimeout(function () {
g[0].setAttribute('transform', 'scale(' + currentScale + ') rotate(' + newDirection + ' ' + currentSize + ' ' + currentSize + ')');
svg[0].setAttribute('data-transform-direction', newDirection);
}, 500);
var isTop = Focus.hasClass(Focus.iframeFocus, 'mf-bar-top');
if ((!isTop && newDirection == 90) || (isTop && newDirection == -90)) {
// Open it up
Focus.setDefaultBarPosition(isTop);
Focus.removeClass(collapser, 'mf-bar-collapsed');
Focus.enableIframeResizer();
} else {
// Collapse it
var iframeHeight = Focus.iframe.style.height;
iframeHeight.replace('px', '');
var newMargin = (parseInt(iframeHeight) * -1) + 'px';
if (isTop) {
Focus.iframe.style.marginTop = newMargin;
} else {
Focus.iframe.style.marginBottom = newMargin;
}
Focus.addClass(collapser, 'mf-bar-collapsed');
Focus.disableIFrameResizer();
}
},
// Register scroll events, etc
registerFocusEvent: function () {
window.addEventListener('resize', function () {
Focus.disableIFrameResizer();
Focus.enableIframeResizer();
});
if (Focus.debug)
console.log('registerFocusEvent()');
{% if useScrollEvent %}
if (Focus.debug)
console.log('scroll event registered');
{% if useTimeout %}
if (Focus.debug)
console.log('timeout event registered');
setTimeout(function () {
window.addEventListener('scroll', Focus.engageVisitorAtScrollPosition);
}, {{ timeout }});
{% else %}
window.addEventListener('scroll', Focus.engageVisitorAtScrollPosition);
{% endif %}
{% elseif useUnloadEvent %}
if (Focus.debug)
console.log('show when visitor leaves');
{% if useTimeout %}
if (Focus.debug)
console.log('timeout event registered');
setTimeout(function () {
document.documentElement.addEventListener('mouseleave', Focus.engageVisitor);
}, {{ timeout }});
{% else %}
document.documentElement.addEventListener('mouseleave', Focus.engageVisitor);
{% endif %}
// Add a listener to every link
{% if linkActivation %}
var elements = document.getElementsByTagName('a');
for (var i = 0, len = elements.length; i < len; i++) {
var href = elements[i].getAttribute('href');
if (href && href.indexOf('#') != 0 && href.indexOf('javascript:') != 0) {
elements[i].onclick = function (event) {
if (typeof Focus.modalsDismissed["{{ focus.id }}"] == 'undefined') {
if (Focus.engageVisitor()) {
event.preventDefault();
}
}
}
}
}
{% endif %}
{% else %}
if (Focus.debug)
console.log('show immediately');
{% if useTimeout %}
if (Focus.debug)
console.log('timeout event registered');
setTimeout(function () {
// Give a slight delay to allow browser to process style injection into header
Focus.engageVisitor();
}, {{ timeout }});
{% else %}
// Give a slight delay to allow browser to process style injection into header
Focus.engageVisitor();
{% endif %}
{% endif %}
},
// Insert global style into page head
insertStyleIntoHead: function () {
if (!window.MauticFocusParentHeadStyleInserted) {
if (Focus.debug)
console.log('insertStyleIntoHead()');
var css = "{{- parentCssContent|e('js') -}}",
head = document.head || document.getElementsByTagName('head')[0],
style = document.createElement('style');
head.appendChild(style);
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
} else if (Focus.debug) {
console.log('Shared style already inserted into head');
}
},
// Inserts styling into the iframe's head
insertFocusStyleIntoIframeHead: function () {
// Insert style into iframe header
var frameDoc = Focus.iframe.contentDocument;
var frameHead = frameDoc.getElementsByTagName('head').item(0);
var css = "{{- cssContent|e('js') -}}";
var style = frameDoc.createElement('style');
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(frameDoc.createTextNode(css));
}
frameHead.appendChild(style);
var metaTag = frameDoc.createElement('meta');
metaTag.name = "viewport"
metaTag.content = "width=device-width,initial-scale=1,minimum-scale=1.0 maximum-scale=1.0"
frameHead.appendChild(metaTag);
},
// Generates the focus HTML
engageVisitor: function () {
var now = Math.floor(Date.now() / 1000);
if (Focus.cookies.hasItem('mautic_focus_{{ focus.id }}')) {
if (Focus.debug)
console.log('Cookie exists thus checking frequency');
var lastEngaged = parseInt(Focus.cookies.getItem('mautic_focus_{{ focus.id }}')),
frequency = '{{ props.frequency }}',
engage;
if (Focus.ignoreConverted && lastEngaged == -1) {
if (Focus.debug)
console.log('Visitor converted; abort');
return false;
}
switch (frequency) {
case 'once':
engage = false;
if (Focus.debug)
console.log('Engage once, abort');
break;
case 'everypage':
engage = true;
if (Focus.debug)
console.log('Engage on every page, continue');
break;
case 'q2min':
engage = (now - lastEngaged) >= 120;
if (Focus.debug) {
var debugMsg = 'Engage q2 minute, ';
if (engage) {
debugMsg += 'continue';
} else {
debugMsg += 'engage in ' + (120 - (now - lastEngaged)) + ' seconds';
}
console.log(debugMsg);
}
break;
case 'q15min':
engage = (now - lastEngaged) >= 900;
if (Focus.debug) {
var debugMsg = 'Engage q15 minute, ';
if (engage) {
debugMsg += 'continue';
} else {
debugMsg += 'engage in ' + (120 - (now - lastEngaged)) + ' seconds';
}
console.log(debugMsg);
}
break;
case 'hourly':
engage = (now - lastEngaged) >= 3600;
if (Focus.debug) {
var debugMsg = 'Engage hourly, ';
if (engage) {
debugMsg += 'continue';
} else {
debugMsg += 'engage in ' + (120 - (now - lastEngaged)) + ' seconds';
}
console.log(debugMsg);
}
break;
case 'daily':
engage = (now - lastEngaged) >= 86400;
if (Focus.debug) {
var debugMsg = 'Engage daily, ';
if (engage) {
debugMsg += 'continue';
} else {
debugMsg += 'engage in ' + (120 - (now - lastEngaged)) + ' seconds';
}
console.log(debugMsg);
}
break;
}
if (!engage) {
return false;
}
}
if (Focus.ignoreClosed && Focus.getCloseCount() > 0) {
if (Focus.debug)
console.log('Visitor has closed the focus; abort');
return false;
}
if (Focus.debug)
console.log('engageVisitor()');
// Inject iframe
Focus.createIframe();
// Inject content into iframe
Focus.iframeDoc.open();
Focus.iframeDoc.write("{focus_content}");
Focus.iframeDoc.close();
var animate = {% if animate %}true{% else %}false{% endif %};
Focus.iframe.onload = function() {
if (Focus.debug)
console.log('iframe loaded for '+Focus.iframe.getAttribute('src'));
// Resize iframe
if (Focus.enableIframeResizer()) {
// Give iframe chance to resize
setTimeout(function () {
if (animate) {
Focus.addClass(Focus.iframe, "mf-animate");
}
Focus.addClass(Focus.iframe, "mf-loaded");
}, 35);
} else {
if (animate) {
Focus.addClass(Focus.iframe, "mf-animate");
}
Focus.addClass(Focus.iframe, "mf-loaded");
}
}
// Set body margin to 0
Focus.iframeDoc.getElementsByTagName('body')[0].style.margin = 0;
Focus.iframeDoc.getElementsByTagName('body')[0].style.overflowX = 'hidden';
// Find elements that should be moved to parent
var move = Focus.iframeDoc.getElementsByClassName('mf-move-to-parent');
for (var i = 0; i < move.length; i++) {
var bodyFirstChild = document.body.firstChild;
Focus.addClass(move[i], 'mf-moved-{{ focus.id }}');
bodyFirstChild.parentNode.insertBefore(move[i], Focus.iframe);
}
// Find elements that should be copied to parent
var copy = Focus.iframeDoc.getElementsByClassName('mf-copy-to-parent');
for (var i = 0; i < copy.length; i++) {
var bodyFirstChild = document.body.firstChild;
var clone = copy[i].cloneNode(true);
Focus.addClass(clone, 'mf-moved-{{ focus.id }}');
bodyFirstChild.parentNode.insertBefore(clone, Focus.iframe);
}
// Get the main focus element
var focus = Focus.iframeDoc.getElementsByClassName('mautic-focus');
Focus.iframeFocus = focus[0];
// Insert style into iframe head
Focus.insertFocusStyleIntoIframeHead();
// Register events
Focus.registerClickEvents();
{% if 'leave' == props.when %}
// Ensure user can leave
document.documentElement.removeEventListener('mouseleave', Focus.engageVisitor);
{% endif %}
// Add cookie of last engagement
if (Focus.debug)
console.log('mautic_focus_{{ focus.id }} cookie set for ' + now);
Focus.cookies.removeItem('mautic_focus_{{ focus.id }}');
Focus.cookies.setItem('mautic_focus_{{ focus.id }}', now, Infinity, '/');
{% if 'bar' == style %}
var collapser = document.getElementsByClassName('mf-bar-collapser-{{ focus.id }}');
if (animate) {
// Give iframe chance to resize
setTimeout(function () {
Focus.toggleBarCollapse(collapser[0], true);
}, 35);
} else {
Focus.toggleBarCollapse(collapser[0], true);
}
{% endif %}
return true;
},
// Enable iframe resizer
enableIframeResizer: function () {
if (typeof Focus.iframeResizerEnabled !== 'undefined') {
return true;
}
if (typeof Focus.iframe === 'undefined') {
return false;
}
{% if style in ['modal', 'notification', 'bar'] %}
Focus.iframeHeight = 0;
Focus.iframeWidth = 0;
Focus.iframeResizeInterval = setInterval(function () {
if (Focus.iframeHeight !== Focus.iframe.style.height) {
var useHeight = ((window.innerHeight < Focus.iframeFocus.offsetHeight) ?
window.innerHeight : Focus.iframeFocus.offsetHeight);
useHeight += 10;
useHeight = useHeight + 'px';
if (Focus.debug) {
console.log('window inner height = ' + window.innerHeight);
console.log('iframe offset height = ' + Focus.iframeFocus.offsetHeight);
console.log('iframe height set to ' + useHeight)
}
Focus.iframe.style.height = useHeight;
Focus.iframeHeight = useHeight;
}
{% if style in ['modal', 'notification'] %}
if (Focus.iframeWidth !== Focus.iframe.style.width) {
if (Focus.debug) {
console.log('window inner width = ' + window.innerWidth);
console.log('iframe offset width = ' + Focus.iframeFocus.offsetWidth);
}
if (window.innerWidth < Focus.iframeFocus.offsetWidth) {
// Responsive iframe
Focus.addClass(Focus.iframeFocus, 'mf-responsive');
Focus.addClass(Focus.iframe, 'mf-responsive');
Focus.iframe.style.width = window.innerWidth + 'px';
Focus.iframe.width = window.innerWidth;
if (Focus.debug)
console.log('iframe set to responsive width: ');
} else {
Focus.iframe.style.width = Focus.iframeFocus.offsetWidth + 'px';
Focus.iframe.width = Focus.iframeFocus.offsetWidth + 'px';
Focus.removeClass(Focus.iframeFocus, 'mf-responsive');
Focus.removeClass(Focus.iframe, 'mf-responsive');
if (Focus.debug)
console.log('iframe not a responsive width');
}
Focus.iframeWidth = Focus.iframe.style.width;
}
{% endif %}
}, 35);
Focus.iframeResizerEnabled = true;
return true;
{% else %}
return false;
{% endif %}
},
// Disable iframe resizer
disableIFrameResizer: function () {
if (typeof Focus.iframeResizerEnabled !== 'undefined') {
delete(Focus.iframeResizerEnabled);
}
{% if style in ['modal', 'notification', 'bar'] %}
clearInterval(Focus.iframeResizeInterval);
{% endif %}
},
// Create iframe to load into body
createIframe: function () {
if (Focus.debug)
console.log('createIframe()');
Focus.iframe = document.createElement('iframe');
Focus.iframe.style.border = 0;
Focus.iframe.style.width = "100%";
Focus.iframe.style.height = "100%";
Focus.iframe.src = "about:blank";
Focus.iframe.scrolling = "auto";
Focus.iframe.className = "{{ iframeClass|raw }}";
var bodyFirstChild = document.body.firstChild;
bodyFirstChild.parentNode.insertBefore(Focus.iframe, bodyFirstChild);
Focus.iframeDoc = Focus.iframe.contentWindow.document;
},
// Execute event at current position
engageVisitorAtScrollPosition: function (event) {
var visualHeight = "innerHeight" in window
? window.innerHeight
: document.documentElement.offsetHeight;
var scrollPos = window.pageYOffset,
atPos = 0;
{% if 'scroll_slight' is same as props.when %}
atPos = 10;
{% elseif 'scroll_middle' is same as props.when %}
scrollPos += (visualHeight / 2);
atPos = (document.body.scrollHeight / 2);
{% elseif 'scroll_bottom' is same as props.when %}
scrollPos += visualHeight;
atPos = document.body.scrollHeight;
{% endif %}
if (Focus.debug)
console.log('scrolling: ' + scrollPos + ' >= ' + atPos);
if (scrollPos >= atPos) {
window.removeEventListener('scroll', Focus.engageVisitorAtScrollPosition);
Focus.engageVisitor();
}
},
// Create cookie noting visitor has been converted if applicable
convertVisitor: function () {
if (Focus.ignoreConverted) {
if (Focus.debug)
console.log('Visitor converted');
Focus.cookies.setItem('mautic_focus_{{ focus.id }}', -1, Infinity, '/');
} else if (Focus.debug) {
console.log('Visitor converted but ignoreConverted not enabled');
}
},
// Element has class
hasClass: function (element, hasClass) {
return ( (" " + element.className + " ").replace(/[\n\t]/g, " ").indexOf(" " + hasClass + " ") > -1 );
},
// Add class to element
addClass: function (element, addClass) {
if (!Focus.hasClass(element, addClass)) {
element.className += " " + addClass;
}
},
// Remove class from element
removeClass: function (element, removeClass) {
element.className = element.className.replace(new RegExp('\\b' + removeClass + '\\b'), '');
},
getCloseCount() {
if (Focus.cookies.hasItem('mautic_focus_{{ focus.id }}_closed')) {
return parseInt(Focus.cookies.getItem('mautic_focus_{{ focus.id }}_closed'))
} else {
return 0;
}
},
incrementCloseCount() {
var closeCount = Focus.getCloseCount();
Focus.cookies.setItem('mautic_focus_{{ focus.id }}_closed', ++closeCount);
},
// Cookie handling
cookies: {
/**
* :: cookies.js ::
* https://developer.mozilla.org/en-US/docs/Web/API/document.cookie
* http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
getItem: function (sKey) {
if (!sKey) {
return null;
}
return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
},
setItem: function (sKey, sValue, vEnd, sPath, sDomain) {
if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) {
return false;
}
this.removeItem(sKey);
var sExpires = "";
if (vEnd) {
switch (vEnd.constructor) {
case Number:
sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
break;
case String:
sExpires = "; expires=" + vEnd;
break;
case Date:
sExpires = "; expires=" + vEnd.toUTCString();
break;
}
}
document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + "; secure";
return true;
},
removeItem: function (sKey, sPath, sDomain) {
if (!this.hasItem(sKey)) {
return false;
}
document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "");
return true;
},
hasItem: function (sKey) {
if (!sKey) {
return false;
}
return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
},
keys: function () {
var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/);
for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) {
aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]);
}
return aKeys;
}
}
};
return Focus;
}
// Initialize
MauticFocus{{ focus.id }}().initialize();
})(window);

View File

@@ -0,0 +1,14 @@
{%- set less -%}
{{- include('@MauticFocus/Builder/Bar/parent.less.twig', with_context=false) -}}
{{- include('@MauticFocus/Builder/Modal/parent.less.twig', with_context=false) -}}
{{- include('@MauticFocus/Builder/Notification/parent.less.twig', with_context=false) -}}
{{- include('@MauticFocus/Builder/Page/parent.less.twig', with_context=false) -}}
{%- endset -%}
{%- set css = less|less_compile -%}
{%- if preview is empty and 'dev' is same as app.environment -%}
{%- set css = css|css_minify -%}
{%- endif -%}
{{- css|raw -}}

View File

@@ -0,0 +1,86 @@
{#
#}
{% set preview = preview|default(false) %}
{% set less %}
.mf-bar-iframe {
z-index: 19000;
}
.mf-content {
line-height: 1.1;
.mf-inner-container {
margin-top: 20px;
}
a.mf-link, .mauticform-button, .mauticform-pagebreak {
padding: 5px 15px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
cursor: pointer;
text-align: center;
text-decoration: none;
border: none;
}
a.mf-link:hover, .mauticform-button:hover, .mauticform-pagebreak:hover {
opacity: 0.9;
text-decoration: none;
border: none;
}
.mauticform-pagebreak {
width: auto !important;
}
}
.mautic-focus {
{% if preview %}
.mauticform-row {
min-height: 0px;
}
{% endif %}
.mauticform_wrapper form {
padding: 0;
margin: 0;
}
.mauticform-input, select {
border-radius: 2px;
padding: 5px 8px;
color: #757575;
border: 1px solid #ababab;
}
.mauticform-input:focus, select:focus {
outline: none;
border: 1px solid #757575;
}
}
{{ include('@MauticFocus/Builder/Bar/style.less.twig', {
'preview': preview,
}, with_context=false) }}
{{ include('@MauticFocus/Builder/Modal/style.less.twig', {
'preview': preview,
}, with_context=false) }}
{{ include('@MauticFocus/Builder/Notification/style.less.twig', {
'preview': preview,
}, with_context=false) }}
{{ include('@MauticFocus/Builder/Page/style.less.twig', {
'preview': preview,
}, with_context=false) }}
{% endset %}
{% set css = less|less_compile %}
{% if preview is empty and 'dev' is same as app.environment %}
{% set css = css|css_minify %}
{% endif %}
{{ css|raw }}

View File

@@ -0,0 +1,168 @@
{#
#}
{{ includeScript('plugins/MauticFocusBundle/Assets/js/focus.js') }}
{% if items|length > 0 %}
<div class="table-responsive page-list">
<table class="table table-hover focus-list" id="focusTable">
<thead>
<tr>
{{ include('@MauticCore/Helper/tableheader.html.twig', {
'checkall': 'true',
'target': '#focusTable',
}) }}
{{ include('@MauticCore/Helper/tableheader.html.twig', {
'sessionVar': 'focus',
'orderBy': 'f.name',
'text': 'mautic.core.name',
'class': 'col-focus-name',
'default': true,
}) }}
{{ include('@MauticCore/Helper/tableheader.html.twig', {
'sessionVar': 'focus',
'orderBy': 'c.title',
'text': 'mautic.core.category',
'class': 'visible-md visible-lg col-focus-category',
}) }}
{{ include('@MauticCore/Helper/tableheader.html.twig', {
'sessionVar': 'focus',
'orderBy': 'f.type',
'text': 'mautic.focus.thead.type',
'class': 'visible-md visible-lg col-focus-type',
}) }}
{{ include('@MauticCore/Helper/tableheader.html.twig', {
'sessionVar': 'focus',
'orderBy': 'f.style',
'text': 'mautic.focus.thead.style',
'class': 'visible-md visible-lg col-focus-style',
}) }}
{{ include('@MauticCore/Helper/tableheader.html.twig', {
'sessionVar': 'focus',
'orderBy': 'f.id',
'text': 'mautic.core.id',
'class': 'visible-md visible-lg col-focus-id',
}) }}
</tr>
</thead>
<tbody>
{% for item in items %}
<tr>
<td>
{{ include('@MauticCore/Helper/list_actions.html.twig', {
'item': item,
'templateButtons': {
'edit': securityHasEntityAccess(permissions['focus:items:editown'], permissions['focus:items:editother'], item.createdBy),
'clone': permissions['focus:items:create'],
'delete': securityHasEntityAccess(permissions['focus:items:deleteown'], permissions['focus:items:deleteother'], item.createdBy),
},
'routeBase': 'focus',
}) }}
</td>
<td>
<div>
{{ include('@MauticCore/Helper/publishstatus_icon.html.twig', {'item': item, 'model': 'focus'}) }}
<a data-toggle="ajax" href="{{ path('mautic_focus_action', {'objectId': item.id, 'objectAction': 'view'}) }}">
{{ item.name }}
</a>
{{ include('@MauticProject/Modules/projects.html.twig') }}
</div>
{{ include('@MauticCore/Helper/description--inline.html.twig', {
'description': item.description
}) }}
</td>
<td class="visible-md visible-lg">
{{ include('@MauticCore/Modules/category--expanded.html.twig', {'category': item.category}) }}
</td>
<td class="visible-md visible-lg">{{ ('mautic.focus.type.' ~ item.type)|trans }}</td>
<td class="visible-md visible-lg">{{ ('mautic.focus.style.' ~ item.style)|trans }}</td>
<td class="visible-md visible-lg">{{ item.id }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="panel-footer">
{{ include('@MauticCore/Helper/pagination.html.twig', {
'totalItems': items|length,
'page': page,
'limit': limit,
'baseUrl': path('mautic_focus_index'),
'sessionVar': 'focus',
}) }}
</div>
{% else %}
{% if searchValue is not empty %}
{{ include('@MauticCore/Helper/noresults.html.twig', {'tip': 'mautic.focus.noresults.tip'}) }}
{% else %}
<div class="mt-80 col-md-offset-2 col-lg-offset-3 col-md-8 col-lg-5 height-auto">
{% set childContainer %}
<div class="mb-md">
{% include '@MauticCore/Components/pictogram.html.twig' with {
'pictogram': 'spotlight',
'size': '80'
} %}
</div>
{{ include('@MauticCore/Components/content-item-row.html.twig', {
type: 'default',
eyebrow: 'mautic.focus.onboarding.eyebrow',
heading: 'mautic.focus.onboarding.purpose.heading',
copy: 'mautic.focus.onboarding.purpose.copy',
}) }}
{% set focusFeaturesContainer %}
<div class="row">
<div class="col-sm-6 col-xs-12">
{{ include('@MauticCore/Components/content-item.html.twig', {
type: 'pictogram',
pictogram: 'web--banners',
heading: 'mautic.focus.onboarding.style.bar.heading',
copy: 'mautic.focus.onboarding.style.bar.copy',
}) }}
</div>
<div class="col-sm-6 col-xs-12">
{{ include('@MauticCore/Components/content-item.html.twig', {
type: 'pictogram',
pictogram: 'design-and-development--01',
heading: 'mautic.focus.onboarding.style.modal.heading',
copy: 'mautic.focus.onboarding.style.modal.copy',
}) }}
</div>
<div class="col-sm-6 col-xs-12">
{{ include('@MauticCore/Components/content-item.html.twig', {
type: 'pictogram',
pictogram: 'notifications',
heading: 'mautic.focus.onboarding.style.notification.heading',
copy: 'mautic.focus.onboarding.style.notification.copy',
}) }}
</div>
<div class="col-sm-6 col-xs-12">
{{ include('@MauticCore/Components/content-item.html.twig', {
type: 'pictogram',
pictogram: 'maximize',
heading: 'mautic.focus.onboarding.style.fullpage.heading',
copy: 'mautic.focus.onboarding.style.fullpage.copy',
}) }}
</div>
</div>
{% endset %}
{{ include('@MauticCore/Components/content-group.html.twig', {
heading: 'mautic.focus.onboarding.styles.heading',
childContainer: focusFeaturesContainer,
}) }}
{% endset %}
{{ include('@MauticCore/Components/content-block.html.twig', {
heading: 'mautic.focus.onboarding.heading',
subheading: 'mautic.focus.onboarding.subheading',
copy: '',
childContainer: childContainer,
}) }}
</div>
{% endif %}
{% endif %}

View File

@@ -0,0 +1,276 @@
{% extends '@MauticCore/Default/content.html.twig' %}
{% block mauticContent %}focus{% endblock %}
{% block headerTitle %}{{ item.name }}{% endblock %}
{% block publishStatus %}
{{- include('@MauticCore/Helper/publishstatus_badge.html.twig', {'entity' : item}) -}}
<div class="label__divider"></div>
{% if item.type is defined and item.type is not empty %}
{% include '@MauticCore/Helper/_tag.html.twig' with {
tags: [{
label: ('mautic.focus.form.type.' ~ item.type),
icon: {
'form': 'ri-survey-fill',
'link': 'ri-link',
'notice': 'ri-information-2-fill'
}[item.type],
color: 'high-contrast',
attributes: {
'data-toggle': 'tooltip',
'data-placement': 'top',
'title': 'mautic.focus.type'|trans
}
}]
} %}
{% endif %}
{% if item.style is defined and item.style is not empty %}
{% include '@MauticCore/Helper/_tag.html.twig' with {
tags: [{
label: ('mautic.focus.style.' ~ item.style),
icon: {
'modal': 'ri-window-2-fill',
'notification': 'ri-notification-3-fill',
'bar': 'ri-layout-bottom-2-fill',
'page': 'ri-macbook-fill'
}[item.style],
color: 'blue',
attributes: {
'data-toggle': 'tooltip',
'data-placement': 'top',
'title': 'mautic.focus.style'|trans
}
}]
} %}
{% endif %}
{% if item.properties.when is defined and item.properties.when is not empty %}
{% include '@MauticCore/Helper/_tag.html.twig' with {
tags: [{
icon: {
'immediately': 'ri-flashlight-fill',
'scroll_slight': 'ri-mouse-fill',
'scroll_middle': 'ri-scroll-to-bottom-fill',
'scroll_bottom': 'ri-scroll-to-bottom-fill',
'leave': 'ri-picture-in-picture-exit-fill'
}[item.properties.when],
label: ('mautic.focus.form.when.' ~ item.properties.when ~ '.description'),
color: 'blue',
icon_only: true
}]
} %}
{% endif %}
{% if item.properties.frequency is defined and item.properties.frequency is not empty %}
{% include '@MauticCore/Helper/_tag.html.twig' with {
tags: [{
icon: {
'everypage': 'ri-repeat-2-fill',
'once': 'ri-repeat-one-fill',
'q2min': 'ri-reset-left-line',
'q15min': 'replay-15-fill',
'hourly': 'ri-history-fill 24-hours-fill',
'daily': 'ri-calendar-schedule-fill'
}[item.properties.frequency],
label: ('mautic.focus.form.frequency.' ~ item.properties.frequency ~ '.description'),
color: 'blue',
icon_only: true
}]
} %}
{% endif %}
{% if item.properties.timeout is defined and item.properties.timeout is not empty %}
{% include '@MauticCore/Helper/_tag.html.twig' with {
tags: [{
label: item.properties.timeout,
icon: 'ri-timer-fill',
color: 'blue',
attributes: {
'data-toggle': 'tooltip',
'data-placement': 'top',
'title': 'mautic.focus.form.timeout.description'|trans
}
}]
} %}
{% endif %}
{% endblock %}
{% block preHeader %}
{{- include('@MauticCore/Helper/page_actions.html.twig',
{
'item' : item,
'templateButtons' : {
'close' : securityIsGranted('focus:items:view'),
},
'routeBase' : 'focus',
'targetLabel': 'mautic.focus.focus_items'|trans
}
) -}}
{{ include('@MauticCore/Modules/category--inline.html.twig', {'category': item.category}) }}
{{ include('@MauticProject/Modules/projects.html.twig') }}
{% endblock %}
{% block actions %}
{{- include('@MauticCore/Helper/page_actions.html.twig', {
'item': item,
'templateButtons': {
'edit': securityHasEntityAccess(permissions['focus:items:editown'], permissions['focus:items:editother'], item.createdBy),
'clone': permissions['focus:items:create'],
'delete': securityHasEntityAccess(permissions['focus:items:deleteown'], permissions['focus:items:deleteother'], item.createdBy),
},
'routeBase': 'focus',
'langVar': 'focus',
}) -}}
{% endblock %}
{% block content %}
{{ includeScript('plugins/MauticFocusBundle/Assets/js/focus.js') }}
<!-- start: box layout -->
<div class="box-layout">
<!-- left section -->
<div class="col-md-9 height-auto">
<div>
<!-- form detail header -->
{% include '@MauticCore/Helper/description--expanded.html.twig' with {'description': item.description} %}
<!--/ form detail header -->
<!-- form detail collapseable -->
<div class="collapse pr-md pl-md" id="focus-details">
<div class="pr-md pl-md pb-md">
<div class="panel shd-none mb-0">
<table class="table table-hover mb-0" data-view-table data-entity-id="{{ item.id }}">
<tbody>
{{ include('@MauticCore/Helper/details.html.twig', {'entity': item}) }}
</tbody>
</table>
</div>
</div>
</div>
<!--/ form detail collapseable -->
</div>
<div>
<!-- form detail collapseable toggler -->
<div class="hr-expand nm">
<span data-toggle="tooltip" title="{{ 'mautic.core.details'|trans }}">
<a href="javascript:void(0)" class="arrow text-secondary collapsed" data-toggle="collapse" data-target="#focus-details"><span class="caret"></span>
{{ 'mautic.core.details'|trans }}
</a>
</span>
</div>
<!--/ form detail collapseable toggler -->
<!-- stats -->
<div class="pa-md">
<div class="row">
<div class="col-sm-12">
{{ include('@MauticCore/Modules/stat--icon.html.twig', {'stats': [
{
'title': 'mautic.focus.details.views',
'value_attr': 'data-focus-total-views-cell',
'value': '<div class="spinner"><i class="ri-loader-3-line ri-spin"></i></div>',
'tooltip': 'mautic.focus.details.views.tooltip',
'icon': 'ri-eye-line',
},
{
'title': 'mautic.focus.details.unique_views',
'value_attr': 'data-focus-total-unique-views-cell',
'value': '<div class="spinner"><i class="ri-loader-3-line ri-spin"></i></div>',
'tooltip': 'mautic.focus.details.unique_views.tooltip',
'icon': 'ri-user-6-line',
}
]}) }}
<div class="panel">
<div class="panel-body box-layout">
<div class="col-xs-4 va-m">
<h5 class="text-white dark-md fw-sb mb-xs">
<span class="ri-line-chart-fill"></span>
{{ 'mautic.focus.graph.stats'|trans }}
</h5>
</div>
<div class="col-xs-8 va-m">
{{ include('@MauticCore/Helper/graph_dateselect.html.twig', {'dateRangeForm': dateRangeForm, 'class': 'pull-right'}) }}
</div>
</div>
<div class="d-flex fd-column pt-0 pl-15 pb-15 pr-15 min-h-256">
{{ include('@MauticCore/Helper/chart.html.twig', {'chartData': stats, 'chartType': 'line', 'chartHeight': 300}) }}
</div>
</div>
</div>
</div>
</div>
<!--/ stats -->
{{ customContent('details.stats.graph.below', _context) }}
{% if trackables is defined and trackables is not empty %}
<!-- tabs controls -->
<ul class="nav nav-tabs nav-tabs-contained">
<li class="active">
<a href="#clicks-container" role="tab" data-toggle="tab">
{{ 'mautic.trackable.click_counts'|trans }}
</a>
</li>
</ul>
<!--/ tabs controls -->
<!-- start: tab-content -->
<div class="tab-content pa-md">
<div class="tab-pane active bdr-w-0" id="clicks-container">
{{ include('@MauticPage/Trackable/click_counts.html.twig', {
'trackables': trackables,
'entity': item,
'channel': 'focus',
}) }}
</div>
</div>
<!-- end: tab-content -->
{% endif %}
</div>
</div>
<!--/ left section -->
<!-- right section -->
<div class="col-md-3 bdr-l height-auto">
<!-- form HTML -->
<div class="pa-md">
{% set aboveFoldContent %}
<h4 class="mb-lg fw-b">{{ 'mautic.focus.install.header'|trans }}</h4>
{% include '@MauticCore/Components/pictogram.html.twig' with {
pictogram: 'embed',
size: 64,
color: 'var(--icon-interactive)'
} %}
{% endset %}
{% set belowFoldContent %}
<p class="mt-lg mb-lg">{{ 'mautic.focus.install.description'|trans }}</p>
<input onclick="this.setSelectionRange(0, this.value.length);" type="text" class="form-control" readonly value="&lt;script src=&quot;{{ url('mautic_focus_generate', {'id': item.id}, true) }}&quot; type=&quot;text/javascript&quot; charset=&quot;utf-8&quot; async=&quot;async&quot;&gt;&lt;/script&gt;"/>
{% endset %}
{{ include('@MauticCore/Components/tile.html.twig', {
'type': 'expandable-interactive',
'aboveFoldContent': aboveFoldContent,
'belowFoldContent': belowFoldContent,
}) }}
</div>
<!--/ form HTML -->
<hr class="hr-w-2" style="width:50%">
{# we can leverage data from audit_log table and build activity feed from it #}
<div class="panel shd-none bdr-rds-0 bdr-w-0 mb-0">
<!-- recent activity -->
{{ include('@MauticCore/Helper/recentactivity.html.twig', {'logs': logs}) }}
</div>
</div>
<!--/ right section -->
</div>
<!--/ end: box layout -->
<input type="hidden" name="entityId" id="entityId" value="{{ item.id }}"/>
{% endblock %}

View File

@@ -0,0 +1,411 @@
{% extends '@MauticCore/Default/content.html.twig' %}
{% block mauticContent %}focus{% endblock %}
{% block headerTitle %}
{% if entity.id %}
{{ 'mautic.focus.edit'|trans({'%name%': entity.name|trans}) }}
{% else %}
{{ 'mautic.focus.new'|trans }}
{% endif %}
{% endblock %}
{% block content %}
{{ includeStylesheet('plugins/MauticFocusBundle/Assets/css/focus.css') }}
{{ form_start(form) }}
<!-- start: box layout -->
<div class="box-layout">
<!-- container -->
<div class="col-md-9 height-auto bdr-r pa-md">
<div class="row">
<div class="col-md-6">{{ form_row(form.name) }}</div>
<div class="col-md-6">{{ form_row(form.website) }}</div>
</div>
<div class="row">
<div class="col-md-12">{{ form_row(form.description) }}</div>
</div>
</div>
<div class="col-md-3 height-auto">
<div class="pr-lg pl-lg pt-md pb-md">
{{ form_row(form.category) }}
{{ form_row(form.projects) }}
{{ form_row(form.isPublished) }}
{{ form_row(form.publishUp) }}
{{ form_row(form.publishDown) }}
<hr />
{% include '@MauticCore/FormTheme/Fields/_utm_tags_fields.html.twig' %}
</div>
</div>
</div>
<div class="hide builder focus-builder animation--slide-in-down">
{% set previewWebsiteMenu %}
<!-- Form to get preview URL -->
<div class="website-placeholder well well-lg col-xs-12">
<div class="row">
<div class="mautibot-image col-xs-3 text-center">
<img class="img-responsive" style="max-height: 125px; margin-left: auto; margin-right: auto;" src="{{ mautibotGetImage('wave') }}"/>
</div>
<div class="col-xs-9 layer-two">
<h4><i class="ri-double-quotes-l"></i> {{ 'mautic.core.noresults.tip'|trans }}
<i class="ri-double-quotes-r"></i></h4>
<p class="mt-md">
{{ 'mautic.focus.website_placeholder'|trans }}
</p>
<div class="input-group">
<input id="websiteUrlPlaceholderInput" disabled type="text" class="form-control" placeholder="https://example.com">
<span class="input-group-btn">
<button class="btn btn-ghost btn-fetch" type="button">{{ 'mautic.focus.fetch_snapshot'|trans }}</button>
</span>
</div>
<div class="help-block hide"></div>
</div>
</div>
</div>
{% endset %}
{% include '@MauticCore/Components/uishell.html.twig' with {
Header: {
ariaLabel: 'mautic.focus.builder',
children: {
HeaderName: {
prefix: entity.name is empty ? '' : 'mautic.focus.focus_item',
children: entity.name|default('mautic.focus.unsaved'),
},
'HeaderNavigation': {
'children': [
{
'HeaderMenuDropdown': {
'menuLinkName': 'mautic.focus.preview',
'renderMenuContent': previewWebsiteMenu,
},
},
],
},
HeaderGlobal: {
children: [
{
'HeaderGlobalAction': {
ariaLabel: 'mautic.core.close.builder',
onClick: 'Mautic.closeFocusBuilder(this);',
renderActionIcon: 'ri-close-line',
className: 'btn-close-builder btn-nospin',
}
}
],
},
},
},
} %}
<div class="builder-content">
<div class="website-preview">
<!-- Viewport switcher -->
<div class="viewport-switcher text-center">
<div class="btn btn-sm btn-success btn-nospin btn-viewport" data-viewport="desktop">
<i class="ri-smartphone-line ri-2x"></i>
</div>
</div>
<!-- Website preview block -->
<div id="websiteScreenshot">
<div class="screenshot-container text-center">
<div class="preview-body center"></div>
<div id="websiteCanvas"></div>
</div>
</div>
</div>
</div>
<!-- Builder -->
<div class="builder-panel builder-panel-focus">
<div class="builder-panel-top">
<p>
</p>
</div>
{% set class = form.type.vars.data is defined and form.type.vars.data is not empty ? 'focus-type-' ~ form.type.vars.data : 'focus-type-all' %}
{% set class = form.style.vars.data is defined and form.style.vars.data is not empty ? class ~ ' focus-style-' ~ form.style.vars.data : class ~ ' focus-style-all' %}
<div class="{{ class }}" style="margin-top: 40px;" id="focusFormContent">
<!-- start focus type -->
<div class="panel panel-default" id="focusType">
<div class="panel-heading">
<h4 class="focus-type-header panel-title">
<a role="button" data-toggle="collapse" href="#focusTypePanel" aria-expanded="true" aria-controls="focusTypePanel">
<i class="ri-focus-2-line"></i> {{ 'mautic.focus.form.type'|trans }}
</a>
</h4>
</div>
<div id="focusTypePanel" class="panel-collapse collapse in" role="tabpanel">
{{ form_widget(form.type) }}
<ul class="list-group mb-0">
<li data-focus-type="form" class="focus-type list-group-item pl-sm pr-sm">
<div class="row">
<div class="col-xs-2">
<i class="ri-2x ri-edit-box-line text-interactive"></i>
</div>
<div class="col-xs-10">
<h4 class="list-group-heading">{{ 'mautic.focus.form.type.form'|trans }}</h4>
<p class="list-group-item-heading small">{{ 'mautic.focus.form.type.form_description'|trans }}</p>
</div>
</div>
</li>
<li class="focus-properties focus-form-properties list-group-item pl-sm pr-sm" style="display: none;"></li>
<li data-focus-type="notice" class="focus-type list-group-item pl-sm pr-sm">
<div class="row">
<div class="col-xs-2">
<i class="ri-2x ri-megaphone-line text-warning"></i>
</div>
<div class="col-xs-10">
<h4 class="list-group-heading">{{ 'mautic.focus.form.type.notice'|trans }}</h4>
<p class="list-group-item-heading small">{{ 'mautic.focus.form.type.notice_description'|trans }}</p>
</div>
</div>
</li>
<li class="focus-properties focus-notice-properties list-group-item pl-sm pr-sm" style="display: none;"></li>
<li data-focus-type="link" class="focus-type list-group-item pl-sm pr-sm">
<div class="row">
<div class="col-xs-2">
<i class="ri-2x ri-corner-up-right-line text-info"></i>
</div>
<div class="col-xs-10">
<h4 class="list-group-heading">{{ 'mautic.focus.form.type.link'|trans }}</h4>
<p class="list-group-item-heading small">{{ 'mautic.focus.form.type.link_description'|trans }}</p>
</div>
</div>
</li>
<li class="focus-properties focus-link-properties list-group-item pl-sm pr-sm" style="display: none;"></li>
</ul>
</div>
<div class="hide" id="focusTypeProperties">
{{ form_row(form.properties.animate) }}
{{ form_row(form.properties.when) }}
{{ form_row(form.properties.timeout) }}
{{ form_row(form.properties.link_activation) }}
{{ form_row(form.properties.frequency) }}
<div class="hidden-focus-type-notice">
{{ form_row(form.properties.stop_after_conversion) }}
</div>
{{ form_row(form.properties.stop_after_close) }}
</div>
</div>
<!-- end focus type -->
<!-- start focus type tab -->
<div class="panel panel-default" id="focusStyle">
<div class="panel-heading">
<h4 class="panel-title focus-style-header">
<a role="button" data-toggle="collapse" href="#focusStylePanel" aria-expanded="true" aria-controls="focusStylePanel">
<i class="ri-mac-line"></i> {{ 'mautic.focus.form.style'|trans }}
</a>
</h4>
</div>
<div id="focusStylePanel" class="panel-collapse collapse" role="tabpanel">
<ul class="list-group mb-0">
<li data-focus-style="bar" class="focus-style visible-focus-style-bar list-group-item pl-sm pr-sm">
<div class="row">
<div class="col-xs-2">
<i class="pl-2 ri-2x ri-subtract-line text-interactive"></i>
</div>
<div class="col-xs-10">
<h4 class="list-group-heading">{{ 'mautic.focus.style.bar'|trans }}</h4>
<p class="list-group-item-heading small">{{ 'mautic.focus.style.bar_description'|trans }}</p>
</div>
</div>
</li>
<li class="focus-properties focus-bar-properties list-group-item pl-sm pr-sm" style="display: none;"></li>
<li data-focus-style="modal" class="focus-style visible-focus-style-modal list-group-item pl-sm pr-sm">
<div class="row">
<div class="col-xs-2">
<i class="ri-2x ri-file-list-2-line text-warning"></i>
</div>
<div class="col-xs-10">
<h4 class="list-group-heading">{{ 'mautic.focus.style.modal'|trans }}</h4>
<p class="list-group-item-heading small">{{ 'mautic.focus.style.modal_description'|trans }}</p>
</div>
</div>
</li>
<li class="focus-properties focus-modal-properties list-group-item pl-sm pr-sm" style="display: none;"></li>
<li data-focus-style="notification" class="focus-style visible-focus-style-notification list-group-item pl-sm pr-sm">
<div class="row">
<div class="col-xs-2">
<i class="pl-2 ri-2x ri-information-2-line text-info"></i>
</div>
<div class="col-xs-10">
<h4 class="list-group-heading">{{ 'mautic.focus.style.notification'|trans }}</h4>
<p class="list-group-item-heading small">{{ 'mautic.focus.style.notification_description'|trans }}</p>
</div>
</div>
</li>
<li class="focus-properties focus-notification-properties list-group-item pl-sm pr-sm" style="display: none;"></li>
<li data-focus-style="page" class="focus-style visible-focus-style-page list-group-item pl-sm pr-sm">
<div class="row">
<div class="col-xs-2">
<i class="pl-2 ri-2x ri-square-line text-danger"></i>
</div>
<div class="col-xs-10">
<h4 class="list-group-heading">{{ 'mautic.focus.style.page'|trans }}</h4>
<p class="list-group-item-heading small">{{ 'mautic.focus.style.page_description'|trans }}</p>
</div>
</div>
</li>
<!-- <li class="focus-properties focus-page-properties list-group-item pl-sm pr-sm" style="display: none;"></li> -->
</ul>
</div>
<div class="hide" id="focusStyleProperties">
<!-- bar type properties -->
<div class="focus-hide visible-focus-style-bar">
{{ form_row(form.properties.bar.allow_hide) }}
{{ form_row(form.properties.bar.push_page) }}
{{ form_row(form.properties.bar.sticky) }}
{{ form_row(form.properties.bar.placement) }}
{{ form_row(form.properties.bar.size) }}
</div>
<!-- modal type properties -->
<div class="focus-hide visible-focus-style-modal">
{{ form_row(form.properties.modal.placement) }}
</div>
<!-- notifications type properties -->
<div class="focus-hide visible-focus-style-notification">
{{ form_row(form.properties.notification.placement) }}
</div>
<!-- page type properties -->
<!-- <div class="focus-hide visible-focus-style-page"></div> -->
</div>
</div>
<!-- end focus style -->
<!-- start focus colors -->
<div class="panel panel-default" id="focusColors">
<div class="panel-heading">
<h4 class="panel-title">
<a role="button" data-toggle="collapse" href="#focusColorsPanel" aria-expanded="true" aria-controls="focusColorsPanel">
<i class="ri-paint-brush-line"></i> {{ 'mautic.focus.tab.focus_colors'|trans }}
</a>
</h4>
</div>
<div id="focusColorsPanel" class="panel-collapse collapse" role="tabpanel">
<div class="panel-body pa-xs">
<div class="row">
<div class="form-group col-xs-12 ">
{{ form_label(form.properties.colors.primary) }}
<div class="input-group">
{{ form_widget(form.properties.colors.primary) }}
<span class="input-group-btn">
<button data-dropper="focus_properties_colors_primary" class="btn btn-ghost btn-nospin btn-dropper" type="button"><i class="ri-dropper-line"></i></button>
</span>
</div>
<div class="mt-xs site-color-list hide" id="primary_site_colors"></div>
{{ form_errors(form.properties.colors.primary) }}
</div>
</div>
<div class="row">
<div class="form-group col-xs-12 ">
{{ form_label(form.properties.colors.text) }}
<div class="input-group">
{{ form_widget(form.properties.colors.text) }}
<span class="input-group-btn">
<button data-dropper="focus_properties_colors_text" class="btn btn-ghost btn-nospin btn-dropper" type="button"><i class="ri-dropper-line"></i></button>
</span>
</div>
<div class="mt-xs site-color-list hide" id="text_site_colors"></div>
{{ form_errors(form.properties.colors.text) }}
</div>
</div>
<div class="hidden-focus-type-notice">
<div class="row">
<div class="form-group col-xs-12 ">
{{ form_label(form.properties.colors.button) }}
<div class="input-group">
{{ form_widget(form.properties.colors.button) }}
<span class="input-group-btn">
<button data-dropper="focus_properties_colors_button" class="btn btn-ghost btn-nospin btn-dropper" type="button"><i class="ri-dropper-line"></i></button>
</span>
</div>
<div class="mt-xs site-color-list hide" id="button_site_colors"></div>
{{ form_errors(form.properties.colors.button) }}
</div>
</div>
<div class="row">
<div class="form-group col-xs-12 ">
{{ form_label(form.properties.colors.button_text) }}
<div class="input-group">
{{ form_widget(form.properties.colors.button_text) }}
<span class="input-group-btn">
<button data-dropper="focus_properties_colors_button_text" class="btn btn-ghost btn-nospin btn-dropper" type="button"><i class="ri-dropper-line"></i></button>
</span>
</div>
<div class="mt-xs site-color-list hide" id="button_text_site_colors"></div>
{{ form_errors(form.properties.colors.button_text) }}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- end focus colors -->
<!-- start focus content -->
<div class="panel panel-default" id="focusContent">
<div class="panel-heading">
<h4 class="panel-title">
<a role="button" data-toggle="collapse" href="#focusContentPanel" aria-expanded="true" aria-controls="focusContentPanel">
<i class="ri-newspaper-line"></i> {{ 'mautic.focus.tab.focus_content'|trans }}
</a>
</h4>
</div>
<div id="focusContentPanel" class="panel-collapse collapse" role="tabpanel">
<div class="panel-body pa-xs">
{{ form_row(form.html_mode) }}
{{ form_row(form.editor) }}
{{ form_row(form.html) }}
{{ form_row(form.properties.content.headline) }}
<div class="hidden-focus-style-bar">
{{ form_row(form.properties.content.tagline) }}
</div>
{{ form_row(form.properties.content.font) }}
<!-- form type properties -->
<div class="focus-hide visible-focus-type-form">
<div class="col-sm-12" id="focusFormAlert" data-hide-on='{"focus_html_mode_0":"checked"}'>
<div class="alert alert-info">
{{ 'mautic.focus.form_token.instructions'|trans|purify }}
</div>
</div>
{{ form_row(form.form) }}
</div>
<!-- link type properties -->
<div class="focus-hide visible-focus-type-link">
{{ form_row(form.properties.content.link_text) }}
{{ form_row(form.properties.content.link_url) }}
{{ form_row(form.properties.content.link_new_window) }}
</div>
{{ form_row(form.properties.content.css) }}
</div>
</div>
</div>
<!-- end focus content -->
</div>
</div>
</div>
{{ form_end(form) }}
{{ includeScript('plugins/MauticFocusBundle/Assets/js/focus.js') }}
{% endblock %}

View File

@@ -0,0 +1,66 @@
{#
#}
{% set isIndex = 'index' == tmpl ? true : false %}
{% set tmpl = 'list' %}
{% extends isIndex ? '@MauticCore/Default/content.html.twig' : '@MauticCore/Default/raw_output.html.twig' %}
{% block mauticContent %}focus{% endblock %}
{% block headerTitle %}{{ 'mautic.focus'|trans }}{% endblock %}
{% block content %}
{% if isIndex %}
<div id="page-list-wrapper" class="{% if items|length > 0 or searchValue is not empty %}panel {% endif %}panel-default">
{{ include('@MauticCore/Helper/list_toolbar.html.twig', {
'searchValue': searchValue,
'searchHelp': 'mautic.focus.help.searchcommands',
'action': currentRoute,
'page_actions': {
'templateButtons': {
'new': permissions['focus:items:create'],
},
'routeBase': 'focus',
},
'bulk_actions': {
'routeBase': 'focus',
'templateButtons': {
'delete': permissions['focus:items:delete'],
},
},
'quickFilters': [
{
'search': 'mautic.core.searchcommand.ispublished',
'label': 'mautic.core.form.active',
'tooltip': 'mautic.core.searchcommand.ispublished.description',
'icon': 'ri-check-line'
},
{
'search': 'mautic.core.searchcommand.isunpublished',
'label': 'mautic.core.form.inactive',
'tooltip': 'mautic.core.searchcommand.isunpublished.description',
'icon': 'ri-close-line'
},
{
'search': 'mautic.core.searchcommand.isuncategorized',
'label': 'mautic.core.form.uncategorized',
'tooltip': 'mautic.core.searchcommand.isuncategorized.description',
'icon': 'ri-folder-unknow-line'
},
{
'search': 'mautic.core.searchcommand.ismine',
'label': 'mautic.core.searchcommand.ismine.label',
'tooltip': 'mautic.core.searchcommand.ismine.description',
'icon': 'ri-user-line'
}
]
}) }}
<div class="page-list">
{% endif %}
{{ include('@MauticFocus/Focus/_list.html.twig') }}
{% if isIndex %}
</div>
</div>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,19 @@
{#
Used in the Campaign Builder
1. Add Decision for "Visits Page"
2. Add Action for "Show Focus Item"
#}
{% block focusshow_list_row %}
{{ includeScript('plugins/MauticFocusBundle/Assets/js/focus.js') }}
<div class="row">
<div class="col-xs-12">
{{ form_row(form.focus) }}
</div>
<div class="col-xs-12 mt-lg">
<div class="mt-3">
{{ form_row(form.newFocusButton) }}
{{ form_row(form.editFocusButton) }}
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,16 @@
{% if showMore is defined %}
<a href="{{ url('mautic_focus_index', {'search': searchString}) }}" data-toggle="ajax">
<span>{{ 'mautic.core.search.more'|trans({'%count%': remaining}) }}</span>
</a>
{% else %}
<a href="{{ url('mautic_focus_action', {'objectAction': 'view', 'objectId': item.id}) }}" data-toggle="ajax">
<span class="fw-sb">{{ item.name }}</span>
<span class="ml-4 mr-sm">#{{ item.getId() }}</span>
{{- include('@MauticCore/Helper/publishstatus_badge.html.twig', {
'entity': item,
'status': 'active',
'simplified': 'true'
}) -}}
</a>
<div class="clearfix"></div>
{% endif %}