New Addon

Simple Schedule
This commit is contained in:
2023-07-12 22:23:45 +07:00
parent 6f4a805c95
commit 088878a693
28 changed files with 2513 additions and 0 deletions
@@ -0,0 +1,60 @@
<tr class="config_section"><td colspan="4">MQTT</td></tr>
{% for t in o.MQTT %}
<tr class="config_item">
<td class="config_label">{{ t }}</td>
{% if t=="enabled": %}
<td class="config_input"><input type="checkbox" name="MQTT.{{ t }}" value="1" {{ 'checked ' if o.MQTT[t] else ' ' }} > &nbsp;&nbsp;<em>(need restart)</em></td>
{% else %}
<td class="config_input"><input type="text" value="{{ o.MQTT[t] }}" class="form-control input-sm" name="MQTT.{{ t }}" ></td>
{% endif %}
<td colspan="2">
</tr>
{% endfor %}
<tr class="config_section"><td colspan="4">DOMAINS</td></tr>
{% for t in o.components %}
<tr class="config_item">
<td class="config_label">{{ t }}</td>
<td class="config_input"><input type="checkbox" name="components.{{ t }}" value="1" {{ 'checked ' if o.components[t] else ' ' }} ></td>
<td colspan="2">
</tr>
{% endfor %}
<tr class="config_section"><td colspan="4">TRANSLATIONS</td></tr>
{% for t in o.translations %}
<tr class="config_item">
<td class="config_label">{{ t | replace("text_","") | upper }}</td>
<td class="config_input"><input type="text" value="{{ o.translations[t] }}" class="form-control input-sm" name="translations.{{ t }}" ></td>
<td colspan="2">
</tr>
{% endfor %}
<tr class="config_section"><td colspan="4">Misc</td></tr>
<tr class="config_item">
<td class="config_label">Max retry</td>
<td class="config_input"><input type="text" value="{{ o.max_retry }}" class="form-control input-sm" name="max_retry" ></td>
<td colspan="2">
</tr>
<tr class="config_item">
<td class="config_label">Details uncovered</td>
<td class="config_input"><input type="checkbox" name="details_uncovered" value="1" {{ 'checked ' if o.details_uncovered else ' ' }} ></td>
<td colspan="2">
</tr>
<tr class="config_item">
<td class="config_label">Dark theme</td>
<td class="config_input"><input type="checkbox" name="dark_theme" value="1" {{ 'checked ' if o.dark_theme else ' ' }} ></td>
<td colspan="2">
</tr>
<tr class="config_item">
<td class="config_label">Debug mode</td>
<td class="config_input"><input type="checkbox" name="debug" value="1" {{ 'checked ' if o.debug else ' ' }} ></td>
<td colspan="2">
</tr>
<tr>
<td colspan="4">
<button type="submit" class="btn btn-default bg-success" id="save-config"><span class="mdi mdi-content-save" ></span> {{ o.translations.text_save }} </button>
<button type="button" class="btn btn-secondary" id="close-config"><span class="mdi close-box-outline" ></span> Close </button>
</td>
</tr>
@@ -0,0 +1,35 @@
BODY { background-color: #111111; color: white; }
.table td, .table th { border-top: 1px solid #333; color: white; }
.week_table_header { color: #e1e1e1; }
.badge {font-weight: 400; }
.btn-circle { box-shadow: none; }
.drag_icon { color: white; }
#sidebar {
background-color: #222;
box-shadow: 5px 5px 18px 0px #777;
}
.table-hover>tbody>tr:hover>* {
background-color: rgb(255 255 255 / 15%);
color: white; }
div.row-title P {color: white;}
.week_table_cell { border-bottom: 1px solid #777; }
.text-green { color: lightgreen; }
.text-red { color: #F66; }
#recurring_preview_on,
#recurring_preview_off
{
opacity: 1;
}
#logcontent {color: #000}
@@ -0,0 +1,195 @@
<div>
<div>
<p class="scheduler_id">{{ p.id }}</p>
<form id="edit-form" class="edit-form" action="update" method="post" >
<input type="hidden" name="id" value="{{ p.id }}" >
<div class="edit-section-label"><label>{{ o.translations.text_name }}</label></div>
<div>
<input type="text" name="name" class="form-control input-sm" placeholder="{{ o.translations.text_name }}" value="{{ p.name }}">
</div>
<div>
<label class="checkbox-inline"><input type="checkbox" name="enabled" value="1" {{ 'checked ' if p.enabled else ' ' }} > {{ o.translations.text_enabled }}</label>
&nbsp;&nbsp;&nbsp;
<label class="checkbox-inline"><input type="checkbox" name="dontretry" value="1" {{ 'checked ' if p.dontretry else ' ' }} > Do not retry</label>
</div>
<div class="edit-section-label"><label>{{ o.translations.text_device }}</label></div>
<div class="indexInput">
{% if p.entity_id %}
{% for e in p.entity_id %}
<div id="inputFormRow">
<div class="input-group mb-3">
<select name="entity_id[]" aria-data="{{ e }}" class="form-control entity-dropdown-fix">{{ switchlist|safe }}</select>
<div class="input-group-append"><button id="removeRow" type="button" class="btn btn-danger"><span class="mdi mdi-delete" ></span></button></div>
</div>
</div>
{% endfor %}
{% endif %}
</div>
<div>
<button id="addRow" type="button" class="btn btn-info bg-primary addRow">+</button>
</div>
{% if p.weekly: %}
<input type="hidden" name="type" value="weekly" >
<div class="edit-section-label"><label>{{ o.translations.text_ON }} / {{ o.translations.text_OFF }}</label></div>
<table>
<tr>
<td></td>
<td><span class="badge dowHiglightG ">{{ o.translations.text_ON }}</span></td>
<td><span class="badge dowHiglightR ">{{ o.translations.text_OFF }}</span></td>
</tr>
<tr>
<td>{{ o.translations.text_monday[:2] }}</td>
<td><input type="text" name="on_1" class="form-control input-sm" value="{{ p.weekly.on_1 }}"></td>
<td><input type="text" name="off_1" class="form-control input-sm" value="{{ p.weekly.off_1 }}"></td>
</tr>
<tr>
<td>{{ o.translations.text_tuesday[:2] }}</td>
<td><input type="text" name="on_2" class="form-control input-sm" value="{{ p.weekly.on_2 }}"></td>
<td><input type="text" name="off_2" class="form-control input-sm" value="{{ p.weekly.off_2 }}"></td>
</tr>
<tr>
<td>{{ o.translations.text_wednesday[:2] }}</td>
<td><input type="text" name="on_3" class="form-control input-sm" value="{{ p.weekly.on_3 }}"></td>
<td><input type="text" name="off_3" class="form-control input-sm" value="{{ p.weekly.off_3 }}"></td>
</tr>
<tr>
<td>{{ o.translations.text_thursday[:2] }}</td>
<td><input type="text" name="on_4" class="form-control input-sm" value="{{ p.weekly.on_4 }}"></td>
<td><input type="text" name="off_4" class="form-control input-sm" value="{{ p.weekly.off_4 }}"></td>
</tr>
<tr>
<td>{{ o.translations.text_friday[:2] }}</td>
<td><input type="text" name="on_5" class="form-control input-sm" value="{{ p.weekly.on_5 }}"></td>
<td><input type="text" name="off_5" class="form-control input-sm" value="{{ p.weekly.off_5 }}"></td>
</tr>
<tr>
<td>{{ o.translations.text_saturday[:2] }}</td>
<td><input type="text" name="on_6" class="form-control input-sm" value="{{ p.weekly.on_6 }}"></td>
<td><input type="text" name="off_6" class="form-control input-sm" value="{{ p.weekly.off_6 }}"></td>
</tr>
<tr>
<td>{{ o.translations.text_sunday[:2] }}</td>
<td><input type="text" name="on_7" class="form-control input-sm" value="{{ p.weekly.on_7 }}"></td>
<td><input type="text" name="off_7" class="form-control input-sm" value="{{ p.weekly.off_7 }}"></td>
</tr>
</table>
{% elif p.recurring: %}
<input type="hidden" name="type" value="recurring" >
<input type="hidden" name="on_tod" id="on_tod" value="{{ p.on_tod }}">
<input type="hidden" name="off_tod" id="off_tod" value="{{ p.off_tod }}">
<div class="edit-section-label"><label>{{ o.translations.text_ON }}</label></div>
<div>
{% for wd in range(1, 8): %}
<label class="checkbox-inline"><input type="checkbox" name="on_dow[]" value="{{ wd }}" {{ 'checked' if wd|string in p.on_dow else ' ' }} > {{ weekday[wd] }}</label>
{% endfor%}
</div>
<div class="form-row">
<div class="col-sm-3">
<div class="input-group mb-2">
<div class="input-group-prepend"><div class="input-group-text"><span class="mdi mdi-arrow-expand-right" ></span></div></div>
<input type="text" value="{{ p.recurring.on_start }}" class="form-control form-control-sm time_validate" name="on_start" id="on_start" placeholder="start">
</div>
</div>
<div class="col-sm-3">
<div class="input-group mb-2">
<div class="input-group-prepend"><div class="input-group-text"><span class="mdi mdi-arrow-expand-left" ></span></div></div>
<input type="text" value="{{ p.recurring.on_end }}" class="form-control form-control-sm time_validate" name="on_end" id="on_end" placeholder="end">
</div>
</div>
<div class="col-sm-3">
<div class="input-group mb-2">
<div class="input-group-prepend"><div class="input-group-text"><span class="mdi mdi-arrow-expand-horizontal" ></span></div></div>
<input type="text" value="{{ p.recurring.on_interval }}"class="form-control form-control-sm interval_validate" name="on_interval" id="on_interval" placeholder="interval">
</div>
</div>
<div class="col-auto">
<button type="button" class="btn btn-default bg-primary generate_button" aria-valuetext="on" ><span class="mdi mdi-eye" ></span></button>
</div>
</div>
<div id="recurring_preview_on" class="text-green" style="display:none;" ></div>
<div class="edit-section-label"><label>{{ o.translations.text_OFF }}</label></div>
<div>
{% for wd in range(1, 8): %}
<label class="checkbox-inline"><input type="checkbox" name="off_dow[]" value="{{ wd }}" {{ 'checked' if wd|string in p.off_dow else ' ' }} > {{ weekday[wd] }}</label>
{% endfor%}
</div>
<div class="form-row">
<div class="col-sm-3">
<div class="input-group mb-2">
<div class="input-group-prepend"><div class="input-group-text"><span class="mdi mdi-arrow-expand-right" ></span></div></div>
<input type="text" value="{{ p.recurring.off_start }}" class="form-control form-control-sm time_validate" name="off_start" id="off_start" placeholder="start">
</div>
</div>
<div class="col-sm-3">
<div class="input-group mb-2">
<div class="input-group-prepend"><div class="input-group-text"><span class="mdi mdi-arrow-expand-left" ></span></div></div>
<input type="text" value="{{ p.recurring.off_end }}" class="form-control form-control-sm time_validate" name="off_end" id="off_end" placeholder="end">
</div>
</div>
<div class="col-sm-3">
<div class="input-group mb-2">
<div class="input-group-prepend"><div class="input-group-text"><span class="mdi mdi-arrow-expand-horizontal" ></span></div></div>
<input type="text" value="{{ p.recurring.off_interval }}"class="form-control form-control-sm interval_validate" name="off_interval" id="off_interval" placeholder="interval">
</div>
</div>
<div class="col-auto">
<button type="button" class="btn btn-default bg-primary generate_button" aria-valuetext="off" ><span class="mdi mdi-eye" ></span></button>
</div>
</div>
<div id="recurring_preview_off" class="text-red" style="display:none;" ></div>
{% else %}
<input type="hidden" name="type" value="daily" >
<div class="edit-section-label"><label>{{ o.translations.text_ON }}</label></div>
<div>
<input type="text" name="on_tod" class="form-control input-sm" value="{{ p.on_tod }}">
</div>
<div>
{% for wd in range(1, 8): %}
<label class="checkbox-inline"><input type="checkbox" name="on_dow[]" value="{{ wd }}" {{ 'checked' if wd|string in p.on_dow else ' ' }} > {{ weekday[wd] }}</label>
{% endfor%}
</div>
<div class="edit-section-label"><label>{{ o.translations.text_OFF }}</label></div>
<div>
<input type="text" name="off_tod" class="form-control input-sm" value="{{ p.off_tod }}">
</div>
<div>
{% for wd in range(1, 8): %}
<label class="checkbox-inline"><input type="checkbox" name="off_dow[]" value="{{ wd }}" {{ 'checked' if wd|string in p.off_dow else ' ' }} > {{ weekday[wd] }}</label>
{% endfor%}
</div>
{% endif %}
<div style="clear:both;"></div>
<br/>
<div id="edit_buttons">
<button type="submit" class="btn btn-default bg-success float-left" id="save-button"><span class="mdi mdi-content-save" ></span> {{ o.translations.text_save }} </button>
{% if is_new==False: %}
<button type="button" class="btn btn-default bg-warning float-left" id="clone-button" aria-id="{{ p.id }}" ><span class="mdi mdi-content-copy" ></span> {{ o.translations.text_clone }} </button>
<button type="button" class="btn btn-default bg-danger float-right delete-button" aria-id="{{ p.id }}" ><span class="mdi mdi-delete" ></span> </button>
{% endif %}
</div>
</form>
</div>
</div>
<div style="clear:both;"></div>
<br/>
@@ -0,0 +1,406 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Simple Scheduler for HA</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css" >
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.6.1.min.js" integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.min.js" integrity="sha384-IDwe1+LCz02ROU9k972gdyvl+AESN10+x7tBKgc9I5HFtuNz0wWnPclzo6p9vxnk" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js" integrity="sha256-lSjKY0/srUM9BE3dPm+c4fBo1dky2v27Gdjm2uoZaL0=" crossorigin="anonymous"></script>
<style>
{{ css|safe }}
{% if o.details_uncovered==1 %}
.week_table{ display: table;}
{% endif %}
</style>
</head>
<body>
<div class="wrapper">
<nav id="sidebar">
<button type="button" aria-label="Close" class="btn btn-outline-secondary btn-sm" onclick="toggle_sidebar();">>>></button>
<div id="sidebar-wrapper">
...
</div>
</nav>
<form action="saveconfig" method="get" id="config-form" >
<div class="content" >
<div>
<table class="table table-hover" id="dtable">
<thead class="bg-primary">
<tr>
<th scope="col" colspan="4" >
<span class="titlebar_span" id="title">SimpleScheduler</span>
<span class="titlebar_span" id="show-add"><button type="button" class="btn btn-default bg-white main-color" ><span class="mdi mdi-plus"></span></button></span>
<span class="titlebar_span" id="show-log"><button type="button" class="btn btn-default bg-white main-color" ><span class="mdi mdi-file-document-outline" ></span></button></span>
<span class="titlebar_span" id="show-config"><button type="button" class="btn btn-default bg-white main-color" ><span class="mdi mdi-cog-outline"></span></button></span>
</th>
</tr>
</thead>
<tbody>
{% for s in data %}
<tr data-value="{{ s.id }}" data-order="{{ sort[s.id] }}" style="opacity: {{ '1' if s.enabled else '0.3' }}">
{% if s.weekly %}
<td class="text-center drag_icon fit"> <span class="mdi mdi-calendar-range mdi-24px" ></span> </td>
{% elif s.recurring %}
<td class="text-center drag_icon fit"><span class="mdi mdi-calendar-refresh mdi-24px" ></span></td>
{% else %}
<td class="text-center drag_icon fit"><span class="mdi mdi-calendar-week mdi-24px" ></span></td>
{% endif %}
<td class="text-center fit" >
<button type="button" class="btn btn-default bg-primary edit-button" aria-id="{{ s.id }}" ><span class="mdi mdi-pencil" ></span></button>
&nbsp;
<button type="button" class="btn btn-default bg-primary view-button" aria-id="{{ s.id }}" ><span class="mdi mdi-eye" ></span></button>
</td>
<td class="name_col" >
<div class="row-title"><p data-bs-toggle="tooltip" data-bs-html="true" title="{{ s.id }}" >{{ s.name }}</p></div>
<div class="entities_list">
{% if s.entity_id %}
{% for e in s.entity_id %}
<span class="badge bg-primary" data-bs-toggle="tooltip" data-bs-html="true" title="{{ e }}" >{{ friendlynames[e] }}</span>
{% endfor %}
{% endif %}
</div>
</td>
{% if s.weekly %}
<td>
<div class="week_table w_mode" id="detail_{{ s.id }}">
<div class="week_table_row week_table_header">
<div class="week_table_cell"></div>
{% for wd in range(1, 8): %}
<div class="week_table_cell" style="width: 13.5%;" >
{{ weekday[wd] }}
</div>
{% endfor%}
</div>
<div class="week_table_row text-green week_table_row_bottom_line">
<div class="week_table_cell "><span class="badge dowHiglightG ">{{ o.translations.text_ON }}</span></div>
{% for wd in range(1, 8): %}
<div class="week_table_cell">
{{ format_event(s.weekly['on_'+wd|string], True)|safe }}
</div>
{% endfor%}
</div>
<div class="week_table_row text-red week_table_row_bottom_line">
<div class="week_table_cell "><span class="badge dowHiglightR ">{{ o.translations.text_OFF }}</span></div>
{% for wd in range(1, 8): %}
<div class="week_table_cell">
{{ format_event(s.weekly['off_'+wd|string], False)|safe }}
</div>
{% endfor%}
</div>
</div>
</td>
{% elif s.recurring %}
<td class="event-cell">
<div class="week_table d_mode" id="detail_{{ s.id }}">
<div class="week_table_row ">
<div class="week_table_cell ">
{% if s.on_tod %}
<div class="event-list text-green">
<span> {{ s.recurring.on_start }} <i class="mdi mdi-arrow-left-right-bold" ></i> {{ s.recurring.on_end }} </span>
<span class="mdi mdi-timer-sand" >{{ s.recurring.on_interval }}m</span>
</div>
<!-- <div style="clear:both;" class="event-list text-green">{{ format_event(s.on_tod, True)|safe }}</div> -->
<div style="clear:both;">{{ get_friendly_html_dow(s.on_dow,True)|safe }}</div>
{% endif %}
</div>
<div class="week_table_cell ">
{% if s.off_tod %}
<div class="event-list text-red">
<span> {{ s.recurring.off_start }} <i class="mdi mdi-arrow-left-right-bold" ></i> {{ s.recurring.off_end }} </span>
<span class="mdi mdi-timer-sand" >{{ s.recurring.off_interval }}m</span>
</div>
<!-- <div style="clear:both;" class="event-list text-red">{{ format_event(s.off_tod, False)|safe }}</div> -->
<div style="clear:both;">{{ get_friendly_html_dow(s.off_dow,False)|safe }}</div>
{% endif %}
</div>
</div>
</div>
</td>
{% else %}
<td class="event-cell">
<div class="week_table d_mode" id="detail_{{ s.id }}">
<div class="week_table_row ">
<div class="week_table_cell ">
{% if s.on_tod %}
<div class="event-list text-green">{{ format_event(s.on_tod, True)|safe }}</div>
<div style="clear:both;">{{ get_friendly_html_dow(s.on_dow,True)|safe }}</div>
{% endif %}
</div>
<div class="week_table_cell ">
{% if s.off_tod %}
<div class="event-list text-red">{{ format_event(s.off_tod, False)|safe }}</div>
<div style="clear:both;">{{ get_friendly_html_dow(s.off_dow,False)|safe }}</div>
{% endif %}
</div>
</div>
</div>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</form>
<div class="overlay"></div>
<footer class="footer">
<div class="statusbar">
<p>
<span class="statusbar_span"><span class="mdi mdi-weather-sunset-up" ></span> {{ statusbarinfo.sunrise }}</span>
<span class="statusbar_span"><span class="mdi mdi-weather-sunset-down" ></span> {{ statusbarinfo.sunset }}</span>
<span class="statusbar_span"><span class="mdi mdi-map-clock-outline" ></span> {{ statusbarinfo.timezone }}</span>
<span class="statusbar_span"><span class="mdi mdi-calendar-clock" ></span> {{ statusbarinfo.scheduler }}</span>
<span class="statusbar_span">MQTT: {{ statusbarinfo.mqtt }}</span>
</p>
</div>
</footer>
</div>
<div id="log_wrapper" >
<div>
<pre id="logcontent"></pre>
<button type="button" class="btn btn-secondary" id="closelog"><span class="mdi close-box-outline" ></span> Close </button>
</div>
</div>
<div id="block_background" ></div>
<script>
$( document ).ready(function() {
var $tbody = $("#dtable tbody");
$tbody.sortable({
distance: 5,
delay: 100,
opacity: 0.6,
cursor: 'move',
update: function(e, tr) {
var orderlist = '';
$('tr.ui-sortable-handle').each(function (i) {
$(this).attr('data-order',i);
orderlist=orderlist+'&list['+i+']='+$(this).attr('data-value');
});
$("#sidebar-wrapper").load("sort?"+orderlist);
}
}).disableSelection();
$tbody.find('tr.ui-sortable-handle').sort(function (a, b) {
var tda = parseInt($(a).attr('data-order'));
var tdb = parseInt($(b).attr('data-order'));
return tda > tdb ? 1
: tda < tdb ? -1
: 0;
}).appendTo($tbody);
});
function toggle_sidebar(){
$("#sidebar").hide();
$("body").css('overflow','auto');
}
$(document).on('click', '.edit-button', function () {
v=$(this).attr('aria-id');
$("#sidebar-wrapper").html('');
$("#sidebar").show();
$("body").css('overflow','hidden');
$("#sidebar-wrapper").load("edit?id="+v, function() {
$(".entity-dropdown-fix").each(function( t ) {
this.value = $(this).attr('aria-data');
});
});
});
$(document).on('click', '.view-button', function () {
var v=$(this).attr('aria-id');
var t="#detail_"+v;
if ($(t).css('display')=="table") {
$(t).css('display','none');
}else{
$(t).css('display','table');
}
});
$(document).on('click', '#show-add', function () {
$("#sidebar-wrapper").html('');
$("#sidebar").show();
$("#sidebar-wrapper").load("new");
});
$(document).on('click', '#show-config', function () {
$("#dtable tbody").load("config");
});
$(document).on('click', '#close-config', function () {
window.location.href="main";
});
$(document).on('click', '#save-config', function () {
var f = document.getElementById("config-form");
$("input:checkbox:not(:checked)").each( function () {
$(this).prop('checked',true);
$(this).attr('value','0');
})
f.submit();
});
$(document).on('click', '#clone-button', function () {
var id=$(this).attr('aria-id');
window.location.href ='clone?id='+id;
});
$(document).on('click', '.delete-button', function () {
var id=$(this).attr('aria-id');
if (window.confirm("Are you sure?")) {
window.location.href ='delete?id='+id;
}
});
$(document).on('click', '.img-add-new', function () {
v=$(this).attr('aria-id');
$("#sidebar-wrapper").html('');
$("#sidebar").show();
$("#sidebar-wrapper").load("edit?id="+0+"&type="+v);
});
$(document).on('click', '.generate_button', function () {
action=$(this).attr('aria-valuetext');
r = document.getElementById('recurring_preview_'+action);
generate_recurrent(action);
if ($(r).css('display')=="none") {
$(r).css('display','block');
}else{
$(r).css('display','none');
}
});
$(document).on('submit', '.edit-form', function () {
var f = document.getElementById("edit-form");
var t = f.type.value;
if (t=="recurring") {
generate_recurrent("on");
generate_recurrent("off");
}
});
$(document).on('keyup', '.time_validate', function () {
obj=$(this);
field=obj[0];
var timeREGEX = /^[0-9]{2}:[0-9]{2}$/;
if (timeREGEX.test(field.value) || field.value=="") {
field.classList.remove("is-invalid");
document.getElementById("save-button").disabled=false;
} else {
field.classList.add("is-invalid");
document.getElementById("save-button").disabled=true;
}
});
$(document).on('keyup', '.interval_validate', function () {
obj=$(this);
field=obj[0];
var intervalREGEX = /^[0-9]{1,3}$/;
if (intervalREGEX.test(field.value) || field.value=="") {
document.getElementById("save-button").disabled=false;
field.classList.remove("is-invalid");
} else {
document.getElementById("save-button").disabled=true;
field.classList.add("is-invalid");
}
});
$(document).on('click', '#removeRow', function () {
$(this).closest('#inputFormRow').remove();
});
$(document).on('click', '#show-log', function () {
$("#logcontent").load("log" , function() {
$('#logcontent').scrollTop( $('#logcontent')[0].scrollHeight );
});
$("#log_wrapper").css('display','block');
$("#block_background").css('width','100%');
$("#block_background").css('height','100%');
$("#block_background").css('background-color','#777777e6');
});
$(document).on('click', '#closelog', function () {
$("#log_wrapper").css('display','none');
$("#block_background").css('width','0%');
$("#block_background").css('height','0%');
$("#block_background").css('background-color','#77777700');
});
function generate_recurrent(action) {
r = document.getElementById('recurring_preview_'+action);
r.innerHTML = "";
start=document.getElementById(action+'_start').value;
end=document.getElementById(action+'_end').value;
interval=document.getElementById(action+'_interval').value;
var startDate= new Date("2022-01-01T" + start +":00Z");
var endDate = new Date("2022-01-01T" + end +":00Z");
s = startDate.getTime();
e = endDate.getTime();
if (s<e) {
while ( s<=e ) {
out = new Date(s)
t = out.toUTCString().substring(17, 22)
if (t.length>0) r.innerHTML += t + " ";
s = s + (interval * 60000);
}
} else {
r.innerHTML = ""
}
document.getElementById(action+'_tod').value=r.innerText;
}
var intervalcheck = window.setInterval(function(){
$.get("dirty", function( r ) {
if (r=="1") location.reload();
});
}, 3000);
$(document).on('click', '#addRow', function () {
var html = '';
html += '<div id="inputFormRow">';
html += '<div class="input-group mb-3">';
html += '<select name="entity_id[]" class="form-control">{{ switchlist|safe }}</select>';
html += '<div class="input-group-append"><button id="removeRow" type="button" class="btn btn-danger"><span class="mdi mdi-delete" ></span></button></div>';
html += '</div>';
html += '</div>';
$("#info").html('Clic ADD');
$('.indexInput').append(html);
});
</script>
</body>
</html>
@@ -0,0 +1,418 @@
:root {
--maincolor: #007bff;
}
H5 {margin-bottom: 0 ; line-height: 14px; }
.main-color { color: var(--maincolor)!important; }
div.content { margin-bottom: 2em; }
.table td, .table th {
vertical-align: top;
border-bottom: 1px solid var(--maincolor);
border-top: none;
}
THEAD {
line-height: 3em;
}
#sidebar {
display:none;
min-width: 250px;
max-width: 30%;
height: 100%;
position: fixed;
top: 0;
right: 0;
padding: 1em;
z-index: 9999;
background-color: rgba(255,255,255,0.98);
box-shadow: 5px 5px 18px 0px #000;
overflow-y: auto;
}
.edit-form > div {
margin: 1em 0;
}
.form-row span.mdi { font-size: 14px; }
.btn-default { color: white;}
.dowIcon {
border: 0px solid ;
border-radius: 20px;
background: grey;
color: white;
font-size: 0.8rem;
width: 1.8rem;
height: 1.8rem;
line-height: 1.8rem;
text-align: center;
margin-right: 0.1em;
display: inline-block;
text-shadow: 1px 1px 1px #333;
box-shadow: inset -3px -4px 6px #00000077;
}
.dowHiglightR { background: red ; }
.dowHiglightG { background: green ; }
.icon-space {width: 32px;}
.text-green {color:green;}
.text-red {color:red;}
.text-white {color:white;}
.bg-primary {
color:white;
background-color: #03a9f4!important;
}
.titlebar_span {
font-size: 1.25em;
margin-right: 1em;
text-shadow: 1px 1px 3px #000;
}
.titlebar_span button {
box-shadow: 2px 2px 2px 0px #00000077;
font-size: 1.25em;
line-height: 1em;
}
div.row-title P {
font-size: 1.2em;
line-height: 1.2em;
margin-bottom: 0;
}
div.edit-section-label {
width: 100%;
border-bottom: 1px solid #777;
margin-top: 1em;
}
div.edit-section-label label{
line-height: 1em;
font-weight: bold;
}
.btn-circle.btn-xl {
width: 70px;
height: 70px;
padding: 10px 16px;
border-radius: 35px;
font-size: 24px;
line-height: 1.33;
opacity: 0.9;
}
.btn-circle {
width: 30px;
height: 30px;
padding: 6px 0px;
border-radius: 15px;
text-align: center;
font-size: 12px;
line-height: 1.42857;
background: navy;
color: white;
box-shadow: 2px 2px 10px 0px #777;
}
.floating-bottom-right {
position: fixed;
bottom: 5%;
right: 5%;
}
td.name_col{
width: 25%;
max-width: 400px;
}
.event-list > span {
font-size: 1rem;
margin-right: 1rem;
line-height: 1.6 rem;
float:left;
}
span.event-type-b {
font-size: 1rem;
color: #d39e00;
margin-left: 0.2rem;
}
span.event-type-t {
font-size: 1rem;
color: #8b442b;
margin-left: 0.1rem;
}
span.event-type-to {
font-size: 1rem;
color: #9c27b0;
margin-left: 0.1rem;
}
span.event-type-p {
font-size: 1rem;
color: #2196f3;
margin-left: 0.1rem;
}
footer {
position: fixed;
bottom: 0;
right: 0;
margin:0;
padding: 0;
width: 100%;
height: 2em;
line-height: 2em;
font-size: 1em;
background-color: grey;
color: black
}
footer .statusbar {
margin-left: 1em;
}
.statusbar_span {margin-right: 2em; }
.statusbar_span .mdi {font-size:1.2em; }
#showlog {cursor:pointer;}
#log_wrapper {
z-index: 9999;
display: none;
position: fixed;
top: 10%;
left: 10%;
width: 80%;
height: 80%;
background-color: white;
padding: 0;
margin: 0;
border: 1px solid #ccc;
overflow: hidden;
box-shadow: 5px 5px 15px 0px #777;
}
#log_wrapper > div {
position: relative;
width: 98%;
height: 96%;
margin: 1%;
padding: 0;
overflow: hidden;
}
#logcontent {
font-size: 1em;
overflow: scroll;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#closelog {
position: absolute;
top: 1em;
right: 3em;
}
#block_background {
position: fixed;
top: 0;
bottom: 0;
height: 0;
width: 0;
background-color: #77777700;
z-index: 9998;
transition: background-color 0.25s;
}
.week_table {
display: none;
width: 100%;
margin: 0px 0px 1em;
}
.week_table_row {
display: table-row;
}
.week_table_header .week_table_cell {
border-bottom: 1px solid #777 !important;
}
.week_table_cell {
display: table-cell;
padding: 3px 10px;
border: none;
text-align: left;
border-bottom: 1px solid #ddd;
}
.week_table_cell > span {
display: block;
}
.d_mode .week_table_cell {
border-bottom: none;
width: 50%;
}
.week_table.d_mode {
margin: 0px 0px;
}
.img-add-new {
display: block;
width: 90%;
margin: 1em auto;
height: auto;
min-height: 3em;
box-shadow: 2px 2px 5px -2px #777;
cursor: pointer;
line-height: 3em;
padding: 0em 1em;
}
.img-add-new > SPAN {
vertical-align: middle;
}
.badge{
color: white;
text-shadow: 1px 1px 1px #333;
}
.hidden_cell {display: none; }
.drag_icon {cursor: move;}
.fit {
white-space: nowrap;
width: 1%;
}
p.scheduler_id {
position: absolute;
top: 1.5em;
right: 2em;
margin: 0;
padding: 0;
opacity: .5;
}
.col-sm-3 {margin-right: 0.5em; }
.col-sm-3:last-child {margin-right: 0; }
.form-row {
display: flex;
flex-wrap: nowrap;
}
#recurring_preview_on,
#recurring_preview_off {
opacity: 0.75;
}
#edit_buttons > button:first-child {
margin-right: 1em;
}
.float-left { float:left}
.float-right { float:right}
tr.config_section {
background: #777;
font-weight: bold;
color: white;
}
tr.config_section td {
border: none;
}
tr.config_item td {
border: none;
}
#config-form .form-control {
padding: 0.1rem 0.75rem;
}
tr.config_item td.config_input,
tr.config_item td.config_label {
width: 10%;
min-width: 150px;
padding: 0.25em 1em;
vertical-align: middle;
}
@media screen and (min-width: 1281px) {
html { font-size: 10pt; }
}
@media screen and (max-width: 1280px) {
html { font-size: 9pt; }
.form-row span.mdi { font-size: 10px; }
#sidebar { max-width: 50%; }
}
@media screen and (max-width: 800px) {
html { font-size: 8pt; }
#dtable TD {
display: block;
text-align: center;
border: none !important;
}
#dtable TD:nth-child(2) { }
#dtable TR {
border-bottom: 1px solid var(--maincolor);
}
#config-form .input-sm {text-align:center;}
td.name_col {width: 100%; max-width: none;}
.event-list > span { float: none; display: inline-block; }
#sidebar { max-width: 90%; }
tr.config_item td.config_input,
tr.config_item td.config_label {
width: 100%;
}
.fit {
white-space: normal;
width: auto;
}
.week_table { margin-bottom: 1em; }
.d_mode .week_table_cell { display: block; text-align: center; width: 100%; }
.week_table.d_mode {margin-bottom: 0em; }
.event-list {
width: 80%;
margin: auto;
}
}
@@ -0,0 +1,4 @@
<div class="edit-section-label"><label>Select type:</label></div>
<div id="add-d" class="img-add-new bg-primary" aria-id="D" ><span class="mdi mdi-calendar-week mdi-24px" ></span> Daily</div>
<div id="add-w" class="img-add-new bg-primary" aria-id="W" ><span class="mdi mdi-calendar-range mdi-24px" ></span> Weekly</div>
<div id="add-r" class="img-add-new bg-primary" aria-id="R" ><span class="mdi mdi-calendar-refresh mdi-24px" ></span> Recurring</div>