Initial Upload

This commit is contained in:
Matt Batchelder
2025-12-02 10:32:59 -05:00
commit 05ce0da296
2240 changed files with 467811 additions and 0 deletions

View File

@@ -0,0 +1,385 @@
{#
/**
* Copyright (C) 2020 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/>.
*/
#}
<script type="text/javascript" nonce="{{ cspNonce }}">
/**
* Setup Display Profile setting forms
*/
function displayProfileFormOpen() {
// TIMERS
setupFormFields(
$('#timers-container'),
Handlebars.compile($('#template-timers').html()),
$('#timers-container').data('values'),
$('#timers-container').data('options'),
timersFormInit,
timersFormInit
);
// PICTURE OPTIONS
setupFormFields(
$('#picture-options-container'),
Handlebars.compile($('#template-picture-options').html()),
$('#picture-options-container').data('values'),
$('#picture-options-container').data('options'),
pictureOptionsFormInit,
pictureOptionsFormUpdate
);
// Android location field
setAndroidDimensions($('.tab-pane#location'));
// Popovers
$('[data-toggle="popover"]').popover();
}
/**
* Android dimension field
* @param {jquery} container
*/
function setAndroidDimensions($container) {
const $inputField = $container.find('#screenDimensions');
const template = Handlebars.compile($('#android-dimension-fields').html());
// Prevent to run if screen dimensions does not exist
if($inputField.length <= 0){
return;
}
let fieldsTemplate;
// Hide input
$inputField.attr('type', 'hidden');
// Parse value if exists and assign it to the elements
if($inputField.val() != "") {
let values = $inputField.val().split(',');
fieldsTemplate = template({
top: values[0],
left: values[1],
width: values[2],
height: values[3]
});
} else {
fieldsTemplate = template();
}
// Add fields to parent container
$inputField.parent().prepend(fieldsTemplate);
// Initialise values
$container.on('change', '.androidDimensionInput', function() {
// Get all separated values
var valueLeft = $container.find('#dimensionLeft').val();
var valueTop = $container.find('#dimensionTop').val();
var valueWidth = $container.find('#dimensionWidth').val();
var valueHeight = $container.find('#dimensionHeight').val();
// Set default colour
$('.androidDimensionInput').css('background-color', '#fff');
// Set value to hidden input
if(valueLeft != '' && valueTop != '' && valueWidth != '' && valueWidth >= 0 && valueHeight != '' && valueHeight >= 0) {
$inputField.val([valueLeft, valueTop, valueWidth, valueHeight].toString());
} else {
// Invalid value
$inputField.val('');
// If some of the elements aren't empty and it's invalid, show a specific background
if(valueLeft != '' || valueTop != '' || valueWidth != '' || valueHeight != ''){
$('.androidDimensionInput').css('background-color', '#ffce9c');
}
}
});
}
/**
* Setup form dynamic fields
* @param {jquery} container
* @param {hbstemplate} template
* @param {Object} values - Defined values
* @param {Object} options - All the options
*/
function setupFormFields(container, template, values, options, callbackFuncInit, callbackFuncUpdate) {
// Prevent forms to setup inexisting fields
if(container.length === 0) {
return;
}
if(Object.keys(values).length == 0) {
// Add a template row
var context = {
options: options,
index: 1,
name: "",
values: {},
buttonGlyph: "fa-plus"
};
container.append(template(context));
} else {
// For each of the existing codes, create form components
var i = 0;
$.each(values, function(index, values) {
i++;
var context = {
options: options,
index: i,
name: index,
values: values,
buttonGlyph: ((i == 1) ? "fa-plus" : "fa-minus")
};
container.append(template(context));
});
}
// Button click handle
container.on("click", "button", function(e) {
e.preventDefault();
// find the gylph
if($(this).find("i").hasClass("fa-plus")) {
var context = {
options: options,
index: container.find('.multiSelect:last').data('index') + 1,
name: "",
values: {},
buttonGlyph: "fa-minus"
};
// Append new object to container
container.append(template(context));
// Initialize form fields
callbackFuncUpdate(container, options, values);
} else {
// Remove this row
$(this).closest(".form-group").remove();
}
});
// Initialize form fields
callbackFuncInit(container, options, values);
}
/**
* Init/Update timePicker fields
*/
function timersFormInit(container) {
var customTimeFormat = 'HH:mm';
container.find('.input-group:not(.timerInit) .timePickerDisplayEditForm').each(function() {
if(calendarType == 'Jalali') {
initDatePicker(
$(this),
customTimeFormat,
customTimeFormat,
{
onlyTimePicker: true,
format: customTimeFormat,
timePicker: {
second: {
enabled: false
}
},
altFieldFormatter: function(unixTime) {
var newDate = moment.unix(unixTime / 1000);
newDate.set('second', 0);
return newDate.format(customTimeFormat);
}
}
);
} else {
initDatePicker(
$(this),
customTimeFormat,
customTimeFormat,
{
enableTime: true,
noCalendar: true,
time_24hr: true,
altFormat: customTimeFormat
}
);
}
$(this).parent().addClass('timerInit');
});
}
/**
* Initialise all form fields
*/
function pictureOptionsFormInit(container, options, values) {
container.find('.multiSelect').each(function() {
pictureOptionsFormChangeInputs($(this).val(), $(this).closest('.row'), options[$(this).val()], values);
});
container.on('change', '.multiSelect', function() {
pictureOptionsFormChangeInputs($(this).val(), $(this).closest('.row'), options[$(this).val()], values);
});
}
/**
* Update the last added field
*/
function pictureOptionsFormUpdate(container, options, values) {
container.find('.multiSelect:last').each(function() {
pictureOptionsFormChangeInputs($(this).val(), $(this).closest('.row'), options[$(this).val()], values);
});
}
/**
* Populate and create the slider
*/
function pictureOptionsFormChangeInputs(selProperty, row, propertyOptions, values) {
if(selProperty == undefined || selProperty == '') {
row.find('.multiSelectInputs').html(Handlebars.compile($('#template-picture-options-none').html())());
return;
}
// Add empty template to the container
var template = Handlebars.compile($('#template-picture-options-slider').html());
row.find('.multiSelectInputs').html(template({
index: row.find('.multiSelect').data('index')
}));
var propertyValue = values[selProperty];
var sliderOptions = propertyOptions.sliderOptions;
// Find respective index
if(typeof(propertyValue) == "string") {
for (var index = 0; index < sliderOptions.ticks_labels.length; index++) {
var label = sliderOptions.ticks_labels[index];
if(label == propertyValue) {
propertyValue = index;
}
}
}
// Set value to the options
sliderOptions.value = ((propertyValue != undefined) ? propertyValue : 0);
// Init slider
row.find('.pictureControlsSlider').bootstrapSlider(sliderOptions);
// Refresh on tab switch to fix broken labels
$('a[data-toggle="tab"]').on('shown.bs.tab', function() {
row.find('.pictureControlsSlider').bootstrapSlider('refresh', { useCurrentValue: true });
});
}
// Equals helper for the templates below
Handlebars.registerHelper('eq', function(v1, v2, opts) {
if (v1 === v2) {
return opts.fn(this);
} else {
return opts.inverse(this);
}
});
</script>
<style>
/*
* Slider width fix
*/
.slider:not(.scaled-slider) {
width: 100% !important;
}
</style>
{% verbatim %}
<script type="text/x-handlebars-template" id="template-timers">
<div class="form-group col-sm-12 row form-group-timers">
<div class="col-sm-1">
<button type="button" class="btn btn-white"><i class="fa {{ buttonGlyph }}"></i></button>
</div>
<div class="col-sm-5">
<select class="form-control multiSelect" name="timers[{{ index }}][day]" data-index="{{ index }}">
<option value=""></option>
{{#each options}}
<option value="{{ id }}" {{#eq id ../name}} selected{{/eq}}>{{ name }}</option>
{{/each}}
</select>
</div>
<div class="col-sm-3 multiSelectInputs">
<div class="input-group">
<input class="form-control timePickerDisplayEditForm timersOn" type="text" name="timers[{{ index }}][on]" id="timersOn{{ index }}" value="{{ values.on }}" />
<span class="input-group-addon date-clear-button d-none" role="button"><i class="fa fa-times"></i></span>
</div>
</div>
<div class="col-sm-3 multiSelectInputs">
<div class="input-group">
<input class="form-control timePickerDisplayEditForm timersOff" type="text" name="timers[{{ index }}][off]" id="timersOff{{ index }}" value="{{ values.off }}" />
<span class="input-group-addon date-clear-button d-none" role="button"><i class="fa fa-times"></i></span>
</div>
</div>
</div>
</script>
<script type="text/x-handlebars-template" id="template-picture-options">
<div class="form-group col-sm-12 row form-group-picture-options">
<div class="col-sm-1">
<button type="button" class="btn btn-white"><i class="fa {{ buttonGlyph }}"></i></button>
</div>
<div class="col-sm-5">
<select class="form-control multiSelect" name="pictureControls[{{ index }}][property]" data-index="{{ index }}">
<option value=""></option>
{{#each options}}
<option value="{{@key}}" {{#eq @key ../name}} selected{{/eq}}>{{ name }}</option>
{{/each}}
</select>
</div>
<div class="col-sm-6 multiSelectInputs">
{% endverbatim %}
<p class="btn btn-block btn-primary" disabled>{% trans "Select a property to display inputs" %}</p>
{% verbatim %}
</div>
</div>
</script>
<script type="text/x-handlebars-template" id="template-picture-options-slider">
<input type="text" class="pictureControlsSlider" name="pictureControls[{{ index }}][value]"/>
</script>
<script type="text/x-handlebars-template" id="template-picture-options-none">
{% endverbatim %}
<p class="btn btn-block btn-primary" disabled>{% trans "Select a property to display inputs" %}</p>
{% verbatim %}
</script>
<script type="text/x-handlebars-template" id="android-dimension-fields">
<div class="row">
<input type="number" value="{{ top }}" class="col-3 form-control androidDimensionInput" name="dimensionTop" id="dimensionTop" placeholder="{% endverbatim %}{{ "Top"|trans }}{% verbatim %}"></input>
<input type="number" value="{{ left }}" class="col-3 form-control androidDimensionInput" name="dimensionLeft" id="dimensionLeft" placeholder="{% endverbatim %}{{ "Left"|trans }}{% verbatim %}"></input>
<input type="number" value="{{ width }}" class="col-3 form-control androidDimensionInput" min="0" name="dimensionWidth" id="dimensionWidth" placeholder="{% endverbatim %}{{ "Width"|trans }}{% verbatim %}"></input>
<input type="number" value="{{ height }}" class="col-3 form-control androidDimensionInput" min="0" name="dimensionHeight" id="dimensionHeight" placeholder="{% endverbatim %}{{ "Height"|trans }}{% verbatim %}"></input>
<div class="d-flex validation-error-container flex-column p-1 m-0 text-left"></div>
</div>
</script>
{% endverbatim %}