Skip to content

Instantly share code, notes, and snippets.

@rsp9u
Created January 9, 2020 08:38
Show Gist options
  • Save rsp9u/c600fc0f25707a630bef9bbe925d1c0b to your computer and use it in GitHub Desktop.
Save rsp9u/c600fc0f25707a630bef9bbe925d1c0b to your computer and use it in GitHub Desktop.
Convertor for drawing a plantuml gantt chart with new syntax in Growi. This should be added to Custom Script.
@startgantt
project starts the 2020/1/1
-- milestones --
[マイルストーンA] as msA
[マイルストーンB] as msB
[マイルストーンC] as msC
-- tasks --
[タスク1] as task1
[タスク2] as task2
[タスク3] as task3
-- マイルストーン --
msA
>! 2020/1/1
.! 2020/1/1
msB
>! 2020/1/3
.! 2020/1/4
msC
>! 2020/1/5
-- タスク --
task1
>> 2020/1/1
>= 10 days @bob
.> 2020/1/2
.= 9 days
task2
>> task1's end
>= 5 days @alice
task3
>> task2's end
>< 2020/1/6
@endgantt
function extractGanttContents(plantstr) {
var arr = [...plantstr.matchAll(/^@startgantt$[\s\S]+?^@endgantt$/gm)];
return arr.map(function (x) {return x[0]});
}
function extractTasksOrMilestones(identity, ganttstr) {
let r = [];
let rm = [];
let b = false;
for (var line of ganttstr.split("\n")) {
if (line === `-- ${identity} --`) {
b = true;
} else if (b === true && line.startsWith("--")) {
b = false;
rm.push(line);
} else if (b === true) {
var sp = line.split(/\s+/);
if (sp.length === 3 && sp[1] === "as") {
r.push({text: sp[0], alias: sp[2]});
}
} else {
rm.push(line);
}
}
return {
list: r,
removed: rm.join("\n"),
}
}
function joinChildren(ganttstr) {
var ret = [];
var prev = "";
var b = false;
for (var line of ganttstr.split("\n")) {
if (line.startsWith(" ")) {
if (b === false) {
ret = ret.slice(0, -1);
b = true;
}
ret.push([prev, line.trim()].join(" "));
} else {
ret.push(line);
b = false;
prev = line;
}
}
return ret.join("\n");
}
function replaceVerbs(ganttstr) {
var ret = [];
for (var line of ganttstr.split("\n")) {
var col = line.split(/\s+/);
if (col.length < 2) {
continue;
}
if (col[1].startsWith(".")) {
col[0] = col[0].slice(0, -1) + " ]";
var colored = col[0] + " is colored in Violet/DarkViolet";
if (!ret.includes(colored)) {
ret.push(colored);
}
}
if (col[1].startsWith(">")) {
var colored = col[0] + " is colored in GreenYellow/Green";
if (!ret.includes(colored)) {
ret.push(colored);
}
}
if (col[1].startsWith(">=") || col[1].startsWith(">>") || col[1].startsWith("><")) {
if (line.includes("@")) {
var i = 0;
for (var c of col) {
if (c.startsWith("@")) {
col[0] += ` on {${c.slice(1)}}`;
break;
}
i += 1;
}
col.splice(i, 1);
}
}
if (col[1].match(/[>.]!/)) {
var s = [col[0], "happens at"];
Array.prototype.push.apply(s, col.slice(2));
ret.push(s.join(" "));
} else if (col[1].match(/[>.]=/)) {
var s = [col[0], "lasts"];
Array.prototype.push.apply(s, col.slice(2));
ret.push(s.join(" "));
} else if (col[1].match(/[>.]>/)) {
var s = [col[0], "starts at"];
Array.prototype.push.apply(s, col.slice(2));
ret.push(s.join(" "));
} else if (col[1].match(/[>.]</)) {
var s = [col[0], "ends at"];
Array.prototype.push.apply(s, col.slice(2));
ret.push(s.join(" "));
} else {
ret.push(line);
}
}
return ret.join("\n");
}
function convertGantt(plantstr) {
var ret = plantstr;
var contents = extractGanttContents(plantstr);
for (var c of contents) {
var tasks = extractTasksOrMilestones("tasks", c);
var milestones = extractTasksOrMilestones("milestones", tasks.removed);
var newC = milestones.removed;
// replace aliases
for (var task of tasks.list) {
var regex = new RegExp(task.alias, "g");
newC = newC.replace(regex, task.text);
}
for (var milestone of milestones.list) {
var regex = new RegExp(milestone.alias, "g");
newC = newC.replace(regex, milestone.text);
}
newC = joinChildren(newC);
newC = replaceVerbs(newC);
ret = ret.replace(c, ["@startuml", newC, "@enduml"].join("\n"));
}
ret = ret.replace(/@startgantt/, "")
ret = ret.replace(/@endgantt/, "")
return ret;
}
window.addEventListener('load', (event) => {
growiRenderer.preProcessors.push({process: convertGantt});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment