Files
kupshop/admin/templates/window/sliders.tpl
2025-08-02 16:30:27 +02:00

729 lines
34 KiB
Smarty

{extends "../window.tpl"}
{block tabs}
{windowTab id='Bannery' label="Bannery"}
{if {find_module name="products_sections"} && $body.acn == "edit"}
{windowTab id='flapRelation' label={'flapRelation'|translate:'parameters'}}
{/if}
{/block}
{block tabsContent}
<input type="hidden" name="page" value="{$pager.number}">
<div id="Bannery" class="tab-pane fade active in boxStatic window-sliders">
<legend>Bannery</legend>
<div class="row">
<div class="col-md-6">
<div class="form-group form-group-flex">
<label class="col-md-3 control-label">{'name'|translate}</label>
<div class="col-md-9">
<input type="text" class="form-control input-sm" name="data[name]" size="20" maxlength="30"
value="{$body.data.name}">
</div>
</div>
</div>
{if isSuperuser()}
<div class="col-md-6">
<div class="form-group form-group-flex">
<label class="col-md-3 control-label">
<span class="glyphicon glyphicon-flash" style="color: #aab2bd;" title="Vidí pouze superadmin"></span>
Label
</label>
<div class="col-md-9">
<input type="text" class="form-control input-sm" name="data[label]" maxlength="50" value="{$body.data.label}">
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group form-group-flex">
<label class="col-md-3 control-label">
<span class="glyphicon glyphicon-flash" style="color: #aab2bd;" title="Vidí pouze superadmin"></span>
{'size'|translate}
</label>
<div class="col-md-9">
<input type="text" class="form-control input-sm" name="data[size]" maxlength="30"
value="{$body.data.size}">
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group form-group-flex">
<label class="col-md-3 control-label">
<span class="glyphicon glyphicon-flash" style="color: #aab2bd;" title="Vidí pouze superadmin"></span>
{'size_tablet'|translate}
</label>
<div class="col-md-9">
<input type="text" class="form-control input-sm" name="data[size_tablet]" maxlength="30"
value="{$body.data.size_tablet}">
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group form-group-flex">
<label class="col-md-3 control-label">
<span class="glyphicon glyphicon-flash" style="color: #aab2bd;" title="Vidí pouze superadmin"></span>
{'size_mobile'|translate}
</label>
<div class="col-md-9">
<input type="text" class="form-control input-sm" name="data[size_mobile]" maxlength="30"
value="{$body.data.size_mobile}">
</div>
</div>
</div>
{/if}
</div>
<hr>
<div id="sliders">
<div class="row m-b-2">
<div class="col-md-6">
<a href="#" data-form-add class="btn btn-success btn-block">
<span class="glyphicon glyphicon-plus"></span>&nbsp;{'addBannerItem'|translate}
</a>
</div>
{if $body.data.size and !$body.data.size_tablet and !$body.data.size_mobile}
<div class="col-md-6">
<span class="help-block">
{'bannerSizeNote'|translate}
<strong>{$body.data.size}</strong>
{'pixels'|translate}
</span>
</div>
{/if}
</div>
<div id="sliders">
<div id="sorter">
{foreach array_merge([[]], $body.images) as $key => $image}
<div class="panel {if $key > 0 and !$image.active}old{/if}" {if $key == 0}data-form-new style="display: none;"
{else}data-form-item{/if}>
<input type="hidden" name="data[images][{$key}][id]" value="{$image.id}">
<input type="hidden" name="data[images][{$key}][id_photo]" value="{$image.id_photo}">
<div class="panel-body">
<div class="row row-flex">
<div class="col-md-1 text-center actions">
{if $key > 0}
<span class="drag-drop-mover"><span class="bi bi-arrows-move handle"></span></span>
{/if}
</div>
{if $key > 0}
<div class="col-md-3 text-center photo">
<a href="{get_photo photo=$image.img size='slider'}" class="thumbnail" data-rel="bigphoto">
<img src="{get_photo photo=$image.img size='slider'}" class="img-rounded img-limited">
</a>
</div>
<div class="col-md-3 sizes">
{* Desktop obrázek - vždy by měl být nastaven, pokud je slider uložen *}
<div>
<span class="fc icons_desktop"></span>
{* Náhled obrázku *}
<a href="{get_photo photo=$image.img size='slider'}" data-rel="bigphoto">{$body.data.size}</a>
{* Editace obrázku *}
<a href="javascript:nw('photos', '{$image.img.id}');">
<span class=" glyphicon glyphicon-cog"></span>{'edit'|translate}
</a>
</div>
{* Verze obrázku pro tablet - nemusí být nastaven, pokud je slider uložen,
takže mu dáváme možnost obrázek dohrát, když ještě není nastaven *}
{if $body.data.size_tablet or $image.img.imageTablet}
<div>
<span class="fc icons_tablet"></span>
{* Náhled obrázku *}
{if $image.img.imageTablet}
<a href="{get_photo photo=$image.img size='slider' version='tablet'}" data-rel="bigphoto">
{$body.data.size_tablet|default:"Tablet"}
</a>
{else}
{$body.data.size_tablet|default:"Tablet"}
{/if}
{* Editace / upload obrázku *}
{if !$image.img.imageTablet}
<input type="file" class="filestyle" name="image[{$key}][tablet]"
data-input="false" data-buttonText="Nahrát">
{else}
<a href="javascript:nw('photos', '{$image.img.id}', 'flap=flapResponsive');"
title="Upravit banner"><span class="glyphicon glyphicon-cog"></span>{'edit'|translate}
</a>
{/if}
</div>
{/if}
{* Verze obrázku pro mobil - nemusí být nastaven, pokud je slider uložen,
takže mu dáváme možnost obrázek dohrát, když ještě není nastaven *}
{if $body.data.size_mobile or $image.img.imageMobile}
<div>
<span class="fc icons_mobile"></span>
{* Náhled obrázku *}
{if $image.img.imageMobile}
<a href="{get_photo photo=$image.img size='slider' version='mobile'}" data-rel="bigphoto">
{$body.data.size_mobile|default:"Mobil"}
</a>
{else}
{$body.data.size_mobile|default:"Mobil"}
{/if}
{* Editace / upload obrázku *}
{if !$image.img.imageMobile}
<input type="file" class="filestyle" name="image[{$key}][mobile]"
data-input="false" data-buttonText="Nahrát">
{else}
<a href="javascript:nw('photos', '{$image.img.id}', 'flap=flapResponsive');">
<span class="glyphicon glyphicon-cog"></span>{'edit'|translate}
</a>
{/if}
</div>
{/if}
<div>
<span class="help-block m-t-0">
<strong>ID:</strong> {$image.id}
</span>
</div>
</div>
{else}
<div class="col-md-3 text-center photo">
<a href="{get_photo photo=0 size='slider'}" class="thumbnail" rel="bigphoto">
<img src="{get_photo photo=0 size='slider'}" class="img-rounded img-limited" style="max-height: 70px;">
</a>
</div>
<div class="col-md-3 sizes unstyled">
<div>
<span class="fc icons_desktop"></span>
{$body.data.size}
<input type="file" class="filestyle" name="image[{$key}][desktop]" data-input="false"
data-buttonText="Nahrát">
</div>
{if $body.data.size_tablet or $image.img.imageTablet}
<div>
<span class="fc icons_tablet"></span>
{$body.data.size_tablet}
<input type="file" class="filestyle" name="image[{$key}][tablet]" data-input="false"
data-buttonText="Nahrát">
</div>
{/if}
{if $body.data.size_mobile or $image.img.imageMobile}
<div>
<span class="fc icons_mobile"></span>
{$body.data.size_mobile}
<input type="file" class="filestyle" name="image[{$key}][mobile]" data-input="false"
data-buttonText="Nahrát">
</div>
{/if}
</div>
{/if}
<div class="col-md-4 dates">
<div class="row form-group">
<div class="col-md-5 control-label">
<label>{'labelFrom'|translate}</label>
</div>
<div class="col-md-7">
<input type="text" name="data[images][{$key}][date_from]"
id="{if $key == 0}date_from_init{else}date_from{$key}{/if}" class="form-control input-sm"
value="{$image.date_from|format_datetime:"empty"}" autocomplete="off">
{if $key != 0}
{insert_calendar selector="#date_from`$key`" format='datetime'}
{/if}
</div>
</div>
<div class="row form-group">
<div class="col-md-5 control-label">
<label>{'labelTo'|translate}</label>
</div>
<div class="col-md-7">
<input type="text" name="data[images][{$key}][date_to]"
id="{if $key == 0}date_to_init{else}date_to{$key}{/if}" class="form-control input-sm"
value="{$image.date_to|format_datetime:"empty"}" autocomplete="off">
{if $key != 0}
{insert_calendar selector="#date_to`$key`" format='datetime'}
{/if}
</div>
</div>
{if !$body.duplicate}
<a class="badge" href="javascript:topPosition('{$image.id}')" title="{'topPositionTitle'|translate}">
<span class="glyphicon glyphicon-arrow-up handle"></span>{'topPosition'|translate}
</a>
{/if}
</div>
<div class="col-md-1 open">
<a href="" data-opener=".opener-content-{$key}">
<span class="is-active"><span class="glyphicon glyphicon-chevron-down"></span> {'more'|translate}</span>
<span class="is-inactive"><span class="glyphicon glyphicon-chevron-up"></span> {'less'|translate}</span>
</a>
</div>
<div class="col-md-1 delete">
<a class="btn-sm btn btn-danger" data-form-delete>
<input class="hidden" type="checkbox" name="data[images][{$key}][delete]">
<span class="glyphicon glyphicon-remove"></span>
</a>
</div>
</div>
<div class="row opener-content" style="display: none;">
<div class="col-md-12">
{block "description"}
<div class="row form-group">
<div class="col-md-2 control-label">
<label>Nadpis</label>
</div>
<div class="col-md-10">
<textarea name="data[images][{$key}][data][title]" class="form-control input-sm">{$image.data.title}</textarea>
</div>
</div>
<div class="row form-group">
<div class="col-md-2 control-label">
<label>{'labelDescription'|translate}</label>
</div>
<div class="col-md-10">
<input type="hidden" name="data[images][{$key}][position]"
value="{$image.position}" data-sort="">
<textarea name="data[images][{$key}][description]" id="sliderTitleID0"
class="form-control input-sm">{$image.description}</textarea>
</div>
</div>
{/block}
<div class="row form-group">
<div class="col-md-2 control-label">
<label>{'labelLink'|translate}</label>
</div>
<div class="col-md-10">
<input type="text" class="form-control input-sm"
name="data[images][{$key}][link]" size="15" value="{$image.link}"
style="width: 100%;">
</div>
</div>
<div class="row form-group">
<div class="col-md-2 control-label">
<label>{'figure'|translate}</label>
</div>
<div class="col-md-10">
{print_toggle nameRaw="data[images][`$key`][figure]" value=$image.figure}
{include "utils/translations.figure.tpl"
figureData=$image.sliderTranslationsFigure
parentFigure=$image.figure
inputPrefix="data[images][`$key`]"
parentFigureInput="[name=\"data[images][`$key`][figure]\"]"
}
</div>
</div>
{block "custom-data"}
{if in_array($body.data.label, ["home"])}
<div class="row form-group">
<div class="col-md-2 control-label">
<label for="custom-color">Tlačítko</label>
</div>
<div class="col-md-10">
<input name="data[images][{$key}][data][btn]" value="{$image.data.btn}" class="form-control">
</div>
</div>
<div class="row form-group">
<div class="col-md-2 control-label">
<label for="custom-color">Pozadí</label>
</div>
<div class="col-md-4">
<select name="data[images][{$key}][data][color]" class="form-control">
<option value="black" {if $image.data.color == "black"}selected{/if}>Tmavé</option>
<option value="white" {if $image.data.color == "white"}selected{/if}>Světlé</option>
</select>
</div>
</div>
{ifmodule COMPONENTS}
<div class="row form-group">
<div class="col-md-2 control-label">
<label for="custom-color">Barva tlačítka</label>
</div>
<div class="col-md-4">
<select name="data[images][{$key}][data][btncolor]" class="form-control">
<option value="light" {if $image.data.btncolor == "light"}selected{/if}>Světlé</option>
<option value="dark" {if $image.data.btncolor == "dark"}selected{/if}>Tmavé</option>
</select>
</div>
</div>
{/ifmodule}
{if $cfg.tpl.slider_product}
<div class="row form-group">
<div class="col-md-2 control-label">
<label>Produkt</label>
</div>
<div class="col-md-10">
<select name="data[images][{$key}][data][products][]" multiple='multiple'
class="selecter selecter-sortable" id="products{$key}"
data-preload="products" data-autocomplete="productId">
{foreach $image.data.products as $product}
<option value="{$product}" selected>{$product}</option>
{/foreach}
</select>
</div>
</div>
{/if}
{/if}
{/block}
</div>
</div>
</div>
</div>
{/foreach}
</div>
</div>
{include "utils/pager.tpl"}
</div>
{if empty($body.images)}
<script src="./static/js/jquery.datetimepicker.js"></script>
<script src="./static/js/jquery-ui.datepicker-cs.js"></script>
{/if}
<script>
$('#sliders').on('click', '[data-opener]', function () {
let $target = $(this).closest('.panel-body').find('.opener-content');
$target.slideToggle();
$(this).toggleClass('active');
return false;
});
var inited = 0
initForm({
selector: '#sliders',
beforeAdd: function (original) {
var $item = original()
window.preloadAutocompletes($item);
var $input = $item.find('#date_from_init')
$input.attr('id', 'date_from_init' + inited)
$input.datetimepicker({
dateFormat: 'd.m.yy',
timeFormat: 'hh:mm:ss'
})
$input = $item.find('#date_to_init')
$input.attr('id', 'date_to_init' + inited)
$input.datetimepicker({
dateFormat: 'd.m.yy',
timeFormat: 'hh:mm:ss'
})
inited++
return false
},
})
</script>
<script>
$('#sorter').sortable({
helper: function (e, row) {
var $row = $(row)
var $helper = $row.clone().addClass('drag-drop')
return $helper[0]
},
stop: function (event, ui) {
$(this).children().each(function (index, item) {
$(item).find('[data-sort]').val($(item).index() +{($pager.number-1)*$pager.onPage}).change()
})
},
handle: '.handle',
placeholder: 'placeholder'
})
function topPosition(id) {
if (id) {
document.location = document.location + '&acn=drag&page=1&moved_item=' + id
}
return false
}
</script>
</div>
{if {find_module name="products_sections"} && $body.acn == "edit"}
<div id="flapRelation" class="tab-pane fade boxStatic box">
{$positions = KupShop\ContentBundle\Util\SliderUtil::getPositions()}
<div class="row bottom-space">
<div class="col-xs-6">
<div class="wpj-form-group">
<label>{'addSection'|translate}</label>
<div data-sections-autocomplete></div>
</div>
</div>
</div>
<div class="wpj-panel wpj-panel-default">
<div class="wpj-panel-heading">
<div class="row">
<div class="col-xs-2">
<small>{'sectionName'|translate:'sliders'}</small>
</div>
{foreach $positions as $position => $positionName}
<div class="col-xs-2">
<div class="checkbox">
<input
type="checkbox"
class="check"
id="check-all-{$position}"
data-check-all="{$position}"
/>
<label for="check-all-{$position}">
{if count($positions) === 1}
Banner
{else}
{$positionName} banner
{/if}
</label>
</div>
</div>
{/foreach}
<div class="col-xs-2 m-l-auto">
<small>{'sectionTags'|translate:'sliders'}</small>
</div>
</div>
</div>
<div class="wpj-list-group">
<div class="wpj-list-group-item" style="display: none;" data-form-new>
<div class="row" data-section-id="">
<div class="col-xs-2" data-section-name></div>
<div class="col-xs-2 m-l-auto" data-section-badges></div>
</div>
</div>
{foreach $body.data.slider_sections as $sliderSection}
{$sectionId = $sliderSection.id}
<div class="wpj-list-group-item" data-form-item>
<div class="row" data-section-id="{$sectionId}">
<div class="col-xs-2" data-section-name>
<strong>{$sliderSection.name}</strong><br />
<small class="text-muted">{if strcasecmp($sliderSection.name, $sliderSection.full_path)}{$sliderSection.full_path}{/if}</small>
</div>
{foreach $positions as $position => $_}
{$sliderPosition = $sliderSection.positions[$position]}
<span data-checkbox='{ldelim}"id_section":{$sectionId},"id_slider":{$body.ID},"position":"{$position}"{rdelim}'
{if $sliderPosition.id_slider == $body.ID}data-checked{/if}
data-title="{$sliderPosition.slider_name}"
></span>
{/foreach}
<div class="col-xs-2 m-l-auto" data-section-badges>
{foreach $sliderSection.badges as $badge}
{$badge.title = $badge.translate_key|translate:'sections'}
<span data-badge='{$badge|json_encode nofilter}'></span>
{/foreach}
</div>
</div>
</div>
{/foreach}
</div>
</div>
</div>
{/if}
{/block}
<script type="text/javascript">
{block onready append}
initForm({
selector: '#flapRelation',
});
async function checkAndAddSection(sectionId, withSubsections = false) {
{literal}
if (!$(`[data-section-id="${sectionId}"]`).length) {
await addSectionRow(sectionId);
return true;
}
{/literal}
if (!withSubsections) {
alert('Tato sekce je už přidána.');
}
return false;
}
async function addSectionRow(sectionId) {
const sliderId = {$body.ID};
{literal}
const endpoint = `launch.php?s=sliders.php&acn=ajaxSection&id_section=${sectionId}`;
const url = new URL(endpoint, window.location.href);
let newSection = undefined;
try {
newSection = await fetch(url.href, { method: 'POST' }).then(response => response.json());
} catch (e) {
console.error(e);
}
if (!newSection) {
alert('Nepodařilo se přidat sekci.');
return;
}
const $newItem = addNewItem($('#flapRelation [data-form-new]'));
$newItem.find('[data-section-id]').attr('data-section-id', sectionId);
const $name = $newItem.find('[data-section-name]');
const isTopsection = newSection.name === newSection.full_path;
$name.prop('innerHTML', `
<strong>${newSection.name}</strong><br />
<small class="text-muted">${!isTopsection ? newSection.full_path : ''}</small>
`);
let $afterElement = $name;
for (const position in newSection.positions) {
const sliderAtPosition = newSection.positions[position];
const checkboxValue = {
position,
id_slider: sliderId,
id_section: sectionId,
};
const $newCheckbox = createCheckbox(
sliderAtPosition?.id_slider === sliderId || Object.keys(newSection.positions).length === 1,
sliderAtPosition?.slider_name,
checkboxValue,
);
$newCheckbox.insertAfter($afterElement);
$afterElement = $newCheckbox;
}
if (newSection.badges) {
const $badgesTarget = $newItem.find('[data-section-badges]');
for (const badge of newSection.badges) {
const $badge = createBadge(badge.title, badge.class, badge.icon);
$badgesTarget.append($badge);
}
}
shouldCheckAllBeChecked();
{/literal}
}
function addWithSubsections(idTopsection) {
const endpoint = '{path('kupshop_catalog_admin_sectionsautocomplete_getsubsections', ['id' => '$', 'all_subsections' => 1])}';
{literal}
const url = new URL(
endpoint.replace(encodeURIComponent('$'), idTopsection),
`${window.location.protocol}${window.location.host}`,
);
fetch(url.href)
.then(response => response.json())
.then(async subsections => {
if (!Array.isArray(subsections)) {
alert('Nepodařilo se přidat sekce');
console.error('Subsections are not an array', subsections);
return;
}
const results = await Promise.all([
checkAndAddSection(idTopsection, true),
...subsections.map(section => checkAndAddSection(section.id, true))
]);
const addedCount = results.filter(Boolean).length;
if (addedCount > 0) {
alert(`${addedCount} sekcí bylo přidáno.`);
} else {
alert('Všechny sekce jsou již přidány.');
}
})
.catch(alert);
{/literal}
}
function createBadge(title, className, icon = undefined) {
{literal}
const iconSpan = icon ? `<span class="bi bi-${icon}"></span>` : '';
return $(`
<span class="badge ${className}" title="${title}" data-toggle="tooltip">
${iconSpan}
<span class="tooltip-text m-l-1">${title}</span>
</span>
`);
{/literal}
}
function createCheckbox(isChecked, title, value) {
{literal}
const uniqueIndex = `${value.id_section}_${value.position}`;
const $checkbox = $(`
<div class="col-xs-2" data-slider-position="${value.position}">
<div class="checkbox">
<input
type="checkbox"
name="data[slider_sections][${uniqueIndex}]"
class="check"
value='${JSON.stringify(value)}'
${isChecked ? 'checked' : ''}
id="${uniqueIndex}"
/>
<label for="${uniqueIndex}">${title || ''}</label>
</div>
</div>
`);
$checkbox.find('.check').on('change', function () {
shouldCheckAllBeChecked();
});
return $checkbox;
{/literal}
}
$('[data-badge]').each(function () {
const $this = $(this);
const badgeProps = $this.data('badge');
const $badge = createBadge(badgeProps.title, badgeProps.class, badgeProps.icon);
$this.replaceWith($badge);
});
$('[data-checkbox]').each(function () {
{literal}
const $this = $(this);
const checkboxProps = $this.data('checkbox');
const $checkbox = createCheckbox(
'checked' in $this.prop('dataset'),
$this.data('title'),
checkboxProps,
);
$this.replaceWith($checkbox);
{/literal}
});
const $_checkAllCheckboxes = $('[data-check-all]');
function shouldCheckAllBeChecked() {
$_checkAllCheckboxes.each(function () {
const $this = $(this);
if ($('[data-section-id][data-section-id!=""]').length === 0) {
$this.parent('.checkbox').hide();
return;
}
$this.parent('.checkbox').show();
this.checked = $(`[data-slider-position="${ldelim}$this.data('check-all'){rdelim}"] .check:not(:checked)`).length === 0;
});
}
$(function () {
{literal}
$_checkAllCheckboxes.on('change', function () {
$(`[data-slider-position="${this.dataset.checkAll}"] .check`).prop('checked', this.checked);
});
shouldCheckAllBeChecked();
const { prepareRuntime, mountAutocomplete } = wpj.SectionsAutocomplete;
const container = $('[data-sections-autocomplete]').get(0);
prepareRuntime().then(() => mountAutocomplete(container, {
onAddSection: checkAndAddSection,
onAddWithSubsections: addWithSubsections,
}));
{/literal}
});
{/block}
</script>