Changed how stript-task will be integrated into MeshCentral, added run button to device general tab.
Ylian Saint-Hilaire committed
Aug 18, 2022 at 21:31 UTC
44af3a24084efcda8268d4f4937515fec019f313
10 files changed
+44
-2550
agents/meshcore.js
-10
@@ -708,7 +708,6 @@ db = require('SimpleDataStore').Shared();
708
sha = require('SHA256Stream');
709
mesh = require('MeshAgent');
710
childProcess = require('child_process');
711
-try { scriptTask = require('script-task').CreateScriptTask(mesh); } catch (ex) { }
711
712
if (mesh.hasKVM == 1) { // if the agent is compiled with KVM support
713
// Check if this computer supports a desktop
@@ -1556,10 +1555,6 @@ function handleServerCommand(data) {
1555
try { require(data.plugin).consoleaction(data, data.rights, data.sessionid, this); } catch (ex) { throw ex; }
1556
break;
1557
}
1559
- case 'task': {
1560
- if (scriptTask) { scriptTask.consoleAction(data, data.rights, data.sessionid, false); }
1561
- break;
1562
- }
1558
case 'coredump':
1559
// Set the current agent coredump situation.s
1560
if (data.value === true) {
@@ -4565,11 +4560,6 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
4560
}
4561
break;
4562
}
4568
- case 'task': {
4569
- if (!scriptTask) { response = "Tasks are not supported on this agent"; }
4570
- else { response = scriptTask.consoleAction(args, rights, sessionid, true); }
4571
- break;
4572
- }
4563
case 'plugin': {
4564
if (typeof args['_'][0] == 'string') {
4565
try {
agents/modules_meshcore/script-task.js
deleted
-416
@@ -1,416 +0,0 @@
1
-/**
2
-* @description MeshCentral Script-Task
3
-* @author Ryan Blenis
4
-* @copyright
5
-* @license Apache-2.0
6
-*/
7
-
8
-'use strict';
9
-function CreateScriptTask(parent) {
10
- var obj = {};
11
- var db = require('SimpleDataStore').Shared();
12
- var pendingDownload = [];
13
- var debugFlag = false;
14
- var runningJobs = [];
15
- var runningJobPIDs = {};
16
-
17
- function dbg(str) {
18
- if (debugFlag !== true) return;
19
- var fs = require('fs');
20
- var logStream = fs.createWriteStream('scripttask.txt', { 'flags': 'a' });
21
- // use {'flags': 'a'} to append and {'flags': 'w'} to erase and write a new file
22
- logStream.write('\n' + new Date().toLocaleString() + ': ' + str);
23
- logStream.end('\n');
24
- }
25
-
26
- function removeFromArray(arr, from, to) {
27
- var rest = arr.slice((to || from) + 1 || arr.length);
28
- arr.length = from < 0 ? arr.length + from : from;
29
- return arr.push.apply(arr, rest);
30
- };
31
-
32
- obj.consoleAction = function(args, rights, sessionid, interactive) {
33
- //sendConsoleText('task: ' + JSON.stringify(args), sessionid); // Debug
34
-
35
- /*
36
- if (typeof args['_'] == 'undefined') {
37
- args['_'] = [];
38
- args['_'][1] = args.pluginaction; // TODO
39
- args['_'][2] = null;
40
- args['_'][3] = null;
41
- args['_'][4] = null;
42
- }
43
- */
44
-
45
- var fnname = args['_'][0];
46
- if (fnname == null) { return "Valid task commands are: trigger, cache, clear, clearCache, debug, list"; }
47
-
48
- switch (fnname.toLowerCase()) {
49
- case 'trigger': {
50
- var jObj = {
51
- jobId: args.jobId,
52
- scriptId: args.scriptId,
53
- replaceVars: args.replaceVars,
54
- scriptHash: args.scriptHash,
55
- dispatchTime: args.dispatchTime
56
- };
57
- //dbg('jObj args is ' + JSON.stringify(jObj));
58
- var sObj = getScriptFromCache(jObj.scriptId);
59
- //dbg('sobj = ' + JSON.stringify(sObj) + ', shash = ' + jObj.scriptHash);
60
- if ((sObj == null) || (sObj.contentHash != jObj.scriptHash)) {
61
- // get from the server, then run
62
- //dbg('Getting and caching script '+ jObj.scriptId);
63
- parent.SendCommand({ action: 'script-task', subaction: 'getScript', scriptId: jObj.scriptId, sessionid: sessionid, tag: 'console' });
64
- pendingDownload.push(jObj);
65
- } else {
66
- // ready to run
67
- runScript(sObj, jObj, sessionid);
68
- }
69
- break;
70
- }
71
- case 'cache': {
72
- var sObj = args.script;
73
- cacheScript(sObj);
74
- var setRun = [];
75
- if (pendingDownload.length) {
76
- pendingDownload.forEach(function (pd, k) {
77
- if ((pd.scriptId == sObj._id) && (pd.scriptHash == sObj.contentHash)) {
78
- if (setRun.indexOf(pd) === -1) { runScript(sObj, pd, sessionid); setRun.push(pd); }
79
- removeFromArray(pendingDownload, k);
80
- }
81
- });
82
- }
83
- break;
84
- }
85
- case 'clear': {
86
- clearCache();
87
- parent.SendCommand({ action: 'script-task', subaction: 'clearAllPendingTasks', sessionid: sessionid, tag: 'console' });
88
- return "Cache cleared. All pending tasks cleared.";
89
- }
90
- case 'clearcache': {
91
- clearCache();
92
- return "The script cache has been cleared";
93
- }
94
- case 'debug': {
95
- debugFlag = (debugFlag) ? false : true;
96
- var str = (debugFlag) ? 'on' : 'off';
97
- return 'Debugging is now ' + str;
98
- }
99
- case 'list': {
100
- var ret = '';
101
- if (pendingDownload.length == 0) return "No tasks pending script download";
102
- pendingDownload.forEach(function (pd, k) { ret += 'Task ' + k + ': ' + 'TaskID: ' + pd.jobId + ' ScriptID: ' + pd.scriptId + '\r\n'; });
103
- return ret;
104
- }
105
- default: {
106
- dbg('Unknown action: ' + fnname + ' with data ' + JSON.stringify(args));
107
- break;
108
- }
109
- }
110
- }
111
-
112
- function finalizeJob(job, retVal, errVal, sessionid) {
113
- if (errVal != null && errVal.stack != null) errVal = errVal.stack;
114
- removeFromArray(runningJobs, runningJobs.indexOf(job.jobId));
115
- if (typeof runningJobPIDs[job.jobId] != 'undefined') delete runningJobPIDs[job.jobId];
116
- parent.SendCommand({
117
- action: 'script-task',
118
- subaction: 'taskComplete',
119
- jobId: job.jobId,
120
- scriptId: job.scriptId,
121
- retVal: retVal,
122
- errVal: errVal,
123
- dispatchTime: job.dispatchTime, // include original run time (long running tasks could have tried a re-send)
124
- sessionid: sessionid,
125
- tag: 'console'
126
- });
127
- }
128
-
129
- //@TODO Test powershell on *nix devices with and without powershell installed
130
- function runPowerShell(sObj, jObj, sessionid) {
131
- if (process.platform != 'win32') return runPowerShellNonWin(sObj, jObj);
132
- const fs = require('fs');
133
- var rand = Math.random().toString(32).replace('0.', '');
134
-
135
- var oName = 'st' + rand + '.txt';
136
- var pName = 'st' + rand + '.ps1';
137
- var pwshout = '', pwsherr = '', cancontinue = false;
138
- try {
139
- fs.writeFileSync(pName, sObj.content);
140
- var outstr = '', errstr = '';
141
- var child = require('child_process').execFile(process.env['windir'] + '\\system32\\WindowsPowerShell\\v1.0\\powershell.exe', ['-NoLogo']);
142
- child.stderr.on('data', function (chunk) { errstr += chunk; });
143
- child.stdout.on('data', function (chunk) { });
144
- runningJobPIDs[jObj.jobId] = child.pid;
145
- child.stdin.write('.\\' + pName + ' | Out-File ' + oName + ' -Encoding UTF8\r\n');
146
- child.on('exit', function (procRetVal, procRetSignal) {
147
- dbg('Exiting with ' + procRetVal + ', Signal: ' + procRetSignal);
148
- if (errstr != '') {
149
- finalizeJob(jObj, null, errstr, sessionid);
150
- try { fs.unlinkSync(oName); fs.unlinkSync(pName); } catch (ex) { dbg('Could not unlink files, error was: ' + ex); }
151
- return;
152
- }
153
- if (procRetVal == 1) {
154
- finalizeJob(jObj, null, 'Process terminated unexpectedly.', sessionid);
155
- try { fs.unlinkSync(oName); fs.unlinkSync(pName); } catch (ex) { dbg('Could not unlink files, error was: ' + ex); }
156
- return;
157
- }
158
- try { outstr = fs.readFileSync(oName, 'utf8').toString(); } catch (ex) { outstr = (procRetVal) ? 'Failure' : 'Success'; }
159
- if (outstr) {
160
- //outstr = outstr.replace(/[^\x20-\x7E]/g, '');
161
- try { outstr = outstr.trim(); } catch (ex) { }
162
- } else {
163
- outstr = (procRetVal) ? 'Failure' : 'Success';
164
- }
165
- dbg('Output is: ' + outstr);
166
- finalizeJob(jObj, outstr, null, sessionid);
167
- try { fs.unlinkSync(oName); fs.unlinkSync(pName); } catch (ex) { }
168
- });
169
- child.stdin.write('exit\r\n');
170
- //child.waitExit(); // this was causing the event loop to stall on long-running scripts, switched to '.on exit'
171
-
172
- } catch (ex) {
173
- dbg('Error block was (PowerShell): ' + ex);
174
- finalizeJob(jObj, null, ex, sessionid);
175
- }
176
- }
177
-
178
- function runPowerShellNonWin(sObj, jObj, sessionid) {
179
- const fs = require('fs');
180
- var rand = Math.random().toString(32).replace('0.', '');
181
-
182
- var path = '';
183
- var pathTests = ['/usr/local/mesh', '/tmp', '/usr/local/mesh_services/meshagent', '/var/tmp'];
184
- pathTests.forEach(function (p) { if (path == '' && fs.existsSync(p)) { path = p; } });
185
- dbg('Path chosen is: ' + path);
186
- path = path + '/';
187
-
188
- var oName = 'st' + rand + '.txt';
189
- var pName = 'st' + rand + '.ps1';
190
- var pwshout = '', pwsherr = '', cancontinue = false;
191
- try {
192
- var childp = require('child_process').execFile('/bin/sh', ['sh']);
193
- childp.stderr.on('data', function (chunk) { pwsherr += chunk; });
194
- childp.stdout.on('data', function (chunk) { pwshout += chunk; });
195
- childp.stdin.write('which pwsh' + '\n');
196
- childp.stdin.write('exit\n');
197
- childp.waitExit();
198
- } catch (ex) { finalizeJob(jObj, null, "Couldn't determine pwsh in env: " + ex, sessionid); }
199
- if (pwsherr != '') { finalizeJob(jObj, null, "PowerShell env determination error: " + pwsherr, sessionid); return; }
200
- if (pwshout.trim() != '') { cancontinue = true; }
201
- if (cancontinue === false) { finalizeJob(jObj, null, "PowerShell is not installed", sessionid); return; }
202
- try {
203
- fs.writeFileSync(path + pName, '#!' + pwshout + '\n' + sObj.content.split('\r\n').join('\n').split('\r').join('\n'));
204
- var outstr = '', errstr = '';
205
- var child = require('child_process').execFile('/bin/sh', ['sh']);
206
- child.stderr.on('data', function (chunk) { errstr += chunk; });
207
- child.stdout.on('data', function (chunk) { });
208
- runningJobPIDs[jObj.jobId] = child.pid;
209
-
210
- child.stdin.write('cd ' + path + '\n');
211
- child.stdin.write('chmod a+x ' + pName + '\n');
212
- child.stdin.write('./' + pName + ' > ' + oName + '\n');
213
- child.on('exit', function (procRetVal, procRetSignal) {
214
- if (errstr != '') {
215
- finalizeJob(jObj, null, errstr, sessionid);
216
- try {
217
- fs.unlinkSync(path + oName);
218
- fs.unlinkSync(path + pName);
219
- } catch (ex) { dbg('Could not unlink files, error was: ' + ex + ' for path ' + path); }
220
- return;
221
- }
222
- if (procRetVal == 1) {
223
- finalizeJob(jObj, null, 'Process terminated unexpectedly.', sessionid);
224
- try {
225
- fs.unlinkSync(path + oName);
226
- fs.unlinkSync(path + pName);
227
- } catch (ex) { dbg('Could not unlink files1, error was: ' + ex + ' for path ' + path); }
228
- return;
229
- }
230
- try { outstr = fs.readFileSync(path + oName, 'utf8').toString(); } catch (es) { outstr = (procRetVal) ? 'Failure' : 'Success'; }
231
- if (outstr) {
232
- //outstr = outstr.replace(/[^\x20-\x7E]/g, '');
233
- try { outstr = outstr.trim(); } catch (ex) { }
234
- } else {
235
- outstr = (procRetVal) ? 'Failure' : 'Success';
236
- }
237
- dbg('Output is: ' + outstr);
238
- finalizeJob(jObj, outstr, null, sessionid);
239
- try { fs.unlinkSync(path + oName); fs.unlinkSync(path + pName); } catch (ex) { dbg('Could not unlink files2, error was: ' + ex + ' for path ' + path); }
240
- });
241
- child.stdin.write('exit\n');
242
- } catch (ex) {
243
- dbg('Error block was (PowerShellNonWin): ' + ex);
244
- finalizeJob(jObj, null, ex, sessionid);
245
- }
246
- }
247
-
248
- function runBat(sObj, jObj, sessionid) {
249
- if (process.platform != 'win32') { finalizeJob(jObj, null, "Platform not supported.", sessionid); return; }
250
- const fs = require('fs');
251
- var rand = Math.random().toString(32).replace('0.', '');
252
- var oName = 'st' + rand + '.txt';
253
- var pName = 'st' + rand + '.bat';
254
- try {
255
- fs.writeFileSync(pName, sObj.content);
256
- var outstr = '', errstr = '';
257
- var child = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe');
258
- child.stderr.on('data', function (chunk) { errstr += chunk; });
259
- child.stdout.on('data', function (chunk) { });
260
- runningJobPIDs[jObj.jobId] = child.pid;
261
- child.stdin.write(pName + ' > ' + oName + '\r\n');
262
- child.stdin.write('exit\r\n');
263
-
264
- child.on('exit', function (procRetVal, procRetSignal) {
265
- if (errstr != '') {
266
- try { fs.unlinkSync(oName); fs.unlinkSync(pName); } catch (ex) { dbg('Could not unlink files, error was: ' + ex); }
267
- finalizeJob(jObj, null, errstr, sessionid);
268
- return;
269
- }
270
- if (procRetVal == 1) {
271
- try { fs.unlinkSync(oName); fs.unlinkSync(pName); } catch (ex) { dbg('Could not unlink files, error was: ' + ex); }
272
- finalizeJob(jObj, null, 'Process terminated unexpectedly.', sessionid);
273
- return;
274
- }
275
- try { outstr = fs.readFileSync(oName, 'utf8').toString(); } catch (ex) { outstr = (procRetVal) ? 'Failure' : 'Success'; }
276
- if (outstr) {
277
- //outstr = outstr.replace(/[^\x20-\x7E]/g, '');
278
- try { outstr = outstr.trim(); } catch (ex) { }
279
- } else {
280
- outstr = (procRetVal) ? 'Failure' : 'Success';
281
- }
282
- dbg('Output is: ' + outstr);
283
- try { fs.unlinkSync(oName); fs.unlinkSync(pName); } catch (ex) { dbg('Could not unlink files, error was: ' + ex); }
284
- finalizeJob(jObj, outstr, null, sessionid);
285
- });
286
- } catch (ex) {
287
- dbg('Error block was (BAT): ' + ex);
288
- finalizeJob(jObj, null, ex, sessionid);
289
- }
290
- }
291
-
292
- function runBash(sObj, jObj, sessionid) {
293
- if (process.platform == 'win32') { finalizeJob(jObj, null, "Platform not supported.", sessionid); return; }
294
- //dbg('proc is ' + JSON.stringify(process));
295
- const fs = require('fs');
296
- var path = '';
297
- var pathTests = ['/usr/local/mesh', '/tmp', '/usr/local/mesh_services/meshagent', '/var/tmp'];
298
- pathTests.forEach(function (p) {
299
- if (path == '' && fs.existsSync(p)) { path = p; }
300
- });
301
- dbg('Path chosen is: ' + path);
302
- path = path + '/';
303
- //var child = require('child_process');
304
- //child.execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], { type: 1 });
305
-
306
- var rand = Math.random().toString(32).replace('0.', '');
307
- var oName = 'st' + rand + '.txt';
308
- var pName = 'st' + rand + '.sh';
309
- try {
310
- fs.writeFileSync(path + pName, sObj.content);
311
- var outstr = '', errstr = '';
312
- var child = require('child_process').execFile('/bin/sh', ['sh']);
313
- child.stderr.on('data', function (chunk) { errstr += chunk; });
314
- child.stdout.on('data', function (chunk) { });
315
- runningJobPIDs[jObj.jobId] = child.pid;
316
- child.stdin.write('cd ' + path + '\n');
317
- child.stdin.write('chmod a+x ' + pName + '\n');
318
- child.stdin.write('./' + pName + ' > ' + oName + '\n');
319
- child.stdin.write('exit\n');
320
-
321
- child.on('exit', function (procRetVal, procRetSignal) {
322
- if (errstr != '') {
323
- try { fs.unlinkSync(path + oName); fs.unlinkSync(path + pName); } catch (ex) { dbg('Could not unlink files, error was: ' + ex + ' for path ' + path); }
324
- finalizeJob(jObj, null, errstr, sessionid);
325
- return;
326
- }
327
- if (procRetVal == 1) {
328
- try { fs.unlinkSync(path + oName); fs.unlinkSync(path + pName); } catch (ex) { dbg('Could not unlink files1, error was: ' + ex + ' for path ' + path); }
329
- finalizeJob(jObj, null, "Process terminated unexpectedly.", sessionid);
330
- return;
331
- }
332
- try { outstr = fs.readFileSync(path + oName, 'utf8').toString(); } catch (ex) { outstr = (procRetVal) ? 'Failure' : 'Success'; }
333
- if (outstr) {
334
- //outstr = outstr.replace(/[^\x20-\x7E]/g, '');
335
- try { outstr = outstr.trim(); } catch (ex) { }
336
- } else {
337
- outstr = (procRetVal) ? 'Failure' : 'Success';
338
- }
339
- dbg('Output is: ' + outstr);
340
- try { fs.unlinkSync(path + oName); fs.unlinkSync(path + pName); } catch (ex) { dbg('Could not unlink files2, error was: ' + ex + ' for path ' + path); }
341
- finalizeJob(jObj, outstr, null, sessionid);
342
- });
343
- } catch (ex) {
344
- dbg('Error block was (bash): ' + ex);
345
- finalizeJob(jObj, null, ex, sessionid);
346
- }
347
- }
348
-
349
- function jobIsRunning(jObj) {
350
- if (runningJobs.indexOf(jObj.jobId) === -1) return false;
351
- return true;
352
- }
353
-
354
- function runScript(sObj, jObj, sessionid) {
355
- // get current processes and clean running jobs if they are no longer running (computer fell asleep, user caused process to stop, etc.)
356
- if (process.platform != 'linux' && runningJobs.length) { // linux throws errors here in the meshagent for some reason
357
- require('process-manager').getProcesses(function (plist) {
358
- dbg('Got process list');
359
- dbg('There are currently ' + runningJobs.length + ' running jobs.');
360
- if (runningJobs.length) {
361
- runningJobs.forEach(function (jobId, idx) {
362
- dbg('Checking for running job: ' + jobId + ' with PID ' + runningJobPIDs[jobId]);
363
- if (typeof plist[runningJobPIDs[jobId]] == 'undefined' || typeof plist[runningJobPIDs[jobId]].cmd != 'string') {
364
- dbg('Found job with no process. Removing running status.');
365
- delete runningJobPIDs[jobId];
366
- removeFromArray(runningJobs, runningJobs.indexOf(idx));
367
- //dbg('RunningJobs: ' + JSON.stringify(runningJobs));
368
- //dbg('RunningJobsPIDs: ' + JSON.stringify(runningJobPIDs));
369
- }
370
- });
371
- }
372
- });
373
- }
374
- if (jobIsRunning(jObj)) { dbg('Job already running job id [' + jObj.jobId + ']. Skipping.'); return; }
375
- if (jObj.replaceVars != null) {
376
- Object.getOwnPropertyNames(jObj.replaceVars).forEach(function (key) {
377
- var val = jObj.replaceVars[key];
378
- sObj.content = sObj.content.replace(new RegExp('#' + key + '#', 'g'), val);
379
- dbg('replacing var ' + key + ' with ' + val);
380
- });
381
- sObj.content = sObj.content.replace(new RegExp('#(.*?)#', 'g'), 'VAR_NOT_FOUND');
382
- }
383
- runningJobs.push(jObj.jobId);
384
- dbg('Running Script ' + sObj._id);
385
- switch (sObj.filetype) {
386
- case 'ps1': runPowerShell(sObj, jObj, sessionid); break;
387
- case 'bat': runBat(sObj, jObj, sessionid); break;
388
- case 'bash': runBash(sObj, jObj, sessionid); break;
389
- default: dbg('Unknown filetype: ' + sObj.filetype); break;
390
- }
391
- }
392
-
393
- function getScriptFromCache(id) {
394
- var script = db.Get('scriptTask_script_' + id);
395
- if (script == '' || script == null) return null;
396
- try { script = JSON.parse(script); } catch (ex) { return null; }
397
- return script;
398
- }
399
-
400
- function cacheScript(sObj) {
401
- db.Put('scriptTask_script_' + sObj._id, sObj);
402
- }
403
-
404
- function clearCache() {
405
- db.Keys.forEach(function (k) { if (k.indexOf('scriptTask_script_') === 0) { db.Put(k, null); db.Delete(k); } });
406
- }
407
-
408
- function sendConsoleText(text, sessionid) {
409
- if (typeof text == 'object') { text = JSON.stringify(text); }
410
- parent.SendCommand({ action: 'msg', type: 'console', value: 'XXX: ' + text, sessionid: sessionid });
411
- }
412
-
413
- return obj;
414
-}
415
-
416
-module.exports = { CreateScriptTask: CreateScriptTask };
\ No newline at end of file
public/tail.datetime/tail.datetime-default-blue.min.css
deleted
-3
@@ -1,3 +0,0 @@
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
deleted
-1
@@ -1 +0,0 @@
1
-{"version":3,"sources":["$stdin"],"names":[],"mappings":"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"}
\ No newline at end of file
public/tail.datetime/tail.datetime.min.js
deleted
-2
@@ -1,2 +0,0 @@
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
+10
-704
@@ -1,714 +1,20 @@
1
-/**
2
-* @description MeshCentral ScriptTask
3
-* @author Ryan Blenis
4
-* @copyright
1
+/**
2
+* @description MeshCentral task manager
3
+* @author Ylian Saint-Hilaire
4
+* @copyright Intel Corporation 2018-2022
5
* @license Apache-2.0
6
+* @version v0.0.1
7
*/
8
9
+/*jslint node: true */
10
+/*jshint node: true */
11
+/*jshint strict:false */
12
+/*jshint -W097 */
13
+/*jshint esversion: 6 */
14
'use strict';
15
16
module.exports.createTaskManager = function (parent) {
17
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
- };
18
19
return obj;
20
}
\ No newline at end of file
views/default.handlebars
+34
-22
@@ -5537,25 +5537,7 @@
5537
p2downloadDeviceInfo();
5538
} else if (op == 106) {
5539
// Run commands
5540
- var wintype = false, linuxtype = false, agenttype = false, chkNodeIds = getCheckedDevices();
5541
- for (var i in chkNodeIds) {
5542
- var n = getNodeFromId(chkNodeIds[i]);
5543
- if (n.agent) { if ((GetNodeRights(n) & 24) == 24) { agenttype = true; } if ((n.agent.id > 0) && (n.agent.id < 5)) { wintype = true; } else { linuxtype = true; } }
5544
- }
5545
- if ((wintype == true) || (linuxtype == true) || (agenttype == true)) {
5546
- var x = "Run commands on selected devices." + '<br />';
5547
- x += '<select id=d2cmdtype onclick=d2runCommandValidate() style=width:100%;margin-bottom:4px;margin-top:4px>';
5548
- if (wintype == true) { x += '<option value=1>' + "Windows Command Prompt" + '</option><option value=2>' + "Windows PowerShell" + '</option>'; }
5549
- if (linuxtype == true) { x += '<option value=3>' + "Linux/BSD/macOS Command Shell" + '</option>'; }
5550
- if (agenttype == true) { x += '<option value=4>' + "Agent Console" + '</option>'; } // MESHRIGHT_REMOTECONTROL & MESHRIGHT_AGENTCONSOLE are needed
5551
- x += '</select>';
5552
- x += '<select id=d2cmduser style=width:100%;margin-bottom:4px><option value=0>' + "Run as agent" + '</option><option value=1>' + "Run as user, agent if no user" + '</option><option value=2>' + "Must run as user" + '</option></select>';
5553
- x += '<textarea id=d2runcmd style=background-color:#fcf3cf;width:100%;height:200px;resize:none;overflow-y:scroll></textarea>';
5554
- setDialogMode(2, "Run Commands", 3, d2groupActionFunctionRunCommands, x);
5555
- Q('d2runcmd').focus();
5556
- //QE('idx_dlgOkButton', true);
5557
- d2runCommandValidate();
5558
- }
5540
+ d2runCommandDialog({ nodeids: getCheckedDevices(), title: "Run commands on selected devices.", func: uncheckAllDevices });
5541
} else if (op == 107) {
5542
// Edit tags
5543
var x = "Perform batch device tag operation" + '<br /><br />';
@@ -5611,7 +5593,6 @@
5593
}
5594
}
5595
5614
- function d2runCommandValidate() { QV('d2cmduser', Q('d2cmdtype').value < 4); }
5596
function d2batchUploadValidate() { QE('idx_dlgOkButton', (Q('d2uploadinput').files.length != 0) && ((Q('d2winuploadpath') == null) || (Q('d2winuploadpath').value != '')) && ((Q('d2linuxuploadpath') == null) || (Q('d2linuxuploadpath').value != ''))); }
5597
function d2batchUploadValidateOk() { Q('d2batchUploadSubmit').click(); }
5598
function d2groupActionFunctionAgentUpdateExec() { meshserver.send({ action: 'updateAgents', nodeids: getCheckedDevices() }); }
@@ -5728,10 +5709,34 @@
5709
5710
function d2groupActionFunctionDelCheck() { QE('idx_dlgOkButton', Q('d2check').checked); }
5711
function d2groupActionFunctionDelExec() { meshserver.send({ action: 'removedevices', nodeids: getCheckedDevices() }); uncheckAllDevices(); }
5731
- function d2groupActionFunctionRunCommands() {
5712
+
5713
+ function d2runCommandDialog(options) {
5714
+ var wintype = false, linuxtype = false, agenttype = false;
5715
+ for (var i in options.nodeids) {
5716
+ var n = getNodeFromId(options.nodeids[i]);
5717
+ if (n.agent) { if ((GetNodeRights(n) & 24) == 24) { agenttype = true; } if ((n.agent.id > 0) && (n.agent.id < 5)) { wintype = true; } else { linuxtype = true; } }
5718
+ }
5719
+ if ((wintype == true) || (linuxtype == true) || (agenttype == true)) {
5720
+ var x = options.title + '<br />';
5721
+ x += '<select id=d2cmdtype onclick=d2runCommandValidate() style=width:100%;margin-bottom:4px;margin-top:4px>';
5722
+ if (wintype == true) { x += '<option value=1>' + "Windows Command Prompt" + '</option><option value=2>' + "Windows PowerShell" + '</option>'; }
5723
+ if (linuxtype == true) { x += '<option value=3>' + "Linux/BSD/macOS Command Shell" + '</option>'; }
5724
+ if (agenttype == true) { x += '<option value=4>' + "Agent Console" + '</option>'; } // MESHRIGHT_REMOTECONTROL & MESHRIGHT_AGENTCONSOLE are needed
5725
+ x += '</select>';
5726
+ x += '<select id=d2cmduser style=width:100%;margin-bottom:4px><option value=0>' + "Run as agent" + '</option><option value=1>' + "Run as user, agent if no user" + '</option><option value=2>' + "Must run as user" + '</option></select>';
5727
+ x += '<textarea id=d2runcmd style=background-color:#fcf3cf;width:100%;height:200px;resize:none;overflow-y:scroll></textarea>';
5728
+ setDialogMode(2, "Run Commands", 3, d2groupActionFunctionRunCommands, x, options);
5729
+ Q('d2runcmd').focus();
5730
+ //QE('idx_dlgOkButton', true);
5731
+ d2runCommandValidate();
5732
+ }
5733
+ }
5734
+ function d2runCommandValidate() { QV('d2cmduser', Q('d2cmdtype').value < 4); }
5735
+ function d2groupActionFunctionRunCommands(b, options) {
5736
var type = 3;
5737
try { type = parseInt(Q('d2cmdtype').value); } catch (ex) { }
5734
- meshserver.send({ action: 'runcommands', nodeids: getCheckedDevices(), type: type, cmds: Q('d2runcmd').value, runAsUser: parseInt(Q('d2cmduser').value) }); uncheckAllDevices();
5738
+ meshserver.send({ action: 'runcommands', nodeids: options.nodeids, type: type, cmds: Q('d2runcmd').value, runAsUser: parseInt(Q('d2cmduser').value) });
5739
+ if (options.func) { options.func(); }
5740
}
5741
5742
function onSortSelectChange(skipsave) {
@@ -7174,6 +7179,7 @@
7179
if (((meshrights & (4 + 8 + 64 + 262144)) != 0) && (node.mtype < 3) && ((node.agent == null) || (node.agent.id != 34))) { x += '<input type=button value="' + "Actions" + '" title="' + "Perform power actions on the device" + '" onclick=deviceActionFunction() />'; }
7180
x += '<input type=button value="' + "Notes" + '" title="' + "View notes about this device" + '" onclick=showNotes(' + ((meshrights & 128) == 0) + ',"' + encodeURIComponentEx(node._id) + '") />';
7181
x += '<input type=button value="' + "Log Event" + '" title="' + "Write an event for this device" + '" onclick=writeDeviceEvent("' + encodeURIComponentEx(node._id) + '") />';
7182
+ if ((node.mtype == 2) && (connectivity & 1) && (meshrights == 0xFFFFFFFF)) { x += '<input type=button value="' + "Run" + '" title="' + "Run commands on this device" + '" onclick=runDeviceCmd("' + encodeURIComponentEx(node._id) + '") />'; }
7183
if (node.mtype != 4) {
7184
if ((meshrights & 8) && ((connectivity & 1) || ((node.pmt == 1) && ((features2 & 2) != 0)))) { x += '<input type=button value="' + "Message" + '" title="' + "Display a text message on the remote device" + '" onclick=deviceMessageFunction() />'; }
7185
//if ((connectivity & 1) && (meshrights & 8) && (node.agent.id < 5)) { x += '<input type=button value=Toast title="' + "Display a text message of the remote device" + '" onclick=deviceToastFunction() />'; }
@@ -7632,6 +7638,12 @@
7638
return str.join(', ');
7639
}
7640
7641
+ // Run commands on current device
7642
+ function runDeviceCmd(nodeid) {
7643
+ if (xxdialogMode) return;
7644
+ d2runCommandDialog({ nodeids: [ decodeURIComponent(nodeid) ], title: "Run commands on this device." });
7645
+ }
7646
+
7647
function writeDeviceEvent(nodeid) {
7648
if (xxdialogMode) return;
7649
setDialogMode(2, "Add Device Event", 3, writeDeviceEventEx, '<textarea id=d2devEvent style=background-color:#fcf3cf;width:100%;height:200px;resize:none;overflow-y:scroll></textarea><span style=font-size:10px>' + "This will add an entry to this device's event log." + '<span>', nodeid);
views/task-schedule.handlebars
deleted
-249
@@ -1,249 +0,0 @@
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
deleted
-73
@@ -1,73 +0,0 @@
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
deleted
-1070
@@ -1,1070 +0,0 @@
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