+ .tid application/x-tiddler TiddlyWeb-style tiddler text file
+ .txt text/plain plain text file interpreted as the tiddler text
+ .html text/html plain HTML file interpreted as the tiddler text
+ .js application/javascript JavaScript file interpreted as the tiddler text
+ .json application/json JSON object containing an array of tiddler field hashmaps
+ .tiddlywiki application/x-tiddlywiki TiddlyWiki HTML document containing one or more tiddler
s
+
+#### TiddlerOutput.register(tiddlerConverters)
+
+Registers serializers for these output types:
+
+ Extension MIME types Description
+ --------- --------- -----------
+ .tiddler application/x-tiddler-html-div TiddlyWiki storeArea-style
+ .tid application/x-tiddler TiddlyWeb-style tiddler text file
+
+### TextProcessors.js
+
+Text processors are components that know how to parse and render tiddlers of particular types. The core of TiddlyWiki is the WikiText processor, which can parse TiddlyWiki wikitext into a JavaScript object tree representation, and then render the tree into HTML or plain text. Other text processors planned include:
+
+* `JSONText` to allow JSON objects to display nicely, and make their content available with TiddlyWiki section/slice notation
+* `CSSText` to parse CSS, and process extensions such as transclusion, theming and variables
+* `JavaScriptText` to parse JavaScript tiddlers for clearer display, and allow sandboxed execution through compilation
+
+Note that text processors encapsulate two operations: parsing into a tree, and rendering that tree into text representations. Parsing doesn't need a context, but rendering needs to have access to a context consisting of a WikiStore to use to retrieve any referenced tiddlers, and the title of the tiddler that is being rendered.
+
+#### textProcessors = new TextProcessors()
+
+Applications should create a TextProcessors object to keep track of the available text processors.
+
+#### textProcessors.registerTextProcessor(mimeType,textProcessor)
+
+Registers an instance of a text processor class to handle text with a particular MIME type. For example:
+
+ var options = {
+ ...
+ };
+ textProcessors.registerTextProcessor("text/x-tiddlywiki",new WikiTextProcessor(options));
+
+The text processor object must support the following methods:
+
+ // Parses some text and returns a parse tree object
+ var parseTree = textProcessor.parse(text)
+
+Parser objects support the following methods:
+
+ // Renders a subnode of the parse tree to a representation identified by MIME type,
+ // as if rendered within the context of the specified WikiStore and tiddler title
+ var renderedText = parseTree.render(type,treenode,store,title)
+
+#### textProcessors.parse(type,text)
+
+Chooses a text processor based on the MIME type of the content and calls the `parse` method to parse the text into a parse tree. Returns null if the type was not recognised by a registered parser.
+
+If the MIME type is unrecognised or unknown, it defaults to "text/x-tiddlywiki".
+
+### WikiTextProcessor.js
+
+A text processor that parses and renders TiddlyWiki style wiki text.
+
+This module privately includes the following modules:
+
+* WikiTextParser.js containing the wiki text parsing engine
+* WikiTextRules.js containing the rules driving the wiki text parsing engine
+* WikiTextRenderer.js containing the wiki text rendering engine
+* WikiTextMacros.js containing the predefined macros used by the renderer
+
+#### var wikiTextProcessor = new WikiTextProcessor(options)
+
+Creates a new instance of the wiki text processor with the specified options. The options are a hashmap of optional members as follows:
+
+* **enableRules:** An array of names of wiki text rules to enable. If not specified, all rules are available
+* **extraRules:** An array of additional rule handlers to add
+* **enableMacros:** An array of names of macros to enable. If not specified, all macros are available
+* **extraMacros:** An array of additional macro handlers to add
+
+### WikiStore.js
+
+A collection of uniquely titled tiddlers. Although the tiddlers themselves are immutable, new tiddlers can be stored under an existing title, replacing the previous tiddler.
+
+Each wiki store is connected to a shadow store that is also a WikiStore() object. Under certain circumstances, when an attempt is made to retrieve a tiddler that doesn't exist in the store, the search continues into its shadow store (and so on, if the shadow store itself has a shadow store).
+
+#### var store = new WikiStore(options)
+
+Creates a new wiki store. The options are a hashmap of optional members as follows:
+
+* **textProcessors:** A reference to the TextProcessors() instance to be used to resolve parsing and rendering requests
+* **shadowStore:** An optional reference to an existing WikiStore to use as the source of shadow tiddlers. Pass null to disable shadow tiddlers for the new store
+
+#### store.shadows
+
+Exposes a reference to the shadow store for this store.
+
+#### store.clear()
+
+Clears the store of all tiddlers.
+
+#### store.getTiddler(title)
+
+Attempts to retrieve the tiddler with a given title. Returns `null` if the tiddler doesn't exist.
+
+#### store.getTiddlerText(title,defaultText)
+
+Retrieves the text of a particular tiddler. If the tiddler doesn't exist, then the defaultText is returned, or `null` if not specified.
+
+#### store.deleteTiddler(title)
+
+Deletes the specified tiddler from the store.
+
+#### store.tiddlerExists(title)
+
+Returns a boolean indicating whether a particular tiddler exists.
+
+#### store.addTiddler(tiddler)
+
+Adds the specified tiddler object to the store. The tiddler can be specified as a Tiddler() object or a hashmap of tiddler fields.
+
+#### store.forEachTiddler([sortField,]callback)
+
+Invokes a callback for each tiddler in the store, optionally sorted by a particular field. The callback is called with the title of the tiddler and a reference to the tiddler itself. For example:
+
+ store.forEachTiddler(function(title,tiddler) {
+ console.log(title);
+ });
+
+#### store.parseTiddler(title)
+
+Returns the parse tree object for a tiddler, which may be cached within the tiddler.
+
+#### store.renderTiddler(type,title)
+
+Returns a dynamically generated rendering of the tiddler in a representation identified by a MIME type.
+
+### Recipe.js
+
+The Recipe() class loads a TiddlyWiki recipe file, resolving references to subrecipe files. Tiddlers referenced by the recipe are loaded into a WikiStore. A fully loaded recipe can then be cooked to produce an HTML or RSS TiddlyWiki representation of the recipe.
+
+#### var recipe = new Recipe(options,callback)
+
+Creates a new Recipe object by loading the specified recipe file. On completion the callback is invoked with a single parameter `err` that is null if the recipe loading was successful, or an Error() object otherwise.
+
+ var recipe = new Recipe({
+ filepath: "recent.recipe",
+ tiddlerConverters: tiddlerConverters,
+ store: store
+ },function callback(err) {
+ if(err) {
+ throw err;
+ } else {
+ console.log(recipe.cook())
+ }
+ }
+
+Options is a hashmap with the following mandatory fields:
+
+* **filepath:** The filepath to the recipe file to load
+* **tiddlerConverters:** The TiddlerConverters() object to use to serialize and deserialize tiddlers
+* **textProcessors:** The TextProcessors() object to use to parse and render tiddler text
+* **store:** The WikiStore object to use to store the tiddlers in the recipe
+
+The options can also contain these optional fields:
+
+* (none at present)
+
+#### recipe.cook()
+
+Cooks a TiddlyWiki HTML file from the recipe and returns it as a string.
+
+#### recipe.cookRss()
+
+Cooks a TiddlyWiki RSS file from the recipe and returns it as a string.
diff --git a/tiddlywiki.js b/tiddlywiki.js
index b978121d9..4da1658f7 100644
--- a/tiddlywiki.js
+++ b/tiddlywiki.js
@@ -8,9 +8,10 @@ TiddlyWiki command line interface
var WikiStore = require("./js/WikiStore.js").WikiStore,
Tiddler = require("./js/Tiddler.js").Tiddler,
Recipe = require("./js/Recipe.js").Recipe,
- Tiddler = require("./js/Tiddler.js").Tiddler,
tiddlerInput = require("./js/TiddlerInput.js"),
tiddlerOutput = require("./js/TiddlerOutput.js"),
+ TextProcessors = require("./js/TextProcessors.js").TextProcessors,
+ WikiTextProcessor = require("./js/WikiTextProcessor.js").WikiTextProcessor,
TiddlerConverters = require("./js/TiddlerConverters.js").TiddlerConverters,
util = require("util"),
fs = require("fs"),
@@ -42,19 +43,27 @@ var parseOptions = function(args,defaultSwitch) {
return result;
};
-var tiddlerConverters = new TiddlerConverters(),
+var textProcessors = new TextProcessors(),
+ tiddlerConverters = new TiddlerConverters(),
switches = parseOptions(Array.prototype.slice.call(process.argv,2),"dummy"),
- store = new WikiStore(),
+ store = new WikiStore({
+ textProcessors: textProcessors
+ }),
recipe = null,
lastRecipeFilepath = null,
currSwitch = 0;
+
+textProcessors.registerTextProcessor("text/x-tiddlywiki",new WikiTextProcessor({}));
// Register the standard tiddler serializers and deserializers
tiddlerInput.register(tiddlerConverters);
tiddlerOutput.register(tiddlerConverters);
// Add the shadow tiddlers that are built into TiddlyWiki
-var shadowShadowStore = new WikiStore(null),
+var shadowShadowStore = new WikiStore({
+ textProcessors: textProcessors,
+ shadowStore: null
+ }),
shadowShadows = [
{title: "StyleSheet", text: ""},
{title: "MarkupPreHead", text: ""},
@@ -123,7 +132,8 @@ var commandLineSwitches = {
recipe = new Recipe({
filepath: args[0],
store: store,
- tiddlerConverters: tiddlerConverters
+ tiddlerConverters: tiddlerConverters,
+ textProcessors: textProcessors
},function() {
callback(null);
});
@@ -203,7 +213,9 @@ var commandLineSwitches = {
// Dumbly, this implementation wastes the recipe processing that happened on the --recipe switch
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/html"});
- store = new WikiStore();
+ store = new WikiStore({
+ textProcessors: textProcessors
+ });
recipe = new Recipe(store,lastRecipeFilepath,function() {
response.end(recipe.cook(), "utf8");
});
@@ -219,7 +231,7 @@ var commandLineSwitches = {
tiddler = store.getTiddler(title);
if(tiddler) {
response.writeHead(200, {"Content-Type": "text/html"});
- response.end(tiddler.getParseTree().render("text/html"),"utf8");
+ response.end(store.renderTiddler("text/html",title),"utf8");
} else {
response.writeHead(404);
response.end();
diff --git a/wikitest.js b/wikitest.js
index 4d64a0cba..3c405b274 100644
--- a/wikitest.js
+++ b/wikitest.js
@@ -14,7 +14,8 @@ verifying that the output matches `.html` and `.txt`.
var Tiddler = require("./js/Tiddler.js").Tiddler,
WikiStore = require("./js/WikiStore.js").WikiStore,
- WikiTextRenderer = require("./js/WikiTextRenderer.js").WikiTextRenderer,
+ TextProcessors = require("./js/TextProcessors.js").TextProcessors,
+ WikiTextProcessor = require("./js/WikiTextProcessor.js").WikiTextProcessor,
TiddlerConverters = require("./js/TiddlerConverters.js").TiddlerConverters,
tiddlerInput = require("./js/TiddlerInput.js"),
utils = require("./js/Utils.js"),
@@ -23,12 +24,16 @@ var Tiddler = require("./js/Tiddler.js").Tiddler,
path = require("path");
var testdirectory = process.argv[2],
+ textProcessors = new TextProcessors(),
tiddlerConverters = new TiddlerConverters(),
- store = new WikiStore(),
+ store = new WikiStore({
+ textProcessors: textProcessors
+ }),
files = fs.readdirSync(testdirectory),
titles = [],
f,t,extname,basename;
+textProcessors.registerTextProcessor("text/x-tiddlywiki",new WikiTextProcessor({}));
tiddlerInput.register(tiddlerConverters);
for(f=0; f