441 lines
14 KiB
JavaScript
441 lines
14 KiB
JavaScript
|
// -*- coding: utf-8 -*-
|
||
|
//@require base.js
|
||
|
|
||
|
/* convention de nommage:
|
||
|
|
||
|
funcTodo: fonction qui agit sur ou retourne une instance de Tiddler
|
||
|
funcTODO: fonction qui agit sur ou affiche un élément visuel.
|
||
|
*/
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
// Gestion des TODOs
|
||
|
|
||
|
function getAllTodos(types, expectedTags) {
|
||
|
// Lister les todos des types spécifiés ("TODO" ou "DONE"), et qui contiennent
|
||
|
// tous les tags de expectedTags.
|
||
|
if (!expectedTags) expectedTags = [];
|
||
|
|
||
|
var tiddlersMatchingTags = function(tiddlers, exceptedTags, sortBy, reverse) {
|
||
|
// retourner les tiddlers de tiddlers qui contiennent tous les tags de expectedTags
|
||
|
var result = [];
|
||
|
for(var i = 0; i < tiddlers.length; i++) {
|
||
|
if (expectedTags.length) {
|
||
|
var allTagsOk = true;
|
||
|
for (var j = 0; j < expectedTags.length; j++) {
|
||
|
if (! tiddlers[i].tags.containsTag(expectedTags[j])) {
|
||
|
allTagsOk = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!allTagsOk) continue;
|
||
|
}
|
||
|
|
||
|
result.push(tiddlers[i]);
|
||
|
}
|
||
|
|
||
|
if (!sortBy) sortBy = "title";
|
||
|
result.sortBy(sortBy, reverse);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
var result = [];
|
||
|
for (var i = 0; i < types.length; i++) {
|
||
|
var type = types[i];
|
||
|
var reverse = false;
|
||
|
if (type.charAt(0) == "+") {
|
||
|
type = type.substr(1);
|
||
|
} else if (type.charAt(0) == "-") {
|
||
|
type = type.substr(1);
|
||
|
var reverse = true;
|
||
|
}
|
||
|
result = result.concat(tiddlersMatchingTags(store.getTaggedTiddlers(type), expectedTags, "title", reverse));
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
function getTodoText(tiddler) {
|
||
|
// Retourner "[[todoTitle]] - firstLine"
|
||
|
if (!(tiddler instanceof Tiddler)) tiddler = store.tiddlers[tiddler];
|
||
|
if (!(tiddler instanceof Tiddler)) return;
|
||
|
|
||
|
var title = tiddler.title;
|
||
|
var text = "[[" + title + "]]";
|
||
|
var line = Tiddlers.getFirstLine(tiddler);
|
||
|
if (line != "") text += " - " + line;
|
||
|
|
||
|
return text;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
// Les macros pour gérer les TODOs
|
||
|
|
||
|
// Créer un nouveau TODO
|
||
|
config.macros.newTODO = {label: "new TODO", prompt: "Create a new TODO tiddler", accessKey: "T"};
|
||
|
config.macros.newTODO.handler = function(place, macroName, params) {
|
||
|
if (!readOnly) {
|
||
|
createTiddlyButton(place, this.label, this.prompt, this.onClick, null, null, this.accessKey);
|
||
|
}
|
||
|
}
|
||
|
config.macros.newTODO.onClick = function(e) {
|
||
|
e = ClickHandler.getEvent(e);
|
||
|
|
||
|
var now = new Date();
|
||
|
var todoname = now.formatString("TODO-YYYY0MM0DD");
|
||
|
var title = todoname + "-" + (store.getTaggedTiddlers(todoname).length + 1);
|
||
|
|
||
|
clearMessage();
|
||
|
displayTiddler(null, title, 2, null, null, false, false);
|
||
|
var body = document.getElementById("editorBody" + title);
|
||
|
if (body) body.focus();
|
||
|
|
||
|
var tagsBox = document.getElementById("editorTags" + title);
|
||
|
if(tagsBox) {
|
||
|
var tags = tagsBox.value.splitTags();
|
||
|
tags.removeTag("DONE").addTag("TODO").addTag(todoname);
|
||
|
tagsBox.value = tags.joinTags();
|
||
|
}
|
||
|
|
||
|
return ClickHandler.end(e);
|
||
|
}
|
||
|
|
||
|
// Créer un nouveau bug
|
||
|
config.macros.newBUG = {label: "new BUG", prompt: "Create a new BUG tiddler", accessKey: "B"};
|
||
|
config.macros.newBUG.handler = function(place, macroName, params) {
|
||
|
if (!readOnly) {
|
||
|
createTiddlyButton(place, this.label, this.prompt, this.onClick, null, null, this.accessKey);
|
||
|
}
|
||
|
}
|
||
|
config.macros.newBUG.onClick = function(e) {
|
||
|
e = ClickHandler.getEvent(e);
|
||
|
|
||
|
var now = new Date();
|
||
|
var bugname = now.formatString("BUG-YYYY0MM0DD");
|
||
|
var title = bugname + "-" + (store.getTaggedTiddlers(bugname).length + 1);
|
||
|
|
||
|
clearMessage();
|
||
|
displayTiddler(null, title, 2, null, null, false, false);
|
||
|
var body = document.getElementById("editorBody" + title);
|
||
|
if (body) body.focus();
|
||
|
|
||
|
var tagsBox = document.getElementById("editorTags" + title);
|
||
|
if(tagsBox) {
|
||
|
var tags = tagsBox.value.splitTags();
|
||
|
tags.removeTag("DONE").addTag("BUG").addTag(bugname);
|
||
|
tagsBox.value = tags.joinTags();
|
||
|
}
|
||
|
|
||
|
return ClickHandler.end(e);
|
||
|
}
|
||
|
|
||
|
// marquer un TODO comme étant effectué
|
||
|
config.macros.markDONE = {label: "mark as DONE", prompt: "Mark a TODO/BUG tiddler as DONE", accessKey: "D"};
|
||
|
config.macros.markDONE.handler = function(place, macroName, params) {
|
||
|
if (!readOnly) {
|
||
|
createTiddlyButton(place, this.label, this.prompt, this.onClick, null, null, this.accessKey);
|
||
|
}
|
||
|
}
|
||
|
config.macros.markDONE.onClick = function(e) {
|
||
|
e = ClickHandler.getEvent(e);
|
||
|
|
||
|
if (currentTiddler) {
|
||
|
var title = currentTiddler;
|
||
|
|
||
|
var tags = Tiddlers.valueOf(title).tags;
|
||
|
if (tags.containsTag("TODO") || tags.containsTag("BUG")) {
|
||
|
clearMessage();
|
||
|
displayTiddler(null, title, 2, null, null, false, false);
|
||
|
|
||
|
var tagsBox = document.getElementById("editorTags" + title);
|
||
|
if(tagsBox) {
|
||
|
var tags = tagsBox.value.splitTags();
|
||
|
tags.removeTag("TODO").removeTag("BUG").addTag("DONE");
|
||
|
tagsBox.value = tags.joinTags();
|
||
|
|
||
|
var body = document.getElementById("editorBody" + title);
|
||
|
var text = body.value;
|
||
|
if (text.length > 0 && text.charAt(text.length - 1) != "\n") text += "\n";
|
||
|
text += "\nFAIT le " + new Date().formatString("0DD/0MM/YYYY");
|
||
|
body.value = text;
|
||
|
body.focus();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ClickHandler.end(e);
|
||
|
}
|
||
|
|
||
|
// Afficher un lien vers un TODO et une description du TODO
|
||
|
config.macros.todoLink = {};
|
||
|
config.macros.todoLink.handler = function(place, macroName, params) {
|
||
|
if (!params.length) return;
|
||
|
|
||
|
wikify(getTodoText(params[0]), place);
|
||
|
}
|
||
|
|
||
|
// Lister tous les TODOs, ceux à faire et ceux qui sont faits
|
||
|
config.macros.listTODOs = {};
|
||
|
config.macros.listTODOs.handler = function(place, macroName, params) {
|
||
|
var todos = getAllTodos(["-TODO", "BUG", "DONE"], params);
|
||
|
if (todos.length) {
|
||
|
var list = document.createElement("ul");
|
||
|
place.appendChild(list);
|
||
|
|
||
|
for(var i = 0; i < todos.length; i++) {
|
||
|
item = document.createElement("li");
|
||
|
list.appendChild(item);
|
||
|
|
||
|
var element = item;
|
||
|
var tags = todos[i].tags;
|
||
|
if (tags.containsTag("DONE")) {
|
||
|
striked = createTiddlyElement(element, "strike");
|
||
|
element = striked;
|
||
|
}
|
||
|
|
||
|
wikify(getTodoText(todos[i]), element);
|
||
|
}
|
||
|
} else {
|
||
|
place.appendChild(document.createTextNode("Il n'y a pas de TODOs en cours"));
|
||
|
}
|
||
|
}
|
||
|
function refreshTODOs(hint) {
|
||
|
refreshTiddler("TODOs");
|
||
|
}
|
||
|
config.notifyTiddlers.push({name: null, notify: refreshTODOs});
|
||
|
config.shadowTiddlers.TODOs = "<<listTODOs>>";
|
||
|
|
||
|
// Créer une nouvelle release
|
||
|
config.macros.newRelease = {label: "new release", prompt: "Create a new release", accessKey: "R"};
|
||
|
config.macros.newRelease.handler = function(place, macroName, params) {
|
||
|
if (!readOnly) {
|
||
|
createTiddlyButton(place, this.label, this.prompt, this.onClick, null, null, this.accessKey);
|
||
|
}
|
||
|
}
|
||
|
config.macros.newRelease.onClick = function(e) {
|
||
|
e = ClickHandler.getEvent(e);
|
||
|
|
||
|
var now = new Date();
|
||
|
var releasename = now.formatString("Release-YYYY0MM0DD");
|
||
|
var title = releasename;
|
||
|
var releases = store.getTaggedTiddlers(releasename);
|
||
|
if (releases.length > 0) {
|
||
|
title += "-" + releases.length;
|
||
|
}
|
||
|
|
||
|
clearMessage();
|
||
|
displayTiddler(null, title, 2, null, null, false, false);
|
||
|
var body = document.getElementById("editorBody" + title);
|
||
|
if (body && body.value == "") {
|
||
|
// ne créer le contenu que la première fois.
|
||
|
var text = "release du " + now.formatString("0DD/0MM/YYYY") + "\nversion: \n";
|
||
|
|
||
|
// lister tous les TODOs faits en cours
|
||
|
var todos = getAllTodos(["DONE"]);
|
||
|
for (var i = 0; i < todos.length; i++) {
|
||
|
if (i == 0) text += "\n";
|
||
|
text += "* <<todoLink " + todos[i].title + ">>\n";
|
||
|
}
|
||
|
|
||
|
body.value = text;
|
||
|
body.focus();
|
||
|
}
|
||
|
|
||
|
var tagsBox = document.getElementById("editorTags" + title);
|
||
|
if(tagsBox) {
|
||
|
var tags = tagsBox.value.splitTags();
|
||
|
tags.addTag("release").addTag(releasename);
|
||
|
tagsBox.value = tags.joinTags();
|
||
|
}
|
||
|
|
||
|
return ClickHandler.end(e);
|
||
|
}
|
||
|
TiddlyWiki.prototype.saveTiddler_patchedByTODO = TiddlyWiki.prototype.saveTiddler;
|
||
|
TiddlyWiki.prototype.saveTiddler = function(title, newTitle, newBody, modifier, modified, tags) {
|
||
|
var tiddler = this.saveTiddler_patchedByTODO(title, newTitle, newBody, modifier, modified, tags);
|
||
|
|
||
|
if (tiddler.tags.containsTag("release")) {
|
||
|
var todos = store.getTaggedTiddlers("DONE");
|
||
|
for (var i = 0; i < todos.length; i++) {
|
||
|
var todo = todos[i];
|
||
|
todo.tags.removeTag("DONE").addTag("RELEASED");
|
||
|
|
||
|
store.saveTiddler(todo.title, todo.title, todo.text, todo.modifier, undefined, todo.tags);
|
||
|
refreshTiddler(todos[i].title);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return tiddler;
|
||
|
}
|
||
|
|
||
|
function getVersionText(tiddler) {
|
||
|
var version = "";
|
||
|
var tiddler = Tiddlers.valueOf(tiddler);
|
||
|
if (tiddler) {
|
||
|
var re_version = new RegExp("^version:(.*)$", "gm");
|
||
|
var matched = re_version.exec(tiddler.text);
|
||
|
if (matched) {
|
||
|
version = matched[1].trim();
|
||
|
}
|
||
|
}
|
||
|
return version;
|
||
|
}
|
||
|
|
||
|
function getReleaseText(tiddler) {
|
||
|
// Retourner "[[versionText|releaseTitle]] - firstLine"
|
||
|
var text = "";
|
||
|
var tiddler = Tiddlers.valueOf(tiddler);
|
||
|
if (tiddler) {
|
||
|
var title = tiddler.title;
|
||
|
var version = getVersionText(tiddler);
|
||
|
if (version != "") {
|
||
|
text = "[[" + version + "|" + title + "]]";
|
||
|
} else {
|
||
|
text = "[[" + title + "]]";
|
||
|
}
|
||
|
var line = Tiddlers.getFirstLine(tiddler);
|
||
|
if (line != "") text += " - " + line;
|
||
|
}
|
||
|
return text;
|
||
|
}
|
||
|
|
||
|
config.macros.listReleases = {};
|
||
|
config.macros.listReleases.handler = function(place, macroName, params) {
|
||
|
var releases = store.getTaggedTiddlers("release");
|
||
|
releases.sortBy("title", true);
|
||
|
if (releases.length) {
|
||
|
var list = document.createElement("ul");
|
||
|
place.appendChild(list);
|
||
|
|
||
|
var len = releases.length;
|
||
|
if (len > 7) len = 7;
|
||
|
for(var i = 0; i < len; i++) {
|
||
|
item = document.createElement("li");
|
||
|
list.appendChild(item);
|
||
|
|
||
|
wikify(getReleaseText(releases[i]), item);
|
||
|
}
|
||
|
} else {
|
||
|
place.appendChild(document.createTextNode("Il n'y a pas de releases en cours"));
|
||
|
}
|
||
|
}
|
||
|
function refreshReleases(hint) {
|
||
|
refreshTiddler("Releases");
|
||
|
}
|
||
|
config.notifyTiddlers.push({name: null, notify: refreshReleases});
|
||
|
config.shadowTiddlers.Releases = "<<listReleases>>";
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
// Le formatter todo
|
||
|
// ce formatter affiche une case à cocher qu'il est possible de cocher pour signifier que l'action
|
||
|
// associée à la case à cocher est effectuée
|
||
|
// format: [] pour les actions non faites
|
||
|
// [x] pour les actions faites
|
||
|
|
||
|
var lastTodoId;
|
||
|
|
||
|
var displayTiddler_patchedByTodo = window.displayTiddler;
|
||
|
window.displayTiddler = function(src, title, state, highlightText, highlightCaseSensitive, animate, slowly) {
|
||
|
// réinitialiser le numéro du dernier todo à chaque affichage
|
||
|
lastTodoId = 0;
|
||
|
displayTiddler_patchedByTodo(src, title, state, highlightText, highlightCaseSensitive, animate, slowly);
|
||
|
}
|
||
|
|
||
|
config.formatters.push({
|
||
|
name: "todo",
|
||
|
match: "\\[\\]|\\[[xX\\*]\\]",
|
||
|
terminator: "\\n|\\|",
|
||
|
handler: function(w) {
|
||
|
var formatter = this;
|
||
|
var place = w.output;
|
||
|
|
||
|
var tiddler = findContainingTiddler(place);
|
||
|
if (!tiddler) return;
|
||
|
|
||
|
var title = tiddler.id.substr(7);
|
||
|
var todoId = lastTodoId++;
|
||
|
var cbId = "todo" + todoId + "@" + title;
|
||
|
var wrapperId = "todoWrapper" + todoId + "@:" + title;
|
||
|
|
||
|
var matched = w.source.substr(w.matchStart, w.matchLength);
|
||
|
var done = matched != "[]";
|
||
|
var onClick = function(e) {
|
||
|
e = ClickHandler.getEvent(e);
|
||
|
|
||
|
if (!readOnly) {
|
||
|
// lire les infos sur le tiddler
|
||
|
var body = store.getTiddlerText(title);
|
||
|
var tags = Tiddlers.getTags(title);
|
||
|
|
||
|
// trouver le texte [] qui correspond à todoId
|
||
|
var id = 0;
|
||
|
var re_macro = new RegExp(formatter.match, "mg");
|
||
|
do {
|
||
|
var mo = re_macro.exec(body);
|
||
|
if (mo) {
|
||
|
if (id++ == todoId) break;
|
||
|
}
|
||
|
} while (mo);
|
||
|
|
||
|
// changer la valeur
|
||
|
if (mo) {
|
||
|
var done = mo[0] == "[]";
|
||
|
body = body.substr(0, mo.index) + (done? "[x]": "[]") + body.substr(mo.index + mo[0].length);
|
||
|
|
||
|
lastTodoId = 0;
|
||
|
store.saveTiddler(title, title, body, config.options.txtUserName, new Date(), tags);
|
||
|
if (config.options.chkAutoSave) saveChanges();
|
||
|
refreshTiddler(title);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ClickHandler.end(e);
|
||
|
};
|
||
|
|
||
|
var span = createTiddlyElement(place, "span");
|
||
|
var cb = createTiddlyElement(span, "input");
|
||
|
cb.type = "checkbox";
|
||
|
cb.id = cbId;
|
||
|
cb.checked = done;
|
||
|
cb.onclick = onClick;
|
||
|
var label = createTiddlyElement(span, "label");
|
||
|
label.setAttribute("for", cbId);
|
||
|
var wrapper = createTiddlyElement(label, "span", wrapperId);
|
||
|
if (done) {
|
||
|
wrapper.setAttribute("style", "text-decoration: line-through;");
|
||
|
}
|
||
|
w.subWikify(wrapper, this.terminator);
|
||
|
w.nextMatch--; // ne pas manger le terminator
|
||
|
}
|
||
|
});
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
// L'interface par défaut
|
||
|
|
||
|
config.shadowTiddlers.MainMenu = "\
|
||
|
<<calendar>>\n\
|
||
|
<<newTiddler>>\n\
|
||
|
----\n\
|
||
|
[[Releases]]\n\
|
||
|
<<newRelease>>\n\
|
||
|
----\n\
|
||
|
[[TODOs]]\n\
|
||
|
<<newTODO>>\n\
|
||
|
<<newBUG>>\n\
|
||
|
<<markDONE>>\
|
||
|
";
|
||
|
config.shadowTiddlers.DefaultTiddlers = "\
|
||
|
Releases\n\
|
||
|
TODOs\n\
|
||
|
EnCours\
|
||
|
";
|
||
|
config.shadowTiddlers.SiteTitle = "TODO";
|
||
|
config.shadowTiddlers.SiteSubtitle = "Gestion de tâches";
|
||
|
|
||
|
config.shadowTiddlers.KeyShortcuts += "\
|
||
|
|Alt + T|Créer un nouveau TODO|\n\
|
||
|
|Alt + B|Créer un nouveau BUG|\n\
|
||
|
|Alt + D|Terminer un TODO|\n\
|
||
|
|Alt + R|Créer une nouvelle release|\n\
|
||
|
";
|