// -*- 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 = "<>"; // 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 += "* <>\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 = "<>"; ////////////////////////////////////////////////// // 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 = "\ <>\n\ <>\n\ ----\n\ [[Releases]]\n\ <>\n\ ----\n\ [[TODOs]]\n\ <>\n\ <>\n\ <>\ "; 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\ ";