Refactored to separate files for each class
WIP: Added project-planner provider
This commit is contained in:
parent
7491df9c75
commit
d36b98a20c
406
ryjsxt.js
406
ryjsxt.js
|
@ -1,406 +0,0 @@
|
|||
/**
|
||||
* Ray's JavaScript Extension
|
||||
* @version v0.1.0.021 (2023/12/11 0056)
|
||||
*/
|
||||
|
||||
|
||||
Array.prototype.index = function (propName, value) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (typeof(this[i][propName]) == "undefined") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this[i][propName] == value){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
};
|
||||
|
||||
Array.prototype.insert = function(index, item) {
|
||||
if (index < 0) {
|
||||
this.splice(0, 0, item);
|
||||
} else if (index >= this.length) {
|
||||
this.push(0, 0, item);
|
||||
} else {
|
||||
this.splice(index, 0, item);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.joinIfNotNullOrWhitespace = function (separator) {
|
||||
const a = this;
|
||||
|
||||
let result = "";
|
||||
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (String.isNullOrWhitespace(this[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!String.isNullOrWhitespace(result)) {
|
||||
result += separator;
|
||||
}
|
||||
|
||||
result += this[i];
|
||||
};
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Array.prototype.first = function (propName, value) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (typeof(this[i][propName]) == "undefined") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this[i][propName] == value){
|
||||
return this[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
Array.prototype.indexes = function (propName, value) {
|
||||
let result = [];
|
||||
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (typeof(this[i][propName]) == "undefined") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this[i][propName] == value){
|
||||
result.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Array.prototype.orderBy = function (propName) {
|
||||
this.sort(function(a, b) {
|
||||
if (a[propName] < b[propName]) {
|
||||
return -1;
|
||||
} else if (a[propName] > b[propName]) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.orderByDesc = function (propName) {
|
||||
this.sort(function(a, b) {
|
||||
if (a[propName] < b[propName]) {
|
||||
return 1;
|
||||
} else if (a[propName] > b[propName]) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.removeAt = function(index) {
|
||||
if ((index < 0) || (index >= this.length)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.splice(index, 1);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.select = function (propName, value) {
|
||||
let result = [];
|
||||
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (typeof(this[i][propName]) == "undefined") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this[i][propName] == value){
|
||||
result.push(this[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
Boolean.isFalse = function(value) {
|
||||
const a = this;
|
||||
|
||||
if (String.isNullOrUndefined(value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return value.toString().containsCI("false", "f", "y", "0", "x");
|
||||
};
|
||||
|
||||
Boolean.isTrue = function(value) {
|
||||
const a = this;
|
||||
|
||||
if (String.isNullOrUndefined(value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return value.toString().containsCI("true", "t", "n", "1", "o");
|
||||
};
|
||||
|
||||
Boolean.ifTrue = function(value, trueValue, falseValue) {
|
||||
const a = this;
|
||||
|
||||
return (Boolean.isTrue(value) ? trueValue : falseValue);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
Date.addDays = function (date, days) {
|
||||
let result = new Date(date);
|
||||
|
||||
result.addDays(days);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Date.addMonths = function (date, months) {
|
||||
let result = new Date(date);
|
||||
|
||||
result.addMonths(months);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Date.addYears = function (date, years) {
|
||||
let result = new Date(date);
|
||||
|
||||
result.addYears(years);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Date.prototype.addDays = function (days) {
|
||||
this.setDate(this.getDate() + parseInt(days));
|
||||
}
|
||||
|
||||
Date.prototype.addMonths = function (months) {
|
||||
this.setMonth(this.getMonth() + parseInt(months));
|
||||
}
|
||||
|
||||
Date.prototype.addYears = function (years) {
|
||||
this.setFullYear(this.getFullYear() + parseInt(years));
|
||||
}
|
||||
|
||||
Date.prototype.toCString = function(pattern) {
|
||||
let result = pattern;
|
||||
|
||||
result = result.replace("fffffff", this.getMilliseconds().toString().padStart(7, '0'));
|
||||
result = result.replace("ffffff", this.getMilliseconds().toString().padStart(6, '0'));
|
||||
result = result.replace("fffff", this.getMilliseconds().toString().padStart(5, '0'));
|
||||
result = result.replace("yyyy", this.getFullYear().toString().padStart(4, '0'));
|
||||
result = result.replace("MMMM", "{1}");
|
||||
result = result.replace("dddd", "{2}");
|
||||
result = result.replace("ffff", this.getMilliseconds().toString().padStart(4, '0'));
|
||||
result = result.replace("yyy", this.getFullYear().toString().padStart(3, '0'));
|
||||
result = result.replace("MMM", "{3}");
|
||||
result = result.replace("ddd", "{4}");
|
||||
result = result.replace("fff", this.getMilliseconds().toString().padStart(3, '0'));
|
||||
result = result.replace("zzz", "");
|
||||
result = result.replace("yy", this.getFullYear().toString().slice(-2));
|
||||
result = result.replace("MM", (this.getMonth() + 1).toString().padStart(2, '0'));
|
||||
result = result.replace("dd", this.getDate().toString().padStart(2, '0'));
|
||||
result = result.replace("HH", this.getHours().toString().padStart(2, '0'));
|
||||
result = result.replace("hh", (this.getHours() > 12 ? (this.getHours() - 12) : this.getHours()).toString().padStart(2, '0'));
|
||||
result = result.replace("mm", this.getMinutes().toString().padStart(2, '0'));
|
||||
result = result.replace("ss", this.getSeconds().toString().padStart(2, '0'));
|
||||
result = result.replace("ff", this.getMilliseconds().toString().padStart(2, '0'));
|
||||
result = result.replace("tt", "{5}");
|
||||
result = result.replace("zz", "");
|
||||
result = result.replace("y", this.getFullYear().toString());
|
||||
result = result.replace("M", (this.getMonth() + 1).toString());
|
||||
result = result.replace("d", this.getDate().toString());
|
||||
result = result.replace("H", this.getHours().toString());
|
||||
result = result.replace("h", (this.getHours() > 12 ? (this.getHours() - 12) : this.getHours()).toString());
|
||||
result = result.replace("m", this.getMinutes().toString());
|
||||
result = result.replace("s", this.getSeconds().toString());
|
||||
result = result.replace("z", "");
|
||||
result = result.replace("t", "{6}");
|
||||
result = result.replace("Z", "");
|
||||
|
||||
result = result.replace("{1}", this.toLocaleString('default', { month: 'long' }));
|
||||
result = result.replace("{2}", this.toLocaleString('default', { weekday: 'long' }));
|
||||
result = result.replace("{3}", this.toLocaleString('default', { month: 'short' }));
|
||||
result = result.replace("{4}", this.toLocaleString('default', { weekday: 'short' }));
|
||||
result = result.replace("{5}", (this.getHours() >= 12 ? "PM" : "AM"));
|
||||
result = result.replace("{6}", (this.getHours() >= 12 ? "P" : "A"));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Document.ready = async function(fn) {
|
||||
(async function() {
|
||||
(document.readyState !== 'loading') ?
|
||||
fn() : document.addEventListener('DOMContentLoaded',
|
||||
function() {
|
||||
fn();
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Math.randomN = function (min, max) {
|
||||
min = Math.ceil(min);
|
||||
max = Math.floor(max);
|
||||
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
String.isNullOrUndefined = function(value) {
|
||||
if (typeof (value) == "undefined") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
String.isNullOrWhitespace = function(value) {
|
||||
const a = this;
|
||||
|
||||
if (String.isNullOrUndefined(value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof(value) == "string") {
|
||||
return (value.trim().length <= 0);
|
||||
} else {
|
||||
return (value.toString().trim().length <= 0);
|
||||
}
|
||||
};
|
||||
|
||||
String.joinIfNotNullOrWhitespace = function (separator, ...values) {
|
||||
const a = this;
|
||||
|
||||
let result = "";
|
||||
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
if (String.isNullOrWhitespace(values[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!String.isNullOrWhitespace(result)) {
|
||||
result += separator;
|
||||
}
|
||||
|
||||
result += values[i];
|
||||
};
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
String.prototype.contains = function(...args) {
|
||||
for (let arg of args) {
|
||||
if (this == arg) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
String.prototype.containsCI = function(...args) {
|
||||
for (let arg of args) {
|
||||
if (this.toLowerCase() == arg.toLowerCase()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
String.prototype.encodeHtmlLinks = function() {
|
||||
return value.replace(/(http[s]{0,1}:\/\/[^\s]+)/g, "<a href='$1'>$1</a>");
|
||||
};
|
||||
|
||||
String.prototype.toTitleCase = function () {
|
||||
let result = this;
|
||||
|
||||
result = result.replace(/([A-Z]{1})/g, " $1");
|
||||
result = result.trim();
|
||||
result = result.charAt(0).toUpperCase() + result.substr(1);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
String.prototype.getFilename = function () {
|
||||
return this.substring(this.lastIndexOf('/') + 1);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
Window.goToTop = function() {
|
||||
Window.scrollTo(0, 0);
|
||||
};
|
||||
|
||||
Window.fragment = {
|
||||
get: function() {
|
||||
if (!window.location.hash) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const n = window.location.hash.indexOf("?");
|
||||
if (n < 0) {
|
||||
return window.location.hash.substring(1);
|
||||
} else {
|
||||
return window.location.hash.substring(1, n);
|
||||
}
|
||||
},
|
||||
getQuery: function() {
|
||||
if (!window.location.hash) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let hashQueryString = window.location.hash;
|
||||
const n = hashQueryString.indexOf("?");
|
||||
if (n < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
hashQueryString = hasQueryString.substring(n + 1);
|
||||
|
||||
const params = new URLSearchParams(hashQueryString);
|
||||
const result = {}
|
||||
for(const [key, value] of params.entries()) {
|
||||
result[key] = value;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
clear: function() {
|
||||
location.hash = "";
|
||||
history.replaceState("", "", location.pathname);
|
||||
}
|
||||
};
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,157 @@
|
|||
<!doctype html>
|
||||
<html lang="en-GB">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="content-type" content="text/html" charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="description" content="" />
|
||||
<meta name="keyword" content="" />
|
||||
|
||||
<script src="ryz-js-ext/ryz-js-ext-array.js"></script>
|
||||
<script src="ryz-js-ext/ryz-js-ext-boolean.js"></script>
|
||||
<script src="ryz-js-ext/ryz-js-ext-date.js"></script>
|
||||
<script src="ryz-js-ext/ryz-js-ext-document.js"></script>
|
||||
<script src="ryz-js-ext/ryz-js-ext-math.js"></script>
|
||||
<script src="ryz-js-ext/ryz-js-ext-string.js"></script>
|
||||
<script src="ryz-js-ext/ryz-js-ext-window.js"></script>
|
||||
<!-- <script src="ryzjsext.min.js"></script> -->
|
||||
|
||||
<script src="ryz-gantts.js"></script>
|
||||
<!-- <script src="bsdialog4.min.js"></script> -->
|
||||
<title></title>
|
||||
|
||||
<style>
|
||||
|
||||
.text-sm {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
var gantt1 = new RyzGantt({ Name: "New Project 1" });
|
||||
|
||||
gantt1.AddTask({
|
||||
ID: 1,
|
||||
Name: "Task A",
|
||||
StartDelay: 0,
|
||||
Duration: 1,
|
||||
DependsOnTaskID: null,
|
||||
IsCollated: false,
|
||||
CollatedTaskID: null
|
||||
});
|
||||
|
||||
gantt1.AddTask({
|
||||
ID: 2,
|
||||
Name: "Task B",
|
||||
StartDelay: 1,
|
||||
Duration: 1,
|
||||
DependsOnTaskID: 1,
|
||||
IsCollated: false,
|
||||
CollatedTaskID: null
|
||||
});
|
||||
|
||||
gantt1.AddTask({
|
||||
ID: 3,
|
||||
Name: "Task C",
|
||||
StartDelay: 5,
|
||||
Duration: 1,
|
||||
DependsOnTaskID: null,
|
||||
IsCollated: false,
|
||||
CollatedTaskID: null
|
||||
});
|
||||
|
||||
gantt1.AddTask({
|
||||
ID: 4,
|
||||
Name: "Task D",
|
||||
StartDelay: 1,
|
||||
Duration: 1,
|
||||
DependsOnTaskID: 3,
|
||||
IsCollated: false,
|
||||
CollatedTaskID: null
|
||||
});
|
||||
|
||||
gantt1.AddTask({
|
||||
ID: 5,
|
||||
Name: "Task B1",
|
||||
StartDelay: 4,
|
||||
Duration: 1,
|
||||
DependsOnTaskID: 2,
|
||||
IsCollated: true,
|
||||
CollatedTaskID: null
|
||||
});
|
||||
|
||||
gantt1.AddTask({
|
||||
ID: 6,
|
||||
Name: "Task B11",
|
||||
StartDelay: 0,
|
||||
Duration: 1,
|
||||
DependsOnTaskID: null,
|
||||
IsCollated: false,
|
||||
CollatedTaskID: 5
|
||||
});
|
||||
|
||||
gantt1.AddTask({
|
||||
ID: 7,
|
||||
Name: "Task B12",
|
||||
StartDelay: 0,
|
||||
Duration: 7,
|
||||
DependsOnTaskID: null,
|
||||
IsCollated: false,
|
||||
CollatedTaskID: 5
|
||||
});
|
||||
|
||||
gantt1.AddTask({
|
||||
ID: 8,
|
||||
Name: "Task E",
|
||||
StartDelay: 3,
|
||||
Duration: 1,
|
||||
DependsOnTaskID: null,
|
||||
IsCollated: true,
|
||||
CollatedTaskID: null
|
||||
});
|
||||
|
||||
gantt1.AddTask({
|
||||
ID: 9,
|
||||
Name: "Task E1",
|
||||
StartDelay: 3,
|
||||
Duration: 1,
|
||||
DependsOnTaskID: null,
|
||||
IsCollated: false,
|
||||
CollatedTaskID: 8
|
||||
});
|
||||
|
||||
gantt1.InvalidateTasks();
|
||||
|
||||
console.log(gantt1.ExportTasks);
|
||||
|
||||
// console.log(gantt1.Tasks);
|
||||
|
||||
|
||||
|
||||
|
||||
// var dataSet = [
|
||||
// { key: "b", value: "B2", num: 2, f: 2.2, date: new Date(2001, 2, 2) },
|
||||
// { key: "d", value: "D4", num: 4, f: 4.4, date: new Date(2001, 4, 4) },
|
||||
// { key: "a", value: "A1", num: 1, f: 1.1, date: new Date(2001, 10, 1) },
|
||||
// { key: "e", value: "E5", num: 5, f: 5.5, date: new Date(2001, 5, 5) },
|
||||
// { key: "c", value: "C3", num: 3, f: 3.3, date: new Date(2001, 3, 3) }
|
||||
// ];
|
||||
|
||||
// // let result = dataSet.index("key", "d");
|
||||
// //dataSet = dataSet.orderBy("date");
|
||||
// dataSet = dataSet.orderByDesc("date");
|
||||
|
||||
// console.log(result);
|
||||
// console.log(dataSet);
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,421 @@
|
|||
class RyzGantt {
|
||||
constructor(options) {
|
||||
const a = this;
|
||||
const _options = Object.assign(a.NewProject, options);
|
||||
|
||||
a.Project = _options;
|
||||
a.Tasks = [];
|
||||
}
|
||||
|
||||
initialiseComponents() {
|
||||
const a = this;
|
||||
}
|
||||
|
||||
|
||||
get NewProject() {
|
||||
return {
|
||||
Name: "",
|
||||
Description: "",
|
||||
StartDate: Date.today(),
|
||||
Tag: null,
|
||||
StartOfWeek: 1, // Monday
|
||||
WorkHours: [0, 7.5, 7.5, 7.5, 7.5, 7.5, 0] // 0 = Sunday
|
||||
};
|
||||
}
|
||||
|
||||
get NewTask() {
|
||||
return {
|
||||
// Order: null,
|
||||
ID: null,
|
||||
Name: "",
|
||||
Description: "",
|
||||
Tag: null,
|
||||
// StartDate: null, // new Date(),
|
||||
// FinishDate: null, // new Date(),
|
||||
StartDelay: 0, // Days
|
||||
Duration: 1, // Days
|
||||
DependsOnTaskID: null,
|
||||
IsCollated: false,
|
||||
CollatedTaskID: null,
|
||||
// CalcWorkHours: 0,
|
||||
ActuWorkHours: null
|
||||
};
|
||||
}
|
||||
|
||||
get NewTaskNode() {
|
||||
return {
|
||||
Order: null,
|
||||
ID: null,
|
||||
Name: "",
|
||||
Description: "",
|
||||
Tag: null,
|
||||
StartDate: null, // new Date(),
|
||||
FinishDate: null, // new Date(),
|
||||
StartDelay: 0, // Days
|
||||
Duration: 1, // Days
|
||||
DependsOnTaskID: null,
|
||||
IsCollated: false,
|
||||
CollatedTaskID: null,
|
||||
CalcWorkHours: 0,
|
||||
ActuWorkHours: null,
|
||||
Tasks: []
|
||||
};
|
||||
}
|
||||
|
||||
get ExportTasks() {
|
||||
const a = this;
|
||||
|
||||
let result = [];
|
||||
|
||||
a.#exportTasks(result, a.Tasks.copy());
|
||||
|
||||
for (var i=0; i<result.length; i++) {
|
||||
result[i].Order = (i + 1);
|
||||
|
||||
delete result[i].Tasks;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AddTask(task) {
|
||||
const a = this;
|
||||
const newTask = Object.assign(a.NewTask, task);
|
||||
const newTaskNode = Object.assign(a.NewTaskNode, newTask);
|
||||
|
||||
if ((newTaskNode.DependsOnTaskID == null) && (newTaskNode.CollatedTaskID == null)) {
|
||||
a.Tasks.push(newTaskNode);
|
||||
} else if (newTaskNode.DependsOnTaskID != null) {
|
||||
const node = a.FindTask(newTaskNode.DependsOnTaskID);
|
||||
|
||||
if (node != null) {
|
||||
node.Tasks.push(newTaskNode);
|
||||
} else {
|
||||
a.#log("Task not found (" + newTaskNode.DependsOnTaskID + ")");
|
||||
}
|
||||
} else if (newTaskNode.CollatedTaskID != null) {
|
||||
const node = a.FindTask(newTaskNode.CollatedTaskID);
|
||||
|
||||
if (node != null) {
|
||||
node.Tasks.push(newTaskNode);
|
||||
} else {
|
||||
a.#log("Task not found (" + newTaskNode.CollatedTaskID + ")");
|
||||
}
|
||||
} else {
|
||||
a.#log("Task not found (" + newTaskNode.ID + ")");
|
||||
}
|
||||
}
|
||||
|
||||
ClearTasks() {
|
||||
const a = this;
|
||||
|
||||
a.Tasks = [];
|
||||
}
|
||||
|
||||
FindTask(id) {
|
||||
const a = this;
|
||||
|
||||
return a.#searchForTaskID(a.Tasks, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get node type.
|
||||
* @returns {int} enum
|
||||
*
|
||||
* 0 = orphan
|
||||
* 1 = task no-parent/root
|
||||
* 2 = task no-parent/root, collated/group
|
||||
* 3 = task with parent
|
||||
* 4 = task with parent, collated/group
|
||||
* 5 = sub-task
|
||||
* 6 = sub-task, collated/group
|
||||
*
|
||||
*/
|
||||
GetNodeType(node) {
|
||||
if (node == null) {
|
||||
// 0 = orphan
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((node.DependsOnTaskID == null) && (node.CollatedTaskID == null) && (node.IsCollated == false)) {
|
||||
// 1 = task no-parent/root
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((node.DependsOnTaskID == null) && (node.CollatedTaskID == null) && (node.IsCollated == true)) {
|
||||
// 2 = task no-parent/root, collated/group
|
||||
return 2;
|
||||
}
|
||||
|
||||
if ((node.DependsOnTaskID != null) && (node.CollatedTaskID == null) && (node.IsCollated == false)) {
|
||||
// 3 = task with parent
|
||||
return 3;
|
||||
}
|
||||
|
||||
if ((node.DependsOnTaskID != null) && (node.CollatedTaskID == null) && (node.IsCollated == true)) {
|
||||
// 4 = task with parent, collated/group
|
||||
return 4;
|
||||
}
|
||||
|
||||
if ((node.CollatedTaskID != null) && (node.IsCollated == false)) {
|
||||
// 5 = sub-task
|
||||
return 5;
|
||||
}
|
||||
|
||||
if ((node.CollatedTaskID != null) && (node.IsCollated == true)) {
|
||||
// 6 = sub-task, collated/group
|
||||
return 6;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
InvalidateTasks() {
|
||||
const a = this;
|
||||
|
||||
// a.#log(a.Tasks.copy());
|
||||
|
||||
a.Recalc();
|
||||
|
||||
// a.#log(a.Tasks.copy());
|
||||
|
||||
// return;
|
||||
|
||||
|
||||
// a.#resetTasks();
|
||||
|
||||
// console.log("Original");
|
||||
// console.log(a.Tasks.copy());
|
||||
|
||||
// // Get root nodes
|
||||
// let nodes = a.Tasks.selectMany(
|
||||
// { propName: "DependsOnTaskID", value: null },
|
||||
// { propName: "CollatedTaskID", value: null }
|
||||
// );
|
||||
// nodes.orderBy("StartDelay");
|
||||
|
||||
// a.Tasks.removeRange(nodes);
|
||||
|
||||
// console.log("Root");
|
||||
// console.log(a.Tasks.copy());
|
||||
// console.log(nodes.copy());
|
||||
|
||||
// //
|
||||
// for (let i=(nodes.length - 1); i>=0; i--) {
|
||||
// // Find dependent tasks
|
||||
// let foundNodes = a.Tasks.select("DependsOnTaskID", nodes[i].ID);
|
||||
// foundNodes.forEach(e => {
|
||||
// nodes.insert((i + 1), e);
|
||||
// });
|
||||
|
||||
// a.Tasks.removeRange(foundNodes);
|
||||
|
||||
// // Add child tasks
|
||||
// if (nodes[i].IsCollated == true) {
|
||||
// foundNodes = a.Tasks.select("CollatedTaskID", nodes[i].ID);
|
||||
// foundNodes.forEach(e => {
|
||||
// nodes.insert((i + 1), e);
|
||||
// });
|
||||
|
||||
// a.Tasks.removeRange(foundNodes);
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
// // console.log(a.Tasks.copy());
|
||||
|
||||
|
||||
// // a.Tasks = a.#findTasksL0(a.Tasks);
|
||||
|
||||
// console.log("Final");
|
||||
// console.log(a.Tasks.copy());
|
||||
// console.log(nodes.copy());
|
||||
}
|
||||
|
||||
|
||||
// #popL0Tasks(array) {
|
||||
// const a = this;
|
||||
|
||||
// let nodes = array.selectMany(
|
||||
// { propName: "DependsOnTaskID", value: null },
|
||||
// { propName: "CollatedTaskID", value: null }
|
||||
// );
|
||||
// nodes = nodes.orderBy("StartDelay");
|
||||
|
||||
// array.removeRange(nodes);
|
||||
|
||||
// return nodes;
|
||||
// }
|
||||
|
||||
// #addTasks(sourceTasksArray, targetTasksArray, index) {
|
||||
// const a = this;
|
||||
|
||||
// const nodes = sourceTasksArray.select("DependsOnTaskID", targetTasksArray[index].ID);
|
||||
|
||||
// for (let i=0; i<nodes.length; i++) {
|
||||
// targetTasksArray.insert((index + 1), nodes[i]);
|
||||
// }
|
||||
|
||||
// sourceTasksArray.removeRange(nodes);
|
||||
// }
|
||||
|
||||
Recalc() {
|
||||
const a = this;
|
||||
|
||||
a.Sort();
|
||||
|
||||
// Get flat reference
|
||||
let result = [];
|
||||
a.#exportTasks(result, a.Tasks);
|
||||
|
||||
// Reset calculated values
|
||||
for (var i=0; i<result.length; i++) {
|
||||
result[i].Order = (i + 1);
|
||||
result[i].StartDate = null;
|
||||
result[i].FinishDate = null;
|
||||
result[i].CalcWorkHours = null;
|
||||
}
|
||||
|
||||
for (var i=0; i<result.length; i++) {
|
||||
const nodeType = a.GetNodeType(result[i]);
|
||||
|
||||
switch (nodeType) {
|
||||
case 1: // task no-parent/root
|
||||
result[i].StartDate = Date.addDays(a.Project.StartDate, result[i].StartDelay);
|
||||
result[i].FinishDate = Date.addDays(result[i].StartDate, result[i].Duration);
|
||||
break;
|
||||
case 2: // task no-parent/root, collated/group
|
||||
break;
|
||||
case 3: // task with parent
|
||||
const node = result.first("ID", result[i].DependsOnTaskID);
|
||||
if (node != null) {
|
||||
if (node.FinishDate != null) {
|
||||
result[i].StartDate = Date.addDays(node.FinishDate, result[i].StartDelay);
|
||||
result[i].FinishDate = Date.addDays(result[i].StartDate, result[i].Duration);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 4: // task with parent, collated/group
|
||||
break;
|
||||
case 5: // sub-task
|
||||
break;
|
||||
case 6: // sub-task, collated/group
|
||||
break;
|
||||
default: // orphan
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// a.#resetTasks(a.Tasks);
|
||||
// a.#recalcTasks(a.Project.StartDate, a.Tasks);
|
||||
}
|
||||
|
||||
Sort() {
|
||||
const a = this;
|
||||
|
||||
a.#sortTasks(a.Tasks);
|
||||
}
|
||||
|
||||
|
||||
#exportTasks(outputArray, array) {
|
||||
const a = this;
|
||||
|
||||
for (let i=0; i<array.length; i++) {
|
||||
outputArray.push(array[i]);
|
||||
|
||||
if (array[i].Tasks.length > 0) {
|
||||
a.#exportTasks(outputArray, array[i].Tasks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#log(message) {
|
||||
console.log(message);
|
||||
}
|
||||
|
||||
// #recalcTasks(startDate, array) {
|
||||
// const a = this;
|
||||
|
||||
// for (let i=0; i<array.length; i++) {
|
||||
// array[i].Order = null;
|
||||
// array[i].StartDate = Date.addDays(startDate, array[i].StartDelay);
|
||||
// array[i].FinishDate = null;
|
||||
// // array[i].CalcWorkHours = null;
|
||||
|
||||
// if (array[i].IsCollated == true) {
|
||||
// if (array[i].Tasks.length > 0) {
|
||||
// a.#recalcTasks(array[i].StartDate, array[i].Tasks);
|
||||
// }
|
||||
|
||||
// } else {
|
||||
// array[i].FinishDate = Date.addDays(array[i].StartDate, array[i].Duration);
|
||||
|
||||
// if (array[i].Tasks.length > 0) {
|
||||
// a.#recalcTasks(array[i].FinishDate, array[i].Tasks);
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// // if (array[i].Tasks.length > 0) {
|
||||
// // a.#recalcTasks(array[i].StartDate, array[i].Tasks);
|
||||
// // }
|
||||
// }
|
||||
// }
|
||||
|
||||
// #resetTasks(array) {
|
||||
// const a = this;
|
||||
|
||||
// for (let i=0; i<array.length; i++) {
|
||||
// array[i].Order = null;
|
||||
// array[i].StartDate = null;
|
||||
// array[i].FinishDate = null;
|
||||
// array[i].CalcWorkHours = null;
|
||||
|
||||
// if (array[i].Tasks.length > 0) {
|
||||
// a.#resetTasks(array[i].Tasks);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#searchForTaskID(array, id) {
|
||||
const a = this;
|
||||
|
||||
for (let i=0; i<array.length; i++) {
|
||||
if (array[i].ID == id) {
|
||||
return array[i];
|
||||
}
|
||||
|
||||
if (array[i].Tasks.length > 0) {
|
||||
const result = a.#searchForTaskID(array[i].Tasks, id);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#sortTasks(array) {
|
||||
const a = this;
|
||||
|
||||
array.orderBy("StartDelay");
|
||||
|
||||
for (let i=0; i<array.length; i++) {
|
||||
if (array[i].Tasks.length <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
array[i].Tasks.orderBy("StartDelay");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
Array.prototype.addRange = function (array) {
|
||||
if (array == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
this.push(array[i]);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.copy = function () {
|
||||
return JSON.parse(JSON.stringify(this));
|
||||
};
|
||||
|
||||
Array.prototype.index = function (propName, value) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (typeof(this[i][propName]) == "undefined") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this[i][propName] == value){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
};
|
||||
|
||||
Array.prototype.insert = function(index, item) {
|
||||
if (index < 0) {
|
||||
this.splice(0, 0, item);
|
||||
} else if (index >= this.length) {
|
||||
this.push(item);
|
||||
} else {
|
||||
this.splice(index, 0, item);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.joinIfNotNullOrWhitespace = function (separator) {
|
||||
const a = this;
|
||||
|
||||
let result = "";
|
||||
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (String.isNullOrWhitespace(this[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!String.isNullOrWhitespace(result)) {
|
||||
result += separator;
|
||||
}
|
||||
|
||||
result += this[i];
|
||||
};
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Array.prototype.first = function (propName, value) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (typeof(this[i][propName]) == "undefined") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this[i][propName] == value){
|
||||
return this[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
Array.prototype.indexes = function (propName, value) {
|
||||
let result = [];
|
||||
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (typeof(this[i][propName]) == "undefined") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this[i][propName] == value){
|
||||
result.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Array.prototype.orderBy = function (propName) {
|
||||
this.sort(function(a, b) {
|
||||
if (a[propName] < b[propName]) {
|
||||
return -1;
|
||||
} else if (a[propName] > b[propName]) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.orderByDesc = function (propName) {
|
||||
this.sort(function(a, b) {
|
||||
if (a[propName] < b[propName]) {
|
||||
return 1;
|
||||
} else if (a[propName] > b[propName]) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.remove = function (element) {
|
||||
let result = [];
|
||||
|
||||
for (let i=0; i<this.length; i++) {
|
||||
if (this[i] == element) {
|
||||
result.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i=(result.length - 1); i>=0; i--) {
|
||||
this.removeAt(result[i]);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.removeAt = function(index) {
|
||||
if ((index < 0) || (index >= this.length)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.splice(index, 1);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.removeRange = function (array) {
|
||||
for (let i=0; i<array.length; i++) {
|
||||
this.remove(array[i]);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find elements where a property equals a value.
|
||||
* @returns {Array} Of elements found.
|
||||
*/
|
||||
Array.prototype.select = function (propName, value) {
|
||||
let result = [];
|
||||
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (typeof(this[i][propName]) == "undefined") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this[i][propName] == value){
|
||||
result.push(this[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Array.prototype.selectMany = function (...filters) {
|
||||
let result = this;
|
||||
|
||||
filters.forEach(e => {
|
||||
result = result.select(e.propName, e.value);
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
Boolean.isFalse = function(value) {
|
||||
const a = this;
|
||||
|
||||
if (String.isNullOrUndefined(value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return value.toString().containsCI("false", "f", "y", "0", "x");
|
||||
};
|
||||
|
||||
Boolean.isTrue = function(value) {
|
||||
const a = this;
|
||||
|
||||
if (String.isNullOrUndefined(value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return value.toString().containsCI("true", "t", "n", "1", "o");
|
||||
};
|
||||
|
||||
Boolean.ifTrue = function(value, trueValue, falseValue) {
|
||||
const a = this;
|
||||
|
||||
return (Boolean.isTrue(value) ? trueValue : falseValue);
|
||||
};
|
|
@ -0,0 +1,93 @@
|
|||
Date.addDays = function (date, days) {
|
||||
let result = new Date(date);
|
||||
|
||||
result.addDays(days);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Date.addMonths = function (date, months) {
|
||||
let result = new Date(date);
|
||||
|
||||
result.addMonths(months);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Date.addYears = function (date, years) {
|
||||
let result = new Date(date);
|
||||
|
||||
result.addYears(years);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Date.today = function () {
|
||||
let result = new Date();
|
||||
|
||||
result.setHours(0);
|
||||
result.setMinutes(0);
|
||||
result.setSeconds(0);
|
||||
result.setMilliseconds(0);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
Date.prototype.addDays = function (days) {
|
||||
this.setDate(this.getDate() + parseInt(days));
|
||||
}
|
||||
|
||||
Date.prototype.addMonths = function (months) {
|
||||
this.setMonth(this.getMonth() + parseInt(months));
|
||||
}
|
||||
|
||||
Date.prototype.addYears = function (years) {
|
||||
this.setFullYear(this.getFullYear() + parseInt(years));
|
||||
}
|
||||
|
||||
Date.prototype.toCString = function(pattern) {
|
||||
let result = pattern;
|
||||
|
||||
result = result.replace("fffffff", this.getMilliseconds().toString().padStart(7, '0'));
|
||||
result = result.replace("ffffff", this.getMilliseconds().toString().padStart(6, '0'));
|
||||
result = result.replace("fffff", this.getMilliseconds().toString().padStart(5, '0'));
|
||||
result = result.replace("yyyy", this.getFullYear().toString().padStart(4, '0'));
|
||||
result = result.replace("MMMM", "{1}");
|
||||
result = result.replace("dddd", "{2}");
|
||||
result = result.replace("ffff", this.getMilliseconds().toString().padStart(4, '0'));
|
||||
result = result.replace("yyy", this.getFullYear().toString().padStart(3, '0'));
|
||||
result = result.replace("MMM", "{3}");
|
||||
result = result.replace("ddd", "{4}");
|
||||
result = result.replace("fff", this.getMilliseconds().toString().padStart(3, '0'));
|
||||
result = result.replace("zzz", "");
|
||||
result = result.replace("yy", this.getFullYear().toString().slice(-2));
|
||||
result = result.replace("MM", (this.getMonth() + 1).toString().padStart(2, '0'));
|
||||
result = result.replace("dd", this.getDate().toString().padStart(2, '0'));
|
||||
result = result.replace("HH", this.getHours().toString().padStart(2, '0'));
|
||||
result = result.replace("hh", (this.getHours() > 12 ? (this.getHours() - 12) : this.getHours()).toString().padStart(2, '0'));
|
||||
result = result.replace("mm", this.getMinutes().toString().padStart(2, '0'));
|
||||
result = result.replace("ss", this.getSeconds().toString().padStart(2, '0'));
|
||||
result = result.replace("ff", this.getMilliseconds().toString().padStart(2, '0'));
|
||||
result = result.replace("tt", "{5}");
|
||||
result = result.replace("zz", "");
|
||||
result = result.replace("y", this.getFullYear().toString());
|
||||
result = result.replace("M", (this.getMonth() + 1).toString());
|
||||
result = result.replace("d", this.getDate().toString());
|
||||
result = result.replace("H", this.getHours().toString());
|
||||
result = result.replace("h", (this.getHours() > 12 ? (this.getHours() - 12) : this.getHours()).toString());
|
||||
result = result.replace("m", this.getMinutes().toString());
|
||||
result = result.replace("s", this.getSeconds().toString());
|
||||
result = result.replace("z", "");
|
||||
result = result.replace("t", "{6}");
|
||||
result = result.replace("Z", "");
|
||||
|
||||
result = result.replace("{1}", this.toLocaleString('default', { month: 'long' }));
|
||||
result = result.replace("{2}", this.toLocaleString('default', { weekday: 'long' }));
|
||||
result = result.replace("{3}", this.toLocaleString('default', { month: 'short' }));
|
||||
result = result.replace("{4}", this.toLocaleString('default', { weekday: 'short' }));
|
||||
result = result.replace("{5}", (this.getHours() >= 12 ? "PM" : "AM"));
|
||||
result = result.replace("{6}", (this.getHours() >= 12 ? "P" : "A"));
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
Document.ready = async function(fn) {
|
||||
(async function() {
|
||||
(document.readyState !== 'loading') ?
|
||||
fn() : document.addEventListener('DOMContentLoaded',
|
||||
function() {
|
||||
fn();
|
||||
});
|
||||
})();
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
Math.randomN = function (min, max) {
|
||||
min = Math.ceil(min);
|
||||
max = Math.floor(max);
|
||||
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
};
|
|
@ -0,0 +1,83 @@
|
|||
String.isNullOrUndefined = function(value) {
|
||||
if (typeof (value) == "undefined") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
String.isNullOrWhitespace = function(value) {
|
||||
const a = this;
|
||||
|
||||
if (String.isNullOrUndefined(value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof(value) == "string") {
|
||||
return (value.trim().length <= 0);
|
||||
} else {
|
||||
return (value.toString().trim().length <= 0);
|
||||
}
|
||||
};
|
||||
|
||||
String.joinIfNotNullOrWhitespace = function (separator, ...values) {
|
||||
const a = this;
|
||||
|
||||
let result = "";
|
||||
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
if (String.isNullOrWhitespace(values[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!String.isNullOrWhitespace(result)) {
|
||||
result += separator;
|
||||
}
|
||||
|
||||
result += values[i];
|
||||
};
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
String.prototype.contains = function(...args) {
|
||||
for (let arg of args) {
|
||||
if (this == arg) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
String.prototype.containsCI = function(...args) {
|
||||
for (let arg of args) {
|
||||
if (this.toLowerCase() == arg.toLowerCase()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
String.prototype.encodeHtmlLinks = function() {
|
||||
return value.replace(/(http[s]{0,1}:\/\/[^\s]+)/g, "<a href='$1'>$1</a>");
|
||||
};
|
||||
|
||||
String.prototype.toTitleCase = function () {
|
||||
let result = this;
|
||||
|
||||
result = result.replace(/([A-Z]{1})/g, " $1");
|
||||
result = result.trim();
|
||||
result = result.charAt(0).toUpperCase() + result.substr(1);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
String.prototype.getFilename = function () {
|
||||
return this.substring(this.lastIndexOf('/') + 1);
|
||||
};
|
|
@ -0,0 +1,43 @@
|
|||
Window.goToTop = function() {
|
||||
Window.scrollTo(0, 0);
|
||||
};
|
||||
|
||||
Window.fragment = {
|
||||
get: function() {
|
||||
if (!window.location.hash) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const n = window.location.hash.indexOf("?");
|
||||
if (n < 0) {
|
||||
return window.location.hash.substring(1);
|
||||
} else {
|
||||
return window.location.hash.substring(1, n);
|
||||
}
|
||||
},
|
||||
getQuery: function() {
|
||||
if (!window.location.hash) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let hashQueryString = window.location.hash;
|
||||
const n = hashQueryString.indexOf("?");
|
||||
if (n < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
hashQueryString = hasQueryString.substring(n + 1);
|
||||
|
||||
const params = new URLSearchParams(hashQueryString);
|
||||
const result = {}
|
||||
for(const [key, value] of params.entries()) {
|
||||
result[key] = value;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
clear: function() {
|
||||
location.hash = "";
|
||||
history.replaceState("", "", location.pathname);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Ray's JavaScript Extension
|
||||
* @version v0.1.0.021 (2023/12/11 0056)
|
||||
*/
|
Loading…
Reference in New Issue