More work on integrating the script-task.
Ylian Saint-Hilaire committed
Aug 18, 2022 at 18:03 UTC
1b67b8436954f00abee27e802dd2dc87050f1780
10 files changed
+2120
-14
MeshCentralServer.njsproj
+1
@@ -238,6 +238,7 @@
238
<Compile Include="public\scripts\common-0.0.1.js" />
239
<Compile Include="public\scripts\meshcentral.js" />
240
<Compile Include="redirserver.js" />
241
+ <Compile Include="taskmanager.js" />
242
<Compile Include="translate\translate.js" />
243
<Compile Include="ua-parser.js" />
244
<Compile Include="webauthn.js" />
meshagent.js
+1
-14
@@ -1740,20 +1740,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1740
}
1741
case 'script-task': {
1742
// These command are for running regular batch jobs on the remote device
1743
- switch (command.subaction) {
1744
- case 'getScript': {
1745
- console.log('getScript');
1746
- break;
1747
- }
1748
- case 'clearAllPendingTasks': {
1749
- console.log('clearAllPendingTasks');
1750
- break;
1751
- }
1752
- case 'taskComplete': {
1753
- console.log('taskComplete');
1754
- break;
1755
- }
1756
- }
1743
+ if (parent.parent.taskManager != null) { parent.parent.taskManager.agentAction(command, obj); }
1744
break;
1745
}
1746
default: {
meshcentral.js
+6
@@ -33,6 +33,7 @@ function CreateMeshCentralServer(config, args) {
33
obj.amtScanner = null;
34
obj.amtManager = null;
35
obj.meshScanner = null;
36
+ obj.taskManager = null;
37
obj.letsencrypt = null;
38
obj.eventsDispatch = {};
39
obj.fs = require('fs');
@@ -1497,6 +1498,11 @@ function CreateMeshCentralServer(config, args) {
1498
return;
1499
}
1500
1501
+ // Setup the task manager
1502
+ if ((obj.config) && (obj.config.settings) && (obj.config.settings.taskmanager == true)) {
1503
+ obj.taskManager = require('./taskmanager').createTaskManager(obj);
1504
+ }
1505
+
1506
// Start plugin manager if configuration allows this.
1507
if ((obj.config) && (obj.config.settings) && (obj.config.settings.plugins != null) && (obj.config.settings.plugins != false) && ((typeof obj.config.settings.plugins != 'object') || (obj.config.settings.plugins.enabled != false))) {
1508
obj.pluginHandler = require('./pluginHandler.js').pluginHandler(obj);
public/tail.datetime/tail.datetime-default-blue.min.css
new
+3
@@ -0,0 +1,3 @@
1
+@charset "UTF-8"; /* pytesNET/tail.DateTime v.0.4.14 */
2
+/* @author SamBrishes, pytesNET <sam@pytes.net> | @license MIT */
3
+.tail-datetime-calendar,.tail-datetime-calendar *,.tail-datetime-calendar :after,.tail-datetime-calendar :before{box-sizing:border-box;-webkit-box-sizing:border-box}.tail-datetime-calendar{top:0;left:0;width:275px;height:auto;margin:15px;padding:0;z-index:3000;display:block;position:absolute;visibility:hidden;direction:ltr;border-collapse:separate;font-family:"Open Sans",Calibri,Arial,sans-serif;background-color:#fff;border-width:0;border-style:solid;border-color:transparent;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,.3125);-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3125)}.tail-datetime-calendar:after{clear:both;content:"";display:block;font-size:0;visibility:hidden}.tail-datetime-calendar.calendar-static{top:auto;left:auto;margin-left:auto;margin-right:auto;position:static;visibility:visible}.tail-datetime-calendar button.calendar-close{top:100%;right:15px;color:#303438;width:35px;height:25px;margin:1px 0 0 0;padding:5px 10px;opacity:.5;outline:0;display:inline-block;position:absolute;font-size:14px;line-height:1.125em;text-shadow:none;background-color:#fff;background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDEyIDE2Ij48cGF0aCBmaWxsPSIjMzAzNDM4IiBkPSJNNy40OCA4bDMuNzUgMy43NS0xLjQ4IDEuNDhMNiA5LjQ4bC0zLjc1IDMuNzUtMS40OC0xLjQ4TDQuNTIgOCAuNzcgNC4yNWwxLjQ4LTEuNDhMNiA2LjUybDMuNzUtMy43NSAxLjQ4IDEuNDhMNy40OCA4eiIvPjwvc3ZnPg==");background-repeat:no-repeat;background-position:center center;border-width:0;border-style:solid;border-color:transparent;border-radius:0 0 3px 3px;box-shadow:0 1px 3px rgba(0,0,0,.3125);-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3125);transition:opacity 142ms linear;-webkit-transition:opacity 142ms linear}.tail-datetime-calendar button.calendar-close:hover{opacity:1}.tail-datetime-calendar .calendar-tooltip{color:#fff;width:auto;margin:0;padding:0;display:block;position:absolute;background-color:#202428;border-radius:3px}.tail-datetime-calendar .calendar-tooltip:before{top:-7px;left:50%;width:0;height:0;margin:0 0 0 -6px;content:"";display:block;position:absolute;border-width:0 7px 7px 7px;border-style:solid;border-color:transparent transparent #202428 transparent}.tail-datetime-calendar .calendar-tooltip .tooltip-inner{width:auto;margin:0;padding:4px 7px;display:block;font-size:12px;line-height:14px}.tail-datetime-calendar .calendar-actions{color:#fff;width:100%;height:36px;margin:0;padding:0;display:table;overflow:hidden;border-spacing:0;border-collapse:separate;background-color:#149be6;border-width:0;border-style:solid;border-color:transparent;border-radius:3px 3px 0 0}.tail-datetime-calendar .calendar-actions span{margin:0;padding:0;display:table-cell;position:relative;text-align:center;line-height:36px;text-shadow:-1px -1px 0 #0e6ca0;background-repeat:no-repeat;background-position:center center}.tail-datetime-calendar .calendar-actions span[data-action]{cursor:pointer}.tail-datetime-calendar .calendar-actions span.action{width:36px;font-size:22px}.tail-datetime-calendar .calendar-actions span.label{width:auto}.tail-datetime-calendar .calendar-actions span:first-child:before,.tail-datetime-calendar .calendar-actions span:last-child:before{top:5px;bottom:5px;width:1px;height:auto;margin:0;padding:0;content:"";display:inline-block;position:absolute;background-color:#107bb7}.tail-datetime-calendar .calendar-actions span:first-child:before{right:-1px}.tail-datetime-calendar .calendar-actions span:last-child:before{left:-1px}.tail-datetime-calendar .calendar-actions span:first-child:hover:before,.tail-datetime-calendar .calendar-actions span:last-child:hover:before{display:none}.tail-datetime-calendar .calendar-actions span[data-action]:hover{background-color:#107bb7}.tail-datetime-calendar .calendar-actions span.action-prev{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2IiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgNiAxNiI+PHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTTYgMkwwIDhsNiA2VjJ6Ii8+PC9zdmc+")}.tail-datetime-calendar .calendar-actions span.action-next{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2IiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgNiAxNiI+PHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTTAgMTRsNi02LTYtNnYxMnoiLz48L3N2Zz4=")}.tail-datetime-calendar .calendar-actions span.action-submit{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDEyIDE2Ij48cGF0aCBmaWxsPSIjZmZmZmZmIiBkPSJNMTIgNWwtOCA4LTQtNCAxLjUtMS41TDQgMTBsNi41LTYuNUwxMiA1eiIvPjwvc3ZnPg==")}.tail-datetime-calendar .calendar-actions span.action-cancel{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDEyIDE2Ij48cGF0aCBmaWxsPSIjZmZmZmZmIiBkPSJNNy40OCA4bDMuNzUgMy43NS0xLjQ4IDEuNDhMNiA5LjQ4bC0zLjc1IDMuNzUtMS40OC0xLjQ4TDQuNTIgOCAuNzcgNC4yNWwxLjQ4LTEuNDhMNiA2LjUybDMuNzUtMy43NSAxLjQ4IDEuNDhMNy40OCA4eiIvPjwvc3ZnPg==")}.tail-datetime-calendar .calendar-datepicker{width:100%;margin:0;padding:0;display:block;position:relative}.tail-datetime-calendar .calendar-datepicker table{width:100%;margin:0;padding:0;border-spacing:0;border-collapse:separate}.tail-datetime-calendar .calendar-datepicker table tr td,.tail-datetime-calendar .calendar-datepicker table tr th{color:#303438;height:30px;padding:0;position:relative;font-size:13px;text-align:center;font-weight:400;text-shadow:none;line-height:30px;background-color:transparent;border-width:0;border-style:solid;border-color:transparent;border-radius:0}.tail-datetime-calendar .calendar-datepicker table tr th{color:#fff;background-color:#303438}.tail-datetime-calendar .calendar-datepicker table tr td{cursor:pointer}.tail-datetime-calendar .calendar-datepicker table tr td span.inner{margin:0;padding:0;display:inline-block}.tail-datetime-calendar .calendar-datepicker table tr td.date-disabled{cursor:not-allowed;color:#909498;background-color:#f0f0f0}.tail-datetime-calendar .calendar-datepicker table tr td.date-disabled:after{left:3px;bottom:3px;width:35px;height:1px;margin:0;padding:0;content:"";display:inline-block;position:absolute;background-color:#bfbfbf;transform-origin:2px -5px;transform:rotate(-45deg);-moz-transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}.tail-datetime-calendar .calendar-datepicker table tr td.date-next,.tail-datetime-calendar .calendar-datepicker table tr td.date-previous{color:#909498;background-color:#f0f0f0}.tail-datetime-calendar .calendar-datepicker table tr td .tooltip-tick,.tail-datetime-calendar .calendar-datepicker table tr td.date-today:before{top:5px;width:5px;height:5px;margin:0;padding:0;z-index:20;content:"";display:inline-block;position:absolute;border-width:0;border-style:solid;border-color:transparent;border-radius:50%}.tail-datetime-calendar .calendar-datepicker table tr td.date-today:before{left:5px;background-color:#32b93c}.tail-datetime-calendar .calendar-datepicker table tr td .tooltip-tick{right:5px;background-color:#202428}.tail-datetime-calendar .calendar-datepicker table tr td .tooltip-tick:after,.tail-datetime-calendar .calendar-datepicker table tr td .tooltip-tick:before{display:none}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week{width:14.28571429%;height:35px}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week span.inner{width:31px;height:31px;line-height:29px;border-width:1px;border-style:solid;border-color:transparent;border-radius:50%}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day:hover span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week:hover span.inner{border-color:#ccc}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day.date-disabled span.inner,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day.date-disabled:hover span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week.date-disabled span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week.date-disabled:hover span.inner{border-color:transparent}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day.date-select span.inner,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day.date-select:hover span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week.date-select span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week.date-select:hover span.inner{color:#32b93c;border-color:#32b93c}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year{width:33.33333333%;height:40px;transition:color 142ms linear;-webkit-transition:color 142ms linear}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade.date-today:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month.date-today:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year.date-today:before{left:50%;margin-left:-2.5px}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner{width:auto;height:31px;line-height:29px}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner:before{width:20px;height:20px;content:"";z-index:15;display:inline-block;position:absolute;border-width:1px;border-style:solid;border-color:transparent;transition:all 142ms linear;-webkit-transition:all 142ms linear}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner:before{top:0;left:0}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade:hover span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month:hover span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year:hover span.inner:before{top:6px;left:6px;border-top-color:#ccc;border-left-color:#ccc}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner:after{right:0;bottom:0}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade:hover span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month:hover span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year:hover span.inner:after{right:6px;bottom:6px;border-right-color:#ccc;border-bottom-color:#ccc}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year{width:25%}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner{height:54px;padding:7px 15px;text-align:left;line-height:20px}.tail-datetime-calendar .calendar-timepicker{width:100%;margin:0;padding:0;display:block;text-align:center;border-width:1px 0 0 0;border-style:solid;border-color:#d9d9d9}.tail-datetime-calendar .calendar-timepicker .timepicker-field{width:28%;margin:0;padding:15px 0 7px 0;display:inline-block;position:relative;text-align:center}.tail-datetime-calendar .calendar-timepicker .timepicker-field:first-of-type{text-align:right}.tail-datetime-calendar .calendar-timepicker .timepicker-field:last-of-type{text-align:left}.tail-datetime-calendar .calendar-timepicker .timepicker-field input[type=text]{color:#303438;width:100%;height:29px;margin:0;z-index:4;padding:3px 20px 3px 5px;outline:0;display:inline-block;position:relative;font-size:12px;text-align:center;line-height:23px;appearance:textfield;-moz-appearance:textfield;-webkit-appearance:textfield;background-color:#f0f0f0;border-width:0;border-style:solid;border-color:transparent;border-radius:3px;box-shadow:none;-webkit-box-shadow:none;transition:color 142ms linear,border 142ms linear,background 142ms linear;-webkit-transition:color 142ms linear,border 142ms linear,background 142ms linear}.tail-datetime-calendar .calendar-timepicker .timepicker-field input[type=text]:hover{color:#303438;background-color:#e0e0e0}.tail-datetime-calendar .calendar-timepicker .timepicker-field input[type=text]:focus{color:#fff;background-color:#32b93c}.tail-datetime-calendar .calendar-timepicker .timepicker-field input[type=text]:disabled{cursor:not-allowed;color:#a0a4a8;background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step{width:20px;height:15px;right:0;margin:0;padding:0;z-index:15;display:inline-block;position:absolute;background-color:#f0f0f0;box-shadow:none;-webkit-box-shadow:none;transition:border 142ms linear,background 142ms linear;-webkit-transition:border 142ms linear,background 142ms linear}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step:before{top:4px;left:50%;width:0;height:0;margin:0 0 0 -4px;padding:0;content:"";display:inline-block;position:absolute;transition:border 142ms linear;-webkit-transition:border 142ms linear}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-up{top:15px;border-width:0 0 1px 1px;border-style:solid;border-color:#fff;border-radius:0 2px 0 0}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-up:hover{background-color:#e0e0e0}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-up:before{border-width:0 4px 5px 4px;border-style:solid;border-color:transparent transparent #303438 transparent}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-down{top:29px;border-width:1px 0 0 1px;border-style:solid;border-color:#fff;border-radius:0 0 2px 0}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-down:hover{background-color:#e0e0e0}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-down:before{border-width:5px 4px 0 4px;border-style:solid;border-color:#303438 transparent transparent transparent}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button.step-up{border-color:rgba(255,255,255,.8);background-color:#32b93c}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button.step-up:hover{background-color:#27912f}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button.step-up:before{border-bottom-color:#fff}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button+button.step-down{border-color:rgba(255,255,255,.8);background-color:#32b93c}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button+button.step-down:hover{background-color:#27912f}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button+button.step-down:before{border-top-color:#fff}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button.step-up{cursor:not-allowed;border-color:rgba(255,255,255,.8);background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button.step-up:hover{background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button.step-up:before{border-bottom-color:#a0a4a8}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button+button.step-down{cursor:not-allowed;border-color:rgba(255,255,255,.8);background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button+button.step-down:hover{background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button+button.step-down:before{border-top-color:#a0a4a8}.tail-datetime-calendar .calendar-timepicker .timepicker-field label{color:#303438;margin:0;padding:0;display:block;font-size:12px;text-align:center}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch{cursor:pointer;margin:15px 0 -5px 0;display:block;text-align:center;vertical-align:top}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch:after,.tail-datetime-calendar .calendar-timepicker label.timepicker-switch:before{width:auto;margin:0;padding:0 5px;font-size:12px;line-height:16px;vertical-align:top}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch:before{content:attr(data-am)}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch:after{content:attr(data-pm)}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]{display:none}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]+span{display:inline-block;position:relative;vertical-align:top}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]+span:before{width:50px;height:16px;content:"";display:inline-block;vertical-align:top;border-width:1px;border-style:solid;border-color:#149be6;border-radius:14px;transition:border 284ms linear;-webkit-transition:border 284ms linear}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]+span:after{top:3px;left:4px;right:30px;width:auto;height:10px;margin:0;padding:0;content:"";display:inline-block;position:absolute;background-color:#149be6;border-radius:15px;vertical-align:top;transition:left 284ms linear,right 284ms linear 284ms,background 284ms linear;-webkit-transition:left 284ms linear,right 284ms linear 284ms,background 284ms linear}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]:checked+span:before{border-color:#32b93c}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]:checked+span:after{left:30px;right:4px;background-color:#32b93c;transition:right 284ms linear,left 284ms linear 284ms,background 284ms linear;-webkit-transition:right 284ms linear,left 284ms linear 284ms,background 284ms linear}.tail-datetime-calendar .calendar-actions+.calendar-timepicker{border-width:0}.tail-datetime-calendar.rtl{direction:rtl}.tail-datetime-calendar.rtl .calendar-actions span.action-next,.tail-datetime-calendar.rtl .calendar-actions span.action-prev{transform:rotate(180deg);-moz-transform:rotate(180deg);-webkit-transform:rotate(180deg)}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.date-disabled:after{right:3px;transform:rotate(45deg);-moz-transform:rotate(45deg);-webkit-transform:rotate(45deg)}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.date-today:before{right:5px}.tail-datetime-calendar.rtl .calendar-datepicker table tr td .tooltip-tick{left:5px}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade.date-today:before,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-month.date-today:before,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-year.date-today:before{right:50%;margin-right:-2.5px}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade:hover span.inner:before,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-month:hover span.inner:before,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-year:hover span.inner:before{right:6px;border-right-color:#ccc}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade span.inner:after,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-month span.inner:after,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-year span.inner:after{left:0}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade:hover span.inner:after,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-month:hover span.inner:after,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-year:hover span.inner:after{left:6px;border-left-color:#ccc}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade span.inner{text-align:right}.tail-datetime-calendar.rtl .calendar-timepicker .timepicker-field:first-child{text-align:left;padding-left:0;padding-right:25px}.tail-datetime-calendar.rtl .calendar-timepicker .timepicker-field:last-child{text-align:right;padding-left:25px;padding-right:0}.tail-datetime-calendar.rtl .calendar-timepicker .timepicker-field:first-child input[type=text]{margin-left:-1px;margin-right:0;border-radius:0 3px 3px 0}.tail-datetime-calendar.rtl .calendar-timepicker .timepicker-field:last-child input[type=text]{margin-left:0;margin-right:-1px;border-radius:3px 0 0 3px}
\ No newline at end of file
public/tail.datetime/tail.datetime-default-blue.min.map
new
+1
@@ -0,0 +1 @@
1
+{"version":3,"sources":["$stdin"],"names":[],"mappings":"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"}
\ No newline at end of file
public/tail.datetime/tail.datetime.min.js
new
+2
@@ -0,0 +1,2 @@
1
+/* pytesNET/tail.DateTime v.0.4.14 | Basic Version | @author SamBrishes, pytesNET <sam@pytes.net> | @license MIT */
2
+!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t,t.document)}):"object"==typeof module&&module.exports?module.exports=e(t,t.document):(void 0===t.tail&&(t.tail={}),t.tail.DateTime=t.tail.datetime=e(t,t.document),"undefined"!=typeof jQuery&&(jQuery.fn.DateTime=jQuery.fn.datetime=function(t){var e,i=[];return this.each(function(){!1!==(e=tail.DateTime(this,t))&&i.push(e)}),1===i.length?i[0]:0!==i.length&&i}),"undefined"!=typeof MooTools&&(Element.implement({DateTime:function(t){return new tail.DateTime(this,t)}}),Element.implement({datetime:function(t){return new tail.DateTime(this,t)}})))}(window,function(h,d){"use strict";function u(t,e){return!!(t&&"classList"in t)&&t.classList.contains(e)}function a(t,e){return t&&"classList"in t?t.classList.add(e):void 0}function n(t,e){return t&&"classList"in t?t.classList.remove(e):void 0}function s(t,e,i){if(CustomEvent&&CustomEvent.name)var a=new CustomEvent(e,i);else(a=d.createEvent("CustomEvent")).initCustomEvent(e,!!i.bubbles,!!i.cancelable,i.detail);return t.dispatchEvent(a)}function o(t,e){if("function"==typeof Object.assign)return Object.assign({},t,e||{});var i=Object.constructor();for(var a in t)i[a]=a in e?e[a]:t[a];return i}function p(t,e){var i=d.createElement(t);return i.className=e&&e.join?e.join(" "):e||"",i}function r(t){return t.charAt(0).toUpperCase()+t.slice(1)}function c(t,e,i){var a=t instanceof Date?t:!!t&&new Date(t);return a instanceof Date&&!isNaN(a.getDate())&&(i&&a.setHours(0,0,0,0),!0===e?a.getTime():a)}d.forms.inputmode=!0;var l=function(t,e){if((t="string"==typeof t?d.querySelectorAll(t):t)instanceof NodeList||t instanceof HTMLCollection||t instanceof Array){for(var i=[],a=t.length,n=0;n<a;n++)i.push(new l(t[n],e));return 1===i.length?i[0]:0!==i.length&&i}if(!(t instanceof Element))return!1;if(!(this instanceof l))return new l(t,e);if(l.inst[t.getAttribute("data-tail-datetime")])return l.inst[t.getAttribute("data-tail-datetime")];if(t.getAttribute("data-datetime")){var s=JSON.parse(t.getAttribute("data-datetime").replace(/\'/g,'"'));s instanceof Object&&(e=o(e,s))}return this.e=t,this.id=++l.count,this.con=o(l.defaults,e),(l.inst["tail-"+this.id]=this).e.setAttribute("data-tail-datetime","tail-"+this.id),this.init()};return l.version="0.4.14",l.status="beta",l.count=0,l.inst={},l.defaults={animate:!0,classNames:!1,closeButton:!0,dateFormat:"YYYY-mm-dd",dateStart:!1,dateRanges:[],dateBlacklist:!0,dateEnd:!1,locale:"en",position:"bottom",rtl:"auto",startOpen:!1,stayOpen:!1,time12h:!1,timeFormat:"HH:ii:ss",timeHours:!0,timeMinutes:!0,timeSeconds:0,timeIncrement:!0,timeStepHours:1,timeStepMinutes:5,timeStepSeconds:5,today:!0,tooltips:[],viewDefault:"days",viewDecades:!0,viewYears:!0,viewMonths:!0,viewDays:!0,weekStart:0},l.strings={en:{months:["January","February","March","April","May","June","July","August","September","October","November","December"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shorts:["SUN","MON","TUE","WED","THU","FRI","SAT"],time:["Hours","Minutes","Seconds"],header:["Select a Month","Select a Year","Select a Decade","Select a Time"]},modify:function(t,e,i){if(!(t in this))return!1;if(e instanceof Object)for(var a in e)this.modify(t,a,e[a]);else this[t][e]="string"==typeof i?i:this[t][e];return!0},register:function(t,e){return"string"==typeof t&&e instanceof Object&&(this[t]=e,!0)}},l.prototype={init:function(){this.prepare();var t=this.__.shorts.slice(this.con.weekStart).concat(this.__.shorts.slice(0,this.con.weekStart));this.weekdays="<thead>\n<tr>\n";for(var e=0;e<7;e++)this.weekdays+='<th class="calendar-week">'+t[e]+"</th>";this.weekdays+="\n</tr>\n</thead>",this.select=c(this.e.getAttribute("data-value")||this.e.value),(!this.select||this.select<this.con.dateStart||this.select>this.con.dateEnd)&&(this.select=null),null==this.view&&(this.view={type:this.con.viewDefault,date:this.select||new Date});var i=["Hours","Minutes","Seconds"];for(e=0;e<3;e++)if("number"==typeof this.con["time"+i[e]])this.view.date["set"+i[e]](this.con["time"+i[e]]);else for(;this.view.date["get"+i[e]]()%this.con["timeStep"+i[e]]!=0;)this.view.date["set"+i[e]](this.view.date["get"+i[e]]()+1);return this.ampm=!!this.con.time12h&&12<this.view.date.getHours(),this.events={},this.dt=this.renderCalendar(),this.con.startOpen&&this.open(),this.select&&this.selectDate(this.select),this.bind()},prepare:function(){if(this.__=o(l.strings.en,l.strings[this.con.locale]||{}),this.con.dateStart=c(this.con.dateStart,!0,!0)||-9999999999999,this.con.dateEnd=c(this.con.dateEnd,!0,!0)||9999999999999,this.con.viewDefault=this.con.dateFormat?this.con.viewDefault:"time","string"==typeof this.con.weekStart&&(this.con.weekStart=l.strings.en.shorts.indexOf(this.con.weekStart)),this.con.weekStart<0&&6<this.con.weekStart&&(this.con.weekStart=0),0<this.con.dateRanges.length){for(var t=[],e=(n=this.con.dateRanges).length,i=0;i<e;i++)n[i]instanceof Object&&(n[i].start||n[i].days)&&(!1===(n[i].start=c(n[i].start||!1,!0,!0))?n[i].start=n[i].end=1/0:(!1===(n[i].end=c(n[i].end||!1,!0,!0))&&(n[i].end=n[i].start),n[i].start=n[i].start>n[i].end?[n[i].end,n[i].end=n[i].start][0]:n[i].start),n[i].days=!("days"in n[i])||n[i].days,n[i].days="boolean"!=typeof n[i].days?function(t){for(var e=[],i=t.length,a=0;a<i;a++)"string"==typeof t[a]&&(t[a]=l.strings.en.shorts.indexOf(t[a])),0<=t[a]&&t[a]<=6&&e.push(t[a]);return e}(n[i].days instanceof Array?n[i].days:[n[i].days]):[0,1,2,3,4,5,6],t.push({start:n[i].start,end:n[i].end,days:n[i].days}));this.con.dateRanges=t}if(0<this.con.tooltips.length){t=[];var a,n,s=this.con.tooltips;for(e=s.length,i=0;i<e;i++)s[i]instanceof Object&&s[i].date&&(s[i].date instanceof Array?(a=c(s[i].date[0]||!1,!0,!0),n=c(s[i].date[1]||!1,!0,!0)||a):a=n=c(s[i].date||!1,!0,!0),a&&t.push({date:a!==n?[a,n]:a,text:s[i].text||"Tooltip",color:s[i].color||"inherit",element:s[i].element||(r=d.createElement("DIV"),r.className="calendar-tooltip",r.innerHTML='<div class="tooltip-inner">'+s[i].text||"Tooltip</div>",r)}));this.con.tooltips=t}var r;return this},bind:function(){var e=this;return void 0===this._bind&&(this.e.addEventListener("focusin",function(t){e.open.call(e)}),this.e.addEventListener("keyup",function(t){e.callback.call(e,t)}),d.addEventListener("keyup",function(t){e.dt.contains(t.target)&&e.callback.call(e,t)}),d.addEventListener("click",function(t){e.dt.contains(t.target)?e.callback.call(e,t):!e.e.contains(t.target)&&u(e.dt,"calendar-open")&&(t.target==e.dt||t.target==e.e||e.con.stayOpen||e.close.call(e))}),d.addEventListener("mouseover",function(t){e.dt.contains(t.target)&&e.callback.call(e,t)}),this._bind=!0),this},callback:function(t){var e,i=t.target,a="getAttribute",n="data-action",s=i[a](n)?i:i.parentElement[a](n)?i.parentElement:i,r="data-tooltip";if("mouseover"==t.type&&(!1!==(e=i[a](r)?i:!!s[a](r)&&s)?this.dt.querySelector("#tooltip-"+e[a](r)+"-"+e[a](r+"-time"))||this.showTooltip(e[a](r),e,e[a](r+"-time")):this.dt.querySelector(".calendar-tooltip:not(.remove)")&&this.hideTooltip(this.dt.querySelector(".calendar-tooltip").id.slice(8))),"click"==t.type){if(!s||1!=t.buttons&&1!=(t.which||t.button))return;if(s.hasAttribute("data-disabled"))return;switch(s[a](n)){case"prev":case"next":return this.browseView(s[a](n));case"cancel":this.con.stayOpen||this.close();break;case"submit":return this.con.stayOpen||this.close(),this.selectDate(this.fetchDate(parseInt(s[a]("data-date"))));case"view":return this.switchDate(s[a]("data-year")||null,s[a]("data-month")||null,s[a]("data-day")||null),this.switchView(s[a]("data-view"))}}if("keyup"==t.type){if("INPUT"!=t.target.tagName&&t.target!==this.e&&/calendar-(static|close)/i.test(this.dt.className))return!1;13==(t.keyCode||t.which)&&(this.selectDate(this.fetchDate(this.select)),t.stopPropagation(),this.con.stayOpen||this.close()),27==(t.keyCode||t.which)&&(this.con.stayOpen||this.close())}},trigger:function(t){var e={bubbles:!1,cancelable:!0,detail:{args:arguments,self:this}};"change"==t&&(s(this.e,"input",e),s(this.e,"change",e)),s(this.dt,"tail::"+t,e);for(var i=(this.events[t]||[]).length,a=0;a<i;a++)this.events[t][a].cb.apply(this,function(t,e,i){for(var a=e.length,n=0;n<a;++n)t[n-1]=e[n];return t[n]=i,t}(new Array(arguments.length),arguments,this.events[t][a].args));return!0},calcPosition:function(){var t=this.dt.style,e=h.getComputedStyle(this.dt),i=parseInt(e.marginLeft)+parseInt(e.marginRight),a=parseInt(e.marginTop)+parseInt(e.marginBottom),n=this.e.getBoundingClientRect().top+h.scrollY,s=this.e.getBoundingClientRect().left-h.scrollX,r=this.e.offsetWidth||0,o=this.e.offsetHeight||0;switch(t.visibility="hidden",this.con.position){case"top":var c=n-(this.dt.offsetHeight+a),l=s+r/2-(this.dt.offsetWidth/2+i/2);break;case"left":c=n+o/2-(this.dt.offsetHeight/2+a),l=s-(this.dt.offsetWidth+i);break;case"right":c=n+o/2-(this.dt.offsetHeight/2+a),l=s+r;break;default:c=n+o,l=s+r/2-(this.dt.offsetWidth/2+i/2)}return t.top=(0<=c?c:this.e.offsetTop)+"px",t.left=(0<=l?l:0)+"px",t.visibility="visible",this},convertDate:function(t,e){var i,a={H:String("00"+t.getHours()).toString().slice(-2),G:(i=t.getHours(),i%12?i%12:12),A:12<=t.getHours()?"PM":"AM",a:12<=t.getHours()?"pm":"am",i:String("00"+t.getMinutes()).toString().slice(-2),s:String("00"+t.getSeconds()).toString().slice(-2),Y:t.getFullYear(),y:parseInt(t.getFullYear().toString().slice(2)),m:String("00"+(t.getMonth()+1)).toString().slice(-2),M:this.__.months[t.getMonth()].slice(0,3),F:this.__.months[t.getMonth()],d:String("00"+t.getDate()).toString().slice(-2),D:this.__.days[t.getDay()],l:this.__.shorts[t.getDay()].toLowerCase()};return e.replace(/([HGismd]{1,2}|[Y]{2,4}|y{2})/g,function(t){return 4==t.length||2==t.length?a[t.slice(-1)].toString().slice(-Math.abs(t.length)):1==t.length&&"0"==t[0]?a[t.slice(-1)].toString().slice(-1):a[t.slice(-1)].toString()}).replace(/(A|a|M|F|D|l)/g,function(t){return a[t]})},renderCalendar:function(){var t=["tail-datetime-calendar","calendar-close"],e=!0===this.con.classNames?this.e.className.split(" "):this.con.classNames;if(["top","left","right","bottom"].indexOf(this.con.position)<0){var i=d.querySelector(this.con.position);t.push("calendar-static")}(!0===this.con.rtl||0<=["ar","he","mdr","sam","syr"].indexOf(this.con.rtl))&&t.push("rtl"),this.con.stayOpen&&t.push("calendar-stay"),(e="function"==typeof e.split?e.split(" "):e)instanceof Array&&(t=t.concat(e));var a=p("DIV",t),n=!1;if(a.id="tail-datetime-"+this.id,this.con.dateFormat?n='<span class="action action-prev" data-action="prev"></span><span class="label" data-action="view" data-view="up"></span><span class="action action-next" data-action="next"></span>':this.con.timeFormat&&(n='<span class="action action-submit" data-action="submit"></span><span class="label"></span><span class="action action-cancel" data-action="cancel"></span>'),a.innerHTML=n?'<div class="calendar-actions">'+n+"</div>":"",this.con.dateFormat&&this.renderDatePicker(a,this.con.viewDefault),this.con.timeFormat&&this.renderTimePicker(a),this.con.closeButton&&!i){var s=p("BUTTON","calendar-close"),r=this;s.addEventListener("click",function(t){t.preventDefault(),r.close()}),a.appendChild(s)}return(i||d.body).appendChild(a),a},renderDatePicker:function(t,e){if((!e||["decades","years","months","days"].indexOf(e)<0)&&(e=this.con.viewDays?"days":this.con.viewMonths?"months":this.con.viewYears?"years":!!this.con.viewDecades&&"decades"),!e||!this.con["view"+r(e)]||!this.con.dateFormat)return!1;var i=d.createElement("DIV");return i.className="calendar-datepicker calendar-view-"+e,i.innerHTML=this["view"+r(e)](),t.querySelector(".calendar-datepicker")?t.replaceChild(i,t.querySelector(".calendar-datepicker")):t.appendChild(i),this.view.type=e,this.handleLabel(t)},renderTimePicker:function(t){if(!this.con.timeFormat)return!1;var e,i,a=[],n=0;if(this.con.time12h){var s=12<this.view.date.getHours()?'checked="checked" ':"";a.push('<label class="timepicker-switch" data-am="AM" data-pm="PM"><input type="checkbox" value="1" data-input="PM" '+s+"/><span></span></label>")}for(var r in{Hours:0,Minutes:0,Seconds:0})!1!==this.con["time"+r]?((e=d.createElement("INPUT")).type="text",e.disabled=null===this.con["time"+r],e.setAttribute("min","Hours"===r&&this.con.time12h?"01":"00"),e.setAttribute("max","Hours"!==r?"60":this.con.time12h?"13":"24"),e.setAttribute("step",this.con["timeStep"+r]),e.setAttribute("value",(i=this.view.date["get"+r]())<10?"0"+i:i),e.setAttribute("pattern","d*"),e.setAttribute("inputmode","numeric"),e.setAttribute("data-input",r.toLowerCase()),a.push('<div class="timepicker-field timepicker-'+r.toLowerCase()+'">'+e.outerHTML+'<button class="picker-step step-up"></button><button class="picker-step step-down"></button><label>'+this.__.time[n++]+"</label></div>")):a.push((n++,null));var o=p("DIV","calendar-timepicker"),c=this;o.innerHTML=a.join("\n");var l=o.querySelectorAll("input");for(n=0;n<l.length;n++)"checkbox"!==l[n].type?(l[n].addEventListener("input",function(t){c.handleTime.call(c,this)}),l[n].addEventListener("keydown",function(t){var e=event.keyCode||event.which||0;if(38===e||40===e)return t.preventDefault(),c.handleStep.call(c,this,38===e?"up":"down"),!1})):l[n].addEventListener("change",function(t){c.handleTime.call(c,this)});for(l=o.querySelectorAll("button"),n=0;n<l.length;n++)l[n].addEventListener("mousedown",function(t){t.preventDefault();var e=this.parentElement.querySelector("input");return c.handleStep.call(c,e,u(this,"step-up")?"up":"down"),!1});var h=t.querySelector(".calendar-timepicker");return t[h?"replaceChild":"appendChild"](o,h),this.handleLabel(t)},handleTime:function(t){this.con.time12h&&"checkbox"===t.type&&(this.ampm=t.checked);var e=t.parentElement.parentElement;e=[e.querySelector("input[data-input=hours]")||{value:0},e.querySelector("input[data-input=minutes]")||{value:0},e.querySelector("input[data-input=seconds]")||{value:0}],this.selectTime(parseInt(e[0].value)+(this.ampm?12:0),parseInt(e[1].value),parseInt(e[2].value)),e[2].value=this.view.date.getSeconds(),e[1].value=this.view.date.getMinutes(),this.con.time12h?e[0].value=12<this.view.date.getHours()?this.view.date.getHours()-12:this.view.date.getHours():e[0].value=this.view.date.getHours()},handleStep:function(t,e,i){var a=null,n=parseInt(t.value),s=parseInt(t.getAttribute("min")),r=parseInt(t.getAttribute("max")),o=t.getAttribute("data-input"),c=parseInt(t.getAttribute("step"));if("up"===e?(a=r<=n+c||null,t.value=r<=n+c?13===r?1:0:n+c,this.ampm=!!this.con.time12h&&12<=this.view.date.getHours()+1):"down"===e&&(a=!(n-c<s)&&null,t.value=n-c<s?r-c:n-c,this.ampm=!!this.con.time12h&&this.view.date.getHours()-1<=0),t.value<10&&(t.value="0"+t.value),this.con.timeIncrement&&null!==a){var l=t.parentElement.previousElementSibling;l&&!1===l.disabled?this.handleStep(l.querySelector("input"),a?"up":"down",!0):"hours"==o&&this.view.date.setDate(this.view.date.getDate()+(a?1:-1))}if(void 0!==i&&!0===i)return!1;var h=t.parentElement.parentElement;if(this.selectTime(parseInt((h.querySelector("input[data-input=hours]")||{value:0}).value)+(this.ampm?12:0),parseInt((h.querySelector("input[data-input=minutes]")||{value:0}).value),parseInt((h.querySelector("input[data-input=seconds]")||{value:0}).value)),this.con.time12h){var d=t.parentElement.parentElement.querySelector("input[type=checkbox]");d&&d.checked!==12<this.view.date.getHours()&&(d.checked=12<this.view.date.getHours())}return!0},handleLabel:function(t){var e,i,a=t.querySelector(".label");switch(this.view.type){case"days":e=this.__.months[this.view.date.getMonth()]+", "+this.view.date.getFullYear();break;case"months":e=this.view.date.getFullYear();break;case"years":e=(i=parseInt(this.view.date.getFullYear().toString().slice(0,3)+"0"))+" - "+(i+10);break;case"decades":e=(i=parseInt(this.view.date.getFullYear().toString().slice(0,2)+"00"))+" - "+(i+100);break;case"time":e=this.__.header[3]}return a.innerText=e,t},viewDecades:function(){var t=this.view.date.getFullYear(),e=new Date(this.view.date.getTime()),i=this.con.today?(new Date).getYear():0;e.setFullYear(t-parseInt(t.toString()[3])-30);for(var a,n,s=[],r=[],o=1;o<=16;o++)a="calendar-decade"+(i>=e.getYear()&&i<=e.getYear()+10?" date-today":""),n='data-action="view" data-view="down" data-year="'+e.getFullYear()+'"',s.push('<td class="'+a+'" '+n+'><span class="inner">'+e.getFullYear()+" - "+(e.getFullYear()+10)+"</span></td>"),4<=o&&o%4==0&&(r.push("<tr>\n"+s.join("\n")+"\n</tr>"),s=[]),e.setFullYear(e.getFullYear()+10);return'<table class="calendar-decades"><thead><tr><th colspan="4">'+this.__.header[2]+"</th></tr></thead><tbody>"+r.join("\n")+"</tbody></table>"},viewYears:function(){var t=this.view.date.getFullYear(),e=new Date(this.view.date.getTime()),i=this.con.today?(new Date).getYear():0;e.setFullYear(t-parseInt(t.toString()[3])-2);for(var a,n,s=[],r=[],o=1;o<=16;o++)a="calendar-year"+(e.getYear()==i?" date-today":""),n='data-action="view" data-view="down" data-year="'+e.getFullYear()+'"',s.push('<td class="'+a+'" '+n+'><span class="inner">'+e.getFullYear()+"</span></td>"),4<=o&&o%4==0&&(r.push("<tr>\n"+s.join("\n")+"\n</tr>"),s=[]),e.setFullYear(e.getFullYear()+1);return'<table class="calendar-years"><thead><tr><th colspan="4">'+this.__.header[1]+"</th></tr></thead><tbody>"+r.join("\n")+"</tbody></table>"},viewMonths:function(){var t=this.__.months,e=this.con.today?(new Date).getMonth():-1;e=this.view.date.getYear()==(new Date).getYear()?e:-1;for(var i,a,n=[],s=[],r=0;r<12;r++)i="calendar-month"+(e==r?" date-today":""),a='data-action="view" data-view="down" data-month="'+r+'"',n.push('<td class="'+i+'" '+a+'><span class="inner">'+t[r]+"</span></td>"),3==n.length&&(s.push("<tr>\n"+n.join("\n")+"\n</tr>"),n=[]);return'<table class="calendar-months"><thead><tr><th colspan="3">'+this.__.header[0]+"</th></tr></thead><tbody>"+s.join("\n")+"</tbody></table>"},viewDays:function(){var i,t,e,a,n,s,r=new Date(this.view.date.getTime()),o=(new Date).toDateString(),c=r.getMonth(),l=[],h=[],d=[0,[]],u=([].concat(this.con.tooltips),[0,0]);for(r.setHours(0,0,0,0),r.setDate(1),r.setDate(1-(r.getDay()-this.con.weekStart));h.length<6;)i=r.getTime(),s=[].concat(this.con.dateRanges),e='data-action="submit" data-date="'+r.getTime()+'"',t="calendar-day date-"+(r.getMonth()>c?"next":r.getMonth()<c?"previous":"current"),this.con.today&&o==r.toDateString()&&(t+=" date-today"),this.con.dateBlacklist&&(i<this.con.dateStart||i>this.con.dateEnd)?d=[i<this.con.dateStart?this.con.dateStart:1/0,[0,1,2,3,4,5,6],!0]:0<this.con.dateRanges.length?s.filter(function(t){return t.start==1/0||i>=t.start&&i<=t.end?!(d=[t.end,t.days]):t.start>i},this):3==d.length&&(d=[0,[0,1,2,3,4,5,6]]),0<this.con.tooltips.length&&this.con.tooltips.filter(function(t,e){t.date instanceof Array?t.date[0]<=i&&t.date[1]>=i&&(u=[t.date[1],e,t.color]):t.date==i&&(u=[t.date,e,t.color])},this),u[0]<i&&(u=[0,0]),(n=d[0]>=i&&0<=d[1].indexOf(r.getDay()))&&this.con.dateBlacklist||!n&&!this.con.dateBlacklist?(t+=" date-disabled",e+=' data-disabled="true"'):0!==d[0]&&d[0]<=i&&(d=[0,[]]),this.select&&this.select.toDateString()==r.toDateString()&&(t+=" date-select"),a='<span class="inner">'+r.getDate()+"</span>",0<u[0]&&(t+=" date-tooltip",e+=' data-tooltip="'+u[1]+'" data-tooltip-time="'+i+'"',"inherit"!==u[2]?a+='<span class="tooltip-tick" style="background:'+u[2]+';"></span>':a+='<span class="tooltip-tick"></span>'),l.push('<td class="'+t+'" '+e+">"+a+"</td>"),7==l.length&&(h.push("<tr>\n"+l.join("\n")+"\n</tr>"),l=[]),r.setDate(r.getDate()+1);return h="<tbody>"+h.join("\n")+"</tbody>",'<table class="calendar-days">'+this.weekdays+h+"</table>"},showTooltip:function(t,e,i){var a,n=this.con.tooltips[t].element,s=n.style,r=this.dt.querySelector(".calendar-datepicker");s.cssText="opacity:0;visibility:hidden;",n.id="tooltip-"+t+"-"+i,r.appendChild(n),a=n.offsetWidth,n.offsetHeight,s.top=e.offsetTop+e.offsetHeight+"px",s.left=e.offsetLeft+e.offsetWidth/2-a/2+"px",s.visibility="visible",this.con.animate?(n.setAttribute("data-top",parseInt(s.top)),s.top=parseInt(s.top)+5+"px",function t(){parseFloat(s.top)>n.getAttribute("data-top")&&(s.top=parseFloat(s.top)-.5+"px"),(s.opacity=parseFloat(s.opacity)+.125)<1&&setTimeout(t,20)}()):s.opacity=1},hideTooltip:function(t){var e=this.dt.querySelector("#tooltip-"+t),i=e.style;this.con.animate?(e.className+=" remove",function t(){if(parseFloat(i.top)<parseInt(e.getAttribute("data-top"))+5&&(i.top=parseFloat(i.top)+.5+"px"),(i.opacity-=.125)<0)return(e.className="calendar-tooltip")?e.parentElement.removeChild(e):"";setTimeout(t,20)}()):e.parentElement.removeChild(e)},switchView:function(t){var e=[null,"days","months","years","decades",null];return-1==e.indexOf(t)&&("up"==t?t=e[(e.indexOf(this.view.type)||5)+1]||null:"down"==t&&(t=e[(e.indexOf(this.view.type)||1)-1]||null),t&&this.con["view"+r(t)]||(t=!1)),!!t&&(this.renderDatePicker(this.dt,t),this.trigger("view",t))},switchDate:function(t,e,i,a){return"auto"===i&&(i=this.view.date.getDate(),(1===this.view.date.getMonth()&&28<=i||30<=i)&&(i=(i=new Date(t,e+1,0)).getDate())),this.view.date.setFullYear(null==t?this.view.date.getFullYear():t,null==e?this.view.date.getMonth():e,i||this.view.date.getDate()),!0===a||this.switchView(this.view.type)},switchMonth:function(t,e){return"string"==typeof t&&(t=0<=["previous","prev"].indexOf(t)?-1:1,t=this.view.date.getMonth()+type),this.switchDate(e||this.getFullYear(),t)},switchYear:function(t){return"string"==typeof t&&(t=0<=["previous","prev"].indexOf(t)?-1:1,t=this.view.date.getFullYear()+type),this.switchDate(t)},browseView:function(t){switch(t=0<=["previous","prev"].indexOf(t)?-1:1,this.view.type){case"days":return this.switchDate(null,this.view.date.getMonth()+t,"auto");case"months":return this.switchDate(this.view.date.getFullYear()+t,null,"auto");case"years":return this.switchDate(this.view.date.getFullYear()+10*t,null,"auto");case"decades":return this.switchDate(this.view.date.getFullYear()+100*t,null,"auto")}return!1},fetchDate:function(t){t=c(t||!1)||this.view.date;var e=this.dt.querySelectorAll("input[type=number]");return e&&3==e.length&&t.setHours(e[0].value||0,e[1].value||0,e[2].value||0,0),t},selectDate:function(t,e,i,a,n,s){var r=new Date,o=[];return this.con.dateFormat&&o.push(this.con.dateFormat),this.con.timeFormat&&o.push(this.con.timeFormat),this.select=t instanceof Date?t:new Date(t||(null==t?this.view.date.getFullYear():r.getFullYear()),e||(null==e?this.view.date.getMonth():r.getMonth()),i||(null==i?this.view.date.getDate():r.getDate()),a||(null==a?this.view.date.getHours():0),n||(null==n?this.view.date.getMinutes():0),s||(null==s?this.view.date.getSeconds():0)),this.view.date=new Date(this.select.getTime()),this.e.value=this.convertDate(this.select,o.join(" ")),this.e.setAttribute("data-value",this.select.getTime()),this.switchView("days"),this.trigger("change")},selectTime:function(t,e,i){return this.selectDate(void 0,void 0,void 0,t,e,i)},open:function(){if(!u(this.dt,"calendar-close"))return this;var e=this,i=this.dt.style;return i.display="block",i.opacity=this.con.animate?0:1,n(this.dt,"calendar-close"),a(this.dt,"calendar-idle"),u(this.dt,"calendar-static")||e.calcPosition(),function t(){if(1<=(i.opacity=parseFloat(i.opacity)+.125))return n(e.dt,"calendar-idle"),a(e.dt,"calendar-open"),e.trigger("open");setTimeout(t,20)}(),this},close:function(){if(!u(this.dt,"calendar-open"))return this;var e=this,i=this.dt.style;return i.display="block",i.opacity=this.con.animate?1:0,n(this.dt,"calendar-open"),a(this.dt,"calendar-idle"),function t(){if((i.opacity-=.125)<=0)return n(e.dt,"calendar-idle"),a(e.dt,"calendar-close"),i.display="none",e.trigger("close");setTimeout(t,20)}(),this},toggle:function(){return u(this.dt,"calendar-open")?this.close():u(this.dt,"calendar-close")?this.open():this},on:function(t,e,i){return!(["open","close","change","view"].indexOf(t)<0||"function"!=typeof e)&&(t in this.events||(this.events[t]=[]),this.events[t].push({cb:e,args:i instanceof Array?i:[]}),this)},remove:function(){return this.e.removeAttribute("data-tail-datetime"),this.e.removeAttribute("data-value"),this.dt.parentElement.removeChild(this.dt),this},reload:function(){return this.remove(),this.init()},config:function(t,e,i){if(t instanceof Object){for(var a in t)this.config(a,t[a],!1);return this.reload(),this.con}return void 0===t?this.con:t in this.con&&(void 0===e?this.con[t]:(this.con[t]=e,!1!==this.rebuild&&this.reload(),this))}},l});
taskmanager.js
new
+714
@@ -0,0 +1,714 @@
1
+/**
2
+* @description MeshCentral ScriptTask
3
+* @author Ryan Blenis
4
+* @copyright
5
+* @license Apache-2.0
6
+*/
7
+
8
+'use strict';
9
+
10
+module.exports.createTaskManager = function (parent) {
11
+ var obj = {};
12
+ obj.parent = parent.webserver;
13
+ obj.meshServer = parent;
14
+ obj.db = null;
15
+ obj.intervalTimer = null;
16
+ obj.debug = obj.meshServer.debug;
17
+ obj.VIEWS = __dirname + '/views/';
18
+ obj.exports = [
19
+ 'onDeviceRefreshEnd',
20
+ 'resizeContent',
21
+ 'historyData',
22
+ 'variableData',
23
+ 'malix_triggerOption'
24
+ ];
25
+
26
+ obj.malix_triggerOption = function(selectElem) {
27
+ selectElem.options.add(new Option("ScriptTask - Run Script", "scripttask_runscript"));
28
+ }
29
+ obj.malix_triggerFields_scripttask_runscript = function() {
30
+
31
+ }
32
+ obj.resetQueueTimer = function() {
33
+ clearTimeout(obj.intervalTimer);
34
+ obj.intervalTimer = setInterval(obj.queueRun, 1 * 60 * 1000); // every minute
35
+ };
36
+
37
+ // Start the task manager
38
+ obj.server_startup = function() {
39
+ obj.meshServer.pluginHandler.scripttask_db = require (__dirname + '/db.js').CreateDB(obj.meshServer);
40
+ obj.db = obj.meshServer.pluginHandler.scripttask_db;
41
+ obj.resetQueueTimer();
42
+ };
43
+
44
+ obj.onDeviceRefreshEnd = function() {
45
+ pluginHandler.registerPluginTab({ tabTitle: 'ScriptTask', tabId: 'pluginScriptTask' });
46
+ QA('pluginScriptTask', '<iframe id="pluginIframeScriptTask" style="width: 100%; height: 800px;" scrolling="no" frameBorder=0 src="/pluginadmin.ashx?pin=scripttask&user=1" />');
47
+ };
48
+
49
+ /*
50
+ // may not be needed, saving for later. Can be called to resize iFrame
51
+ obj.resizeContent = function() {
52
+ var iFrame = document.getElementById('pluginIframeScriptTask');
53
+ var newHeight = 800;
54
+ var sHeight = iFrame.contentWindow.document.body.scrollHeight;
55
+ if (sHeight > newHeight) newHeight = sHeight;
56
+ if (newHeight > 1600) newHeight = 1600;
57
+ iFrame.style.height = newHeight + 'px';
58
+ };
59
+ */
60
+
61
+ obj.queueRun = async function() {
62
+ var onlineAgents = Object.keys(obj.meshServer.webserver.wsagents);
63
+ //obj.debug('ScriptTask', 'Queue Running', Date().toLocaleString(), 'Online agents: ', onlineAgents);
64
+
65
+ obj.db.getPendingJobs(onlineAgents)
66
+ .then(function(jobs) {
67
+ if (jobs.length == 0) return;
68
+ //@TODO check for a large number and use taskLimiter to queue the jobs
69
+ jobs.forEach(function(job) {
70
+ obj.db.get(job.scriptId)
71
+ .then(async function(script) {
72
+ script = script[0];
73
+ var foundVars = script.content.match(/#(.*?)#/g);
74
+ var replaceVars = {};
75
+ if (foundVars != null && foundVars.length > 0) {
76
+ var foundVarNames = [];
77
+ foundVars.forEach(function(fv) { foundVarNames.push(fv.replace(/^#+|#+$/g, '')); });
78
+
79
+ var limiters = {
80
+ scriptId: job.scriptId,
81
+ nodeId: job.node,
82
+ meshId: obj.meshServer.webserver.wsagents[job.node]['dbMeshKey'],
83
+ names: foundVarNames
84
+ };
85
+ var finvals = await obj.db.getVariables(limiters);
86
+ var ordering = { 'global': 0, 'script': 1, 'mesh': 2, 'node': 3 }
87
+ finvals.sort(function(a, b) { return (ordering[a.scope] - ordering[b.scope]) || a.name.localeCompare(b.name); });
88
+ finvals.forEach(function(fv) { replaceVars[fv.name] = fv.value; });
89
+ replaceVars['GBL:meshId'] = obj.meshServer.webserver.wsagents[job.node]['dbMeshKey'];
90
+ replaceVars['GBL:nodeId'] = job.node;
91
+ //console.log('FV IS', finvals);
92
+ //console.log('RV IS', replaceVars);
93
+ }
94
+ var dispatchTime = Math.floor(new Date() / 1000);
95
+ var jObj = {
96
+ action: 'task',
97
+ subaction: 'triggerJob',
98
+ jobId: job._id,
99
+ scriptId: job.scriptId,
100
+ replaceVars: replaceVars,
101
+ scriptHash: script.contentHash,
102
+ dispatchTime: dispatchTime
103
+ };
104
+ //obj.debug('ScriptTask', 'Sending job to agent');
105
+ try {
106
+ obj.meshServer.webserver.wsagents[job.node].send(JSON.stringify(jObj));
107
+ obj.db.update(job._id, { dispatchTime: dispatchTime });
108
+ } catch (ex) { }
109
+ })
110
+ .catch(function (ex) { console.log('task: Could not dispatch job.', ex) });
111
+ });
112
+ })
113
+ .then(function() {
114
+ obj.makeJobsFromSchedules();
115
+ obj.cleanHistory();
116
+ })
117
+ .catch(function(ex) { console.log('task: Queue Run Error: ', ex); });
118
+ };
119
+
120
+ obj.cleanHistory = function() {
121
+ if (Math.round(Math.random() * 100) == 99) {
122
+ //obj.debug('Task', 'Running history cleanup');
123
+ obj.db.deleteOldHistory();
124
+ }
125
+ };
126
+
127
+ obj.downloadFile = function(req, res, user) {
128
+ var id = req.query.dl;
129
+ obj.db.get(id)
130
+ .then(function(found) {
131
+ if (found.length != 1) { res.sendStatus(401); return; }
132
+ var file = found[0];
133
+ res.setHeader('Content-disposition', 'attachment; filename=' + file.name);
134
+ res.setHeader('Content-type', 'text/plain');
135
+ //var fs = require('fs');
136
+ res.send(file.content);
137
+ });
138
+ };
139
+
140
+ obj.updateFrontEnd = async function(ids){
141
+ if (ids.scriptId != null) {
142
+ var scriptHistory = null;
143
+ obj.db.getJobScriptHistory(ids.scriptId)
144
+ .then(function(sh) {
145
+ scriptHistory = sh;
146
+ return obj.db.getJobSchedulesForScript(ids.scriptId);
147
+ })
148
+ .then(function(scriptSchedule) {
149
+ var targets = ['*', 'server-users'];
150
+ obj.meshServer.DispatchEvent(targets, obj, { nolog: true, action: 'task', subaction: 'historyData', scriptId: ids.scriptId, nodeId: null, scriptHistory: scriptHistory, nodeHistory: null, scriptSchedule: scriptSchedule });
151
+ });
152
+ }
153
+ if (ids.nodeId != null) {
154
+ var nodeHistory = null;
155
+ obj.db.getJobNodeHistory(ids.nodeId)
156
+ .then(function(nh) {
157
+ nodeHistory = nh;
158
+ return obj.db.getJobSchedulesForNode(ids.nodeId);
159
+ })
160
+ .then(function(nodeSchedule) {
161
+ var targets = ['*', 'server-users'];
162
+ obj.meshServer.DispatchEvent(targets, obj, { nolog: true, action: 'task', subaction: 'historyData', scriptId: null, nodeId: ids.nodeId, scriptHistory: null, nodeHistory: nodeHistory, nodeSchedule: nodeSchedule });
163
+ });
164
+ }
165
+ if (ids.tree === true) {
166
+ obj.db.getScriptTree()
167
+ .then(function(tree) {
168
+ var targets = ['*', 'server-users'];
169
+ obj.meshServer.DispatchEvent(targets, obj, { nolog: true, action: 'task', subaction: 'newScriptTree', tree: tree });
170
+ });
171
+ }
172
+ if (ids.variables === true) {
173
+ obj.db.getVariables()
174
+ .then(function(vars) {
175
+ var targets = ['*', 'server-users'];
176
+ obj.meshServer.DispatchEvent(targets, obj, { nolog: true, action: 'task', subaction: 'variableData', vars: vars });
177
+ });
178
+ }
179
+ };
180
+
181
+ obj.handleAdminReq = function(req, res, user) {
182
+ if ((user.siteadmin & 0xFFFFFFFF) == 1 && req.query.admin == 1)
183
+ {
184
+ // admin wants admin, grant
185
+ var vars = {};
186
+ res.render(obj.VIEWS + 'admin', vars);
187
+ return;
188
+ } else if (req.query.admin == 1 && (user.siteadmin & 0xFFFFFFFF) == 0) {
189
+ // regular user wants admin
190
+ res.sendStatus(401);
191
+ return;
192
+ } else if (req.query.user == 1) {
193
+ // regular user wants regular access, grant
194
+ if (req.query.dl != null) return obj.downloadFile(req, res, user);
195
+ var vars = {};
196
+
197
+ if (req.query.edit == 1) { // edit script
198
+ if (req.query.id == null) return res.sendStatus(401);
199
+ obj.db.get(req.query.id)
200
+ .then(function(scripts) {
201
+ if (scripts[0].filetype == 'proc') {
202
+ vars.procData = JSON.stringify(scripts[0]);
203
+ res.render(obj.VIEWS + 'procedit', vars);
204
+ } else {
205
+ vars.scriptData = JSON.stringify(scripts[0]);
206
+ res.render(obj.VIEWS + 'scriptedit', vars);
207
+ }
208
+ });
209
+ return;
210
+ } else if (req.query.schedule == 1) {
211
+ var vars = {};
212
+ res.render(obj.VIEWS + 'schedule', vars);
213
+ return;
214
+ }
215
+ // default user view (tree)
216
+ vars.scriptTree = 'null';
217
+ obj.db.getScriptTree()
218
+ .then(function(tree) {
219
+ vars.scriptTree = JSON.stringify(tree);
220
+ res.render(obj.VIEWS + 'user', vars);
221
+ });
222
+ return;
223
+ } else if (req.query.include == 1) {
224
+ switch (req.query.path.split('/').pop().split('.').pop()) {
225
+ case 'css': res.contentType('text/css'); break;
226
+ case 'js': res.contentType('text/javascript'); break;
227
+ }
228
+ res.sendFile(__dirname + '/includes/' + req.query.path); // don't freak out. Express covers any path issues.
229
+ return;
230
+ }
231
+ res.sendStatus(401);
232
+ return;
233
+ };
234
+
235
+ obj.historyData = function (message) {
236
+ if (typeof pluginHandler.scripttask.loadHistory == 'function') pluginHandler.scripttask.loadHistory(message);
237
+ if (typeof pluginHandler.scripttask.loadSchedule == 'function') pluginHandler.scripttask.loadSchedule(message);
238
+ };
239
+
240
+ obj.variableData = function (message) {
241
+ if (typeof pluginHandler.scripttask.loadVariables == 'function') pluginHandler.scripttask.loadVariables(message);
242
+ };
243
+
244
+ obj.determineNextJobTime = function(s) {
245
+ var nextTime = null;
246
+ var nowTime = Math.floor(new Date() / 1000);
247
+
248
+ // special case: we've reached the end of our run
249
+ if (s.endAt !== null && s.endAt <= nowTime) {
250
+ return nextTime;
251
+ }
252
+
253
+ switch (s.recur) {
254
+ case 'once':
255
+ if (s.nextRun == null) nextTime = s.startAt;
256
+ else nextTime = null;
257
+ break;
258
+ case 'minutes':
259
+ /*var lRun = s.nextRun || nowTime;
260
+ if (lRun == null) lRun = nowTime;
261
+ nextTime = lRun + (s.interval * 60);
262
+ if (s.startAt > nextTime) nextTime = s.startAt;*/
263
+ if (s.nextRun == null) { // hasn't run yet, set to start time
264
+ nextTime = s.startAt;
265
+ break;
266
+ }
267
+ nextTime = s.nextRun + (s.interval * 60);
268
+ // this prevents "catch-up" tasks being scheduled if an endpoint is offline for a long period of time
269
+ // e.g. always make sure the next scheduled time is relevant to the scheduled interval, but in the future
270
+ if (nextTime < nowTime) {
271
+ // initially I was worried about this causing event loop lockups
272
+ // if there was a long enough time gap. Testing over 50 years of backlog for a 3 min interval
273
+ // still ran under a fraction of a second. Safe to say this approach is safe! (~8.5 million times)
274
+ while (nextTime < nowTime) {
275
+ nextTime = nextTime + (s.interval * 60);
276
+ }
277
+ }
278
+ if (s.startAt > nextTime) nextTime = s.startAt;
279
+ break;
280
+ case 'hourly':
281
+ if (s.nextRun == null) { // hasn't run yet, set to start time
282
+ nextTime = s.startAt;
283
+ break;
284
+ }
285
+ nextTime = s.nextRun + (s.interval * 60 * 60);
286
+ if (nextTime < nowTime) {
287
+ while (nextTime < nowTime) {
288
+ nextTime = nextTime + (s.interval * 60 * 60);
289
+ }
290
+ }
291
+ if (s.startAt > nextTime) nextTime = s.startAt;
292
+ break;
293
+ case 'daily':
294
+ if (s.nextRun == null) { // hasn't run yet, set to start time
295
+ nextTime = s.startAt;
296
+ break;
297
+ }
298
+ nextTime = s.nextRun + (s.interval * 60 * 60 * 24);
299
+ if (nextTime < nowTime) {
300
+ while (nextTime < nowTime) {
301
+ nextTime = nextTime + (s.interval * 60 * 60 * 24);
302
+ }
303
+ }
304
+ if (s.startAt > nextTime) nextTime = s.startAt;
305
+ break;
306
+ case 'weekly':
307
+ var tempDate = new Date();
308
+ var nowDate = new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate());
309
+
310
+ if (s.daysOfWeek.length == 0) {
311
+ nextTime = null;
312
+ break;
313
+ }
314
+ s.daysOfWeek = s.daysOfWeek.map(function (el) { Number(el) });
315
+ var baseTime = s.startAt;
316
+ //console.log('dow is ', s.daysOfWeek);
317
+ var lastDayOfWeek = Math.max(...s.daysOfWeek);
318
+ var startX = 0;
319
+ //console.log('ldow is ', lastDayOfWeek);
320
+ if (s.nextRun != null) {
321
+ baseTime = s.nextRun;
322
+ //console.log('basetime 2: ', baseTime);
323
+ if (nowDate.getDay() == lastDayOfWeek) {
324
+ baseTime = baseTime + ( s.interval * 604800 ) - (lastDayOfWeek * 86400);
325
+ //console.log('basetime 3: ', baseTime);
326
+ }
327
+ startX = 0;
328
+ } else if (s.startAt < nowTime) {
329
+ baseTime = Math.floor(nowDate.getTime() / 1000);
330
+ //console.log('basetime 4: ', baseTime);
331
+ }
332
+ //console.log('startX is: ', startX);
333
+ //var secondsFromMidnight = nowTimeDate.getSeconds() + (nowTimeDate.getMinutes() * 60) + (nowTimeDate.getHours() * 60 * 60);
334
+ //console.log('seconds from midnight: ', secondsFromMidnight);
335
+ //var dBaseTime = new Date(0); dBaseTime.setUTCSeconds(baseTime);
336
+ //var dMidnight = new Date(dBaseTime.getFullYear(), dBaseTime.getMonth(), dBaseTime.getDate());
337
+ //baseTime = Math.floor(dMidnight.getTime() / 1000);
338
+ for (var x = startX; x <= 7; x++){
339
+ var checkDate = baseTime + (86400 * x);
340
+ var d = new Date(0); d.setUTCSeconds(checkDate);
341
+ var dm = new Date(d.getFullYear(), d.getMonth(), d.getDate());
342
+
343
+ console.log('testing date: ', dm.toLocaleString()); // dMidnight.toLocaleString());
344
+ //console.log('if break check :', (s.daysOfWeek.indexOf(d.getDay()) !== -1 && checkDate >= nowTime));
345
+ //console.log('checkDate vs nowTime: ', (checkDate - nowTime), ' if positive, nowTime is less than checkDate');
346
+ if (s.nextRun == null && s.daysOfWeek.indexOf(dm.getDay()) !== -1 && dm.getTime() >= nowDate.getTime()) break;
347
+ if (s.daysOfWeek.indexOf(dm.getDay()) !== -1 && dm.getTime() > nowDate.getTime()) break;
348
+ //if (s.daysOfWeek.indexOf(d.getDay()) !== -1 && Math.floor(d.getTime() / 1000) >= nowTime) break;
349
+ }
350
+ var sa = new Date(0); sa.setUTCSeconds(s.startAt);
351
+ var sad = new Date(sa.getFullYear(), sa.getMonth(), sa.getDate());
352
+ var diff = (sa.getTime() - sad.getTime()) / 1000;
353
+ nextTime = Math.floor(dm.getTime() / 1000) + diff;
354
+ //console.log('next schedule is ' + d.toLocaleString());
355
+ break;
356
+ default:
357
+ nextTime = null;
358
+ break;
359
+ }
360
+
361
+ if (s.endAt != null && nextTime > s.endAt) nextTime = null; // if the next time reaches the bound of the endAt time, nullify
362
+
363
+ return nextTime;
364
+ };
365
+
366
+ obj.makeJobsFromSchedules = function(scheduleId) {
367
+ //obj.debug('ScriptTask', 'makeJobsFromSchedules starting');
368
+ return obj.db.getSchedulesDueForJob(scheduleId)
369
+ .then(function(schedules) {
370
+ //obj.debug('ScriptTask', 'Found ' + schedules.length + ' schedules to process. Current time is: ' + Math.floor(new Date() / 1000));
371
+ if (schedules.length) {
372
+ schedules.forEach(function(s) {
373
+ var nextJobTime = obj.determineNextJobTime(s);
374
+ var nextJobScheduled = false;
375
+ if (nextJobTime === null) {
376
+ //obj.debug('ScriptTask', 'Removing Job Schedule for', JSON.stringify(s));
377
+ obj.db.removeJobSchedule(s._id);
378
+ } else {
379
+ //obj.debug('ScriptTask', 'Scheduling Job for', JSON.stringify(s));
380
+ obj.db.get(s.scriptId)
381
+ .then(function(scripts) {
382
+ // if a script is scheduled to run, but a previous run hasn't completed,
383
+ // don't schedule another job for the same (device probably offline).
384
+ // results in the minimum jobs running once an agent comes back online.
385
+ return obj.db.getIncompleteJobsForSchedule(s._id)
386
+ .then(function(jobs) {
387
+ if (jobs.length > 0) { /* obj.debug('Task', 'Skipping job creation'); */ return Promise.resolve(); }
388
+ else { /* obj.debug('Task', 'Creating new job'); */ nextJobScheduled = true; return obj.db.addJob( { scriptId: s.scriptId, scriptName: scripts[0].name, node: s.node, runBy: s.scheduledBy, dontQueueUntil: nextJobTime, jobSchedule: s._id } ); }
389
+ });
390
+ })
391
+ .then(function() {
392
+ if (nextJobScheduled) { /* obj.debug('Plugin', 'ScriptTask', 'Updating nextRun time'); */ return obj.db.update(s._id, { nextRun: nextJobTime }); }
393
+ else { /* obj.debug('Plugin', 'ScriptTask', 'NOT updating nextRun time'); */ return Promise.resolve(); }
394
+ })
395
+ .then(function() {
396
+ obj.updateFrontEnd( { scriptId: s.scriptId, nodeId: s.node } );
397
+ })
398
+ .catch(function(ex) { console.log('Task: Error managing job schedules: ', ex); });
399
+ }
400
+ });
401
+ }
402
+ });
403
+ };
404
+
405
+ obj.deleteElement = function (command) {
406
+ var delObj = null;
407
+ obj.db.get(command.id)
408
+ .then(function(found) {
409
+ var file = found[0];
410
+ delObj = {...{}, ...found[0]};
411
+ return file;
412
+ })
413
+ .then(function(file) {
414
+ if (file.type == 'folder') return obj.db.deleteByPath(file.path); //@TODO delete schedules for scripts within folders
415
+ if (file.type == 'script') return obj.db.deleteSchedulesForScript(file._id);
416
+ if (file.type == 'jobSchedule') return obj.db.deletePendingJobsForSchedule(file._id);
417
+ })
418
+ .then(function() {
419
+ return obj.db.delete(command.id)
420
+ })
421
+ .then(function() {
422
+ var updateObj = { tree: true };
423
+ if (delObj.type == 'jobSchedule') {
424
+ updateObj.scriptId = delObj.scriptId;
425
+ updateObj.nodeId = delObj.node;
426
+ }
427
+ return obj.updateFrontEnd( updateObj );
428
+ })
429
+ .catch(function(ex) { console.log('Task: Error deleting ', ex.stack); });
430
+ };
431
+
432
+ // Process 'task' commands received by an agent
433
+ obj.agentAction = function (command, agent) {
434
+ console.log('task-agentAction', command);
435
+ switch (command.subaction) {
436
+ case 'getScript':
437
+ // TODO
438
+ break;
439
+ case 'clearAllPendingTasks':
440
+ // TODO
441
+ break;
442
+ case 'taskComplete':
443
+ // TODO
444
+ break;
445
+ }
446
+ }
447
+
448
+ obj.serveraction = function(command, myparent, grandparent) {
449
+ switch (command.subaction) {
450
+ case 'addScript':
451
+ obj.db.addScript(command.name, command.content, command.path, command.filetype)
452
+ .then(function() { obj.updateFrontEnd( { tree: true } ); });
453
+ break;
454
+ case 'new':
455
+ var parent_path = '', new_path = '';
456
+ obj.db.get(command.parent_id)
457
+ .then(function(found) { if (found.length > 0) { var file = found[0]; parent_path = file.path; } else { parent_path = 'Shared'; } })
458
+ .then(function () { obj.db.addScript(command.name, '', parent_path, command.filetype); })
459
+ .then(function() { obj.updateFrontEnd( { tree: true } ); });
460
+ break;
461
+ case 'rename':
462
+ obj.db.get(command.id)
463
+ .then(function(docs) {
464
+ var doc = docs[0];
465
+ if (doc.type == 'folder') {
466
+ console.log('old', doc.path, 'new', doc.path.replace(doc.path, command.name));
467
+ return obj.db.update(command.id, { path: doc.path.replace(doc.name, command.name) })
468
+ .then(function() { // update sub-items
469
+ return obj.db.getByPath(doc.path)
470
+ })
471
+ .then(function(found) {
472
+ if (found.length > 0) {
473
+ var proms = [];
474
+ found.forEach(function(f) { proms.push(obj.db.update(f._id, { path: doc.path.replace(doc.name, command.name) } )); })
475
+ return Promise.all(proms);
476
+ }
477
+ })
478
+ } else {
479
+ return Promise.resolve();
480
+ }
481
+ })
482
+ .then(function() {
483
+ obj.db.update(command.id, { name: command.name })
484
+ })
485
+ .then(function() {
486
+ return obj.db.updateScriptJobName(command.id, command.name);
487
+ })
488
+ .then(function() {
489
+ obj.updateFrontEnd( { scriptId: command.id, nodeId: command.currentNodeId, tree: true } );
490
+ });
491
+ break;
492
+ case 'move':
493
+ var toPath = null, fromPath = null, parentType = null;
494
+ obj.db.get(command.to)
495
+ .then(function(found) { // get target data
496
+ if (found.length > 0) {
497
+ var file = found[0];
498
+ toPath = file.path;
499
+ } else throw Error('Target destination not found');
500
+ })
501
+ .then(function() { // get item to be moved
502
+ return obj.db.get(command.id);
503
+ })
504
+ .then(function(found) { // set item to new location
505
+ var file = found[0];
506
+ if (file.type == 'folder') {
507
+ fromPath = file.path;
508
+ toPath += '/' + file.name;
509
+ parentType = 'folder';
510
+ if (file.name == 'Shared' && file.path == 'Shared') throw Error('Cannot move top level directory: Shared');
511
+ }
512
+ return obj.db.update(command.id, { path: toPath } );
513
+ })
514
+ .then(function() { // update sub-items
515
+ return obj.db.getByPath(fromPath)
516
+ })
517
+ .then(function(found) {
518
+ if (found.length > 0) {
519
+ var proms = [];
520
+ found.forEach(function(f) {
521
+ proms.push(obj.db.update(f._id, { path: toPath } ));
522
+ })
523
+ return Promise.all(proms);
524
+ }
525
+ })
526
+ .then(function() {
527
+ return obj.updateFrontEnd( { tree: true } );
528
+ })
529
+ .catch(function(ex) { console.log('Task: Error moving ', ex.stack); });
530
+ break;
531
+ case 'newFolder':
532
+ var parent_path = '';
533
+ var new_path = '';
534
+
535
+ obj.db.get(command.parent_id)
536
+ .then(function(found) {
537
+ if (found.length > 0) {
538
+ var file = found[0];
539
+ parent_path = file.path;
540
+ } else {
541
+ parent_path = 'Shared';
542
+ }
543
+ })
544
+ .then(function() {
545
+ new_path = parent_path + '/' + command.name;
546
+ })
547
+ .then(function() {
548
+ return obj.db.addFolder(command.name, new_path);
549
+ })
550
+ .then(function () {
551
+ return obj.updateFrontEnd( { tree: true } );
552
+ })
553
+ .catch(function(ex) { console.log('Task: Error creating new folder ', ex.stack); });
554
+ break;
555
+ case 'delete':
556
+ obj.deleteElement(command);
557
+ break;
558
+ case 'addScheduledJob':
559
+ /* {
560
+ scriptId: scriptId,
561
+ node: s,
562
+ scheduledBy: myparent.user.name,
563
+ recur: command.recur, // [once, minutes, hourly, daily, weekly, monthly]
564
+ interval: x,
565
+ daysOfWeek: x, // only used for weekly recur val
566
+ // onTheXDay: x, // only used for monthly
567
+ startAt: x,
568
+ endAt: x,
569
+ runCountLimit: x,
570
+ lastRun: x,
571
+ nextRun: x,
572
+ type: "scheduledJob"
573
+ } */
574
+ var sj = command.schedule;
575
+
576
+ var sched = {
577
+ scriptId: command.scriptId,
578
+ node: null,
579
+ scheduledBy: myparent.user.name,
580
+ recur: sj.recur,
581
+ interval: sj.interval,
582
+ daysOfWeek: sj.dayVals,
583
+ startAt: sj.startAt,
584
+ endAt: sj.endAt,
585
+ lastRun: null,
586
+ nextRun: null,
587
+ type: "jobSchedule"
588
+ };
589
+ var sel = command.nodes;
590
+ var proms = [];
591
+ if (Array.isArray(sel)) {
592
+ sel.forEach(function(s) {
593
+ var sObj = {...sched, ...{ node: s }};
594
+ proms.push(obj.db.addJobSchedule( sObj ));
595
+ });
596
+ } else { test.push(sObj);
597
+ proms.push(obj.db.addJobSchedule( sObj ));
598
+ }
599
+ Promise.all(proms)
600
+ .then(function() {
601
+ obj.makeJobsFromSchedules();
602
+ return Promise.resolve();
603
+ })
604
+ .catch(function(ex) { console.log('Task: Error adding schedules. The error was: ', ex); });
605
+ break;
606
+ case 'runScript':
607
+ var scriptId = command.scriptId;
608
+ var sel = command.nodes;
609
+ var proms = [];
610
+ if (Array.isArray(sel)) {
611
+ sel.forEach(function(s) {
612
+ proms.push(obj.db.addJob( { scriptId: scriptId, node: s, runBy: myparent.user.name } ));
613
+ });
614
+ } else {
615
+ proms.push(obj.db.addJob( { scriptId: scriptId, node: sel, runBy: myparent.user.name } ));
616
+ }
617
+ Promise.all(proms)
618
+ .then(function() {
619
+ return obj.db.get(scriptId);
620
+ })
621
+ .then(function(scripts) {
622
+ return obj.db.updateScriptJobName(scriptId, scripts[0].name);
623
+ })
624
+ .then(function() {
625
+ obj.resetQueueTimer();
626
+ obj.queueRun();
627
+ obj.updateFrontEnd( { scriptId: scriptId, nodeId: command.currentNodeId } );
628
+ });
629
+ break;
630
+ case 'getScript':
631
+ //obj.debug('ScriptTask', 'getScript Triggered', JSON.stringify(command));
632
+ obj.db.get(command.scriptId)
633
+ .then(function(script) {
634
+ myparent.send(JSON.stringify({
635
+ action: 'task',
636
+ subaction: 'cacheScript',
637
+ nodeid: myparent.dbNodeKey,
638
+ rights: true,
639
+ sessionid: true,
640
+ script: script[0]
641
+ }));
642
+ });
643
+ break;
644
+ case 'jobComplete':
645
+ //obj.debug('ScriptTask', 'jobComplete Triggered', JSON.stringify(command));
646
+ var jobNodeHistory = null, scriptHistory = null;
647
+ var jobId = command.jobId, retVal = command.retVal, errVal = command.errVal, dispatchTime = command.dispatchTime;
648
+ var completeTime = Math.floor(new Date() / 1000);
649
+ obj.db.update(jobId, {
650
+ completeTime: completeTime,
651
+ returnVal: retVal,
652
+ errorVal: errVal,
653
+ dispatchTime: dispatchTime
654
+ })
655
+ .then(function() {
656
+ return obj.db.get(jobId)
657
+ .then(function(jobs) {
658
+ return Promise.resolve(jobs[0].jobSchedule);
659
+ })
660
+ .then(function(sId) {
661
+ if (sId == null) return Promise.resolve();
662
+ return obj.db.update(sId, { lastRun: completeTime } )
663
+ .then(function() {
664
+ obj.makeJobsFromSchedules(sId);
665
+ });
666
+ });
667
+ })
668
+ .then(function() {
669
+ obj.updateFrontEnd( { scriptId: command.scriptId, nodeId: myparent.dbNodeKey } );
670
+ })
671
+ .catch(function(ex) { console.log('Task: Failed to complete job. ', ex); });
672
+ // update front end by eventing
673
+ break;
674
+ case 'loadNodeHistory':
675
+ obj.updateFrontEnd( { nodeId: command.nodeId } );
676
+ break;
677
+ case 'loadScriptHistory':
678
+ obj.updateFrontEnd( { scriptId: command.scriptId } );
679
+ break;
680
+ case 'editScript':
681
+ obj.db.update(command.scriptId, { type: command.scriptType, name: command.scriptName, content: command.scriptContent })
682
+ .then(function() { obj.updateFrontEnd( { scriptId: command.scriptId, tree: true } ); });
683
+ break;
684
+ case 'clearAllPendingJobs':
685
+ obj.db.deletePendingJobsForNode(myparent.dbNodeKey);
686
+ break;
687
+ case 'loadVariables':
688
+ obj.updateFrontEnd( { variables: true } );
689
+ break;
690
+ case 'newVar':
691
+ obj.db.addVariable(command.name, command.scope, command.scopeTarget, command.value)
692
+ .then(function() { obj.updateFrontEnd( { variables: true } ); })
693
+ break;
694
+ case 'editVar':
695
+ obj.db.update(command.id, {
696
+ name: command.name,
697
+ scope: command.scope,
698
+ scopeTarget: command.scopeTarget,
699
+ value: command.value
700
+ })
701
+ .then(function() { obj.updateFrontEnd( { variables: true } ); })
702
+ break;
703
+ case 'deleteVar':
704
+ obj.db.delete(command.id)
705
+ .then(function() { obj.updateFrontEnd( { variables: true } ); })
706
+ break;
707
+ default:
708
+ console.log('Task: unknown action');
709
+ break;
710
+ }
711
+ };
712
+
713
+ return obj;
714
+}
\ No newline at end of file
views/task-schedule.handlebars
new
+249
@@ -0,0 +1,249 @@
1
+<html>
2
+<head>
3
+ <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
4
+ <link rel="stylesheet" type="text/css" href="/public/tail.DateTime/tail.datetime-default-blue.min.css" />
5
+ <style>
6
+ body {
7
+ font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
8
+ color: white;
9
+ }
10
+
11
+ #scriptContent {
12
+ width: 80%;
13
+ height: 80%;
14
+ }
15
+
16
+ #schedContentC {
17
+ padding: 20px;
18
+ }
19
+
20
+ #controlBar button {
21
+ cursor: pointer;
22
+ }
23
+
24
+ #scriptNameC {
25
+ padding: 20px;
26
+ }
27
+
28
+ #scriptName {
29
+ width: 300px;
30
+ }
31
+
32
+ #controlBar {
33
+ padding: 5px;
34
+ padding-left: 20px;
35
+ }
36
+
37
+ #left {
38
+ height: 100%;
39
+ width: 25%;
40
+ float: left;
41
+ }
42
+
43
+ #right {
44
+ height: 100%;
45
+ width: 75%;
46
+ float: right;
47
+ }
48
+
49
+ body {
50
+ background-color: #036;
51
+ }
52
+
53
+ #intervalListC {
54
+ list-style-type: none;
55
+ }
56
+
57
+ #daysListC {
58
+ list-style-type: none;
59
+ }
60
+
61
+ .rOpt {
62
+ height: 40px;
63
+ }
64
+
65
+ #daysListC {
66
+ display: inline-grid;
67
+ }
68
+
69
+ li {
70
+ padding: 2px;
71
+ }
72
+ </style>
73
+</head>
74
+<body onload="doOnLoad();">
75
+ <script type="text/javascript" src="/public/tail.DateTime/tail.datetime.min.js"></script>
76
+ <div id="scriptTaskSchedule">
77
+ <div id="controlBar">
78
+ <button onclick="goSave();">Schedule</button>
79
+ <button onclick="goCancel();">Cancel</button>
80
+ </div>
81
+ <div id="schedContentC">
82
+ <div id="left">
83
+ <span class="oTitle">Recurrence</span>
84
+ <ul id="intervalListC">
85
+ <li><label><input onclick="intervalSelected(this);" type="radio" checked name="recur" value="once">Once</label></li>
86
+ <li><label><input onclick="intervalSelected(this);" type="radio" name="recur" value="minutes">Minutes</label></li>
87
+ <li><label><input onclick="intervalSelected(this);" type="radio" name="recur" value="hourly">Hourly</label></li>
88
+ <li><label><input onclick="intervalSelected(this);" type="radio" name="recur" value="daily">Daily</label></li>
89
+ <li><label><input onclick="intervalSelected(this);" type="radio" name="recur" value="weekly">Weekly</label></li>
90
+ <!-- li><label><input type="radio" name="recur" value="monthly">Monthly</label></li -->
91
+ </ul>
92
+ </div>
93
+ <div id="right">
94
+ <div class="rOpt">
95
+ <span class="oTitle">Start: </span>
96
+ <input type="text" class="datePick" id="startDate" value="" />
97
+ <input type="text" class="timePick" id="startTime" value="" />
98
+ </div>
99
+ <div class="rOpt" id="intervalC" style="display: none;">
100
+ <span class="oTitle">Every: </span>
101
+ <input type="text" id="interval" value="1" /> <span id="hintText"></span>
102
+ </div>
103
+ <div class="rOpt" id="endC" style="display: none;">
104
+ <span class="oTitle">End: </span>
105
+ <input type="text" class="datePick" id="endDate" value="" />
106
+ <input type="text" class="timePick" id="endTime" value="" />
107
+ <label><input type="checkbox" id="endNever" checked onclick="checkEndNever(this);" /> Never</label>
108
+ </div>
109
+ <div class="rOpt" id="daysC" style="display: none;">
110
+ <span class="oTitle">Days: </span>
111
+ <ul id="daysListC">
112
+ <li><label><input type="checkbox" name="days[]" value="0"> Sunday</label></li>
113
+ <li><label><input type="checkbox" name="days[]" value="1"> Monday</label></li>
114
+ <li><label><input type="checkbox" name="days[]" value="2"> Tuesday</label></li>
115
+ <li><label><input type="checkbox" name="days[]" value="3"> Wednesday</label></li>
116
+ <li><label><input type="checkbox" name="days[]" value="4"> Thursday</label></li>
117
+ <li><label><input type="checkbox" name="days[]" value="5"> Friday</label></li>
118
+ <li><label><input type="checkbox" name="days[]" value="6"> Saturday</label></li>
119
+ </ul>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ </div>
124
+ <script type="text/javascript">
125
+
126
+ function checkEndNever(el) {
127
+ if (el.checked) {
128
+ Q('endDate').value = '';
129
+ Q('endTime').value = '';
130
+ }
131
+ }
132
+ function setTimePick() {
133
+ var d = new Date();
134
+ document.getElementById("startDate").value = d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate();
135
+ document.getElementById("startTime").value = d.getHours() + ':' + d.getMinutes();
136
+ tail.DateTime(".datePick", { position: "bottom", dateStart: Date(), timeFormat: false });
137
+ tail.DateTime(".timePick", { position: "bottom", dateFormat: false, timeFormat: "HH:ii", timeStepMinutes: 15 });
138
+ tail.datetime.inst[document.getElementById('endDate').getAttribute('data-tail-datetime')].on('change', function () {
139
+ document.getElementById('endNever').checked = false;
140
+ });
141
+ tail.datetime.inst[document.getElementById('endTime').getAttribute('data-tail-datetime')].on('change', function () {
142
+ document.getElementById('endNever').checked = false;
143
+ });
144
+ }
145
+
146
+ function doOnLoad() {
147
+ try {
148
+ if (scriptId == null) {
149
+ alert('Page reloaded and data lost. Please re-run scheduler from the main window.');
150
+ goCancel();
151
+ return;
152
+ }
153
+ } catch (e) {
154
+ alert('Page reloaded and data lost. Please re-run scheduler from the main window.');
155
+ goCancel();
156
+ return;
157
+ }
158
+ setTimePick();
159
+ }
160
+
161
+ function intervalSelected(el) {
162
+ var v = el.value;
163
+ switch (v) {
164
+ case 'once':
165
+ QV('intervalC', false);
166
+ QV('endC', false);
167
+ QV('daysC', false);
168
+ break;
169
+ case 'minutes':
170
+ QV('intervalC', true);
171
+ QV('endC', true);
172
+ QV('daysC', false);
173
+ QH('hintText', 'minute(s)');
174
+ break;
175
+ case 'hourly':
176
+ QV('intervalC', true);
177
+ QV('endC', true);
178
+ QV('daysC', false);
179
+ QH('hintText', 'hour(s)');
180
+ break;
181
+ case 'daily':
182
+ QV('intervalC', true);
183
+ QV('endC', true);
184
+ QV('daysC', false);
185
+ QH('hintText', 'day(s)');
186
+ break;
187
+ case 'weekly':
188
+ QV('intervalC', true);
189
+ QV('endC', true);
190
+ QV('daysC', true);
191
+ QH('hintText', 'week(s)');
192
+ break;
193
+ }
194
+ }
195
+ function goSave() {
196
+ var o = {};
197
+ var recurEls = document.getElementsByName("recur");
198
+ recurEls.forEach(function (el) {
199
+ if (el.checked) o.recur = el.value;
200
+ });
201
+ switch (o.recur) {
202
+ case 'once':
203
+ o.startAt = Date.parse(Q('startDate').value + ' ' + Q('startTime').value);
204
+ o.startAt = Math.floor(o.startAt / 1000);
205
+ break;
206
+ case 'minutes':
207
+ case 'hourly':
208
+ case 'daily':
209
+ o.startAt = Date.parse(Q('startDate').value + ' ' + Q('startTime').value);
210
+ o.startAt = Math.floor(o.startAt / 1000);
211
+ o.interval = Number(Q('interval').value);
212
+ if (Q('endNever').checked) o.endAt = null;
213
+ else {
214
+ o.endAt = Date.parse(Q('endDate').value + ' ' + Q('endTime').value);
215
+ o.endAt = Math.floor(o.endAt / 1000);
216
+ }
217
+ break;
218
+ case 'weekly':
219
+ o.startAt = Date.parse(Q('startDate').value + ' ' + Q('startTime').value);
220
+ o.startAt = Math.floor(o.startAt / 1000);
221
+ o.interval = Number(Q('interval').value);
222
+ if (Q('endNever').checked) o.endAt = null;
223
+ else {
224
+ o.endAt = Date.parse(Q('endDate').value + ' ' + Q('endTime').value);
225
+ o.endAt = Math.floor(o.endAt / 1000);
226
+ }
227
+ var dayEls = document.getElementsByName("days[]");
228
+ o.dayVals = [];
229
+ if (dayEls.length) {
230
+ dayEls.forEach(function (de) {
231
+ if (de.checked) o.dayVals.push(de.value);
232
+ });
233
+ }
234
+ break;
235
+ }
236
+ o.scriptId = scriptId;
237
+ o.nodes = nodes;
238
+
239
+ window.opener.schedCallback(o);
240
+ window.close();
241
+ }
242
+
243
+ function goCancel() {
244
+ window.close();
245
+ }
246
+
247
+ </script>
248
+</body>
249
+</html>
\ No newline at end of file
views/task-scriptedit.handlebars
new
+73
@@ -0,0 +1,73 @@
1
+<html>
2
+<head>
3
+ <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
4
+ <style>
5
+ body {
6
+ font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
7
+ color: white;
8
+ }
9
+
10
+ #scriptContent {
11
+ width: 80%;
12
+ height: 80%;
13
+ }
14
+
15
+ #scriptContentC {
16
+ padding: 20px;
17
+ }
18
+
19
+ #controlBar button {
20
+ cursor: pointer;
21
+ }
22
+
23
+ #scriptNameC {
24
+ padding: 20px;
25
+ }
26
+
27
+ #scriptName {
28
+ width: 300px;
29
+ }
30
+
31
+ #controlBar {
32
+ padding: 5px;
33
+ padding-left: 20px;
34
+ }
35
+
36
+ body {
37
+ background-color: #036;
38
+ }
39
+ </style>
40
+</head>
41
+<body onload="doOnLoad();">
42
+ <div id="scriptTaskScriptEdit">
43
+ <div id="scriptNameC">Script Name: <input type="text" value="" id="scriptName" /></div>
44
+ <div id="controlBar">
45
+ <button onclick="goSave();">Save</button>
46
+ <button onclick="goClose();">Close</button>
47
+ </div>
48
+ <div id="scriptContentC">
49
+ <textarea id="scriptContent"></textarea>
50
+ </div>
51
+ </div>
52
+ <script type="text/javascript">
53
+ var scriptData = {{{scriptData}}};
54
+
55
+ function doOnLoad() {
56
+ //QH('scriptContent', scriptData.content);
57
+ Q('scriptContent').value = scriptData.content;
58
+ Q('scriptName').value = scriptData.name;
59
+ }
60
+
61
+ function goSave() {
62
+ scriptData.content = Q('scriptContent').value;
63
+ scriptData.name = Q('scriptName').value;
64
+ window.opener.callback(scriptData);
65
+ //goClose();
66
+ }
67
+
68
+ function goClose() {
69
+ window.close();
70
+ }
71
+ </script>
72
+</body>
73
+</html>
\ No newline at end of file
views/task-user.handlebars
new
+1070
@@ -0,0 +1,1070 @@
1
+<html>
2
+<head>
3
+ <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
4
+ <style>
5
+ body {
6
+ font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
7
+ }
8
+
9
+ #dropBlock {
10
+ /*background-color: gray;
11
+ text-align: center;
12
+ height: 100%;
13
+ width: 100%;
14
+ position: absolute;
15
+ float:left;*/
16
+ width: 100%;
17
+ overflow: hidden;
18
+ position: absolute;
19
+ right: 437px;
20
+ padding-top: 100px;
21
+ text-align: center;
22
+ font-size: 1600%;
23
+ color: #AAA;
24
+ }
25
+
26
+ #scripts_endpoints {
27
+ width: 100%;
28
+ height: 100%;
29
+ }
30
+
31
+ #scriptContainer {
32
+ width: 35%;
33
+ height: 100%;
34
+ float: left;
35
+ }
36
+
37
+ #infoContainer {
38
+ width: 65%;
39
+ height: 100%;
40
+ float: right;
41
+ border-left: 1px;
42
+ }
43
+
44
+ .lifolder {
45
+ background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAM2xV/Xur+XPgP///yH5BAEAAAMALAAAAAAQABAAAAJD3ISZIGHWUGihznesYDYATFVM+D2hJ4lgN1olxALAtAlmPCJvuMmJd6PJckDYwicrHhTD5o7plJmg0Uc0asNMkphHAQA7) no-repeat 16px;
46
+ padding-left: 35px;
47
+ cursor: pointer;
48
+ border: none;
49
+ margin-top: 1px;
50
+ }
51
+
52
+ .liscript {
53
+ background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAPb19IGBgbq6uv///yH5BAEAAAMALAAAAAAQABAAAAIy3ISpxgcPH2ouQgFEw1YmxnUXKEaaEZZnVWZk66JwzKpvuwZzwOgwb/C1gIOA8Yg8DgoAOw==) no-repeat 16px;
54
+ padding-left: 35px;
55
+ cursor: pointer;
56
+ border: none;
57
+ margin-top: 1px;
58
+ }
59
+
60
+ .liselected {
61
+ background-color: lightgray;
62
+ }
63
+
64
+ #controlBar {
65
+ width: 100%;
66
+ height: 20px;
67
+ border-bottom: 1px solid black;
68
+ font-size: smaller;
69
+ margin-bottom: 7px;
70
+ }
71
+
72
+ #controlBar span {
73
+ cursor: pointer;
74
+ padding-left: 4px;
75
+ padding-right: 4px;
76
+ }
77
+
78
+ #controlBar > span:nth-child(n+2) {
79
+ border-left: 1px solid black;
80
+ }
81
+
82
+ .infoBar {
83
+ background-color: #777;
84
+ color: white;
85
+ cursor: pointer;
86
+ padding: 10px;
87
+ width: 100%;
88
+ border: none;
89
+ text-align: left;
90
+ outline: none;
91
+ font-size: 15px;
92
+ }
93
+
94
+ .infoBar.active, .infoBar:hover {
95
+ background-color: #555;
96
+ }
97
+
98
+ .infoContent {
99
+ display: none;
100
+ }
101
+
102
+ #nHistTbl, #sHistTbl, #nSchTbl, #sSchTbl, #varTbl {
103
+ font-size: smaller;
104
+ width: 100%;
105
+ }
106
+
107
+ #nHistTbl td, #sHistTbl td, #nSchTbl td, #sSchTbl td, #varTbl td {
108
+ padding-left: 5px;
109
+ padding-right: 5px;
110
+ }
111
+
112
+ .stNHRow, .stSHRow, .stNSRow, .stSSRow {
113
+ height: 36px;
114
+ max-height: 40px;
115
+ width: 100%;
116
+ }
117
+
118
+ .stNHRow:nth-child(odd) {
119
+ background-color: #CCC;
120
+ }
121
+
122
+ .stSHRow:nth-child(odd) {
123
+ background-color: #CCC;
124
+ }
125
+
126
+ .stNSRow:nth-child(odd) {
127
+ background-color: #CCC;
128
+ }
129
+
130
+ .stSSRow:nth-child(odd) {
131
+ background-color: #CCC;
132
+ }
133
+
134
+ .stVRow:nth-child(odd) {
135
+ background-color: #CCC;
136
+ }
137
+
138
+ .delSched {
139
+ cursor: pointer;
140
+ }
141
+
142
+ .nIcon {
143
+ width: 16px;
144
+ margin-top: 1px;
145
+ margin-left: 2px;
146
+ height: 16px;
147
+ display: inline-block;
148
+ margin-right: 10px;
149
+ }
150
+
151
+ .j1 {
152
+ background: url(../images/icons16.png) 0px 0px;
153
+ height: 16px;
154
+ width: 16px;
155
+ border: none;
156
+ }
157
+
158
+ .j2 {
159
+ background: url(../images/icons16.png) -16px 0px;
160
+ height: 16px;
161
+ width: 16px;
162
+ border: none;
163
+ }
164
+
165
+ .j3 {
166
+ background: url(../images/icons16.png) -32px 0px;
167
+ height: 16px;
168
+ width: 16px;
169
+ border: none;
170
+ }
171
+
172
+ .j4 {
173
+ background: url(../images/icons16.png) -48px 0px;
174
+ height: 16px;
175
+ width: 16px;
176
+ border: none;
177
+ }
178
+
179
+ .j5 {
180
+ background: url(../images/icons16.png) -64px 0px;
181
+ height: 16px;
182
+ width: 16px;
183
+ border: none;
184
+ }
185
+
186
+ .j6 {
187
+ background: url(../images/icons16.png) -80px 0px;
188
+ height: 16px;
189
+ width: 16px;
190
+ border: none;
191
+ }
192
+
193
+ .ftype {
194
+ font-size: small;
195
+ }
196
+
197
+ .tblFloat {
198
+ float: left;
199
+ width: 33%;
200
+ }
201
+
202
+ .flink {
203
+ cursor: pointer;
204
+ }
205
+ </style>
206
+</head>
207
+<body onload="doOnLoad();">
208
+ <div id="scriptTaskUser">
209
+ <div id="dropBlock" style="display:none;"><b>✓</b></div>
210
+ Upload: <input type="file" id="files" name="files[]" multiple onchange="fileUpload();" />
211
+ <hr />
212
+ <div id="controlBar">
213
+ <span onclick="goNew();">New</span>
214
+ <span onclick="goRename();">Rename</span>
215
+ <span onclick="goEdit();">Edit</span>
216
+ <span onclick="goDelete();">Delete</span>
217
+ <span onclick="goNewFolder();">New Folder</span>
218
+ <span onclick="goDownload();">Download</span>
219
+ <span onclick="goRun();">Run</span>
220
+ </div>
221
+ <div id="scripts_endpoints">
222
+ <div id="scriptContainer">
223
+ </div>
224
+ <div id="infoContainer">
225
+ <div id="history">
226
+ <div class="infoBar">Advanced Run</div>
227
+ <div id="multiRun" class="infoContent">
228
+ <div style="padding-top: 15px;"><button onclick="goAdvancedRun();">Schedule on Selected</button></div>
229
+ <div class="tblFloat">
230
+ <table id="mRunTbl" cellspacing="0" cellpadding="0">
231
+ <tr><td><label><input type="checkbox" onclick="selAllNodes(this);"> Select All</label></td></tr>
232
+ </table>
233
+ </div>
234
+ <div class="tblFloat">
235
+ <table id="mRunTblMesh" cellspacing="0" cellpadding="0">
236
+ <tr><td>Meshes</td></tr>
237
+ </table>
238
+ </div>
239
+ <div class="tblFloat">
240
+ <table id="mRunTblTag" cellspacing="0" cellpadding="0">
241
+ <tr><td>Tags</td></tr>
242
+ </table>
243
+ </div>
244
+ </div>
245
+ <div class="infoBar">Node Schedules</div>
246
+ <div id="nSch" class="infoContent">
247
+ <table id="nSchTbl" cellspacing="0" cellpadding="0">
248
+ <th>Script</th>
249
+ <th>Author</th>
250
+ <th>Every</th>
251
+ <th>Starting</th>
252
+ <th>Ending</th>
253
+ <th>Last Run</th>
254
+ <th>Next Run</th>
255
+ <th>Action</th>
256
+ </table>
257
+ </div>
258
+ <div class="infoBar">Script Schedules</div>
259
+ <div id="sSch" class="infoContent">
260
+ <table id="sSchTbl" cellspacing="0" cellpadding="0">
261
+ <th>Node</th>
262
+ <th>Author</th>
263
+ <th>Every</th>
264
+ <th>Starting</th>
265
+ <th>Ending</th>
266
+ <th>Last Run</th>
267
+ <th>Next Run</th>
268
+ <th>Action</th>
269
+ </table>
270
+ </div>
271
+ <div class="infoBar">Node History</div>
272
+ <div id="nodeHistory" class="infoContent">
273
+ <table id="nHistTbl" cellspacing="0" cellpadding="0">
274
+ <th>Time</th>
275
+ <th>Run By</th>
276
+ <th>Script</th>
277
+ <th>Status</th>
278
+ <th>Return Value</th>
279
+ </table>
280
+ </div>
281
+ <div class="infoBar">Script History</div>
282
+ <div id="scriptHistory" class="infoContent">
283
+ <table id="sHistTbl" cellspacing="0" cellpadding="0">
284
+ <th>Time</th>
285
+ <th>Run By</th>
286
+ <th>Node</th>
287
+ <th>Status</th>
288
+ <th>Return Value</th>
289
+ </table>
290
+ </div>
291
+ <div class="infoBar">Variables</div>
292
+ <div id="variables" class="infoContent">
293
+ <table id="varTbl" cellspacing="0" cellpadding="0">
294
+ <th>Variable Name</th>
295
+ <th>Value</th>
296
+ <th>Scope</th>
297
+ <th>Scope Target</th>
298
+ <th>Action</th>
299
+ </table>
300
+ <br />
301
+ <span class="flink" onclick="newVar();return false;">[+]</span>
302
+ </div>
303
+ </div>
304
+
305
+ </div>
306
+ </div>
307
+ </div>
308
+ <script type="text/javascript">
309
+ var scriptTree = {{{scriptTree}}};
310
+ var elementDragged = false;
311
+ var dragCounter = 0;
312
+ var draggedId = null;
313
+ var nodesObj = {};
314
+ var variables = [];
315
+ var varScopes = { global: 'Global', script: 'Script', mesh: 'Mesh', node: 'Node' };
316
+
317
+ function onlyUnique(value, index, self) {
318
+ return self.indexOf(value) === index;
319
+ }
320
+ function resizeIframe() {
321
+ document.body.style.height = 0;
322
+ parent.pluginHandler.scripttask.resizeContent();
323
+ }
324
+ function updateNodesTable() {
325
+ let dRows = document.querySelectorAll('.stNodeRow');
326
+ dRows.forEach((r) => {
327
+ r.parentNode.removeChild(r);
328
+ });
329
+ var tagList = [];
330
+ var nodeRowIns = document.querySelector('#mRunTbl');
331
+ parent.nodes.forEach(function(i) {
332
+ var item = {...i, ...{}};
333
+ if (item.mtype == 2) {
334
+ item.meshName = parent.meshes[item['meshid']].name;
335
+ if (item._id == parent.currentNode._id) item.checked = 'checked '; else item.checked = '';
336
+ let tpl = `<tr class="stNodeRow"><td><label><input type="checkbox" ${item.checked} name="runOn[]" value="${item._id}"> <div class="nIcon j${item.icon}"></div>${item.name}</label></td></tr>`;
337
+ nodeRowIns.insertAdjacentHTML('beforeend', tpl);
338
+ if (i.tags && i.tags.length) item.tags.forEach(function(t) { tagList.push(t) });
339
+ nodesObj[i._id] = i;
340
+ }
341
+ });
342
+ tagList = tagList.filter(onlyUnique); tagList = tagList.sort();
343
+ var nodeRowIns = document.querySelector('#mRunTblMesh');
344
+ for (const i in parent.meshes) { // parent.meshes.forEach(function(i) {
345
+ var item = {...parent.meshes[i], ...{}};
346
+ if (item.mtype == 2) {
347
+ let tpl = `<tr class="stNodeRow"><td><label><input type="checkbox" onclick="selNodesByMesh(this);" value="${item._id}"> ${item.name}</label></td></tr>`;
348
+ nodeRowIns.insertAdjacentHTML('beforeend', tpl);
349
+ }
350
+ }
351
+ var nodeRowIns = document.querySelector('#mRunTblTag');
352
+ tagList.forEach(function(i) {
353
+ let tpl = `<tr class="stNodeRow"><td><label><input type="checkbox" onclick="selNodesByTag(this)" value="${i}"> ${i}</label></td></tr>`;
354
+ nodeRowIns.insertAdjacentHTML('beforeend', tpl);
355
+ });
356
+ }
357
+
358
+ function selNodesByTag(el) {
359
+ var t = el.value;
360
+ var allNodes = Q('mRunTbl').querySelectorAll('input[type="checkbox"][name="runOn[]"]');
361
+ var checked = false;
362
+ if (el.checked) checked = true;
363
+ allNodes.forEach(function(n) {
364
+ if (nodesObj[n.value].tags && nodesObj[n.value].tags.indexOf(t) > -1) n.checked = checked;
365
+ });
366
+ return true;
367
+ }
368
+ function selNodesByMesh(el) {
369
+ var mid = el.value;
370
+ var allNodes = Q('mRunTbl').querySelectorAll('input[type="checkbox"][name="runOn[]"]');
371
+ var checked = false;
372
+ if (el.checked) checked = true;
373
+ allNodes.forEach(function(n) {
374
+ if (nodesObj[n.value].meshid == mid) n.checked = checked;
375
+ });
376
+ return true;
377
+ }
378
+ function selAllNodes(el) {
379
+ var allNodes = Q('mRunTbl').querySelectorAll('input[type="checkbox"][name="runOn[]"]');
380
+ var checked = false;
381
+ if (el.checked) checked = true;
382
+ allNodes.forEach(function(n) {
383
+ n.checked = checked;
384
+ });
385
+ return true;
386
+ }
387
+
388
+ function doOnLoad() {
389
+ redrawScriptTree();
390
+ selectPreviouslySelectedScript();
391
+ updateNodesTable();
392
+ parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'loadNodeHistory', 'nodeId': parent.currentNode._id });
393
+ parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'loadVariables', 'nodeId': parent.currentNode._id });
394
+ }
395
+
396
+ function selectPreviouslySelectedScript() {
397
+ var sel_item = parent.getstore('_scripttask_sel_item', null)
398
+ if (sel_item != null) {
399
+ var s = document.getElementById(sel_item);
400
+ if (s != null) {
401
+ s.classList.toggle('liselected');
402
+ goScript(s);
403
+ }
404
+ }
405
+ if (sel_item != null) parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'loadScriptHistory', 'scriptId': sel_item });
406
+ }
407
+
408
+ function goRun() {
409
+ var selScript = document.querySelectorAll('.liselected');
410
+ if (selScript.length) {
411
+ var scriptId = selScript[0].getAttribute('x-data-id');
412
+ if (scriptId == selScript[0].getAttribute('x-folder-id'))
413
+ {
414
+ parent.setDialogMode(2, "Oops!", 1, null, 'Please select a script. A folder is currently selected.');
415
+ }
416
+ else {
417
+ parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'runScript', 'scriptId': scriptId, 'nodes': [ parent.currentNode._id ], 'currentNodeId': parent.currentNode._id });
418
+ }
419
+ } else {
420
+ parent.setDialogMode(2, "Oops!", 1, null, 'No script has been selected to run on the machines.');
421
+ }
422
+ }
423
+
424
+ function goEdit() {
425
+ var selScript = document.querySelectorAll('.liselected');
426
+ if (selScript.length && (selScript[0].getAttribute('x-data-id') != selScript[0].getAttribute('x-data-folder'))) {
427
+ var scriptId = selScript[0].getAttribute('x-data-id');
428
+ window.open('/pluginadmin.ashx?pin=scripttask&user=1&edit=1&id=' + scriptId, '_blank');
429
+ window.callback = function(sd) {
430
+ parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'editScript', 'scriptId': sd._id, 'scriptType': sd.type, 'scriptName': sd.name, 'scriptContent': sd.content, 'currentNodeId': parent.currentNode._id });
431
+ };
432
+ } else {
433
+ parent.setDialogMode(2, "Oops!", 1, null, 'No script has been selected to edit.');
434
+ }
435
+ }
436
+
437
+ function goAdvancedRun() {
438
+ var cboxes = document.getElementsByName("runOn[]");
439
+ var sel = [];
440
+
441
+ cboxes.forEach((n) => {
442
+ if (n.checked) sel.push(n.value);
443
+ });
444
+ if (sel.length == 0) {
445
+ parent.setDialogMode(2, "Oops!", 1, null, 'No machines have been selected.');
446
+ return;
447
+ }
448
+ var selScript = document.querySelectorAll('.liselected');
449
+ if (selScript.length) {
450
+ var scriptId = selScript[0].getAttribute('x-data-id');
451
+ var sWin = window.open('/pluginadmin.ashx?pin=scripttask&user=1&schedule=1', 'schedule', "width=800,height=600");
452
+ sWin.scriptId = scriptId;
453
+ sWin.nodes = sel;
454
+ window.schedCallback = function(opts) {
455
+ parent.meshserver.send({
456
+ 'action': 'plugin',
457
+ 'plugin': 'scripttask',
458
+ 'pluginaction': 'addScheduledJob',
459
+ 'scriptId': opts.scriptId,
460
+ 'nodes': opts.nodes,
461
+ 'currentNodeId': parent.currentNode._id,
462
+ 'schedule': opts
463
+ });
464
+ };
465
+ } else {
466
+ parent.setDialogMode(2, "Oops!", 1, null, 'No script has been selected to run on the machines.');
467
+ }
468
+ }
469
+
470
+ var coll = document.getElementsByClassName("infoBar");
471
+ for (var i = 0; i < coll.length; i++) {
472
+ coll[i].addEventListener("click", function() {
473
+ this.classList.toggle("active");
474
+ var content = this.nextElementSibling;
475
+ if (content.style.display === "block") {
476
+ content.style.display = "none";
477
+ } else {
478
+ content.style.display = "block";
479
+ }
480
+ content.style.maxHeight = '300px';
481
+ content.style.overflowY = 'scroll';
482
+ resizeIframe();
483
+ });
484
+ }
485
+
486
+ function goDownload() {
487
+ var isSelected = document.querySelectorAll('.liselected');
488
+ if (isSelected.length == 0) return;
489
+ var sel = isSelected[0];
490
+ var id = sel.getAttribute('x-data-id');
491
+ if (id == sel.getAttribute('x-data-folder')) return;
492
+ window.location = '/pluginadmin.ashx?pin=scripttask&user=1&dl='+id;
493
+ }
494
+ function addScript(name, content, path) {
495
+ // file type testing
496
+ var n = name.split('.').pop().toLowerCase();
497
+ if (content.split('\n')[0][0] == '#' && content.split('\n')[0][1] == '!') n = 'bash';
498
+ if (['ps1', 'bat', 'bash'].indexOf(n) !== -1) {
499
+ parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'addScript', name: name, content: content, path: path, filetype: n });
500
+ }
501
+ else {
502
+ parent.setDialogMode(2, "Oops!", 1, null, 'Currently accepted filetypes are .ps1, .bat, and bash scripts.');
503
+ }
504
+ }
505
+ function redrawScriptTree() {
506
+ var lastpath = null;
507
+ var str = '';
508
+ var indent = 0;
509
+ var folder_id = null;
510
+ scriptTree.forEach(function(f) {
511
+ if (f.path != lastpath && f.type == 'folder') {
512
+ indent = (f.path.match(/\//g) || []).length + 1;
513
+ var name = f.path.match(/[^\/]+$/);
514
+ folder_id = f._id;
515
+ str += '<div draggable="true" x-data-path="' + f.path + '" x-data-id="' + f._id + '" x-data-folder="' + folder_id + '" style="margin-left: ' + indent + 'em;" class="lifolder" onclick="toggleCollapse(this);"><span class="fname">' + name + '</span></div>';
516
+ lastpath = f.path;
517
+ indent += 1;
518
+ }
519
+ if (f.type != 'folder') {
520
+ str += '<div id="' + f._id + '" draggable="true" x-data-path="' + f.path + '" x-data-id="' + f._id + '" x-data-folder="' + folder_id + '" style="margin-left: ' + indent + 'em;" class="liscript" onclick="goScript(this);"><span class="fname">' + f.name + '</span> [<span class="ftype">' + f.filetype + '</span>]</div>';
521
+ }
522
+ document.getElementById('scriptContainer').innerHTML = str;
523
+ });
524
+
525
+ var liScripts = document.querySelectorAll('.liscript');
526
+ var liFolders = document.querySelectorAll('.lifolder');
527
+ liScripts.forEach(function(el) {
528
+ el.addEventListener('mousedown', function() { elementDragged = true; });
529
+ el.addEventListener('mouseup', function() { elementDragged = false; });
530
+ el.addEventListener('dragstart', function(evt) { evt.dataTransfer.setData('text/plain', evt.target.getAttribute('x-data-id')); });
531
+ });
532
+ liFolders.forEach(function(el) {
533
+ el.addEventListener('drop', dropMove);
534
+ el.addEventListener('dragover', function(e) { e.preventDefault(); });
535
+ el.addEventListener('mousedown', function() { elementDragged = true; });
536
+ el.addEventListener('mouseup', function() { elementDragged = false; });
537
+ el.addEventListener('dragstart', function(evt) { evt.dataTransfer.setData('text/plain', evt.target.getAttribute('x-data-id')); });
538
+ });
539
+ resizeIframe();
540
+ selectPreviouslySelectedScript();
541
+ }
542
+ parent.pluginHandler.scripttask.newScriptTree = function(message) {
543
+ scriptTree = message.event.tree;
544
+ redrawScriptTree();
545
+ }
546
+ parent.pluginHandler.scripttask.loadHistory = function(message) {
547
+ // cache script names
548
+ var nNames = {};
549
+ parent.nodes.forEach(function(n){
550
+ nNames[n._id] = n.name;
551
+ });
552
+ if (message.event.nodeHistory != null && message.event.nodeId == parent.currentNode._id) {
553
+ var nHistTbl = document.getElementById('nHistTbl');
554
+ var rows = nHistTbl.querySelectorAll('.stNHRow');
555
+ if (rows.length) {
556
+ rows.forEach(function(r) {
557
+ r.parentNode.removeChild(r);
558
+ });
559
+ }
560
+ if (message.event.nodeHistory.length) {
561
+ message.event.nodeHistory.forEach(function(nh) {
562
+ nh.latestTime = Math.max(nh.completeTime, nh.queueTime, nh.dispatchTime, nh.dontQueueUntil);
563
+ });
564
+ message.event.nodeHistory.sort((a, b) => (a.latestTime < b.latestTime) ? 1 : -1);
565
+ message.event.nodeHistory.forEach(function(nh) {
566
+ nh = prepHistory(nh);
567
+ let tpl = '<td>' + nh.timeStr + '</td> \
568
+ <td>' + nh.runBy + '</td> \
569
+ <td>' + nh.scriptName + '</td> \
570
+ <td>' + nh.statusTxt + '</td> \
571
+ <td>' + nh.returnTxt + '</td>';
572
+ let tr = nHistTbl.insertRow(-1);
573
+ tr.innerHTML = tpl;
574
+ tr.classList.add('stNHRow');
575
+ });
576
+ }
577
+ }
578
+ var currentScript = document.getElementById('scriptHistory');
579
+ var currentScriptId = currentScript.getAttribute('x-data-id');
580
+ if (message.event.scriptHistory != null && message.event.scriptId == currentScriptId) {
581
+ var sHistTbl = document.getElementById('sHistTbl');
582
+ var rows = sHistTbl.querySelectorAll('.stSHRow');
583
+ if (rows.length) {
584
+ rows.forEach(function(r) {
585
+ r.parentNode.removeChild(r);
586
+ });
587
+ }
588
+ if (message.event.scriptHistory.length) {
589
+ message.event.scriptHistory.forEach(function(nh) {
590
+ nh.latestTime = Math.max(nh.completeTime, nh.queueTime, nh.dispatchTime, nh.dontQueueUntil);
591
+ });
592
+ message.event.scriptHistory.sort((a, b) => (a.latestTime < b.latestTime) ? 1 : -1);
593
+ message.event.scriptHistory.forEach(function(nh) {
594
+ nh = prepHistory(nh);
595
+ let tpl = '<td>' + nh.timeStr + '</td> \
596
+ <td>' + nh.runBy + '</td> \
597
+ <td>' + nNames[nh.node] + '</td> \
598
+ <td>' + nh.statusTxt + '</td> \
599
+ <td>' + nh.returnTxt + '</td>';
600
+ let tr = sHistTbl.insertRow(-1);
601
+ tr.innerHTML = tpl;
602
+ tr.classList.add('stSHRow');
603
+ });
604
+ }
605
+ }
606
+ resizeIframe();
607
+ }
608
+ function prepHistory(nh) {
609
+ var nowTime = Math.floor(new Date() / 1000);
610
+ var d = new Date(0);
611
+ d.setUTCSeconds(nh.latestTime);
612
+ nh.timeStr = d.toLocaleString();
613
+ if (nh.errorVal != null) { nh.returnTxt = nh.errorVal; } else { nh.returnTxt = nh.returnVal; }
614
+ nh.statusTxt = 'Queued';
615
+ if (nh.dispatchTime != null) nh.statusTxt = 'Running';
616
+ if (nh.errorVal != null) nh.statusTxt = 'Error';
617
+ if (nh.returnVal != null) nh.statusTxt = 'Completed';
618
+ if (nh.dontQueueUntil > nowTime) nh.statusTxt = 'Scheduled';
619
+ if (nh.returnTxt == null) nh.returnTxt = ' ';
620
+ if (nh.statusTxt == 'Completed') {
621
+ nh.statusTxt = '<span title="Completed ' + secondsToHms((nh.completeTime - nh.dispatchTime)) + '">' + nh.statusTxt + '</span>';
622
+ }
623
+ if (isJsonString(nh.returnTxt)) {
624
+ try {
625
+ nh.returnObj = JSON.parse(nh.returnTxt);
626
+ nh.returnTxt = 'Object: ';
627
+ nh.returnTxt += '' + JSON.stringify(nh.returnObj, null, 2);
628
+ nh.returnTxt = nh.returnTxt.replace(/\n\s*\n/g, '\n');
629
+ nh.returnTxt = nh.returnTxt.replace(/(?:\r\n|\r|\n)/g, '<br />');
630
+ } catch(e) { }
631
+ } else {
632
+ if (typeof nh.returnTxt == 'string') {
633
+ nh.returnTxt = nh.returnTxt.replace(/\n\s*\n/g, '\n');
634
+ nh.returnTxt = nh.returnTxt.replace(/(?:\r\n|\r|\n)/g, '<br />');
635
+ }
636
+ }
637
+ return nh;
638
+ }
639
+ parent.pluginHandler.scripttask.loadVariables = function(message) {
640
+ if (message.event.vars.length) {
641
+ var vars = message.event.vars;
642
+ vars.forEach(function(vd) {
643
+ switch (vd.scope) {
644
+ case 'global':
645
+ vd.scopeTargetTxt = vd.scopeTargetHtml = 'N/A';
646
+ break;
647
+ case 'script':
648
+ var s = scriptTree.filter(obj => { return obj._id === vd.scopeTarget })[0]
649
+ vd.scopeTargetHtml = '<span title="' + s.path + '">' + s.name + '</span>';
650
+ vd.scopeTargetTxt = s.name;
651
+ break;
652
+ case 'mesh':
653
+ vd.scopeTargetTxt = vd.scopeTargetHtml = parent.meshes[vd.scopeTarget].name;
654
+ break;
655
+ case 'node':
656
+ var n = parent.nodes.filter(obj => { return obj._id === vd.scopeTarget })[0]
657
+ vd.scopeTargetHtml = '<span title="' + n.meshnamel + '">' + n.name + '</span>';
658
+ vd.scopeTargetTxt = n.name;
659
+ break;
660
+ default:
661
+ vd.scopeTargetTxt = vd.scopeTargetHtml = 'N/A';
662
+ break;
663
+ }
664
+ vd.scopeTxt = varScopes[vd.scope];
665
+ })
666
+ var ordering = { 'global': 0, 'script': 1, 'mesh': 2, 'node': 3 }
667
+ vars.sort((a, b) => {
668
+ return (ordering[a.scope] - ordering[b.scope])
669
+ || a.name.localeCompare(b.name)
670
+ || a.scopeTargetTxt.localeCompare(b.scopeTargetTxt);
671
+ });
672
+ variables = vars;
673
+ parseVariables();
674
+ }
675
+ }
676
+ function parseVariables() {
677
+ var vTbl = document.getElementById('varTbl');
678
+ var rows = vTbl.querySelectorAll('.stVRow');
679
+
680
+ if (rows.length) {
681
+ rows.forEach(function(r) {
682
+ r.parentNode.removeChild(r);
683
+ });
684
+ }
685
+ var scriptEl = document.querySelectorAll('.liselected');
686
+ if (scriptEl.length != 1) return;
687
+ var el = scriptEl[0];
688
+ scopeTargetScriptId = el.getAttribute('x-data-id');
689
+ variables.forEach(function(vd) {
690
+ if (vd.scope == 'script' && vd.scopeTarget != scopeTargetScriptId) return;
691
+ if (vd.scope == 'mesh' && vd.scopeTarget != parent.currentNode.meshid) return;
692
+ if (vd.scope == 'node' && vd.scopeTarget != parent.currentNode._id) return;
693
+ let actionHtml = '<span class="flink" onclick="editVar(this);">Edit</span> <span class="flink" onclick="delVar(this);">Delete</span>';
694
+ let tpl = '<td>' + vd.name + '</td> \
695
+ <td>' + vd.value + '</td> \
696
+ <td>' + vd.scopeTxt + '</td> \
697
+ <td>' + vd.scopeTargetHtml + '</td> \
698
+ <td>' + actionHtml + '</td>';
699
+ let tr = vTbl.insertRow(-1);
700
+ tr.innerHTML = tpl;
701
+ tr.classList.add('stVRow');
702
+ tr.setAttribute('x-data-id', vd._id);
703
+ })
704
+ }
705
+ parent.pluginHandler.scripttask.loadSchedule = function(message) {
706
+ // cache script names
707
+ var nNames = {}, sNames = {};
708
+ parent.nodes.forEach(function(n){
709
+ nNames[n._id] = n.name;
710
+ });
711
+ scriptTree.forEach(function(s) {
712
+ if (s.type == 'script') sNames[s._id] = s.name;
713
+ });
714
+ if (message.event.nodeSchedule != null && message.event.nodeId == parent.currentNode._id) {
715
+ var nTbl = document.getElementById('nSchTbl');
716
+ var rows = nTbl.querySelectorAll('.stNSRow');
717
+ if (rows.length) {
718
+ rows.forEach(function(r) {
719
+ r.parentNode.removeChild(r);
720
+ });
721
+ }
722
+ if (message.event.nodeSchedule.length) {
723
+ message.event.nodeSchedule.forEach(function(nh) {
724
+ nh = prepSchedule(nh);
725
+ let tpl = '<td>' + sNames[nh.scriptId] + '</td> \
726
+ <td>' + nh.scheduledBy + '</td> \
727
+ <td>' + nh.everyTxt + '</td> \
728
+ <td>' + nh.startedTxt + '</td> \
729
+ <td>' + nh.endingTxt + '</td> \
730
+ <td>' + nh.lastRunTxt + '</td> \
731
+ <td>' + nh.nextRunTxt + '</td> \
732
+ <td>' + nh.actionTxt + '</td>';
733
+ let tr = nTbl.insertRow(-1);
734
+ tr.innerHTML = tpl;
735
+ tr.classList.add('stNSRow');
736
+ tr.setAttribute('x-data-id', nh._id);
737
+ });
738
+ }
739
+ }
740
+ var currentScript = document.getElementById('scriptHistory');
741
+ var currentScriptId = currentScript.getAttribute('x-data-id');
742
+ if (message.event.scriptSchedule != null && message.event.scriptId == currentScriptId) {
743
+ var sTbl = document.getElementById('sSchTbl');
744
+ var rows = sTbl.querySelectorAll('.stSSRow');
745
+ if (rows.length) {
746
+ rows.forEach(function(r) {
747
+ r.parentNode.removeChild(r);
748
+ });
749
+ }
750
+ if (message.event.scriptSchedule.length) {
751
+ message.event.scriptSchedule.forEach(function(nh) {
752
+ nh = prepSchedule(nh);
753
+ let tpl = '<td>' + nNames[nh.node] + '</td> \
754
+ <td>' + nh.scheduledBy + '</td> \
755
+ <td>' + nh.everyTxt + '</td> \
756
+ <td>' + nh.startedTxt + '</td> \
757
+ <td>' + nh.endingTxt + '</td> \
758
+ <td>' + nh.lastRunTxt + '</td> \
759
+ <td>' + nh.nextRunTxt + '</td> \
760
+ <td>' + nh.actionTxt + '</td>';
761
+ let tr = sTbl.insertRow(-1);
762
+ tr.innerHTML = tpl;
763
+ tr.classList.add('stSSRow');
764
+ tr.setAttribute('x-data-id', nh._id);
765
+ });
766
+ }
767
+ }
768
+ resizeIframe();
769
+ }
770
+ function prepSchedule(nh) {
771
+ nh.everyTxt = nh.interval + ' ';
772
+ switch (nh.recur) {
773
+ case 'once':
774
+ nh.everyTxt = 'Once';
775
+ break;
776
+ case 'minutes':
777
+ nh.everyTxt += 'minute';
778
+ break;
779
+ case 'hourly':
780
+ nh.everyTxt += 'hour';
781
+ break;
782
+ case 'daily':
783
+ nh.everyTxt += 'day';
784
+ break;
785
+ case 'weekly':
786
+ nh.everyTxt += 'week';
787
+ break;
788
+ case 'monthly':
789
+ nh.everyTxt += 'month';
790
+ break;
791
+ }
792
+ if (nh.interval > 1) nh.everyTxt += 's';
793
+
794
+ if (nh.recur == 'weekly') {
795
+ nh.daysOfWeek = nh.daysOfWeek.map(el => Number(el));
796
+ nh.everyTxt += ' (';
797
+ nh.daysOfWeek.forEach(function(num) {
798
+ switch(num) {
799
+ case 0: nh.everyTxt += 'S'; break;
800
+ case 1: nh.everyTxt += 'M'; break;
801
+ case 2: nh.everyTxt += 'T'; break;
802
+ case 3: nh.everyTxt += 'W'; break;
803
+ case 4: nh.everyTxt += 'R'; break;
804
+ case 5: nh.everyTxt += 'F'; break;
805
+ case 6: nh.everyTxt += 'S'; break;
806
+ }
807
+ });
808
+ nh.everyTxt += ')';
809
+ }
810
+
811
+ var d = new Date(0); d.setUTCSeconds(nh.startAt);
812
+ nh.startedTxt = d.toLocaleString();
813
+ d = new Date(0); d.setUTCSeconds(nh.endAt);
814
+ nh.endingTxt = d.toLocaleString();
815
+ if (nh.endAt == null) nh.endingTxt = 'Never';
816
+ if (nh.recur == 'once') nh.endingTxt = 'After first run';
817
+ d = new Date(0); d.setUTCSeconds(nh.lastRun);
818
+ nh.lastRunTxt = d.toLocaleString();
819
+ if (nh.lastRun == null) nh.lastRunTxt = 'Never';
820
+ d = new Date(0); d.setUTCSeconds(nh.nextRun);
821
+ nh.nextRunTxt = d.toLocaleString();
822
+ if (nh.nextRun == null) nh.nextRunTxt = 'Never';
823
+ if (nh.nextRun < nh.lastRun) nh.nextRunTxt = 'Running now';
824
+
825
+ nh.actionTxt = '<span class="delSched" onclick="deleteSchedule(this);">Delete</span>';
826
+ return nh;
827
+ }
828
+ function secondsToHms(d) {
829
+ d = Number(d);
830
+ if (d == 0) return "immediately";
831
+ var h = Math.floor(d / 3600);
832
+ var m = Math.floor(d % 3600 / 60);
833
+ var s = Math.floor(d % 3600 % 60);
834
+
835
+ var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : "";
836
+ var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : "";
837
+ var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : "";
838
+ return "in " + hDisplay + mDisplay + sDisplay;
839
+ }
840
+ function isJsonString(str) {
841
+ try {
842
+ JSON.parse(str);
843
+ } catch (e) {
844
+ return false;
845
+ }
846
+ return true;
847
+ }
848
+ function newVarEx() {
849
+ var name = parent.document.getElementById('stvarname').value;
850
+ var scope = parent.document.getElementById('stvarscope').value;
851
+ var value = parent.document.getElementById('stvarvalue').value;
852
+ var scopeTarget = null;
853
+ if (scope == 'script') {
854
+ var scriptEl = document.querySelectorAll('.liselected');
855
+ if (scriptEl.length != 1) return;
856
+ var el = scriptEl[0];
857
+ scopeTarget = el.getAttribute('x-data-id');
858
+ } else if (scope == 'mesh') {
859
+ scopeTarget = parent.currentNode.meshid;
860
+ } else if (scope == 'node') {
861
+ scopeTarget = parent.currentNode._id;
862
+ }
863
+ parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'newVar', name: name, scope: scope, scopeTarget: scopeTarget, value: value, currentNodeId: parent.currentNode._id });
864
+
865
+ }
866
+ function newVar() {
867
+ parent.setDialogMode(2, "New Variable", 3, newVarEx, 'Variable Name: <input type="text" id=stvarname /><br />Scope: <select id=stvarscope><option value="global">Global</option><option value="script">Script</option><option value="mesh">Mesh</option><option value="node">Node</option></select><br />Value: <input id="stvarvalue" type="text" />');
868
+ parent.focusTextBox('stvarname');
869
+ }
870
+ function editVarEx() {
871
+ var varid = parent.document.getElementById('stvarid').value;
872
+ var name = parent.document.getElementById('stvarname').value;
873
+ var scope = parent.document.getElementById('stvarscope').value;
874
+ var value = parent.document.getElementById('stvarvalue').value;
875
+ var scopeTarget = null;
876
+ if (scope == 'script') {
877
+ var scriptEl = document.querySelectorAll('.liselected');
878
+ if (scriptEl.length != 1) return;
879
+ var el = scriptEl[0];
880
+ scopeTarget = el.getAttribute('x-data-id');
881
+ } else if (scope == 'mesh') {
882
+ scopeTarget = parent.currentNode.meshid;
883
+ } else if (scope == 'node') {
884
+ scopeTarget = parent.currentNode._id;
885
+ }
886
+ parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'editVar', id: varid, name: name, scope: scope, scopeTarget: scopeTarget, value: value, currentNodeId: parent.currentNode._id });
887
+ }
888
+ function editVar(el) {
889
+ var vid = el.parentNode.parentNode.getAttribute('x-data-id');
890
+ var v = variables.filter(obj => { return obj._id === vid })[0];
891
+ var soptHtml = '';
892
+ for (const [k, t] of Object.entries(varScopes)) {
893
+ soptHtml += '<option value="' + k + '"';
894
+ if (v.scope == k) soptHtml += ' selected';
895
+ soptHtml += '>' + t + '</option>';
896
+ }
897
+ parent.setDialogMode(2, "Edit Variable", 3, editVarEx, 'Variable Name: <input type="text" id=stvarname value="' + v.name + '" /><br />Scope: <select id=stvarscope>' + soptHtml + '</select><br />Value: <input id="stvarvalue" type="text" value="' + v.value + '" /><input type="hidden" id="stvarid" value="' + vid + '" />');
898
+ parent.focusTextBox('stvarname');
899
+ }
900
+ function delVarEx() {
901
+ var varid = parent.document.getElementById('stvarid').value;
902
+ parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'deleteVar', id: varid, currentNodeId: parent.currentNode._id });
903
+
904
+ }
905
+ function delVar(el) {
906
+ var vid = el.parentNode.parentNode.getAttribute('x-data-id');
907
+ var v = variables.filter(obj => { return obj._id === vid })[0];
908
+ parent.setDialogMode(2, "Delete Variable", 3, delVarEx, 'Are you sure you want to delete this?<input type="hidden" id="stvarid" value="' + vid + '" /><br />Name: '+ v.name +'<br />Scope: '+ varScopes[v.scope] +'<br />Value: '+ v.value);
909
+ }
910
+ function renameEx() {
911
+ var name = parent.document.getElementById('stfilename').value;
912
+ var id = parent.document.getElementById('stid').value;
913
+ parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'rename', name: name, id: id, currentNodeId: parent.currentNode._id });
914
+ }
915
+ function goRename() {
916
+ var scriptEl = document.querySelectorAll('.liselected');
917
+ if (scriptEl.length != 1) return;
918
+ var el = scriptEl[0];
919
+ var name = el.querySelector('.fname').innerHTML;
920
+ var id = el.getAttribute('x-data-id');
921
+ parent.setDialogMode(2, "Rename " + name, 3, renameEx, '<input type="text" value="' + name + '" id=stfilename style=width:100% /><input type="hidden" id="stid" value="' + id + '" />');
922
+ parent.focusTextBox('stfilename');
923
+ }
924
+ function newEx() {
925
+ var name = parent.document.getElementById('stfilename').value;
926
+ var parent_id = parent.document.getElementById('stfolderid').value;
927
+ var fileType = parent.document.getElementById('stfiletype').value;
928
+ parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'new', name: name, parent_id: parent_id, filetype: fileType, currentNodeId: parent.currentNode._id });
929
+ }
930
+ function goNew() {
931
+ var scriptEl = document.querySelectorAll('.liselected');
932
+ var folder_id = null;
933
+ if (scriptEl.length > 0) {
934
+ var el = scriptEl[0];
935
+ folder_id = el.getAttribute('x-data-folder');
936
+ }
937
+ parent.setDialogMode(2, "New Script", 3, newEx, 'Name: <input type="text" value="' + name + '" id=stfilename style=width:100% /><br />Type:<select id="stfiletype"><option value="bash">Bash</option><option value="bat">BAT</option><option value="ps1">PS1</option></select><input type="hidden" id="stfolderid" value="' + folder_id + '" />');
938
+ parent.focusTextBox('stfilename');
939
+ }
940
+ function newFolderEx() {
941
+ var name = parent.document.getElementById('stfoldername').value;
942
+ var parent_id = parent.document.getElementById('stfolderid').value;
943
+ parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'newFolder', name: name, parent_id: parent_id });
944
+ }
945
+ function goNewFolder() {
946
+ var scriptEl = document.querySelectorAll('.liselected');
947
+ var folder_id = null;
948
+ if (scriptEl.length > 0) {
949
+ var el = scriptEl[0];
950
+ folder_id = el.getAttribute('x-data-folder');
951
+ }
952
+ parent.setDialogMode(2, "New Folder", 3, newFolderEx, '<input type="text" value="" id=stfoldername style=width:100% /><input type="hidden" id="stfolderid" value="' + folder_id + '" />');
953
+ parent.focusTextBox('stfoldername');
954
+ }
955
+ function goScript(el) {
956
+ var xdi = el.getAttribute('x-data-id');
957
+ var scriptEls = document.querySelectorAll('.liselected');
958
+ parent.putstore('_scripttask_sel_item', xdi);
959
+ scriptEls.forEach(function(e) {
960
+ e.classList.remove('liselected');
961
+ })
962
+ el.classList.add('liselected');
963
+ Q('scriptHistory').setAttribute('x-data-id', el.getAttribute('x-data-id'));
964
+ if (xdi != el.getAttribute('x-data-folder')) {
965
+ parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'loadScriptHistory', scriptId: xdi });
966
+ }
967
+ parseVariables();
968
+ }
969
+ function deleteEx() {
970
+ var id = parent.document.getElementById('stdelid').value;
971
+ parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'delete', id: id });
972
+ }
973
+ function goDelete() {
974
+ var els = document.querySelectorAll('.liselected');
975
+ if (els.length == 0) return;
976
+ var el = els[0];
977
+ var name = el.innerHTML;
978
+ var id = el.getAttribute('x-data-id');
979
+ parent.setDialogMode(2, "Delete " + name, 3, deleteEx, 'Are you sure? <input type="hidden" id="stdelid" value="' + id + '" />');
980
+ }
981
+ function deleteScheduleEx() {
982
+ var id = parent.document.getElementById('stdelid').value;
983
+ parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'delete', id: id });
984
+ }
985
+ function deleteSchedule(el) {
986
+ var id = el.parentNode.parentNode.getAttribute('x-data-id');
987
+ parent.setDialogMode(2, "Delete Schedule", 3, deleteScheduleEx, 'Are you sure you want to delete this schedule? <input type="hidden" id="stdelid" value="' + id + '" />');
988
+ }
989
+ function toggleCollapse(el) {
990
+ var xdf = el.getAttribute('x-data-path');
991
+ var folderEls = document.querySelectorAll('.lifolder, .liscript');
992
+ var showHide = null;
993
+ folderEls.forEach(function(e){
994
+ if (e === el) return;
995
+ if (e.getAttribute('x-data-path').indexOf(xdf) !== -1) {
996
+ if (e.style.display == 'none') {
997
+ if (showHide === null) showHide = '';
998
+ } else {
999
+ if (showHide === null) showHide = 'none';
1000
+ }
1001
+ e.style.display = showHide;
1002
+ }
1003
+ });
1004
+ goScript(el);
1005
+ }
1006
+ function handleFileSelect(evt) {
1007
+ evt.preventDefault();
1008
+ var files = evt.dataTransfer.files; // FileList object
1009
+ // files is a FileList of File objects. List some properties.
1010
+ QV('dropBlock', false);
1011
+ var output = [];
1012
+ fileUpload(files);
1013
+ elementDragged = false;
1014
+ if (dragTimer != null) dragTimer = null;
1015
+ //document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
1016
+ }
1017
+
1018
+ function fileUpload(files) {
1019
+ if (files == null) files = document.getElementById('files').files;
1020
+ var path = null;
1021
+ var isSelected = document.querySelectorAll('.liselected');
1022
+ if (isSelected.length) {
1023
+ var sel = isSelected[0];
1024
+ path = sel.getAttribute('x-data-path');
1025
+ }
1026
+ for (var i = 0, f; f = files[i]; i++) {
1027
+ var reader = new FileReader();
1028
+ reader.fileName = f.name;
1029
+ reader.readAsBinaryString(f);
1030
+ reader.addEventListener('loadend', function(e, file){
1031
+ addScript(e.currentTarget.fileName, e.currentTarget.result, path);
1032
+ });
1033
+ }
1034
+ }
1035
+
1036
+ var dropZone = document.getElementById('scriptTaskUser');
1037
+ var dropBlock = document.getElementById('dropBlock');
1038
+ var dragTimer = null;
1039
+ function allowDrag(e) {
1040
+ if (!elementDragged) { // Test that the item being dragged is a valid one
1041
+ e.dataTransfer.dropEffect = 'copy';
1042
+ QV('dropBlock', true);
1043
+ e.preventDefault();
1044
+ clearTimeout(dragTimer);
1045
+ dragTimer = setTimeout(function(){ dragCounter = 0; QV('dropBlock', false); }, 100);
1046
+ }
1047
+ }
1048
+
1049
+ function dropMove(evt) {
1050
+ const move_id = evt.dataTransfer.getData('text');
1051
+ const container_id = evt.target.parentNode.getAttribute('x-data-id');
1052
+ parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'move', id: move_id, to: container_id });
1053
+ }
1054
+ // file upload events
1055
+ window.addEventListener('dragenter', function(e) {
1056
+ dragCounter++;
1057
+ });
1058
+ dropZone.addEventListener('dragenter', allowDrag);
1059
+ dropZone.addEventListener('dragover', allowDrag);
1060
+ dropZone.addEventListener('dragleave', function(e) {
1061
+ dragCounter--;
1062
+ if (dragCounter == 0) {
1063
+ QV('dropBlock', false);
1064
+ elementDragged = false;
1065
+ }
1066
+ });
1067
+ dropZone.addEventListener('drop', handleFileSelect);
1068
+ </script>
1069
+</body>
1070
+</html>
\ No newline at end of file