mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-23 10:07:19 +00:00
Rejigged macro implementation
Now each macro is in a separate file, and is implemented as a function, rather than being inlined into the compiled tiddler rendering function
This commit is contained in:
parent
3412580af3
commit
9a73b0a6aa
@ -79,8 +79,13 @@ var App = function() {
|
||||
} else {
|
||||
this.store.jsParser = new JavaScriptParser(require("fs").readFileSync("parsers/javascript.pegjs","utf8"));
|
||||
}
|
||||
// Hack to install standard macros
|
||||
this.store.installMacros();
|
||||
// Bit of a hack to set up the macros
|
||||
this.store.installMacro(require("./macros/echo.js").macro);
|
||||
this.store.installMacro(require("./macros/info.js").macro);
|
||||
this.store.installMacro(require("./macros/list.js").macro);
|
||||
this.store.installMacro(require("./macros/tiddler.js").macro);
|
||||
this.store.installMacro(require("./macros/version.js").macro);
|
||||
this.store.installMacro(require("./macros/view.js").macro);
|
||||
// Set up navigation if we're in the browser
|
||||
if(this.isBrowser) {
|
||||
// Install the standard navigators
|
||||
|
193
js/WikiStore.js
193
js/WikiStore.js
@ -19,6 +19,7 @@ var WikiStore = function WikiStore(options) {
|
||||
options = options || {};
|
||||
this.tiddlers = {};
|
||||
this.parsers = {};
|
||||
this.macros = {};
|
||||
this.tiddlerSerializers = {};
|
||||
this.tiddlerDeserializers = {};
|
||||
this.sandbox = options.sandbox;
|
||||
@ -162,26 +163,6 @@ WikiStore.prototype.deserializeTiddlers = function(type,text,srcFields) {
|
||||
}
|
||||
};
|
||||
|
||||
WikiStore.prototype.getFormattedTiddlerField = function(title,field,format,template) {
|
||||
format = format || "text";
|
||||
var tiddler = this.getTiddler(title);
|
||||
if(tiddler && tiddler.fields[field]) {
|
||||
switch(format) {
|
||||
case "text":
|
||||
return utils.htmlEncode(tiddler.fields[field]);
|
||||
case "link":
|
||||
// xxx: Attribute encoding is wrong
|
||||
return "<a href='" + utils.htmlEncode(tiddler.fields[field]) + "'" + this.classesForLink(tiddler.fields[field]) + ">" + utils.htmlEncode(tiddler.fields[field]) + "</a>";
|
||||
case "wikified":
|
||||
return this.renderTiddler("text/html",tiddler.fields.title);
|
||||
case "date":
|
||||
template = template || "DD MMM YYYY";
|
||||
return utils.htmlEncode(utils.formatDateString(tiddler.fields[field],template));
|
||||
}
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
WikiStore.prototype.classesForLink = function(target) {
|
||||
var className = "",
|
||||
externalRegExp = /(?:file|http|https|mailto|ftp|irc|news|data):[^\s'"]+(?:\/|\b)/i;
|
||||
@ -195,90 +176,6 @@ WikiStore.prototype.classesForLink = function(target) {
|
||||
return className !== "" ? " class=\"" + className + "\"" : "";
|
||||
};
|
||||
|
||||
WikiStore.prototype.listTiddlers = function(type,template,emptyMessage) {
|
||||
return "<span>Listing!</span>";
|
||||
};
|
||||
|
||||
WikiStore.prototype.tiddlerInfo = function(title) {
|
||||
var tiddler = this.getTiddler(title),
|
||||
parseTree = this.parseTiddler(title);
|
||||
if(tiddler && parseTree) {
|
||||
var d = parseTree.dependencies;
|
||||
if(d === null) {
|
||||
return "Dependencies: *";
|
||||
} else {
|
||||
return "Dependencies: " + d.join(", ");
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
argOptions: {defaultName:"type"},
|
||||
handler: function(macroNode,args,title) {
|
||||
var type = args.getValueByName("type","all"),
|
||||
template = args.getValueByName("template",null),
|
||||
templateType = "text/x-tiddlywiki", templateText = "<<view title link>>",
|
||||
emptyMessage = args.getValueByName("emptyMessage",null);
|
||||
// Get the template to use
|
||||
template = template ? this.store.getTiddler(template) : null;
|
||||
if(template) {
|
||||
templateType = template.fields.type;
|
||||
templateText = template.fields.text;
|
||||
}
|
||||
// Get the handler and the tiddlers
|
||||
var handler = WikiTextRenderer.macros.list.types[type];
|
||||
handler = handler || WikiTextRenderer.macros.list.types.all;
|
||||
var tiddlers = handler.call(this);
|
||||
// Render them as a list
|
||||
var ul = {type: "ul", children: []};
|
||||
for(var t=0; t<tiddlers.length; t++) {
|
||||
var li = {
|
||||
type: "li",
|
||||
children: [ {
|
||||
type: "context",
|
||||
tiddler: tiddlers[t],
|
||||
children: []
|
||||
} ]
|
||||
};
|
||||
li.children[0].children = this.store.parseText(templateType,templateText).children;
|
||||
ul.children.push(li);
|
||||
}
|
||||
if(ul.children.length > 0) {
|
||||
macroNode.output.push(ul);
|
||||
this.executeMacros(macroNode.output,title);
|
||||
} else if (emptyMessage) {
|
||||
macroNode.output.push({type: "text", value: emptyMessage});
|
||||
}
|
||||
},
|
||||
types: {
|
||||
all: function() {
|
||||
return this.store.getTitles("title","excludeLists");
|
||||
},
|
||||
missing: function() {
|
||||
return this.store.getMissingTitles();
|
||||
},
|
||||
orphans: function() {
|
||||
return this.store.getOrphanTitles();
|
||||
},
|
||||
shadowed: function() {
|
||||
return this.store.getShadowTitles();
|
||||
},
|
||||
touched: function() {
|
||||
// Server syncing isn't implemented yet
|
||||
return [];
|
||||
},
|
||||
filter: function() {
|
||||
// Filters aren't implemented yet
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
*/
|
||||
|
||||
WikiStore.prototype.parseText = function(type,text) {
|
||||
var parser = this.parsers[type];
|
||||
if(!parser) {
|
||||
@ -343,94 +240,10 @@ WikiStore.prototype.renderTiddler = function(type,title,asTitle) {
|
||||
return null;
|
||||
};
|
||||
|
||||
WikiStore.prototype.installMacros = function() {
|
||||
this.macros = {
|
||||
echo: {
|
||||
params: {
|
||||
text: {byPos: 0, type: "text", optional: false}
|
||||
},
|
||||
code: {
|
||||
"text/html": this.jsParser.parse("return utils.htmlEncode(params.text);"),
|
||||
"text/plain": this.jsParser.parse("return params.text;")
|
||||
}
|
||||
},
|
||||
view: {
|
||||
params: {
|
||||
field: {byPos: 0, type: "text", optional: false},
|
||||
format: {byPos: 1, type: "text", optional: true},
|
||||
template: {byPos: 2, type: "text", optional: true}
|
||||
},
|
||||
code: {
|
||||
"text/html": this.jsParser.parse("return store.getFormattedTiddlerField(tiddler.fields.title,params.field,params.format,params.template);"),
|
||||
"text/plain": this.jsParser.parse("return store.getFormattedTiddlerField(tiddler.fields.title,params.field,params.format,params.template);")
|
||||
}
|
||||
},
|
||||
list: {
|
||||
dependantAll: true, // Tiddlers containing <<list>> macro are dependent on every tiddler
|
||||
params: {
|
||||
type: {byName: "default", type: "text", optional: false},
|
||||
template: {byName: true, type: "tiddler", optional: true},
|
||||
emptyMessage: {byName: true, type: "text", optional: true}
|
||||
},
|
||||
code: {
|
||||
"text/html": this.jsParser.parse("return store.listTiddlers(params.type,params.template,params.emptyMessage);"),
|
||||
"text/plain": this.jsParser.parse("return store.listTiddlers(params.type,params.template,params.emptyMessage);")
|
||||
}
|
||||
},
|
||||
version: {
|
||||
params: {
|
||||
},
|
||||
code: {
|
||||
"text/html": this.jsParser.parse("return utils.htmlEncode('5.0.0');"),
|
||||
"text/plain": this.jsParser.parse("return '5.0.0';")
|
||||
}
|
||||
},
|
||||
tiddler: {
|
||||
cascadeParams: true, // Cascade names of named parameters to following anonymous parameters
|
||||
params: {
|
||||
target: {byName: "default", type: "tiddler", optional: false},
|
||||
"with": {byName: true, type: "text", optional: true}
|
||||
},
|
||||
code: {
|
||||
"text/html": this.jsParser.parse("return store.renderTiddler('text/html',params.target);"),
|
||||
"text/plain": this.jsParser.parse("return store.renderTiddler('text/plain',params.target);")
|
||||
}
|
||||
},
|
||||
info: {
|
||||
params: {
|
||||
},
|
||||
code: {
|
||||
"text/html": this.jsParser.parse("return utils.htmlEncode(store.tiddlerInfo(tiddler.fields.title));"),
|
||||
"text/plain": this.jsParser.parse("return store.tiddlerInfo(tiddler.fields.title);")
|
||||
}
|
||||
}
|
||||
};
|
||||
WikiStore.prototype.installMacro = function(macro) {
|
||||
this.macros[macro.name] = macro;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
tiddler: {
|
||||
argOptions: {defaultName:"name",cascadeDefaults:true},
|
||||
handler: function(macroNode,args,title) {
|
||||
var targetTitle = args.getValueByName("name",null),
|
||||
withTokens = args.getValuesByName("with",[]),
|
||||
tiddler = this.store.getTiddler(targetTitle),
|
||||
text = this.store.getTiddlerText(targetTitle,""),
|
||||
t;
|
||||
for(t=0; t<withTokens.length; t++) {
|
||||
var placeholderRegExp = new RegExp("\\$"+(t+1),"mg");
|
||||
text = text.replace(placeholderRegExp,withTokens[t]);
|
||||
}
|
||||
macroNode.output = this.store.parseText(tiddler.fields.type,text).children;
|
||||
// Execute any macros in the copy
|
||||
this.executeMacros(macroNode.output,title);
|
||||
}
|
||||
},
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
exports.WikiStore = WikiStore;
|
||||
|
||||
})();
|
||||
|
@ -84,23 +84,48 @@ WikiTextParseTree.prototype.compileMacroCall = function(type,name,params) {
|
||||
var macroCall = {
|
||||
type: "FunctionCall",
|
||||
name: {
|
||||
type: "Function",
|
||||
name: null,
|
||||
params: ["params"],
|
||||
elements: []},
|
||||
"base": {
|
||||
"base": {
|
||||
"base": {
|
||||
"name": "store",
|
||||
"type": "Variable"
|
||||
},
|
||||
"name": "macros",
|
||||
"type": "PropertyAccess"
|
||||
},
|
||||
"name": {
|
||||
"type": "StringLiteral",
|
||||
"value": name
|
||||
},
|
||||
"type": "PropertyAccess"
|
||||
},
|
||||
"name": "code",
|
||||
"type": "PropertyAccess"
|
||||
},
|
||||
"arguments": [ {
|
||||
"type": "StringLiteral",
|
||||
"value": type
|
||||
},
|
||||
{
|
||||
"type": "Variable",
|
||||
"name": "tiddler"
|
||||
},
|
||||
{
|
||||
"type": "Variable",
|
||||
"name": "store"
|
||||
},
|
||||
{
|
||||
type: "ObjectLiteral",
|
||||
properties: []
|
||||
}]
|
||||
};
|
||||
macroCall.name.elements = macro.code[type].tree.elements;
|
||||
for(p in params) {
|
||||
if(params[p].type === "string") {
|
||||
n = {type: "StringLiteral", value: params[p].value};
|
||||
} else {
|
||||
n = this.store.jsParser.parse(params[p].value).tree.elements[0];
|
||||
}
|
||||
macroCall["arguments"][0].properties.push({
|
||||
macroCall["arguments"][3].properties.push({
|
||||
type: "PropertyAssignment",
|
||||
name: p,
|
||||
value: n
|
||||
@ -108,7 +133,7 @@ WikiTextParseTree.prototype.compileMacroCall = function(type,name,params) {
|
||||
}
|
||||
this.output.push(macroCall);
|
||||
} else {
|
||||
this.pushString("<span class='error errorUnknownMacro'>Unknown macro '" + name + "'</span>");
|
||||
this.pushString("{{** Unknown macro '" + name + "' **}}");
|
||||
}
|
||||
};
|
||||
|
||||
|
27
js/macros/echo.js
Normal file
27
js/macros/echo.js
Normal file
@ -0,0 +1,27 @@
|
||||
/*\
|
||||
title: js/macros/echo.js
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true */
|
||||
"use strict";
|
||||
|
||||
var utils = require("../Utils.js");
|
||||
|
||||
exports.macro = {
|
||||
name: "echo",
|
||||
types: ["text/html","text/plain"],
|
||||
params: {
|
||||
text: {byPos: 0, type: "text", optional: false}
|
||||
},
|
||||
code: function(type,tiddler,store,params) {
|
||||
if(type === "text/html") {
|
||||
return utils.htmlEncode(params.text);
|
||||
} else {
|
||||
return params.text;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
33
js/macros/info.js
Normal file
33
js/macros/info.js
Normal file
@ -0,0 +1,33 @@
|
||||
/*\
|
||||
title: js/macros/info.js
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true */
|
||||
"use strict";
|
||||
|
||||
var utils = require("../Utils.js");
|
||||
|
||||
exports.macro = {
|
||||
name: "info",
|
||||
types: ["text/html","text/plain"],
|
||||
params: {
|
||||
},
|
||||
code: function(type,tiddler,store,params) {
|
||||
var encoder = type === "text/html" ? utils.htmlEncode : function(x) {return x;},
|
||||
parseTree = store.parseTiddler(tiddler.fields.title);
|
||||
if(parseTree) {
|
||||
var d = parseTree.dependencies;
|
||||
if(d === null) {
|
||||
return encoder("Dependencies: *");
|
||||
} else {
|
||||
return encoder("Dependencies: " + d.join(", "));
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
26
js/macros/list.js
Normal file
26
js/macros/list.js
Normal file
@ -0,0 +1,26 @@
|
||||
/*\
|
||||
title: js/macros/list.js
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true */
|
||||
"use strict";
|
||||
|
||||
var utils = require("../Utils.js");
|
||||
|
||||
exports.macro = {
|
||||
name: "list",
|
||||
types: ["text/html","text/plain"],
|
||||
dependantAll: true, // Tiddlers containing <<list>> macro are dependent on every tiddler
|
||||
params: {
|
||||
type: {byName: "default", type: "text", optional: false},
|
||||
template: {byName: true, type: "tiddler", optional: true},
|
||||
emptyMessage: {byName: true, type: "text", optional: true}
|
||||
},
|
||||
code: function(type,tiddler,store,params) {
|
||||
return "Listing!";
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
25
js/macros/tiddler.js
Normal file
25
js/macros/tiddler.js
Normal file
@ -0,0 +1,25 @@
|
||||
/*\
|
||||
title: js/macros/tiddler.js
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true */
|
||||
"use strict";
|
||||
|
||||
var utils = require("../Utils.js");
|
||||
|
||||
exports.macro = {
|
||||
name: "tiddler",
|
||||
types: ["text/html","text/plain"],
|
||||
cascadeParams: true, // Cascade names of named parameters to following anonymous parameters
|
||||
params: {
|
||||
target: {byName: "default", type: "tiddler", optional: false},
|
||||
"with": {byName: true, type: "text", optional: true}
|
||||
},
|
||||
code: function(type,tiddler,store,params) {
|
||||
return store.renderTiddler(type,params.target);
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
22
js/macros/version.js
Normal file
22
js/macros/version.js
Normal file
@ -0,0 +1,22 @@
|
||||
/*\
|
||||
title: js/macros/version.js
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true */
|
||||
"use strict";
|
||||
|
||||
var utils = require("../Utils.js");
|
||||
|
||||
exports.macro = {
|
||||
name: "version",
|
||||
types: ["text/html","text/plain"],
|
||||
params: {
|
||||
},
|
||||
code: function(type,tiddler,store,params) {
|
||||
return "5.0.0";
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
45
js/macros/view.js
Normal file
45
js/macros/view.js
Normal file
@ -0,0 +1,45 @@
|
||||
/*\
|
||||
title: js/macros/view.js
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true */
|
||||
"use strict";
|
||||
|
||||
var utils = require("../Utils.js");
|
||||
|
||||
exports.macro = {
|
||||
name: "view",
|
||||
types: ["text/html","text/plain"],
|
||||
params: {
|
||||
field: {byPos: 0, type: "text", optional: false},
|
||||
format: {byPos: 1, type: "text", optional: true},
|
||||
template: {byPos: 2, type: "text", optional: true}
|
||||
},
|
||||
code: function(type,tiddler,store,params) {
|
||||
var v = tiddler.fields[params.field],
|
||||
encoder = type === "text/html" ? utils.htmlEncode : function(x) {return x;};
|
||||
if(v) {
|
||||
switch(params.format) {
|
||||
case "link":
|
||||
if(type === "text/html") {
|
||||
return "<a href='" + encoder(v) + "'" + store.classesForLink(v) + ">" + encoder(v) + "</a>";
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
case "wikified":
|
||||
return store.renderTiddler(type,tiddler.fields.title);
|
||||
case "date":
|
||||
var template = params.template || "DD MMM YYYY";
|
||||
return encoder(utils.formatDateString(v,template));
|
||||
default: // "text"
|
||||
return encoder(v);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
|
@ -23,6 +23,13 @@ jsmodule: ../js/Navigators.js
|
||||
jsmodule: ../js/StoryNavigator.js
|
||||
jsmodule: ../js/App.js
|
||||
|
||||
jsmodule: ../js/macros/echo.js
|
||||
jsmodule: ../js/macros/info.js
|
||||
jsmodule: ../js/macros/list.js
|
||||
jsmodule: ../js/macros/tiddler.js
|
||||
jsmodule: ../js/macros/version.js
|
||||
jsmodule: ../js/macros/view.js
|
||||
|
||||
jsmodule: ../node_modules/pegjs/lib/peg.js
|
||||
title: pegjs
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user