Merge pull request #111 from jr-k/develop

Release v2.0.3
This commit is contained in:
JRK 2024-07-18 17:21:11 +02:00 committed by GitHub
commit 94c4ad1bb2
24 changed files with 266 additions and 222 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@ jQuery(document).ready(function ($) {
if (confirm(l.js_sysinfo_restart_confirmation)) {
$('body').html($('<div class="reboot">').html(l.js_sysinfo_restart_loading)).css({margin:200});
$.ajax({
url: '/sysinfo/restart?secret_key='+secret_key,
url: route_sysinfo_restart + '?secret_key='+secret_key,
headers: {'Content-Type': 'application/json'},
data: '',
method: 'POST',

View File

@ -1,13 +1,14 @@
jQuery(document).ready(function ($) {
const loadDateTimePicker = function ($els) {
const loadDateTimePicker = function ($els, timeOnly) {
const d = new Date();
$els.each(function () {
var $el = $(this);
$el.flatpickr({
const options = {
enableTime: true,
time_24hr: true,
allowInput: false,
noCalendar: false,
allowInvalidPreload: false,
dateFormat: 'Y-m-d H:i',
defaultHour: d.getHours(),
@ -19,9 +20,15 @@ jQuery(document).ready(function ($) {
d ? `${d.getMinutes()} ${d.getHours()} ${d.getDate()} ${(d.getMonth() + 1)} * ${d.getFullYear()}` : ''
);
}
});
};
if (timeOnly) {
options['noCalendar'] = true;
}
$el.flatpickr(options);
$el.addClass('hidden');
})
});
};
const getId = function ($el) {
@ -36,31 +43,12 @@ jQuery(document).ready(function ($) {
$.ajax({
method: 'POST',
url: '/slideshow/slide/position',
url: route_slide_position,
headers: {'Content-Type': 'application/json'},
data: JSON.stringify(positions),
});
};
const inputTypeUpdate = function () {
const $modal = $('.modal-slide:visible');
const $el = $('#slide-add-type');
const value = $el.val();
const inputType = $el.find('option').filter(function (i, el) {
return $(el).val() === value;
}).data('input');
if ($modal.find('.picker:visible').length === 0) {
$('.slide-add-object-input')
.addClass('hidden')
.prop('disabled', true).prop('required', false)
.filter('#slide-add-object-input-' + inputType)
.removeClass('hidden')
.prop('disabled', false).prop('required', true)
;
}
};
const inputSchedulerUpdate = function () {
const $modal = $('.modal-slide:visible');
const $scheduleStartGroup = $modal.find('.slide-schedule-group');
@ -76,48 +64,24 @@ jQuery(document).ready(function ($) {
const $datetimepickerStart = $scheduleStartGroup.find('.datetimepicker');
const $datetimepickerEnd = $scheduleEndGroup.find('.datetimepicker');
const $isNotification = $isNotificationGroup.find('.trigger');
const $isNotification = $modal.find('#slide-edit-is-notification');
const isNotification = $isNotification.prop('checked');
const isNotification = $isNotification.val() === '1';
let isLoopStart = $triggerStart.val() === 'loop';
let isCronStart = $triggerStart.val() === 'cron';
function updateScheduleChoices(isNotification, isLoopStart, isCronStart) {
let scheduleStartChoices = $.extend({}, schedule_start_choices);
let scheduleEndChoices = $.extend({}, schedule_end_choices);
if (!isNotification || isLoopStart) {
delete scheduleStartChoices['cron'];
delete scheduleEndChoices['duration'];
}
if (isNotification) {
delete scheduleStartChoices['loop'];
delete scheduleEndChoices['stayloop'];
if (isCronStart) {
delete scheduleEndChoices['datetime'];
}
}
return {scheduleStartChoices, scheduleEndChoices};
}
function applyChoices() {
const {
scheduleStartChoices,
scheduleEndChoices
} = updateScheduleChoices(isNotification, isLoopStart, isCronStart);
recreateSelectOptions($triggerStart, scheduleStartChoices);
recreateSelectOptions($triggerEnd, scheduleEndChoices);
}
applyChoices();
const choice_map = choices_map[isNotification ? 'notification' : 'normal']
recreateSelectOptions($triggerStart, Object.keys(choice_map).reduce((obj, key) => {
obj[key] = choices_translations[key];
return obj;
}, {}));
recreateSelectOptions($triggerEnd, choice_map[$triggerStart.val()]);
isLoopStart = $triggerStart.val() === 'loop';
isCronStart = $triggerStart.val() === 'cron';
const isCronEnd = $triggerEnd.val() === 'cron';
const isInWeekMomentStart = $triggerStart.val() === 'inweek';
const isDatetimeStart = $triggerStart.val() === 'datetime';
const isDatetimeEnd = $triggerEnd.val() === 'datetime';
const isStayloopEnd = $triggerEnd.val() === 'stayloop';
@ -126,6 +90,7 @@ jQuery(document).ready(function ($) {
const flushValueStart = isLoopStart;
const flushValueEnd = isLoopStart || isStayloopEnd || isDurationEnd;
const flushDuration = isNotification && isDatetimeEnd;
const datetimepickerWithCalendar = !isInWeekMomentStart;
function toggleVisibility() {
$targetCronFieldStart.toggleClass('hidden', !isCronStart);
@ -155,9 +120,9 @@ jQuery(document).ready(function ($) {
}
}
loadDateTimePicker($modal.find('.datetimepicker'), datetimepickerWithCalendar);
toggleVisibility();
flushValues();
applyChoices();
};
@ -172,27 +137,12 @@ jQuery(document).ready(function ($) {
inputSchedulerUpdate();
});
$(document).on('change', '#slide-add-type', inputTypeUpdate);
// $(document).on('click', '.picker button', function () {
// const $parent = $(this).parents('.modal-slide-add');
// $parent.find('.picker').addClass('hidden').find('select').prop('disabled', true);
// $parent.find('.upload').removeClass('hidden').find('input,select').prop('disabled', false);
// inputTypeUpdate();
// });
$(document).on('click', '.slide-add', function () {
showModal('modal-slide-add');
const $modal = $('.modal-slide-add:visible');
loadDateTimePicker($modal.find('.datetimepicker'));
// $modal.find('.picker').removeClass('hidden').find('select').prop('disabled', false);
// $modal.find('.upload').addClass('hidden').find('input,select').prop('disabled', true);
// $modal.find('button[type=submit]').removeClass('hidden');
// $modal.find('.btn-loading').addClass('hidden');
inputTypeUpdate();
showModal($(this).attr('data-modal'));
const $modal = $('.modal-slide:visible');
inputSchedulerUpdate();
inputContentUpdate();
$('.modal-slide-add input:eq(0)').focus().select();
$modal.find('input[type=text]:visible:eq(0)').focus().select();
});
$(document).on('click', '.content-explr-picker', function () {
@ -226,7 +176,8 @@ jQuery(document).ready(function ($) {
$(document).on('click', '.slide-edit', function () {
const slide = JSON.parse($(this).parents('.slide-item:eq(0)').attr('data-entity'));
showModal('modal-slide-edit');
showModal($(this).attr('data-modal'));
const $modal = $('.modal-slide:visible');
const hasCron = slide.cron_schedule && slide.cron_schedule.length > 0;
const hasDateTime = hasCron && validateCronDateTime(slide.cron_schedule);
@ -237,26 +188,25 @@ jQuery(document).ready(function ($) {
inputContentUpdate(slide.content);
$('.modal-slide-edit input:visible:eq(0)').focus().select();
$('#slide-edit-duration').val(slide.duration);
$('#slide-edit-is-notification').prop('checked', isNotification);
$('#slide-edit-enabled').prop('checked', slide.enabled);
$modal.find('input[type=text]:visible:eq(0)').focus().select();
$modal.find('#slide-edit-duration').val(slide.duration);
$modal.find('#slide-edit-enabled').prop('checked', slide.enabled);
$('#slide-edit-cron-schedule').val(slide.cron_schedule).toggleClass('hidden', !hasCron || hasDateTime);
$('#slide-edit-cron-schedule-trigger').val(hasDateTime ? 'datetime' : (hasCron ? 'cron' : 'loop'));
$modal.find('#slide-edit-cron-schedule').val(slide.cron_schedule).toggleClass('hidden', !hasCron || hasDateTime);
$modal.find('#slide-edit-cron-schedule-trigger').val(hasDateTime ? 'datetime' : (hasCron ? 'cron' : 'loop'));
$('#slide-edit-cron-schedule-end').val(slide.cron_schedule_end).toggleClass('hidden', !hasCronEnd || hasDateTimeEnd);
$('#slide-edit-cron-schedule-end-trigger').val(hasDateTimeEnd ? 'datetime' : (hasCronEnd ? 'cron' : (isNotification ? 'duration' : 'stayloop')));
$modal.find('#slide-edit-cron-schedule-end').val(slide.cron_schedule_end).toggleClass('hidden', !hasCronEnd || hasDateTimeEnd);
$modal.find('#slide-edit-cron-schedule-end-trigger').val(hasDateTimeEnd ? 'datetime' : (hasCronEnd ? 'cron' : (isNotification ? 'duration' : 'stayloop')));
$('#slide-edit-cron-schedule-datetimepicker').toggleClass('hidden', !hasDateTime).val(
$modal.find('#slide-edit-cron-schedule-datetimepicker').toggleClass('hidden', !hasDateTime).val(
hasDateTime ? getCronDateTime(slide.cron_schedule) : ''
);
$('#slide-edit-cron-schedule-end-datetimepicker').toggleClass('hidden', !hasDateTimeEnd).val(
$modal.find('#slide-edit-cron-schedule-end-datetimepicker').toggleClass('hidden', !hasDateTimeEnd).val(
hasDateTimeEnd ? getCronDateTime(slide.cron_schedule_end) : ''
);
$('#slide-edit-id').val(slide.id);
loadDateTimePicker($('.modal-slide-edit .datetimepicker'));
$modal.find('#slide-edit-id').val(slide.id);
loadDateTimePicker($modal.find('.datetimepicker'));
inputSchedulerUpdate();
});
@ -280,7 +230,7 @@ jQuery(document).ready(function ($) {
}
});
$(document).on('submit', '.modal-slide-add form', function () {
$(document).on('submit', '.modal-slide form', function () {
$(this).find('button[type=submit]').addClass('hidden');
$(this).find('.btn-loading').removeClass('hidden');
});

View File

@ -57,7 +57,7 @@
h3 {
align-self: stretch;
margin: 0;
margin: 0 0 10px 0;
font-size: 14px;
display: flex;
flex-direction: row;

View File

@ -1,5 +1,13 @@
.view-playlist-list main .main-container {
.page-content {
.inner {
h3.divide {
margin-top: 50px;
}
}
}
.slides-holder {
ul.slides {

View File

@ -75,8 +75,11 @@
"playlist_button_add": "Add Playlist",
"playlist_button_delete": "Delete Playlist",
"playlist_panel_about_playlist": "About playlist",
"playlist_panel_content_management": "Content management",
"playlist_panel_content_management": "Playlist loop",
"playlist_panel_content_management_desc": "You can add, modify, delete and rearrange the order of contents from this list. Disabled slides will not play in the slideshow.",
"playlist_panel_content_management_notifications": "Playlist notifications",
"playlist_panel_content_management_notifications_desc": "Notifications are slides that appear on top of everything at a time and for a duration you choose. The order in which they appear below is irrelevant.",
"slideshow_slide_button_add_notification": "Add Notification",
"playlist_panel_preview": "Playlist preview",
"playlist_panel_preview_action": "Preview",
"playlist_panel_inactive": "Inactive playlists",

View File

@ -75,8 +75,11 @@
"playlist_button_add": "Agregar Playlist",
"playlist_button_delete": "Eliminar Playlist",
"playlist_panel_about_playlist": "Acerca de la playlist",
"playlist_panel_content_management": "Gestión de contenido",
"playlist_panel_content_management": "Bucle de playlist ",
"playlist_panel_content_management_desc": "Puedes agregar, modificar, eliminar y reorganizar el orden de los contenidos de esta lista. Las diapositivas deshabilitadas no se reproducirán en la presentación de diapositivas.",
"playlist_panel_content_management_notifications": "Notificaciones de listas de reproducción",
"playlist_panel_content_management_notifications_desc": "Las notificaciones son diapositivas que aparecen encima de todo en un momento y durante el tiempo que elijas. El orden en que aparecen a continuación es irrelevante.",
"slideshow_slide_button_add_notification": "Agregar notificación",
"playlist_panel_preview": "Vista previa de la playlist",
"playlist_panel_preview_action": "Avance",
"playlist_panel_inactive": "Playlist inactivas",

View File

@ -75,8 +75,11 @@
"playlist_button_add": "Ajouter Playlist",
"playlist_button_delete": "Supprimer Playlist",
"playlist_panel_about_playlist": "À propos de la playlist",
"playlist_panel_content_management": "Elements de la playlist",
"playlist_panel_content_management": "Boucle de la playlist",
"playlist_panel_content_management_desc": "Vous pouvez ajouter, modifier, supprimer et réorganiser l'ordre des contenus depuis cette liste. Les slides désactivées ne seront pas lues dans le diaporama.",
"playlist_panel_content_management_notifications": "Notifications de la playlist",
"playlist_panel_content_management_notifications_desc": "Les notifications sont des slides qui apparaissent au dessus de tout à un moment et pendant une durée que vous choisissez. L'ordre dans lequel elles apparaissent ci-dessous n'a aucune importance.",
"slideshow_slide_button_add_notification": "Ajouter une notification",
"playlist_panel_preview": "Playlist preview",
"playlist_panel_preview_action": "Prévisualiser",
"playlist_panel_inactive": "Playlist inactives",

View File

@ -75,8 +75,11 @@
"playlist_button_add": "Aggiungi Playlist",
"playlist_button_delete": "Elimina Playlist",
"playlist_panel_about_playlist": "Informazioni sulla playlist",
"playlist_panel_content_management": "Gestione dei contenuti",
"playlist_panel_content_management": "Ciclo della playlist",
"playlist_panel_content_management_desc": "Puoi aggiungere, modificare, eliminare e riorganizzare l'ordine dei contenuti da questo elenco. Le diapositive disabilitate non verranno riprodotte nella presentazione.",
"playlist_panel_content_management_notifications": "Notifiche playlist",
"playlist_panel_content_management_notifications_desc": "Le notifiche sono diapositive che appaiono sopra ogni cosa alla volta e per la durata da te scelta. L'ordine in cui appaiono di seguito è irrilevante.",
"slideshow_slide_button_add_notification": "Aggiungi notifica",
"playlist_panel_preview": "Anteprima della playlist",
"playlist_panel_preview_action": "Anteprima",
"playlist_panel_inactive": "Playlist inattive",

View File

@ -9,7 +9,7 @@ from src.model.entity.Slide import Slide
from src.exceptions.NoFallbackPlaylistException import NoFallbackPlaylistException
from src.service.ModelStore import ModelStore
from src.interface.ObController import ObController
from src.util.utils import get_safe_cron_descriptor, is_valid_cron_date_time, get_cron_date_time
from src.util.utils import get_safe_cron_descriptor, is_cron_calendar_moment, is_cron_in_day_moment, get_cron_date_time
from src.util.UtilNetwork import get_safe_remote_addr, get_network_interfaces
from src.model.enum.AnimationSpeed import animation_speed_duration
@ -144,14 +144,14 @@ class PlayerController(ObController):
else:
continue
has_valid_start_date = 'cron_schedule' in slide and slide['cron_schedule'] and get_safe_cron_descriptor(slide['cron_schedule']) and is_valid_cron_date_time(slide['cron_schedule'])
has_valid_end_date = 'cron_schedule_end' in slide and slide['cron_schedule_end'] and get_safe_cron_descriptor(slide['cron_schedule_end']) and is_valid_cron_date_time(slide['cron_schedule_end'])
has_valid_start_date = 'cron_schedule' in slide and slide['cron_schedule'] and get_safe_cron_descriptor(slide['cron_schedule']) and is_cron_calendar_moment(slide['cron_schedule'])
has_valid_end_date = 'cron_schedule_end' in slide and slide['cron_schedule_end'] and get_safe_cron_descriptor(slide['cron_schedule_end']) and is_cron_calendar_moment(slide['cron_schedule_end'])
if slide['is_notification'] and has_valid_start_date:
if slide['is_notification']:
if has_valid_start_date:
playlist_notifications.append(slide)
else:
logging.warn('Slide {} is notification but start date is invalid'.format(slide['name']))
logging.warn('Slide \'{}\' is a notification but start date is invalid'.format(slide['name']))
else:
if has_valid_start_date:
start_date = get_cron_date_time(slide['cron_schedule'], object=True)

View File

@ -40,7 +40,8 @@ class PlaylistController(ObController):
playlists=playlists,
durations=durations,
slides_with_content=slides_with_content,
slides=self._model_store.slide().get_slides(playlist_id=current_playlist.id) if current_playlist else [],
slides=self._model_store.slide().get_slides(playlist_id=current_playlist.id, is_notification=False) if current_playlist else [],
notifications=self._model_store.slide().get_slides(playlist_id=current_playlist.id, is_notification=True) if current_playlist else [],
foldered_contents=self._model_store.content().get_all_indexed('folder_id', multiple=True),
contents={content.id: {"id": content.id, "name": content.name, "type": content.type.value} for content in self._model_store.content().get_contents()},
working_folder_path=working_folder_path,

View File

@ -64,7 +64,7 @@ class SlideController(ObController):
content_id=request.form['content_id'],
enabled='enabled' in request.form and request.form['enabled'],
duration=request.form['duration'],
is_notification=True if 'is_notification' in request.form else False,
is_notification=True if 'is_notification' in request.form and request.form['is_notification'] == '1' else False,
cron_schedule=request.form['cron_schedule'],
cron_schedule_end=request.form['cron_schedule_end'],
)

View File

@ -87,12 +87,15 @@ class SlideManager(ModelManager):
for slide_id, edits in edits_slides.items():
self._db.update_by_id(self.TABLE_NAME, slide_id, edits)
def get_slides(self, playlist_id: Optional[int] = None, content_id: Optional[int] = None, enabled: Optional[bool] = None) -> List[Slide]:
def get_slides(self, playlist_id: Optional[int] = None, content_id: Optional[int] = None, enabled: Optional[bool] = None, is_notification: Optional[bool] = None) -> List[Slide]:
query = " 1=1 "
if enabled is not None:
query = "{} AND enabled = {} ".format(query, "1" if enabled else "0")
if is_notification is not None:
query = "{} AND is_notification = {} ".format(query, "1" if is_notification else "0")
if playlist_id:
query = "{} {}".format(query, "AND playlist_id = {}".format(playlist_id))

View File

@ -10,7 +10,12 @@ from src.model.hook.HookRegistration import HookRegistration
from src.model.hook.StaticHookRegistration import StaticHookRegistration
from src.model.hook.FunctionalHookRegistration import FunctionalHookRegistration
from src.constant.WebDirConstant import WebDirConstant
from src.util.utils import get_safe_cron_descriptor, is_valid_cron_date_time, seconds_to_hhmmss, am_i_in_docker, truncate, merge_dicts, dictsort
from src.util.utils import get_safe_cron_descriptor, \
is_cron_calendar_moment, \
is_cron_in_day_moment, \
is_cron_in_week_moment, \
seconds_to_hhmmss, am_i_in_docker, \
truncate, merge_dicts, dictsort
class TemplateRenderer:
@ -43,7 +48,8 @@ class TemplateRenderer:
cron_descriptor=self.cron_descriptor,
str=str,
seconds_to_hhmmss=seconds_to_hhmmss,
is_valid_cron_date_time=is_valid_cron_date_time,
is_cron_calendar_moment=is_cron_calendar_moment,
is_cron_in_day_moment=is_cron_in_day_moment,
json_dumps=json.dumps,
merge_dicts=merge_dicts,
dictsort=dictsort,

View File

@ -59,11 +59,31 @@ def camel_to_snake(camel: str) -> str:
return CAMEL_CASE_TO_SNAKE_CASE_PATTERN.sub('_', camel).lower()
def is_valid_cron_date_time(expression: str) -> bool:
def is_cron_calendar_moment(expression: str) -> bool:
pattern = re.compile(r'^(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+\*\s+(\d+)$')
return bool(pattern.match(expression))
def is_cron_in_year_moment(expression: str) -> bool:
pattern = re.compile(r'^(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+\*\s+\*$')
return bool(pattern.match(expression))
def is_cron_in_week_moment(expression: str) -> bool:
pattern = re.compile(r'^(\d+)\s+(\d+)\s+\*\s+\*\s+(\d+)\s+\*$')
return bool(pattern.match(expression))
def is_cron_in_month_moment(expression: str) -> bool:
pattern = re.compile(r'^(\d+)\s+(\d+)\s+(\d+)\s+\*\s+\*\s+\*$')
return bool(pattern.match(expression))
def is_cron_in_day_moment(expression: str) -> bool:
pattern = re.compile(r'^(\d+)\s+(\d+)\s+\*\s+\*\s+\*\s+\*$')
return bool(pattern.match(expression))
def get_cron_date_time(cron_expression: str, object: bool) -> str:
minutes, hours, day, month, _, year = cron_expression.split(' ')
formatted_date_time = f"{year}-{month.zfill(2)}-{day.zfill(2)} {hours.zfill(2)}:{minutes.zfill(2)}"
@ -71,7 +91,7 @@ def get_cron_date_time(cron_expression: str, object: bool) -> str:
def get_safe_cron_descriptor(expression: str, use_24hour_time_format=True, locale_code: Optional[str] = None) -> str:
if is_valid_cron_date_time(expression):
if is_cron_calendar_moment(expression):
[minutes, hours, day, month, _, year] = expression.split(' ')
return "{}-{}-{} at {}:{}".format(
year,

View File

@ -1 +1 @@
2.0.2
2.0.3

View File

@ -1,45 +1,83 @@
<table class="panes variables">
<tbody>
{% set ns = namespace(last_section='') %}
{% for variable in variables %}
{% set section_change = variable.plugin and ns.last_section != variable.plugin %}
<form id="timeForm">
<label for="timePeriod">Sélectionnez une période:</label>
<select id="timePeriod" name="timePeriod" onchange="showFields()">
<option value="">--Sélectionnez--</option>
<option value="year">À un moment dans l'année</option>
<option value="week">À un moment dans la semaine</option>
<option value="month">À un moment dans le mois</option>
<option value="day">À un moment de la journée</option>
<option value="specificDate">À un jour précis dans le calendrier</option>
</select>
{% if section_change %}
{% if not loop.first %}</tbody><tbody>{% endif %}
<tr class="title-item">
<td colspan="3">
{% set plugin = plugins[variable.plugin] %}
{{ t(plugin.use_title()) }}
<div id="yearFields" class="hidden">
<label for="monthOfYear">Mois de l'année:</label>
<input type="number" id="monthOfYear" name="monthOfYear" min="1" max="12">
<label for="dayOfMonthYear">Jour du mois:</label>
<input type="number" id="dayOfMonthYear" name="dayOfMonthYear" min="1" max="30">
<label for="hourYear">Heure:</label>
<input type="number" id="hourYear" name="hourYear" min="0" max="24">
<label for="minuteYear">Minute:</label>
<input type="number" id="minuteYear" name="minuteYear" min="0" max="60">
</div>
{% if plugin.use_description() %}
<div class="more">{{ t(plugin.use_description()) }}</div>
{% endif %}
</td>
</tr>
{% endif %}
<tr class="variable-item variable-edit" data-level="{{ variable.id }}" data-entity="{{ variable.to_json() }}">
<td class="description">
{{ t(variable.description) }}
</td>
<td class="value">
<i class="fa fa-pencil icon-legend"></i>
{% if variable.value %}
{% if variable.type.value == 'bool' %}
{% if variable.display() %}
<i class="fa fa-check alert-success alert-icon icon-value"></i>
{% else %}
<i class="fa fa-times alert-error alert-icon icon-value"></i>
{% endif %}
{% else %}
{{ variable.display() }}
{% endif %}
{% else %}
<span class="empty">{{ l.common_empty }}</span>
{% endif %}
</td>
</tr>
<div id="weekFields" class="hidden">
<label for="dayOfWeek">Jour de la semaine:</label>
<input type="number" id="dayOfWeek" name="dayOfWeek" min="1" max="7">
<label for="hourWeek">Heure:</label>
<input type="number" id="hourWeek" name="hourWeek" min="0" max="24">
<label for="minuteWeek">Minute:</label>
<input type="number" id="minuteWeek" name="minuteWeek" min="0" max="60">
</div>
{% set ns.last_section = variable.plugin %}
{% endfor %}
</tbody>
</table>
<div id="monthFields" class="hidden">
<label for="dayOfMonth">Jour du mois:</label>
<input type="number" id="dayOfMonth" name="dayOfMonth" min="1" max="30">
<label for="hourMonth">Heure:</label>
<input type="number" id="hourMonth" name="hourMonth" min="0" max="24">
<label for="minuteMonth">Minute:</label>
<input type="number" id="minuteMonth" name="minuteMonth" min="0" max="60">
</div>
<div id="dayFields" class="hidden">
<label for="hourDay">Heure:</label>
<input type="number" id="hourDay" name="hourDay" min="0" max="24">
<label for="minuteDay">Minute:</label>
<input type="number" id="minuteDay" name="minuteDay" min="0" max="60">
</div>
<div id="specificDateFields" class="hidden">
<label for="specificDate">Date complète (Y-m-d H-i):</label>
<input type="datetime-local" id="specificDate" name="specificDate">
</div>
<button type="submit">Soumettre</button>
</form>
<script>
function showFields() {
document.getElementById('yearFields').classList.add('hidden');
document.getElementById('weekFields').classList.add('hidden');
document.getElementById('monthFields').classList.add('hidden');
document.getElementById('dayFields').classList.add('hidden');
document.getElementById('specificDateFields').classList.add('hidden');
var timePeriod = document.getElementById('timePeriod').value;
if (timePeriod === 'year') {
document.getElementById('yearFields').classList.remove('hidden');
} else if (timePeriod === 'week') {
document.getElementById('weekFields').classList.remove('hidden');
} else if (timePeriod === 'month') {
document.getElementById('monthFields').classList.remove('hidden');
} else if (timePeriod === 'day') {
document.getElementById('dayFields').classList.remove('hidden');
} else if (timePeriod === 'specificDate') {
document.getElementById('specificDateFields').classList.remove('hidden');
}
}
</script>
<style>
.hidden {
display: none;
}
</style>

View File

@ -6,6 +6,9 @@
{% endblock %}
{% block add_js %}
<script>
route_sysinfo_restart = '{{ url_for('sysinfo_restart') }}';
</script>
<script src="{{ STATIC_PREFIX }}js/restart.js"></script>
{% endblock %}

View File

@ -7,17 +7,30 @@
{{ l.playlist_panel_content_management_desc }}
</p>
{% with slides=slides %}
{% with slides=slides, are_notifications=False %}
{% include 'slideshow/slides/component/table.jinja.html' %}
{% endwith %}
<div class="actions actions-right">
<button type="button" class="btn btn-info slide-add">
<button type="button" class="btn btn-info slide-add" data-modal="modal-slide-add">
<i class="fa fa-plus"></i> {{ l.slideshow_slide_form_add_title }}
</button>
<a href="{{ url_for('slideshow_content_list') }}" class="btn btn-neutral" target="_blank">
<i class="fa fa-upload"></i>
</a>
</div>
<h3 class="divide">
{{ l.playlist_panel_content_management_notifications }}
</h3>
<p>
{{ l.playlist_panel_content_management_notifications_desc }}
</p>
{% with slides=notifications, are_notifications=True %}
{% include 'slideshow/slides/component/table.jinja.html' %}
{% endwith %}
<div class="actions actions-right">
<button type="button" class="btn btn-info slide-add" data-modal="modal-slide-notification-add">
<i class="fa fa-bell"></i> {{ l.slideshow_slide_button_add_notification }}
</button>
</div>
</div>

View File

@ -12,18 +12,35 @@
{% block add_js %}
<script type="text/javascript">
var schedule_start_choices = {
var route_slide_position = '{{ url_for('slideshow_slide_position') }}';
var choices_translations = {
'loop': '{{ l.slideshow_slide_form_label_cron_scheduled_loop }}',
'datetime': '{{ l.slideshow_slide_form_label_cron_scheduled_datetime }}',
'cron': '{{ l.slideshow_slide_form_label_cron_scheduled_cron }}',
};
var schedule_end_choices = {
'stayloop': '{{ l.slideshow_slide_form_label_cron_scheduled_stayloop }}',
'datetime': '{{ l.slideshow_slide_form_label_cron_scheduled_datetime }}',
'duration': '{{ l.slideshow_slide_form_label_cron_scheduled_duration }}',
'inweek': 'in week',
};
var contents =
{{ json_dumps(contents) | safe }}
var choices_map = {
'normal': {
'loop': {},
'datetime': {
'stayloop': choices_translations['stayloop'],
'datetime': choices_translations['datetime']
},
{#'inweek': {'stayloop': choices_translations['stayloop'], 'inweek': choices_translations['inweek']},#}
},
'notification': {
'datetime': {
'datetime': choices_translations['datetime'],
'duration': choices_translations['duration']
},
'cron': {'duration': choices_translations['duration']}
}
}
var contents = {{ json_dumps(contents) | safe }}
</script>
<script src="{{ STATIC_PREFIX }}js/lib/jquery-explr-1.4.js"></script>
<script src="{{ STATIC_PREFIX }}js/lib/jquery-ui.min.js"></script>
@ -32,7 +49,6 @@
<script src="{{ STATIC_PREFIX }}js/lib/qrcode.min.js"></script>
<script src="{{ STATIC_PREFIX }}js/slideshow/slides.js"></script>
<script src="{{ STATIC_PREFIX }}js/playlist/playlists.js"></script>
<script src="{{ STATIC_PREFIX }}js/restart.js"></script>
<script src="{{ STATIC_PREFIX }}js/explorer.js"></script>
{{ HOOK(H_PLAYLIST_JAVASCRIPT) }}
{% endblock %}
@ -110,8 +126,11 @@
<div class="modals-inner">
{% include 'playlist/modal/add.jinja.html' %}
{% include 'playlist/modal/qrcode.jinja.html' %}
{% include 'slideshow/slides/modal/add.jinja.html' %}
{% include 'slideshow/slides/modal/edit.jinja.html' %}
{% with is_notification=True %}{% include 'slideshow/slides/modal/edit.jinja.html' %}{% endwith %}
{% with is_notification=False %}{% include 'slideshow/slides/modal/edit.jinja.html' %}{% endwith %}
{% with is_notification=True %}{% include 'slideshow/slides/modal/add.jinja.html' %}{% endwith %}
{% with is_notification=False %}{% include 'slideshow/slides/modal/add.jinja.html' %}{% endwith %}
</div>
</div>
</div>

View File

@ -3,12 +3,14 @@
{% set content = contents[slide.content_id] %}
<li class="slide-item {{ 'disabled' if not slide.enabled }}" data-level="{{ slide.id }}"
data-entity="{{ slide.to_json({"content": content}) }}">
<div class="head sort">
<a href="javascript:void(0);" class="item-sort slide-sort">
<i class="fa fa-bars icon-left"></i>
</a>
</div>
<a href="javascript:void(0);" class="infos item-edit slide-edit">
{% if not are_notifications %}
<div class="head sort">
<a href="javascript:void(0);" class="item-sort slide-sort">
<i class="fa fa-bars icon-left"></i>
</a>
</div>
{% endif %}
<a href="javascript:void(0);" class="infos item-edit slide-edit" data-modal="{% if are_notifications %}modal-slide-notification-edit{% else %}modal-slide-edit{% endif %}">
<div class="type">
{% set icon = enum_content_type.get_fa_icon(content.type) %}
{% set color = enum_content_type.get_color_icon(content.type) %}
@ -24,7 +26,7 @@
{% if slide.cron_schedule %}
{% set cron_desc = cron_descriptor(slide.cron_schedule) %}
{% if cron_desc %}
{% if is_valid_cron_date_time(slide.cron_schedule) %}
{% if is_cron_calendar_moment(slide.cron_schedule) %}
{% if slide.is_notification %}
🔔 <span class="prefix">{{ l.slideshow_slide_panel_td_cron_scheduled_notify }}</span>
<span class="cron-description">{{ cron_desc }}</span>
@ -46,7 +48,7 @@
{% if slide.cron_schedule_end %}
{% set cron_desc_end = cron_descriptor(slide.cron_schedule_end) %}
{% if cron_desc_end %}
{% if is_valid_cron_date_time(slide.cron_schedule_end) %}
{% if is_cron_calendar_moment(slide.cron_schedule_end) %}
{% if slide.is_notification %}
📆 <span class="prefix">{{ l.slideshow_slide_panel_td_cron_scheduled_date }}</span>
<span class="cron-description">{{ cron_desc_end }}</span>
@ -75,8 +77,12 @@
</div>
</li>
{% else %}
<div class="inner-empty empty-flag ">
<i class="fa fa-image"></i>
<div class="inner-empty empty-flag">
{% if are_notifications %}
<i class="fa fa-bell"></i>
{% else %}
<i class="fa fa-image"></i>
{% endif %}
</div>
{% endfor %}
</ul>

View File

@ -1,4 +1,4 @@
<div class="modal modal-slide-add modal-slide">
<div class="modal modal-slide-{{ 'notification-' if is_notification }}add modal-slide">
<h2>
{{ l.slideshow_slide_form_add_title }}
</h2>
@ -13,6 +13,8 @@
<input name="playlist_id" type="hidden" id="slide-add-playlist-id" value="{{ current_playlist.id }}">
{% endif %}
<input type="text" name="is_notification" id="slide-add-is-notification" value="{{ '1' if is_notification else '0' }}" />
<div class="form-group form-group-horizontal">
<label for="">{{ l.slideshow_slide_form_label_enabled }}</label>
<div class="widget">
@ -42,25 +44,11 @@
{{ l.slideshow_slide_form_section_scheduling }}
</h3>
<div class="form-group form-group-horizontal slide-notification-group">
<label for="">{{ l.slideshow_slide_form_label_is_notification }}</label>
<div class="widget">
<div class="toggle">
<input type="checkbox" class="trigger slide-is-notification" name="is_notification" value="1"
id="slide-add-is-notification"/>
<label for="slide-add-is-notification"></label>
</div>
</div>
</div>
<div class="form-group slide-schedule-group">
<label for="slide-add-cron-schedule">{{ l.slideshow_slide_form_label_cron_scheduled }}</label>
<div class="widget">
<select id="slide-add-cron-schedule-trigger" class="trigger">
<option value="loop">{{ l.slideshow_slide_form_label_cron_scheduled_loop }}</option>
<option value="datetime">{{ l.slideshow_slide_form_label_cron_scheduled_datetime }}</option>
<option value="cron">{{ l.slideshow_slide_form_label_cron_scheduled_cron }}</option>
</select>
<select id="slide-add-cron-schedule-trigger" class="trigger"></select>
<input type="text" id="slide-add-cron-schedule-datetimepicker" class="input-naked datetimepicker"
value=""
placeholder="{{ l.slideshow_slide_form_label_cron_scheduled_datetime_placeholder }}"/>
@ -72,11 +60,7 @@
<div class="form-group slide-schedule-end-group">
<label for="slide-add-cron-schedule-end">{{ l.slideshow_slide_form_label_cron_scheduled_end }}</label>
<div class="widget">
<select id="slide-add-cron-schedule-end-trigger" class="trigger">
<option value="duration">{{ l.slideshow_slide_form_label_cron_scheduled_duration }}</option>
<option value="datetime">{{ l.slideshow_slide_form_label_cron_scheduled_datetime }}</option>
<option value="cron">{{ l.slideshow_slide_form_label_cron_scheduled_cron }}</option>
</select>
<select id="slide-add-cron-schedule-end-trigger" class="trigger"> </select>
<input type="text" id="slide-add-cron-schedule-end-datetimepicker" class="input-naked datetimepicker"
value=""
placeholder="{{ l.slideshow_slide_form_label_cron_scheduled_datetime_placeholder }}"/>

View File

@ -1,18 +1,17 @@
<div class="modal modal-slide-edit modal-slide hidden">
<div class="modal modal-slide-{{ 'notification-' if is_notification }}edit modal-slide hidden">
<h2>
{{ l.slideshow_slide_form_edit_title }}
</h2>
<form class="form" action="{{ url_for('slideshow_slide_edit') }}" method="POST">
<h3>
{{ l.slideshow_slide_form_section_content }}
</h3>
<input type="hidden" name="id" id="slide-edit-id"/>
<input type="hidden" name="is_notification" id="slide-edit-is-notification" value="{{ '1' if is_notification else '0' }}" />
<div class="form-group form-group-horizontal">
<label for="">{{ l.slideshow_slide_form_label_enabled }}</label>
@ -45,25 +44,10 @@
{{ l.slideshow_slide_form_section_scheduling }}
</h3>
<div class="form-group slide-notification-group">
<label for="slide-edit-is-notification">{{ l.slideshow_slide_form_label_is_notification }}</label>
<div class="widget">
<div class="toggle">
<input type="checkbox" class="trigger slide-is-notification" name="is_notification" value="1"
id="slide-edit-is-notification"/>
<label for="slide-edit-is-notification"></label>
</div>
</div>
</div>
<div class="form-group slide-schedule-group">
<label for="slide-edit-cron-schedule">{{ l.slideshow_slide_form_label_cron_scheduled }}</label>
<div class="widget">
<select id="slide-edit-cron-schedule-trigger" class="trigger">
<option value="loop">{{ l.slideshow_slide_form_label_cron_scheduled_loop }}</option>
<option value="datetime">{{ l.slideshow_slide_form_label_cron_scheduled_datetime }}</option>
<option value="cron">{{ l.slideshow_slide_form_label_cron_scheduled_cron }}</option>
</select>
<select id="slide-edit-cron-schedule-trigger" class="trigger"></select>
<input type="text" id="slide-edit-cron-schedule-datetimepicker" class="input-naked datetimepicker"
value=""
placeholder="{{ l.slideshow_slide_form_label_cron_scheduled_datetime_placeholder }}"/>
@ -75,10 +59,7 @@
<div class="form-group slide-schedule-end-group">
<label for="slide-edit-cron-schedule-end">{{ l.slideshow_slide_form_label_cron_scheduled_end }}</label>
<div class="widget">
<select id="slide-edit-cron-schedule-end-trigger" class="trigger">
<option value="duration">{{ l.slideshow_slide_form_label_cron_scheduled_duration }}</option>
<option value="datetime">{{ l.slideshow_slide_form_label_cron_scheduled_datetime }}</option>
</select>
<select id="slide-edit-cron-schedule-end-trigger" class="trigger"></select>
<input type="text" id="slide-edit-cron-schedule-end-datetimepicker" class="input-naked datetimepicker"
value=""
placeholder="{{ l.slideshow_slide_form_label_cron_scheduled_datetime_placeholder }}"/>