smart-nodes
Version:
331 lines (298 loc) • 12.5 kB
HTML
<script type="text/html" data-template-scheduler-row="">
<div>
<div style="display: inline-block; width: 30px; margin-left: 10px;">
<i class="fa fa-calendar"></i>
</div>
<input class="days"/>
</div>
<div style="margin-top: 8px;">
<div style="display: inline-block; width: 30px; margin-left: 10px;">
<i class="fa fa-clock-o"></i>
</div>
<select class="node-input-scheduler-select-hours hour fill24" style="display: inline-block; width: 75px;">
<option value="-1">hour</option>
</select>
:
<select class="node-input-scheduler-select-minutes minute fill60" style="display: inline-block; width: 75px;">
<option value="-1">min</option>
</select>
:
<select class="node-input-scheduler-select-seconds second fill60" style="display: inline-block; width: 75px;">
<option value="-1">sec</option>
</select>
</div>
<div style="margin-top: 8px;">
<div style="display: inline-block; width: 30px; margin-left: 10px;">
<i class="fa fa-envelope"></i>
</div>
<input type="text" class="message"/>
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType("smart_scheduler", {
category: "Smart Nodes",
paletteLabel: "Scheduler",
color: "#6EE2D9",
defaults: {
name: { value: "" },
enabled: { value: false },
schedules: {
value: [],
validate: function (v)
{
let schedules = [];
if (v.length < 1)
{
return true;
}
/** make a first pass and create extra schedules if off is before on
* this so we can calculate overlaps later on */
for (let i = 0; i < v.length; i++)
{
v[i].valid = true;
days = v[i].days;
hour = parseInt(v[i].hour, 10);
minute = parseInt(v[i].minute, 10);
second = parseInt(v[i].second, 10);
message = v[i].message;
schedules.push({
days: v[i].days,
hour: hour,
minute: minute,
second: second,
message: message,
n: i,
valid: true,
});
}
/** validate schedules */
for (let i = 0; i < schedules.length; i++)
{
let s = schedules[i];
/** hours should be 0..23 */
if (s.hour < 0 || s.hour > 23)
{
v[s.n].valid = false;
}
/** minutes and seconds should be 0..59 */
if (s.minute < 0 || s.second < 0 || s.minute > 59 || s.second > 59)
{
v[s.n].valid = false;
}
}
/** if any are not valid return false */
for (i = 0; i < v.length; i++)
{
if (v[i].valid === false)
return false;
}
return true;
},
},
save_state: { value: false },
resend_on_start: { value: false }
},
inputs: 1,
outputs: 1,
icon: "font-awesome/fa-clock-o",
label: function ()
{
return this.name || "Scheduler";
},
oneditprepare: function ()
{
let node = this;
$("#node-input-save_state").on("change", ev =>
{
if (ev.target.checked)
$("#resend_on_start_row").show();
else
$("#resend_on_start_row").hide();
});
$("#node-input-save_state").trigger("change");
/**
* prepare schedule
*/
let scheduleList = $("#node-scheduler-schedules");
scheduleList
.css("min-height", "147px")
.css("min-width", "350px")
.editableList({
sortable: true,
removable: true,
addItem: function (row, index, data)
{
schedule = data.schedule || false;
let template = $("script[data-template-scheduler-row]").html() || "";
$(row).append(template);
fillOptions(row, schedule);
scheduleResize();
},
removeItem: function (data)
{
scheduleResize();
},
});
/**
* pass all existing schedules to editableList or pass an empty one
*/
if (node.schedules.length == 0)
{
scheduleList.editableList("addItem");
}
else
{
for (let i = 0; i < node.schedules.length; i++)
{
let schedule = node.schedules[i];
scheduleList.editableList("addItem", { schedule: schedule, i: i });
}
}
/**
* resize the editableList
*/
function scheduleResize()
{
height = 40 + scheduleList.editableList("length") * 135;
scheduleList.editableList("height", height);
}
/**
* fill the controls with days/hours/minutes/seconds/message
* @param row
*/
function fillOptions(row, schedule)
{
schedule = schedule ? schedule : {
days: "",
hour: -1,
minute: -1,
second: -1,
message: '{"topic": ""}'
};
// Fill days list
row.find(".days")
.typedInput({
types: [
{
default: "",
multiple: true,
options: [
{ value: "1", label: node._("scheduler.ui.monday") },
{ value: "2", label: node._("scheduler.ui.tuesday") },
{ value: "3", label: node._("scheduler.ui.wednesday") },
{ value: "4", label: node._("scheduler.ui.thursday") },
{ value: "5", label: node._("scheduler.ui.friday") },
{ value: "6", label: node._("scheduler.ui.saturday") },
{ value: "0", label: node._("scheduler.ui.sunday") }
],
},
],
});
// Fill hours
let hours = row.find(".fill24");
for (let i = 0; i < 24; i++)
{
i = pad(i);
hours.append($("<option></option>").val(i).text(i));
}
// Fill minutes and seconds
let minsec = row.find(".fill60");
for (let i = 0; i < 60; i++)
{
i = pad(i);
minsec.append($("<option></option>").val(i).text(i));
}
row.find(".message")
.css("max-width", "70%")
.typedInput({
type: "json",
types: ["json"]
});
/**
* set the value of the select boxes
*/
row.find(".days").typedInput("value", schedule.days);
row.find(".hour").val(schedule.hour);
row.find(".minute").val(schedule.minute);
row.find(".second").val(schedule.second);
row.find(".message").typedInput("value", schedule.message);
/** set error on the li */
if (schedule.valid === false)
{
row.closest("li").css("background-color", "#f9b1bf");
}
/** modify some css */
row.parent().find(".red-ui-editableList-item-handle").css("color", "black").css("left", "10px");
row.parent().find(".red-ui-editableList-item-remove").css("right", "10px");
}
/**
* prepend string with 0
* @param s
* @returns {string|*}
*/
function pad(s)
{
s = s.toString();
if (s.length < 2)
{
s = "0".concat(s);
}
return s;
}
},
oneditsave: function ()
{
let node = this;
node.schedules = [];
let scheduleList = $("#node-scheduler-schedules");
let schedules = scheduleList.editableList("items");
schedules.each(function (i)
{
let days = this.find(".days").val();
let hour = this.find(".hour").val();
let minute = this.find(".minute").val();
let second = this.find(".second").val();
let message = this.find(".message").val();
let schedule = {
days: days,
hour: hour,
minute: minute,
second: second,
message: message,
};
/** if any of the inputs was modified, save it */
if (days.length > 0 || hour != -1 || minute != -1 || second != -1 || message != "{}")
{
node.schedules.push(schedule);
}
});
},
});
</script>
<script type="text/html" data-template-name="smart_scheduler">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="scheduler.ui.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]scheduler.ui.name" />
</div>
<div class="form-row">
<label for="node-input-enabled"></label>
<input type="checkbox" id="node-input-enabled" style="width: 20px;" />
<label for="node-input-enabled" style="width: 200px;" data-i18n="scheduler.ui.scheduler_enabled"></label>
</div>
<div class="form-row" style="margin-bottom: 2px;">
<p class="text-center"><i class="fa fa-list"></i> <strong data-i18n="scheduler.ui.schedules"></strong></p>
</div>
<div class="form-row node-scheduler-schedules-row">
<ol id="node-scheduler-schedules"></ol>
</div>
<hr/>
<h4 style="margin: 0.5rem 0;" data-i18n="scheduler.ui.system_start"></h4>
<div class="form-row">
<input type="checkbox" id="node-input-save_state" style="width: 20px;" />
<label for="node-input-save_state" style="width: calc(100% - 30px);" data-i18n="scheduler.ui.save_state"></label>
</div>
<div class="form-row" id="resend_on_start_row">
<input type="checkbox" id="node-input-resend_on_start" style="width: 20px;" />
<label for="node-input-resend_on_start" style="width: calc(100% - 30px);" data-i18n="scheduler.ui.send_after_start"></label>
</div>
</script>