986 lines
31 KiB
JavaScript
986 lines
31 KiB
JavaScript
// -*- coding: utf-8 -*-
|
|
|
|
//////////////////////////////////////////////////
|
|
// Outils divers et méthodes supplémentaires pour les classes de base
|
|
|
|
// Array
|
|
Array.prototype.indexOfItem = function(item) {
|
|
for (var i = 0; i < this.length; i++) {
|
|
if (this[i] == item) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
Array.prototype.containsItem = function(item) {
|
|
return this.indexOfItem(item) != -1;
|
|
}
|
|
|
|
Array.prototype.sortBy = function(field, reverse) {
|
|
if (field == undefined) field = "title";
|
|
this.sort(function(a, b) {
|
|
if (a[field] == b[field]) {
|
|
return 0;
|
|
} else {
|
|
var result = a[field] < b[field]? -1 : +1;
|
|
if (reverse) result = -result;
|
|
return result;
|
|
}
|
|
});
|
|
}
|
|
|
|
// String
|
|
String.prototype.addText = function(item) {
|
|
var str = this;
|
|
if (str != "") str += " ";
|
|
str += item;
|
|
return str;
|
|
}
|
|
|
|
String.prototype.expandVars = function(vars, recursive) {
|
|
var text = this;
|
|
|
|
// remplacer les éléments de date
|
|
var now = vars && vars["now"]? Dat.valueOf(vars["now"]): new Date();
|
|
text = now.expandVars(text);
|
|
|
|
if (vars) {
|
|
// remplacer la valeurs des variables
|
|
var pos = 0;
|
|
var re_var = new RegExp("\\$(?:([a-zA-Z0-9_]+)|{([^}]+)})", "mg");
|
|
do {
|
|
re_var.lastIndex = pos;
|
|
var mo = re_var.exec(text);
|
|
if (mo) {
|
|
if (mo[1]) {
|
|
var name = mo[1];
|
|
var value = vars[name]? vars[name]: mo[0];
|
|
} else {
|
|
var name = mo[2];
|
|
try {
|
|
var value = vars.eval(name);
|
|
} catch(e) {
|
|
var value = e.toString();
|
|
}
|
|
}
|
|
text = text.substr(0, mo.index) + value + text.substr(mo.index + mo[0].length);
|
|
pos = mo.index;
|
|
if (!recursive) pos += new String(value).length;
|
|
}
|
|
} while(mo);
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
function expandVars(template, vars, recursive) {
|
|
return Str.valueOf(template).expandVars(vars, recursive);
|
|
}
|
|
|
|
String.prototype.firstLine = function() {
|
|
// obtenir la première ligne non vide d'une chaine
|
|
var text = this, line = "";
|
|
var start = 0, pos;
|
|
do {
|
|
pos = text.indexOf("\n", start);
|
|
if (pos == -1) {
|
|
line = text.substr(start);
|
|
break;
|
|
} else {
|
|
line = text.substring(start, pos);
|
|
if (new RegExp("\\S").test(line)) {
|
|
break;
|
|
}
|
|
}
|
|
start = pos + 1;
|
|
} while (pos != -1);
|
|
|
|
return line;
|
|
}
|
|
|
|
// Date
|
|
Date.parseFr = function(text) {
|
|
// créer une date à partir d'une chaine de la forme dd/mm/yyyy
|
|
var re_date = new RegExp("([0-9]+)/([0-9]+)/([0-9]+)");
|
|
var mo = re_date.exec(text);
|
|
if (mo) {
|
|
return new Date(parseInt(mo[3], 10), parseInt(mo[2], 10) - 1, parseInt(mo[1], 10));
|
|
} else {
|
|
return new Date(text);
|
|
}
|
|
}
|
|
|
|
var MMM = ["Jan", "Fév", "Mar", "Avr", "Mai", "Jun", "Jui", "Aoû", "Sep", "Oct", "Nov", "Déc"];
|
|
var MMMM = ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"];
|
|
var D = ["L", "M", "M", "J", "V", "S", "D"];
|
|
var DD = ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"];
|
|
var DDD = ["Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"];
|
|
Date.prototype.expandVars = function(text) {
|
|
text = text.replace(/%Y/g, this.getFullYear());
|
|
text = text.replace(/%4m/g, MMMM[this.getMonth()]);
|
|
text = text.replace(/%3m/g, MMM[this.getMonth()]);
|
|
text = text.replace(/%0m/g, String.zeroPad(this.getMonth() + 1, 2));
|
|
text = text.replace(/%m/g, this.getMonth());
|
|
text = text.replace(/%3d/g, DDD[this.getDow()]);
|
|
text = text.replace(/%2d/g, DD[this.getDow()]);
|
|
text = text.replace(/%1d/g, D[this.getDow()]);
|
|
text = text.replace(/%0d/g, String.zeroPad(this.getDate(), 2));
|
|
text = text.replace(/%d/g, this.getDate());
|
|
text = text.replace(/%H/g, this.getHours());
|
|
text = text.replace(/%M/g, this.getMinutes());
|
|
text = text.replace(/%S/g, this.getSeconds());
|
|
return text;
|
|
}
|
|
|
|
Date.prototype.formatFr = function() {
|
|
return this.expandVars("%0d/%0m/%Y");
|
|
}
|
|
|
|
Date.prototype.formatFrLong = function() {
|
|
return this.expandVars("%3d %0d/%0m/%Y");
|
|
}
|
|
|
|
Date.prototype.getWom = function() {
|
|
// obtenir le numéro de la semaine du mois: 0 - 4
|
|
var lundi = this.getMonday();
|
|
var day = lundi.getDate();
|
|
return Math.floor(day/7);
|
|
}
|
|
|
|
Date.prototype.getDow = function() {
|
|
// obtenir le jour de la semaine: 0(lundi) - 6(dimanche)
|
|
var dow = this.getDay();
|
|
dow = (dow + 6) % 7;
|
|
return dow;
|
|
}
|
|
|
|
Date.prototype.getMidnight = function() {
|
|
// obtenir la même date à minuit
|
|
return new Date(this.getFullYear(), this.getMonth(), this.getDate());
|
|
}
|
|
|
|
Date.prototype.addMonths = function(nb) {
|
|
// ajouter nb mois à la date, et retourner la date résultante à minuit
|
|
var y = this.getFullYear(), m = this.getMonth(), d = this.getDate();
|
|
m += nb;
|
|
while (m < 0) {
|
|
m += 12;
|
|
y--;
|
|
}
|
|
while (m > 11) {
|
|
m -= 12;
|
|
y++;
|
|
}
|
|
return new Date(y, m, d);
|
|
}
|
|
|
|
Date.prototype.addDays = function(nb) {
|
|
// ajouter nb jours à la date, et retourner la date résultante à minuit
|
|
var y = this.getFullYear(), m = this.getMonth(), d = this.getDate();
|
|
return new Date(y, m, d + nb);
|
|
}
|
|
|
|
Date.prototype.diffDays = function(date) {
|
|
return (date.getMidnight() - this.getMidnight()) / 86400000;
|
|
}
|
|
|
|
Date.prototype.getMonday = function() {
|
|
// obtenir le lundi de la semaine en cours
|
|
return this.addDays(-this.getDow());
|
|
}
|
|
|
|
Date.prototype.getFirstDay = function() {
|
|
// obtenir le premier jour du mois
|
|
return new Date(this.getFullYear(), this.getMonth(), 1);
|
|
}
|
|
|
|
var NUM_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
Date.prototype.getNumDays = function() {
|
|
// obtenir le nombre de jours de ce mois
|
|
var m = this.getMonth();
|
|
if (m == 1) {
|
|
var y = this.getFullYear();
|
|
var isleap = (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0);
|
|
return NUM_DAYS[m] + (isleap? 1: 0);
|
|
} else {
|
|
return NUM_DAYS[m];
|
|
}
|
|
}
|
|
|
|
Date.prototype.getLastDay = function() {
|
|
// obtenir le dernier jour du mois
|
|
return new Date(this.getFullYear(), this.getMonth(), this.getNumDays());
|
|
}
|
|
|
|
// ClickHandler
|
|
var ClickHandler = {};
|
|
ClickHandler.getEvent = function(e) {
|
|
if (!e) e = window.event;
|
|
return e;
|
|
}
|
|
ClickHandler.end = function(e) {
|
|
e.cancelBubble = true;
|
|
if (e.stopPropagation) e.stopPropagation();
|
|
return false;
|
|
}
|
|
|
|
// Str
|
|
var Str = {};
|
|
Str.valueOf = function(s) {
|
|
if (typeof(s) == "string") s = new String(s);
|
|
if (!(s instanceof String)) {
|
|
if (s == null || s == undefined) s = "";
|
|
s = new String(s);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
// Dat
|
|
var Dat = {};
|
|
Dat.valueOf = function(d) {
|
|
if (d instanceof String || typeof(d) == "string") {
|
|
return Date.parseFr(d);
|
|
} else if (d instanceof Date) {
|
|
return d;
|
|
} else {
|
|
return new Date(d);
|
|
}
|
|
}
|
|
|
|
// Bool
|
|
var Bool = {};
|
|
Bool.valueOf = function(b) {
|
|
if (b instanceof String || typeof(b) == "string") {
|
|
var b = Str.valueOf(b).toLowerCase();
|
|
return ["oui", "o", "yes", "y", "vrai", "v", "true", "t", "1"].containsItem(b);
|
|
}
|
|
return Boolean(b).valueOf();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
// Fonctions pour gérer les tags
|
|
|
|
Array.prototype.removeTag = function(tag) {
|
|
var pos = this.indexOfItem(tag);
|
|
if (pos != -1) {
|
|
this.splice(pos, 1);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
Array.prototype.addTag = function(tag) {
|
|
this.pushUnique(tag);
|
|
return this;
|
|
}
|
|
|
|
Array.prototype.addTags = function(tags) {
|
|
if (tags instanceof String || typeof(tags) == "string") {
|
|
tags = new String(tags).splitTags();
|
|
}
|
|
for (var i = 0; i < tags.length; i++) {
|
|
this.addTag(tags[i]);
|
|
}
|
|
}
|
|
|
|
Array.prototype.containsTag = function(tag) {
|
|
return this.containsItem(tag);
|
|
}
|
|
|
|
Array.prototype.joinTags = function() {
|
|
var result = [];
|
|
for (var i = 0; i < this.length; i++) {
|
|
result.push(String.encodeTiddlyLink(this[i]));
|
|
}
|
|
return result.join(" ");
|
|
}
|
|
|
|
String.prototype.splitTags = function() {
|
|
return this.readBracketedList(true);
|
|
}
|
|
|
|
String.prototype.addTag = function(tag) {
|
|
var thistags = this.splitTags();
|
|
thistags.addTag(tag);
|
|
return thistags.joinTags();
|
|
}
|
|
|
|
String.prototype.addTags = function(tags) {
|
|
var thistags = this.splitTags();
|
|
thistags.addTags(tags);
|
|
return thistags.joinTags();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
// Gestion des tiddlers et patches divers
|
|
|
|
// Tiddlers
|
|
var Tiddlers = {};
|
|
Tiddlers.valueOf = function(tiddler) {
|
|
if (!(tiddler instanceof Tiddler)) {
|
|
tiddler = store.tiddlers[tiddler];
|
|
}
|
|
return tiddler;
|
|
}
|
|
|
|
Tiddlers.getTags = function(tiddler) {
|
|
// obtenir la valeur de tags pour un tiddler
|
|
var tiddler = this.valueOf(tiddler);
|
|
if (tiddler) return tiddler.getTags();
|
|
return "";
|
|
}
|
|
|
|
Tiddlers.getSubtitle = function(tiddler) {
|
|
// obtenir la valeur de subtitle pour un title
|
|
var tiddler = this.valueOf(tiddler);
|
|
if (tiddler) return tiddler.getSubtitle();
|
|
return config.messages.subtitleUnknown;
|
|
}
|
|
|
|
Tiddlers.getFirstLine = function(tiddler) {
|
|
var tiddler = this.valueOf(tiddler);
|
|
if (tiddler) return tiddler.text.firstLine();
|
|
return "";
|
|
}
|
|
|
|
// patches divers
|
|
var createTiddlyButton_patchedByBase = window.createTiddlyButton;
|
|
window.createTiddlyButton = function(parent, text, tooltip, action, klass, id, accessKey) {
|
|
// afficher la touche de raccourci dans le title du bouton
|
|
if (accessKey) {
|
|
if (!tooltip) tooltip = "";
|
|
tooltip = Str.valueOf(tooltip).addText("(Alt + " + accessKey + ")");
|
|
}
|
|
return createTiddlyButton_patchedByBase(parent, text, tooltip, action, klass, id, accessKey);
|
|
}
|
|
|
|
closeTiddler_patchedByBase = window.closeTiddler;
|
|
window.closeTiddler = function(title, slowly) {
|
|
// patcher close pour désactiver l'animation sur la fermeture
|
|
var saveAnimate = config.options.chkAnimate;
|
|
config.options.chkAnimate = false;
|
|
closeTiddler_patchedByBase(title, slowly);
|
|
config.options.chkAnimate = saveAnimate;
|
|
}
|
|
|
|
displayTiddlers_patchedByBase = window.displayTiddlers;
|
|
window.displayTiddlers = function(src, titles, state, highlightText, highlightCaseSensitive, animate, slowly) {
|
|
// patcher displayTiddlers pour permettre l'affichage d'une liste de tiddlers générés par une macro.
|
|
// La macro doit implémenter textHandler pour être reconnue
|
|
if (titles.indexOf("<<") != -1) {
|
|
var pos = 0;
|
|
var re_macro = new RegExp("<<([^>\\s]+)(?:\\s*)([^>]*)>>", "mg");
|
|
do {
|
|
re_macro.lastIndex = pos;
|
|
var mo = re_macro.exec(titles);
|
|
if (mo) {
|
|
var macro = config.macros[mo[1]];
|
|
if (macro && macro.textHandler) {
|
|
var params = mo[2].readMacroParams();
|
|
var text = macro.textHandler(params);
|
|
titles = titles.substr(0, mo.index) + text + titles.substr(mo.index + mo[0].length);
|
|
pos = mo.index + new String(text).length;
|
|
} else {
|
|
pos = mo.index + mo[0].length;
|
|
}
|
|
}
|
|
} while (mo);
|
|
titles = titles.replace(/<<([^>\s]+)(?:\s*)([^>]*)>>/g, "");
|
|
}
|
|
displayTiddlers_patchedByBase(src, titles, state, highlightText,highlightCaseSensitive,animate,slowly);
|
|
}
|
|
|
|
// patcher createTiddlerToolbar pour que la liste des boutons à afficher soit dans un tableau modifiable
|
|
config.views.wikified.toolbarClose.onClick = onClickToolbarClose;
|
|
config.views.wikified.toolbarEdit.onClick = onClickToolbarEdit;
|
|
config.views.wikified.toolbarEdit.notReadOnly = true;
|
|
config.views.wikified.toolbarPermalink.onClick = onClickToolbarPermaLink;
|
|
config.views.wikified.toolbarReferences.onClick = onClickToolbarReferences;
|
|
config.views.wikified.toolbarButtons = [
|
|
config.views.wikified.toolbarClose,
|
|
config.views.wikified.toolbarEdit,
|
|
config.views.wikified.toolbarPermalink,
|
|
config.views.wikified.toolbarReferences];
|
|
|
|
config.views.editor.toolbarDone.onClick = onClickToolbarSave;
|
|
config.views.editor.toolbarDone.notReadOnly = true;
|
|
config.views.editor.toolbarCancel.onClick = onClickToolbarUndo;
|
|
config.views.editor.toolbarDelete.onClick = onClickToolbarDelete;
|
|
config.views.editor.toolbarDelete.notReadOnly = true;
|
|
config.views.editor.toolbarButtons = [
|
|
config.views.editor.toolbarDone,
|
|
config.views.editor.toolbarCancel,
|
|
config.views.editor.toolbarDelete];
|
|
|
|
// Create a tiddler toolbar according to whether it's an editor or not
|
|
createTiddlerToolbar = function(title, isEditor) {
|
|
var theToolbar = document.getElementById("toolbar" + title);
|
|
if(theToolbar) {
|
|
var lingo = config.views;
|
|
if (isEditor) lingo = lingo.editor;
|
|
else lingo = lingo.wikified;
|
|
|
|
removeChildren(theToolbar);
|
|
insertSpacer(theToolbar);
|
|
var toolbarButtons = lingo.toolbarButtons;
|
|
for (var i = 0; i < toolbarButtons.length; i++) {
|
|
var toolbarButton = toolbarButtons[i];
|
|
|
|
if (i > 0) insertSpacer(theToolbar);
|
|
if (!readOnly || !toolbarButton.notReadOnly) {
|
|
createTiddlyButton(theToolbar, toolbarButton.text, toolbarButton.tooltip, toolbarButton.onClick);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function installToolbarButton(toolbarButton, editor, before) {
|
|
// installer un bouton dans la vue wiki (par défaut) ou dans la vue éditeur (si editor==true), avant le bouton before
|
|
var lingo = config.views;
|
|
if (editor) lingo = lingo.editor;
|
|
else lingo = lingo.wikified;
|
|
|
|
var pos = -1;
|
|
if (before) {
|
|
pos = lingo.toolbarButtons.indexOfItem(before);
|
|
}
|
|
if (pos == -1) {
|
|
lingo.toolbarButtons.push(toolbarButton);
|
|
} else {
|
|
lingo.toolbarButtons.splice(pos, 0, toolbarButton);
|
|
}
|
|
}
|
|
|
|
function removeToolbarButton(toolbarButton, editor) {
|
|
var lingo = config.views;
|
|
if (editor) lingo = lingo.editor;
|
|
else lingo = lingo.wikified;
|
|
|
|
var pos = lingo.toolbarButtons.indexOfItem(toolbarButton);
|
|
if (pos != -1) {
|
|
lingo.toolbarButtons.splice(pos, 1);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
// Gestion des paramètres
|
|
|
|
// Process a string list of macro parameters into an array. Parameters can be quoted
|
|
// with "", '', [[]] or left unquoted (and therefore space-separated)
|
|
// On reconnait aussi les paramètres de la forme name="value", name='value' ou name=value
|
|
String.prototype.readMacroParams = function() {
|
|
var regexpMacroParam = new RegExp("(?:\\s*)(?:" +
|
|
"(?:\"([^\"]*)\")|" +
|
|
"(?:'([^']*)')|" +
|
|
"(?:\\[\\[([^\\]]*)\\]\\])|" +
|
|
"([^\"'\\s]\\S*=(?:[^\"'\\s]\\S*|\"[^\"]*\"|'[^']*'))|" +
|
|
"([^\"'\\s]\\S*)" +
|
|
")","mg");
|
|
var params = [];
|
|
do {
|
|
var match = regexpMacroParam.exec(this);
|
|
if(match) {
|
|
if(match[1]) params.push(match[1]); // Double quoted
|
|
else if(match[2]) params.push(match[2]); // Single quoted
|
|
else if(match[3]) params.push(match[3]); // Double-square-bracket quoted
|
|
else if(match[4]) params.push(match[4]); // name=value, name="value" ou name='value'
|
|
else if(match[5]) params.push(match[5]); // Unquoted
|
|
}
|
|
} while(match);
|
|
return params;
|
|
}
|
|
|
|
function Options(params) {
|
|
// Dans un tableau de paramètre construit par String.readMacroParams, reconnaitre les options de la forme name=value
|
|
// L'objet retourné contient le tableau arg qui est une copie de params sans les options, et une propriété pour chaque option.
|
|
|
|
this.args = [];
|
|
var re_option = new RegExp("([^\"'\\s]\\S*)=(?:([^\"'\\s]\\S*)|\"([^\"]*)\"|'([^']*)')");
|
|
for (var i = 0; i < params.length; i++) {
|
|
var mo = re_option.exec(params[i]);
|
|
if (mo) {
|
|
var name = mo[1];
|
|
var value = mo[2]? mo[2]: mo[3]? mo[3]: mo[4]? mo[4]: "";
|
|
this[name] = value;
|
|
} else {
|
|
this.args.push(params[i]);
|
|
}
|
|
}
|
|
}
|
|
Options.prototype.get = function(name, def) {
|
|
// obtenir la valeur d'une option, avec une valeur par défaut
|
|
if (this[name]) return this[name];
|
|
return def;
|
|
}
|
|
Options.prototype.getArg = function(index, def) {
|
|
// obtenir la valeur d'un argument, avec une valeur par défaut
|
|
if (this.args[index]) return this.args[index];
|
|
return def;
|
|
}
|
|
Options.prototype.toParams = function() {
|
|
var params = "";
|
|
for (var i = 0; i < this.args.length; i++) {
|
|
var arg = this.args[i];
|
|
if (new RegExp("\\s").test(arg)) {
|
|
params = params + " \"" + arg + "\"";
|
|
} else {
|
|
params = params + " " + arg;
|
|
}
|
|
}
|
|
for (var prop in this) {
|
|
if (prop != "args" && prop != "get" && prop != "getArg" && prop != "toParams") {
|
|
params = params + " " + prop + "=";
|
|
|
|
var arg = new String(this[prop]);
|
|
if (new RegExp("\\s").test(arg)) {
|
|
params = params + "\"" + arg + "\"";
|
|
} else {
|
|
params = params + arg;
|
|
}
|
|
}
|
|
}
|
|
return params;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
// La macro newTiddler
|
|
// arguments: title text= tooltip= tags=
|
|
|
|
config.macros.newTiddler.handler = function(place, macroName, params) {
|
|
// créer un nouveau tiddler avec le nom params[0] et les tags params[1..n]
|
|
if(!readOnly) {
|
|
var options = new Options(params);
|
|
var legacy = options.args[0]? false: true;
|
|
var tags = expandVars(options.get("tags", ""));
|
|
if (legacy) {
|
|
var title = config.macros.newTiddler.title;
|
|
var tooltip = options.get("tooltip", config.macros.newTiddler.prompt);
|
|
var text = options.get("text", config.macros.newTiddler.label);
|
|
} else {
|
|
var title = expandVars(options.args[0]);
|
|
var tooltip = options.get("tooltip", "Create a new tiddler named " + title);
|
|
var text = options.get("text", "new " + (tags? "tagged ": "") + "tiddler");
|
|
}
|
|
|
|
var onClick = function() {
|
|
displayTiddler(null, title, 2, null, null, false, false);
|
|
var tagsBox = document.getElementById("editorTags" + title);
|
|
if(tagsBox) tagsBox.value = tagsBox.value.addTags(tags);
|
|
if (legacy) {
|
|
var e = document.getElementById("editorTitle" + title);
|
|
e.focus();
|
|
e.select();
|
|
}
|
|
return false;
|
|
}
|
|
createTiddlyButton(place, text, tooltip, onClick, undefined, undefined, legacy? this.accessKey: undefined);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
// Les macros de gestion d'événements
|
|
|
|
// La macro event
|
|
// arguments: date title nbDays= format=
|
|
config.macros.event = {
|
|
TODAY: "aujourd'hui",
|
|
TOMORROW: "demain",
|
|
YESTERDAY: "hier",
|
|
FUTURE_EVENT: "dans $remaining jours",
|
|
PAST_EVENT: "il y a ${-remaining} jours",
|
|
FORMAT: "$remainingDays: $title le $date"
|
|
};
|
|
config.macros.event.getRemainingDays = function(remaining) {
|
|
if (remaining == 0) remainingDays = this.TODAY;
|
|
else if (remaining == 1) remainingDays = this.TOMORROW;
|
|
else if (remaining == -1) remainingDays = this.YESTERDAY;
|
|
else if (remaining < 0) remainingDays = this.PAST_EVENT;
|
|
else remainingDays = this.FUTURE_EVENT;
|
|
|
|
return remainingDays;
|
|
}
|
|
config.macros.event.textHandler = function(params) {
|
|
var options = new Options(params);
|
|
var date = options.args[0]? Date.parseFr(options.args[0]): new Date();
|
|
var title = options.args[1]? options.args[1]: "Unnamed event";
|
|
var nbDays = parseInt(options.get("nbDays", "15"), 10);
|
|
var format = options.get("format", this.FORMAT);
|
|
|
|
var remaining = new Date().diffDays(date);
|
|
var remainingDays = this.getRemainingDays(remaining);
|
|
|
|
var vars = {remaining: remaining, remainingDays: remainingDays, title: title, date: date.formatFr()};
|
|
if (Math.abs(remaining) <= nbDays) return expandVars(format, vars, true);
|
|
}
|
|
config.macros.event.handler = function(place, macroName, params) {
|
|
var text = this.textHandler(params);
|
|
if (text && text != "") wikify(text, place);
|
|
}
|
|
|
|
// La macro showEvents
|
|
// arguments: nbDays= format= headerFormat= noEventsFormat=
|
|
config.macros.showEvents = {
|
|
NO_EVENTS_FORMAT: "Il n'y a pas d'événements en cours",
|
|
HEADER_FORMAT: "|Date|Evénement|",
|
|
FORMAT: "|$date|$title|"
|
|
};
|
|
config.macros.showEvents.textHandler = function(params) {
|
|
var options = new Options(params);
|
|
var noEventsFormat = options.get("noEventsFormat", this.NO_EVENTS_FORMAT);
|
|
var headerFormat = options.get("headerFormat", this.HEADER_FORMAT);
|
|
var format = options.get("format", this.FORMAT);
|
|
|
|
var vars = {}
|
|
var tiddlers = store.reverseLookup("tags", "event", true, "title");
|
|
|
|
if (tiddlers && tiddlers.length) {
|
|
var text = expandVars(headerFormat, vars) + "\n";
|
|
|
|
for (var i = 0; i < tiddlers.length; i++) {
|
|
var tags = tiddlers[i].getTags();
|
|
var re_date = new RegExp("\\s?@([0-9]+/[0-9]+/[0-9]+)\\s?", "g");
|
|
var mo = re_date.exec(tags);
|
|
if (mo) {
|
|
var date = Date.parseFr(mo[1]);
|
|
var title = tiddlers[i].title;
|
|
var remaining = new Date().diffDays(date);
|
|
var remainingDays = config.macros.event.getRemainingDays(remaining);
|
|
|
|
var vars = {remaining: remaining, remainingDays: remainingDays, title: title, date: date.formatFr()};
|
|
text += expandVars(format, vars, true) + "\n";
|
|
}
|
|
}
|
|
} else {
|
|
var text = expandVars(noEventsFormat, vars);
|
|
}
|
|
|
|
return text;
|
|
}
|
|
config.macros.showEvents.handler = function(place, macroName, params) {
|
|
var text = this.textHandler(params);
|
|
if (text && text != "") wikify(text, place);
|
|
}
|
|
|
|
// La macro calendar
|
|
// arguments:
|
|
var currentFirstDay;
|
|
|
|
config.macros.calendar = {};
|
|
config.macros.calendar.refresh = function(e) {
|
|
var target = resolveTarget(ClickHandler.getEvent(e));
|
|
var tiddler = findContainingTiddler(target);
|
|
if (tiddler) {
|
|
refreshTiddler(tiddler.id.substr(7));
|
|
} else {
|
|
while(target && target.id != "mainMenu") {
|
|
target = target.parentNode;
|
|
}
|
|
if (target) {
|
|
refreshMenu();
|
|
}
|
|
}
|
|
}
|
|
config.macros.calendar.handler = function(place, macroName, params) {
|
|
var now = new Date().getMidnight();
|
|
if (currentFirstDay) {
|
|
var firstDay = currentFirstDay;
|
|
} else {
|
|
var firstDay = now.getFirstDay();
|
|
}
|
|
var firstCalDay = firstDay.getMonday();
|
|
|
|
var table, tr, td;
|
|
|
|
buildModifiedTiddlers();
|
|
|
|
table = createTiddlyElement(place, "table");
|
|
table.setAttribute("class", "calendar");
|
|
|
|
var onClickPreviousMonth = function(e) {
|
|
currentFirstDay = currentFirstDay.addMonths(-1);
|
|
config.macros.calendar.refresh(e);
|
|
return false;
|
|
}
|
|
|
|
var onClickNextMonth = function(e) {
|
|
currentFirstDay = currentFirstDay.addMonths(1);
|
|
config.macros.calendar.refresh(e);
|
|
return false;
|
|
}
|
|
|
|
tr = createTiddlyElement(table, "tr");
|
|
tr.setAttribute("class", "navRow");
|
|
|
|
td = createTiddlyElement(tr, "td");
|
|
createTiddlyButton(td, "<", "mois précédent", onClickPreviousMonth);
|
|
|
|
td = createTiddlyElement(tr, "td");
|
|
td.colSpan = 5;
|
|
createTiddlyText(td, MMMM[firstDay.getMonth()] + " " + firstDay.getFullYear());
|
|
|
|
td = createTiddlyElement(tr, "td");
|
|
createTiddlyButton(td, ">", "mois suivant", onClickNextMonth);
|
|
|
|
tr = createTiddlyElement(table, "tr");
|
|
tr.setAttribute("class", "hdrRow");
|
|
|
|
for (var i = 0; i < D.length; i++) {
|
|
td = createTiddlyElement(tr, "td");
|
|
createTiddlyText(td, D[i]);
|
|
}
|
|
|
|
createCal(table, now, firstCalDay, firstDay);
|
|
currentFirstDay = firstDay;
|
|
}
|
|
|
|
function createCal(table, now, firstCalDay, firstDay) {
|
|
var td, tr;
|
|
|
|
var lastDay = firstDay.getLastDay();
|
|
var day = firstCalDay;
|
|
|
|
do {
|
|
tr = createTiddlyElement(table, "tr");
|
|
tr.setAttribute("class", "calRow");
|
|
for (var i = 0; i < 7; i++) {
|
|
td = createTiddlyElement(tr, "td");
|
|
createCalDay(td, day, firstDay, now, lastDay);
|
|
day = day.addDays(1);
|
|
}
|
|
} while (day <= lastDay);
|
|
}
|
|
|
|
function createCalDay(td, day, firstDay, now, lastDay) {
|
|
var modified = getModifiedTiddlers(day);
|
|
var events = getEvents(day);
|
|
var title = day.formatFr();
|
|
|
|
var klass = new String();
|
|
if (day.getTime() == now.getTime()) klass = klass.addText("calToday");
|
|
if (day < firstDay || day > lastDay) klass = klass.addText("calOther");
|
|
if ((modified && modified.length) ||(events && events.length)) {
|
|
klass = klass.addText("calEvent");
|
|
var a = [];
|
|
if (modified && modified.length) a.push("" + modified.length + " tiddler(s)");
|
|
if (events && events.length) a.push("" + events.length + " événements(s)");
|
|
title += ": " + a.join(",");
|
|
}
|
|
td.setAttribute("class", klass);
|
|
|
|
td.title = title;
|
|
td.onclick = function(e) {
|
|
e = ClickHandler.getEvent(e);
|
|
var popup = Popup.create(resolveTarget(e));
|
|
|
|
if (!readOnly) {
|
|
var tags = "event @" + day.formatFr();
|
|
wikify("<<newTiddler text=\"nouvel événement\" tooltip=\"nouvel événement le " + day.formatFr() + "\" tags=\"" + tags + "\">>", popup);
|
|
}
|
|
|
|
var addLinks = function(tiddlers, title, field) {
|
|
if (tiddlers && tiddlers.length) {
|
|
if (field) tiddlers.sortBy(field);
|
|
var div = createTiddlyElement(popup, "div", null, null, title);
|
|
for (var i = 0; i < tiddlers.length; i++) {
|
|
var div = createTiddlyElement(popup, "div");
|
|
var link = createTiddlyLink(div, tiddlers[i].title, false);
|
|
insertSpacer(link);
|
|
insertSpacer(link);
|
|
createTiddlyText(link, tiddlers[i].title);
|
|
}
|
|
}
|
|
}
|
|
|
|
addLinks(events, "événements:");
|
|
addLinks(modified, "modifiés:", "title");
|
|
|
|
Popup.show();
|
|
return ClickHandler.end(e);
|
|
}
|
|
|
|
createTiddlyText(td, day.getDate());
|
|
}
|
|
|
|
var modifiedTiddlers;
|
|
|
|
function buildModifiedTiddlers() {
|
|
modifiedTiddlers = {};
|
|
for (var t in store.tiddlers) {
|
|
var tiddler = store.tiddlers[t];
|
|
var date = tiddler.modified.formatFr();
|
|
if (!modifiedTiddlers[date]) {
|
|
modifiedTiddlers[date] = [];
|
|
}
|
|
modifiedTiddlers[date].push(tiddler);
|
|
}
|
|
}
|
|
|
|
function getModifiedTiddlers(date) {
|
|
return modifiedTiddlers[date.formatFr()];
|
|
}
|
|
|
|
function getEvents(date) {
|
|
return store.reverseLookup("tags", "@" + date.formatFr(), true, "modified");
|
|
}
|
|
|
|
setStylesheet("\
|
|
/** Le calendrier se divise en trois parties: nav (pour la navigation),\
|
|
hdr (pour les jours de la semaine), et cal (pour les jours du calendrier proprement dit)\
|
|
\
|
|
Chaque style est préfixé de nav, hdr ou cal.\
|
|
*/\
|
|
.calendar {\
|
|
margin: 0em;\
|
|
text-align: center;\
|
|
font-size: 9pt;\
|
|
}\
|
|
\
|
|
/** la barre de navigation */\
|
|
.navRow {\
|
|
}\
|
|
\
|
|
/** la ligne d'en-tête, qui contient les jours */\
|
|
.hdrRow {\
|
|
}\
|
|
\
|
|
/** une ligne du calendrier */\
|
|
.calRow {\
|
|
}\
|
|
\
|
|
.calToday { /* cellule de calendrier: date du jour */\
|
|
color: Blue;\
|
|
border: 1px solid black;\
|
|
}\
|
|
\
|
|
.calOther { /* cellule de calendrier: jour d'un autre mois */\
|
|
color: LightSteelBlue;\
|
|
font-size: 8pt;\
|
|
}\
|
|
\
|
|
.calEvent { /* cellule de calendrier: événement disponible */\
|
|
font-weight: bold;\
|
|
text-decoration: underline;\
|
|
}\
|
|
", "calendar");
|
|
|
|
//////////////////////////////////////////////////
|
|
// Gestion de l'autorefresh
|
|
function refreshAllTiddlersTaggedAutoRefresh(hint) {
|
|
// rafraichir tous les tiddlers ayant le tag "autoRefresh"
|
|
var tagged = store.getTaggedTiddlers("autoRefresh");
|
|
for (var i = 0; i < tagged.length; i++) {
|
|
refreshTiddler(tagged[i].title);
|
|
}
|
|
}
|
|
config.notifyTiddlers.push({name: null, notify: refreshAllTiddlersTaggedAutoRefresh});
|
|
|
|
//////////////////////////////////////////////////
|
|
// Le bouton keepThis
|
|
|
|
function keepTiddler(titleToKeep) {
|
|
var display = document.getElementById("tiddlerDisplay");
|
|
var tiddler = display.firstChild;
|
|
while(tiddler) {
|
|
var nextTiddler = tiddler.nextSibling;
|
|
if(tiddler.id) {
|
|
if(tiddler.id.substr(0,7) == "tiddler") {
|
|
var title = tiddler.id.substr(7);
|
|
if(titleToKeep != title && !document.getElementById("editorWrapper" + title))
|
|
display.removeChild(tiddler);
|
|
}
|
|
}
|
|
tiddler = nextTiddler;
|
|
}
|
|
}
|
|
|
|
var toolbarKeep = {text: "keep this", tooltip: "Close all other tiddlers"};
|
|
toolbarKeep.onClick = function(e) {
|
|
e = ClickHandler.getEvent(e);
|
|
|
|
if(this.parentNode.id) {
|
|
keepTiddler(this.parentNode.id.substr(7));
|
|
}
|
|
|
|
return ClickHandler.end(e);
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
// Les macros closeCurrent, editCurrent, saveCurrent
|
|
|
|
config.macros.closeCurrent = {label: "close", prompt: "Close current tiddler", accessKey: "W"};
|
|
config.macros.closeCurrent.handler = function(place, macroName, params) {
|
|
createTiddlyButton(place, this.label, this.prompt, this.onClick, null, null, this.accessKey);
|
|
}
|
|
config.macros.closeCurrent.onClick = function(e) {
|
|
e = ClickHandler.getEvent(e);
|
|
|
|
if (currentTiddler) {
|
|
// ne pas fermer un tiddler s'il est en cours d'édition
|
|
if(!document.getElementById("editorWrapper" + currentTiddler)) {
|
|
clearMessage();
|
|
closeTiddler(currentTiddler, e.shiftKey || e.altKey);
|
|
currentTiddler = null;
|
|
}
|
|
}
|
|
|
|
return ClickHandler.end(e);
|
|
}
|
|
|
|
config.macros.editCurrent = {label: "edit", prompt: "Edit current tiddler", accessKey: "E"};
|
|
config.macros.editCurrent.handler = function(place, macroName, params) {
|
|
if (!readOnly) {
|
|
createTiddlyButton(place, this.label, this.prompt, this.onClick, null, null, this.accessKey);
|
|
}
|
|
}
|
|
config.macros.editCurrent.onClick = function(e) {
|
|
e = ClickHandler.getEvent(e);
|
|
|
|
if (currentTiddler) {
|
|
clearMessage();
|
|
displayTiddler(null, currentTiddler, 2, null, null, false, false);
|
|
}
|
|
|
|
return ClickHandler.end(e);
|
|
}
|
|
|
|
config.macros.saveCurrent = {label: "save", prompt: "Save current tiddler", accessKey: "S"};
|
|
config.macros.saveCurrent.handler = function(place, macroName, params) {
|
|
if (!readOnly) {
|
|
createTiddlyButton(place, this.label, this.prompt, this.onClick, null, null, this.accessKey);
|
|
}
|
|
}
|
|
config.macros.saveCurrent.onClick = function(e) {
|
|
e = ClickHandler.getEvent(e);
|
|
|
|
if (currentTiddler) {
|
|
clearMessage();
|
|
saveTiddler(currentTiddler, e.shiftKey);
|
|
}
|
|
|
|
return ClickHandler.end(e);
|
|
}
|
|
|
|
// patcher les méthodes existantes pour supporter la notion de "current tiddler"
|
|
var currentTiddler = null;
|
|
|
|
var selectTiddler_patchedByBase = window.selectTiddler;
|
|
window.selectTiddler = function(title) {
|
|
// un tiddler sélectionné avec la souris devient le tiddler courant
|
|
selectTiddler_patchedByBase(title);
|
|
currentTiddler = title;
|
|
}
|
|
|
|
var displayTiddler_patchedByBase = window.displayTiddler;
|
|
window.displayTiddler = function(src, title, state, highlightText, highlightCaseSensitive, animate, slowly) {
|
|
displayTiddler_patchedByBase(src, title, state, highlightText, highlightCaseSensitive, animate, slowly);
|
|
// un tiddler que l'on affiche devient le tiddler courant
|
|
currentTiddler = title;
|
|
}
|
|
|
|
var deleteTiddler_patchedByBase = window.deleteTiddler;
|
|
window.deleteTiddler = function(title) {
|
|
deleteTiddler_patchedByBase(title);
|
|
if (title == currentTiddler) {
|
|
// si on supprimer le tiddler courant, il n'y a plus de tiddler courant
|
|
currentTiddler = null;
|
|
}
|
|
}
|