Initial Upload
This commit is contained in:
495
views/xibo-audience-connector-form-javascript.twig
Normal file
495
views/xibo-audience-connector-form-javascript.twig
Normal file
@@ -0,0 +1,495 @@
|
||||
{#
|
||||
/**
|
||||
* Copyright (C) 2022 Xibo Signage Ltd
|
||||
*
|
||||
* Xibo - Digital Signage - http://www.xibo.org.uk
|
||||
*
|
||||
* This file is part of Xibo.
|
||||
*
|
||||
* Xibo is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* Xibo is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Xibo. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#}
|
||||
{% import "forms.twig" as forms %}
|
||||
<script type="text/javascript" nonce="{{ cspNonce }}">
|
||||
{% autoescape "js" %}
|
||||
window.audienceDaysOfWeek = {
|
||||
1: "{{ "Monday"|trans }}",
|
||||
2: "{{ "Tuesday"|trans }}",
|
||||
3: "{{ "Wednesday"|trans }}",
|
||||
4: "{{ "Thursday"|trans }}",
|
||||
5: "{{ "Friday"|trans }}",
|
||||
6: "{{ "Saturday"|trans }}",
|
||||
7: "{{ "Sunday"|trans }}",
|
||||
};
|
||||
{% endautoescape %}
|
||||
|
||||
window.audienceFormOpen = function($audienceConnector) {
|
||||
// Make a datatable
|
||||
var dialog = $audienceConnector.closest('.modal');
|
||||
var $table = $('#audience-dma');
|
||||
var audienceDmaTable;
|
||||
audienceDmaTable = $table.DataTable({
|
||||
language: dataTablesLanguage,
|
||||
dom: dataTablesTemplate,
|
||||
serverSide: false,
|
||||
stateSave: false,
|
||||
responsive: true,
|
||||
filter: true,
|
||||
searchDelay: 3000,
|
||||
order: [[ 0, 'asc']],
|
||||
ajax: {
|
||||
url: $table.data('proxyUrl').replace(':method', 'dmaSearch'),
|
||||
data: function (d) {
|
||||
$.extend(d, $table.closest('.XiboGrid').find('.FilterDiv form').serializeObject());
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{ data: 'name', responsivePriority: 1 },
|
||||
{ data: 'costPerPlay', responsivePriority: 1 },
|
||||
{ data: 'impressionsPerPlay', responsivePriority: 1 },
|
||||
{ data: 'impressionSource', responsivePriority: 10 },
|
||||
{
|
||||
data: 'startDate',
|
||||
responsivePriority: 2,
|
||||
render: function(data, type) {
|
||||
if (type !== 'display' && type !== 'export' || data == null) {
|
||||
return data;
|
||||
}
|
||||
|
||||
return moment(data, systemDateFormat).format(jsDateOnlyFormat);
|
||||
},
|
||||
},
|
||||
{
|
||||
data: 'endDate',
|
||||
responsivePriority: 2,
|
||||
render: function(data, type) {
|
||||
if (type !== 'display' && type !== 'export' || data == null) {
|
||||
return data;
|
||||
}
|
||||
|
||||
return moment(data, systemDateFormat).format(jsDateOnlyFormat);
|
||||
},
|
||||
},
|
||||
{
|
||||
data: 'daysOfWeek',
|
||||
responsivePriority: 2,
|
||||
render: function(data) {
|
||||
let daysOfWeek = [];
|
||||
$.each(data, function(index, el) {
|
||||
daysOfWeek.push(audienceDaysOfWeek[el]);
|
||||
});
|
||||
return daysOfWeek.join(', ');
|
||||
},
|
||||
},
|
||||
{ data: 'startTime', responsivePriority: 2 },
|
||||
{ data: 'endTime', responsivePriority: 2 },
|
||||
{
|
||||
data: 'geoFence',
|
||||
responsivePriority: 3,
|
||||
render: function(data) {
|
||||
let icon;
|
||||
if (data && data.length > 0)
|
||||
icon = "fa-check";
|
||||
else
|
||||
icon = "fa-times";
|
||||
|
||||
return '<span class="fa ' + icon + '"></span>';
|
||||
},
|
||||
},
|
||||
{ data: 'priority', responsivePriority: 2 },
|
||||
{
|
||||
data: function(data) {
|
||||
if (data.displays) {
|
||||
return data.displays.length;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
responsivePriority: 1,
|
||||
},
|
||||
{
|
||||
data: function(data, type, set, meta) {
|
||||
if (type !== 'display') {
|
||||
return '';
|
||||
}
|
||||
return '<a class="btn btn-sm" href="#" id="addDmaBtn"><span class="fa fa-pencil" title="{% trans %}Edit{% endtrans %}"></span></a>'
|
||||
+ '<a class="btn btn-sm" href="#" id="delDmaBtn"><span class="fa fa-trash" title="{% trans %}Delete{% endtrans %}"></span></a>';
|
||||
},
|
||||
responsivePriority: 1,
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
table.on('draw', dataTableDraw);
|
||||
table.on('processing.dt', dataTableProcessing);
|
||||
|
||||
// Add button
|
||||
new $.fn.dataTable.Buttons(audienceDmaTable, {
|
||||
buttons: [
|
||||
{
|
||||
text: '{{ "Add DMA"|trans }}',
|
||||
action: function (e, dt, node, config) {
|
||||
openDmaForm();
|
||||
},
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
audienceDmaTable.buttons().container().css('margin-bottom', '10px').appendTo('#audience-dma_wrapper .dataTables_folder');
|
||||
|
||||
setTimeout(function() {
|
||||
audienceDmaTable.columns.adjust()
|
||||
}, 500);
|
||||
|
||||
// Handle btn click
|
||||
$('#ssp-activity tbody').on('click', 'a', function (e) {
|
||||
let btnType = $(this).attr('id');
|
||||
let id = table.row(e.target.closest('tr')).index();
|
||||
|
||||
if (btnType === 'addDmaBtn') {
|
||||
openDmaForm(id);
|
||||
} else if (btnType === 'delDmaBtn') {
|
||||
deleteDmaForm(id);
|
||||
}
|
||||
});
|
||||
|
||||
// Add an add button.
|
||||
var dmaTemplate = Handlebars.compile($('#xibo-audience-connector-dma-form').html());
|
||||
window.openDmaForm = function(id = null) {
|
||||
let title;
|
||||
let method;
|
||||
let dma;
|
||||
if (id !== null) {
|
||||
dma = audienceDmaTable.rows(id).data()[0];
|
||||
title = '{{ "Edit DMA"|trans }}';
|
||||
method = 'dmaEdit';
|
||||
} else {
|
||||
title = '{{ "Add DMA"|trans }}';
|
||||
method = 'dmaAdd';
|
||||
}
|
||||
|
||||
bootbox.hideAll();
|
||||
const $dialog = bootbox.dialog({
|
||||
message: dmaTemplate({
|
||||
connectorId: $table.data('connectorId'),
|
||||
method: method,
|
||||
dma: dma,
|
||||
impressionSources: $table.data('impressionSources'),
|
||||
}),
|
||||
title: title,
|
||||
animate: false,
|
||||
size: 'large',
|
||||
buttons: {
|
||||
back: {
|
||||
label: '{{ "Back"|trans }}',
|
||||
className: 'btn-white',
|
||||
callback: function() {
|
||||
// Open up the connector config form.
|
||||
bootbox.hideAll();
|
||||
$('[data-connector-class-name-last="XiboAudienceReportingConnector"]').find('.btn-primary').click();
|
||||
}
|
||||
},
|
||||
save: {
|
||||
label: '{{ "Save"|trans }}',
|
||||
className: 'btn-success',
|
||||
callback: function() {
|
||||
// Submit the form in the usual way, and then open up the connector config form.
|
||||
const $form = $dialog.find('form');
|
||||
const button = $dialog.find('.btn-success');
|
||||
button.addClass('disabled').append('<span class="saving fa fa-cog fa-spin p-1"></span>');
|
||||
|
||||
XiboFormSubmit($form, null, function(xhr) {
|
||||
if (xhr.success === false) {
|
||||
button.removeClass('disabled').find('.saving').remove();
|
||||
} else {
|
||||
bootbox.hideAll();
|
||||
$('[data-connector-class-name-last="XiboAudienceReportingConnector"]').find('.btn-primary').click();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
onShown: function(e) {
|
||||
const $form = $(e.target).find('form');
|
||||
|
||||
// Before we initialise we work out if we need to set the initial key/value on the displayGroupId
|
||||
// select list.
|
||||
const $displayGroupId = $form.find('select[name=displayGroupId]');
|
||||
if (dma && dma.displayGroupId) {
|
||||
$displayGroupId.attr('data-initial-key', 'displayGroupId');
|
||||
$displayGroupId.attr('data-initial-value', dma.displayGroupId);
|
||||
}
|
||||
|
||||
// Initialise general fields.
|
||||
XiboInitialise('#' + $form.attr('id'));
|
||||
|
||||
const $daysOfWeek = $form.find('select[name="daysOfWeek[]"]');
|
||||
if (dma && dma.daysOfWeek) {
|
||||
$.each(dma.daysOfWeek, function(index, element) {
|
||||
$daysOfWeek.find('option[value=' + element + ']')
|
||||
.attr('selected', 'selected');
|
||||
});
|
||||
}
|
||||
$daysOfWeek.select2({width: '100%'}).val();
|
||||
|
||||
// Map
|
||||
// ---
|
||||
const getDataProperty = function($element, property, defaultValue = null) {
|
||||
const value = $element.data(property);
|
||||
if (value) {
|
||||
return value;
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
const $containerSelector = $form.find('#audience-dma-map');
|
||||
const $geoFenceField = $form.find('input[name="geoFence"]');
|
||||
if (dma && dma.geoFence) {
|
||||
$geoFenceField.val(JSON.stringify(dma.geoFence));
|
||||
}
|
||||
|
||||
let map = null;
|
||||
$(e.target).find('a[data-toggle="tab"]').on('shown.bs.tab', function (event) {
|
||||
if ($(event.target).attr('href') === '#tab-geo' && map === null) {
|
||||
map = L.map('audience-dma-map').setView(
|
||||
[
|
||||
getDataProperty($containerSelector, 'mapLat', '51'),
|
||||
getDataProperty($containerSelector, 'mapLong', '0.4'),
|
||||
],
|
||||
getDataProperty($containerSelector, 'mapZoom', 13),
|
||||
);
|
||||
|
||||
L.tileLayer(getDataProperty($containerSelector, 'mapTileServer'), {
|
||||
attribution: getDataProperty(
|
||||
$containerSelector,
|
||||
'mapAttribution',
|
||||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
||||
),
|
||||
subdomains: ['a', 'b', 'c'],
|
||||
}).addTo(map);
|
||||
|
||||
// Add a layer for drawn items
|
||||
const drawnItems = new L.FeatureGroup();
|
||||
map.addLayer(drawnItems);
|
||||
|
||||
// Add draw control (toolbar)
|
||||
const drawControl = new L.Control.Draw({
|
||||
position: 'topright',
|
||||
draw: {
|
||||
polyline: false,
|
||||
circle: false,
|
||||
marker: false,
|
||||
circlemarker: false,
|
||||
},
|
||||
edit: {
|
||||
featureGroup: drawnItems,
|
||||
},
|
||||
});
|
||||
|
||||
map.addControl(drawControl);
|
||||
|
||||
// add search Control - allows searching by country/city and automatically
|
||||
// moves map to that location
|
||||
const searchControl = new L.Control.Search({
|
||||
url: 'https://nominatim.openstreetmap.org/search?format=json&q={s}',
|
||||
jsonpParam: 'json_callback',
|
||||
propertyName: 'display_name',
|
||||
propertyLoc: ['lat', 'lon'],
|
||||
marker: L.circleMarker([0, 0], {radius: 30}),
|
||||
autoCollapse: true,
|
||||
autoType: false,
|
||||
minLength: 2,
|
||||
hideMarkerOnCollapse: true,
|
||||
firstTipSubmit: true,
|
||||
});
|
||||
|
||||
map.addControl(searchControl);
|
||||
|
||||
// Draw events
|
||||
map.on('draw:created', function(e) {
|
||||
drawnItems.addLayer(e.layer);
|
||||
$geoFenceField.val(JSON.stringify(drawnItems.toGeoJSON()));
|
||||
});
|
||||
map.on('draw:edited', function(e) {
|
||||
$geoFenceField.val(JSON.stringify(drawnItems.toGeoJSON()));
|
||||
});
|
||||
map.on('draw:deleted', function(e) {
|
||||
e.layers.eachLayer(function(layer) {
|
||||
drawnItems.removeLayer(layer);
|
||||
});
|
||||
$geoFenceField.val(JSON.stringify(drawnItems.toGeoJSON()));
|
||||
});
|
||||
|
||||
// Load existing geoJSON
|
||||
if (dma && dma.geoFence) {
|
||||
L.geoJSON(dma.geoFence, {
|
||||
onEachFeature: function(feature, layer) {
|
||||
drawnItems.addLayer(layer);
|
||||
map.fitBounds(drawnItems.getBounds());
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.deleteDmaForm = function(id) {
|
||||
const dma = audienceDmaTable.rows(id).data()[0];
|
||||
bootbox.hideAll();
|
||||
bootbox.confirm({
|
||||
message: '{{ "Are you sure you want to delete this DMA?"|trans }}',
|
||||
buttons: {
|
||||
confirm: {
|
||||
label: '{{ "Yes"|trans }}',
|
||||
className: 'btn-success',
|
||||
},
|
||||
cancel: {
|
||||
label: '{{ "No"|trans }}',
|
||||
className: 'btn-danger',
|
||||
},
|
||||
},
|
||||
callback: function (result) {
|
||||
if (result) {
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: $table.data('proxyUrl').replace(':method', 'dmaDelete') + '?_id=' + dma._id,
|
||||
success: function(xhr) {
|
||||
if (xhr && !xhr.success) {
|
||||
toastr.error(xhr.message);
|
||||
} else {
|
||||
SystemMessage('{{ "DMA deleted"|trans }}', true);
|
||||
}
|
||||
},
|
||||
error: function(xhr, textStatus, errorThrown) {
|
||||
toastr.error(xhr.message);
|
||||
},
|
||||
complete: function() {
|
||||
$('[data-connector-class-name-last="XiboAudienceReportingConnector"]').find('.btn-primary').click();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$('[data-connector-class-name-last="XiboAudienceReportingConnector"]').find('.btn-primary').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script type="text/x-handlebars-template" id="xibo-audience-connector-dma-form">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li class="nav-item"><a class="nav-link active" href="#tab-general" role="tab" data-toggle="tab"><span>{% trans "General" %}</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#tab-dates" role="tab" data-toggle="tab"><span>{% trans "Date/Time" %}</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#tab-geo" role="tab" data-toggle="tab"><span>{% trans "Geofence" %}</span></a></li>
|
||||
</ul>
|
||||
<form id="{{ random() }}" class="form-horizontal" action="{{ url_for("connector.edit.form.proxy", {id: "{{connectorId}}", method: "{{method}}"}) }}" method="POST">
|
||||
<input type="hidden" name="_id" value="{% verbatim %}{{ dma._id }}{% endverbatim %}">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="tab-general">
|
||||
{% set title %}{% trans "Name" %}{% endset %}
|
||||
{% set helpText %}{% trans "The Name of this DMA - (1 - 50 characters)" %}{% endset %}
|
||||
{{ forms.input("name", title, "{{dma.name}}", helpText) }}
|
||||
|
||||
{% set title %}{% trans "Priority" %}{% endset %}
|
||||
{% set helpText %}{% trans "Set a priority for this DMA. Higher priorities take precedence." %}{% endset %}
|
||||
{{ forms.number("priority", title, "{{dma.priority}}", helpText) }}
|
||||
|
||||
{% set title %}{% trans "Display Group" %}{% endset %}
|
||||
{% set helpText %}{% trans "Which displays would you like this DMA to apply to?" %}{% endset %}
|
||||
{% set attributes = [
|
||||
{ name: "data-width", value: "200px" },
|
||||
{ name: "data-allow-clear", value: "true" },
|
||||
{ name: "data-placeholder--id", value: null },
|
||||
{ name: "data-placeholder--value", value: "" },
|
||||
{ name: "data-search-url", value: url_for("displayGroup.search") },
|
||||
{ name: "data-search-term", value: "displayGroup" },
|
||||
{ name: "data-search-term-tags", value: "tags" },
|
||||
{ name: "data-id-property", value: "displayGroupId" },
|
||||
{ name: "data-text-property", value: "displayGroup" },
|
||||
] %}
|
||||
{{ forms.dropdown("displayGroupId", "single", title, null, null, "displayGroupId", "displayGroup", helpText, "pagedSelect", "", "d", "", attributes) }}
|
||||
|
||||
{% set title %}{% trans "Cost per Play" %}{% endset %}
|
||||
{% set helpText %}{% trans "The cost per play" %}{% endset %}
|
||||
{{ forms.input("costPerPlay", title, "{{dma.costPerPlay}}", helpText) }}
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-2 control-label" for="field-impression-source">
|
||||
{{ "Impression Source"|trans }}
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control" name="impressionSource" id="field-impression-source">{% verbatim %}
|
||||
{{#each impressionSources}}
|
||||
<option name="{{value}}"{{#eq value dma.impressionSource }} selected{{/eq}}>{{name}}</option>
|
||||
{{/each}}
|
||||
{% endverbatim %}</select>
|
||||
<small class="form-text text-muted">{{ "What is the source of this impression figure?"|trans }}</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% set title %}{% trans "Impressions per play" %}{% endset %}
|
||||
{% set helpText %}{% trans "The impressions per play" %}{% endset %}
|
||||
{{ forms.number("impressionsPerPlay", title, "{{dma.impressionsPerPlay}}", helpText) }}
|
||||
</div>
|
||||
<div class="tab-pane" id="tab-dates">
|
||||
{% set title %}{% trans "Start Date" %}{% endset %}
|
||||
{% set helpText %}{% trans "Select the start date for this DMA" %}{% endset %}
|
||||
{{ forms.date("startDate", title, "{{dma.startDate}}", helpText, "starttime-control", "", "") }}
|
||||
|
||||
{% set title %}{% trans "End Date" %}{% endset %}
|
||||
{% set helpText %}{% trans "Select the end date for this DMA" %}{% endset %}
|
||||
{{ forms.date("endDate", title, "{{dma.endDate}}", helpText, "endtime-control", "", "") }}
|
||||
|
||||
{% set title %}{% trans "Days of the week" %}{% endset %}
|
||||
{% set helpText %}{% trans "Which days of the week should the DMA be active?" %}{% endset %}
|
||||
{% set options = [
|
||||
{ id: 1, name: "Monday"|trans },
|
||||
{ id: 2, name: "Tuesday"|trans },
|
||||
{ id: 3, name: "Wednesday"|trans },
|
||||
{ id: 4, name: "Thursday"|trans },
|
||||
{ id: 5, name: "Friday"|trans },
|
||||
{ id: 6, name: "Saturday"|trans },
|
||||
{ id: 7, name: "Sunday"|trans },
|
||||
] %}
|
||||
{{ forms.dropdown("daysOfWeek[]", "dropdownmulti", title, null, options, "id", "name", helpText) }}
|
||||
|
||||
{% set title %}{% trans "Start Time" %}{% endset %}
|
||||
{% set helpText %}{% trans "Select the start time for this DMA" %}{% endset %}
|
||||
{{ forms.time("startTime", title, "{{dma.startTime}}", helpText, "starttime-control", "", "") }}
|
||||
|
||||
{% set title %}{% trans "End Time" %}{% endset %}
|
||||
{% set helpText %}{% trans "Select the end time for this DMA" %}{% endset %}
|
||||
{{ forms.time("endTime", title, "{{dma.endTime}}", helpText, "endtime-control", "", "") }}
|
||||
</div>
|
||||
<div class="tab-pane" id="tab-geo">
|
||||
{{ forms.hidden("geoFence", "{{dma.geoFence}}") }}
|
||||
|
||||
{{ forms.message("Draw areas on the map where you want this DMA to be active."|trans) }}
|
||||
|
||||
<div id="audience-dma-map"
|
||||
data-map-tile-server="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
data-map-lat="{{ settings.DEFAULT_LAT }}"
|
||||
data-map-long="{{ settings.DEFAULT_LONG }}"
|
||||
data-map-zoom="13"
|
||||
style="height: 500px; width: 100%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
Reference in New Issue
Block a user