mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-23 10:07:19 +00:00
Browser now syncs changes with server which syncs with the file system
A bit rough and ready, but this gives us basic support for editting tiddlers in the browser and updating the original file on the server
This commit is contained in:
parent
495ef1ada5
commit
0ac55688c4
24
js/App.js
24
js/App.js
@ -10,6 +10,7 @@ This is the main() function in the browser
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var WikiStore = require("./WikiStore.js").WikiStore,
|
var WikiStore = require("./WikiStore.js").WikiStore,
|
||||||
|
HttpSync = require("./HttpSync.js").HttpSync,
|
||||||
Tiddler = require("./Tiddler.js").Tiddler,
|
Tiddler = require("./Tiddler.js").Tiddler,
|
||||||
tiddlerInput = require("./TiddlerInput.js"),
|
tiddlerInput = require("./TiddlerInput.js"),
|
||||||
tiddlerOutput = require("./TiddlerOutput.js"),
|
tiddlerOutput = require("./TiddlerOutput.js"),
|
||||||
@ -81,6 +82,8 @@ var App = function() {
|
|||||||
var shadowArea = document.getElementById("shadowArea");
|
var shadowArea = document.getElementById("shadowArea");
|
||||||
this.store.shadows.addTiddlers(this.store.deserializeTiddlers("(DOM)",shadowArea));
|
this.store.shadows.addTiddlers(this.store.deserializeTiddlers("(DOM)",shadowArea));
|
||||||
}
|
}
|
||||||
|
// Reset pending events on the store so that we don't get events for the initial load
|
||||||
|
this.store.clearEvents();
|
||||||
// Bit of a hack to set up the macros
|
// Bit of a hack to set up the macros
|
||||||
this.store.installMacro(require("./macros/chooser.js").macro);
|
this.store.installMacro(require("./macros/chooser.js").macro);
|
||||||
this.store.installMacro(require("./macros/command.js").macro);
|
this.store.installMacro(require("./macros/command.js").macro);
|
||||||
@ -102,8 +105,10 @@ var App = function() {
|
|||||||
linkInfo.target = encodeURIComponent(linkInfo.target);
|
linkInfo.target = encodeURIComponent(linkInfo.target);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Set up navigation if we're in the browser
|
// Set up for the browser
|
||||||
if(this.isBrowser) {
|
if(this.isBrowser) {
|
||||||
|
// Set up HttpSync
|
||||||
|
this.httpSync = new HttpSync(this.store);
|
||||||
// Open the PageTemplate
|
// Open the PageTemplate
|
||||||
var renderer = this.store.renderMacro("tiddler",{target: "PageTemplate"});
|
var renderer = this.store.renderMacro("tiddler",{target: "PageTemplate"});
|
||||||
renderer.renderInDom(document.body);
|
renderer.renderInDom(document.body);
|
||||||
@ -118,18 +123,19 @@ var App = function() {
|
|||||||
titleRenderer.refresh(changes);
|
titleRenderer.refresh(changes);
|
||||||
document.title = titleRenderer.render("text/plain");
|
document.title = titleRenderer.render("text/plain");
|
||||||
});
|
});
|
||||||
// Set up a timer to change the value of a tiddler
|
|
||||||
var me = this;
|
|
||||||
window.setInterval(function() {
|
|
||||||
me.store.addTiddler(new Tiddler({
|
|
||||||
title: "ClockTiddler",
|
|
||||||
text: "The time was recently " + (new Date()).toString()
|
|
||||||
}));
|
|
||||||
},3000);
|
|
||||||
// Listen for navigate events that weren't caught
|
// Listen for navigate events that weren't caught
|
||||||
document.addEventListener("tw-navigate",function (event) {
|
document.addEventListener("tw-navigate",function (event) {
|
||||||
renderer.broadcastEvent(event);
|
renderer.broadcastEvent(event);
|
||||||
},false);
|
},false);
|
||||||
|
// Set up a timer to change the value of a tiddler
|
||||||
|
var me = this,
|
||||||
|
s = setInterval || window.setInterval;
|
||||||
|
s(function() {
|
||||||
|
me.store.addTiddler(new Tiddler({
|
||||||
|
title: "ClockTiddler",
|
||||||
|
text: "The time was recently " + (new Date()).toString()
|
||||||
|
}));
|
||||||
|
},3000);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
35
js/HttpSync.js
Normal file
35
js/HttpSync.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*\
|
||||||
|
title: js/HttpSync.js
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function HttpSync(store) {
|
||||||
|
this.store = store;
|
||||||
|
this.changeCounts = {};
|
||||||
|
store.addEventListener("",function(changes) {
|
||||||
|
for(var title in changes) {
|
||||||
|
var tiddler = store.getTiddler(title);
|
||||||
|
if(tiddler) {
|
||||||
|
var fieldStrings = tiddler.getFieldStrings(),
|
||||||
|
fields = {},
|
||||||
|
t;
|
||||||
|
for(t=0; t<fieldStrings.length; t++) {
|
||||||
|
fields[fieldStrings[t].name] = fieldStrings[t].value;
|
||||||
|
}
|
||||||
|
fields.text = tiddler.text;
|
||||||
|
var x = new XMLHttpRequest();
|
||||||
|
x.open("PUT",window.location.toString() + encodeURIComponent(title),true);
|
||||||
|
x.setRequestHeader("Content-type", "application/json");
|
||||||
|
x.send(JSON.stringify(fields));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.HttpSync = HttpSync;
|
||||||
|
|
||||||
|
})();
|
@ -1,5 +1,5 @@
|
|||||||
/*\
|
/*\
|
||||||
title: js/FileStore.js
|
title: js/LocalFileSync.js
|
||||||
|
|
||||||
\*/
|
\*/
|
||||||
(function(){
|
(function(){
|
||||||
@ -8,17 +8,18 @@ title: js/FileStore.js
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var retrieveFile = require("./FileRetriever.js").retrieveFile,
|
var retrieveFile = require("./FileRetriever.js").retrieveFile,
|
||||||
|
utils = require("./Utils.js"),
|
||||||
fs = require("fs"),
|
fs = require("fs"),
|
||||||
path = require("path"),
|
path = require("path"),
|
||||||
url = require("url"),
|
url = require("url"),
|
||||||
util = require("util"),
|
util = require("util"),
|
||||||
async = require("async");
|
async = require("async");
|
||||||
|
|
||||||
function FileStore(dirpath,store,callback) {
|
function LocalFileSync(dirpath,store,callback) {
|
||||||
this.dirpath = dirpath;
|
this.dirpath = dirpath;
|
||||||
this.store = store;
|
this.store = store;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.sources = {}; // A hashmap of <tiddlername>: <srcpath>
|
this.changeCounts = {}; // A hashmap of <tiddlername>: <changeCount>
|
||||||
var self = this;
|
var self = this;
|
||||||
// Set up a queue for loading tiddler files
|
// Set up a queue for loading tiddler files
|
||||||
this.loadQueue = async.queue(function(task,callback) {
|
this.loadQueue = async.queue(function(task,callback) {
|
||||||
@ -68,8 +69,8 @@ function FileStore(dirpath,store,callback) {
|
|||||||
var loadCallback = function(task,tiddlers) {
|
var loadCallback = function(task,tiddlers) {
|
||||||
for(var t=0; t<tiddlers.length; t++) {
|
for(var t=0; t<tiddlers.length; t++) {
|
||||||
var tiddler = tiddlers[t];
|
var tiddler = tiddlers[t];
|
||||||
self.sources[tiddler.title] = task.filepath;
|
|
||||||
self.store.addTiddler(tiddler);
|
self.store.addTiddler(tiddler);
|
||||||
|
self.changeCounts[tiddler.title] = self.store.getChangeCount(tiddler.title);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for(var t=0; t<files.length; t++) {
|
for(var t=0; t<files.length; t++) {
|
||||||
@ -83,8 +84,42 @@ function FileStore(dirpath,store,callback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Set up a queue for saving tiddler files
|
||||||
|
this.saveQueue = async.queue(function(task,callback) {
|
||||||
|
var data = task.data,
|
||||||
|
encoding = "utf8";
|
||||||
|
if(task.binary) {
|
||||||
|
data = new Buffer(task.data,"base64").toString("binary"),
|
||||||
|
encoding = "binary";
|
||||||
|
}
|
||||||
|
fs.writeFile(self.dirpath + "/" + task.name,data,encoding,function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
},10);
|
||||||
|
// Install our event listener to listen out for tiddler changes
|
||||||
|
this.store.addEventListener("",function(changes) {
|
||||||
|
for(var title in changes) {
|
||||||
|
// Get the information about the tiddler
|
||||||
|
var tiddler = self.store.getTiddler(title),
|
||||||
|
changeCount = self.store.getChangeCount(title),
|
||||||
|
lastChangeCount = self.changeCounts[title],
|
||||||
|
files = [];
|
||||||
|
// Construct a changecount record if we don't have one
|
||||||
|
if(!lastChangeCount) {
|
||||||
|
lastChangeCount = 0;
|
||||||
|
self.changeCounts[title] = lastChangeCount;
|
||||||
|
}
|
||||||
|
// Save the tiddler if the changecount has increased
|
||||||
|
if(changeCount > lastChangeCount) {
|
||||||
|
files = self.store.serializeTiddlers([tiddler],"application/x-tiddler");
|
||||||
|
for(var t=0; t<files.length; t++) {
|
||||||
|
self.saveQueue.push(files[t]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.FileStore = FileStore;
|
exports.LocalFileSync = LocalFileSync;
|
||||||
|
|
||||||
})();
|
})();
|
@ -380,7 +380,7 @@ Recipe.tiddlerOutputter = {
|
|||||||
// Ordinary tiddlers are output as a <DIV>
|
// Ordinary tiddlers are output as a <DIV>
|
||||||
for(var t=0; t<tiddlers.length; t++) {
|
for(var t=0; t<tiddlers.length; t++) {
|
||||||
var tid = this.store.getTiddler(tiddlers[t]);
|
var tid = this.store.getTiddler(tiddlers[t]);
|
||||||
out.push(this.store.serializeTiddler("application/x-tiddler-html-div",tid),"\n");
|
out.push(this.store.serializeTiddlers([tid],"application/x-tiddler-html-div")[0].data,"\n");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
javascript: function(out,tiddlers) {
|
javascript: function(out,tiddlers) {
|
||||||
@ -404,7 +404,7 @@ Recipe.tiddlerOutputter = {
|
|||||||
for(var t=0; t<tiddlers.length; t++) {
|
for(var t=0; t<tiddlers.length; t++) {
|
||||||
var title = tiddlers[t],
|
var title = tiddlers[t],
|
||||||
tid = this.store.shadows.getTiddler(title);
|
tid = this.store.shadows.getTiddler(title);
|
||||||
out.push(this.store.serializeTiddler("application/x-tiddler-html-div",tid),"\n");
|
out.push(this.store.serializeTiddlers([tid],"application/x-tiddler-html-div")[0].data,"\n");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
title: function(out,tiddlers) {
|
title: function(out,tiddlers) {
|
||||||
|
@ -1,7 +1,24 @@
|
|||||||
/*\
|
/*\
|
||||||
title: js/TiddlerOutput.js
|
title: js/TiddlerOutput.js
|
||||||
|
|
||||||
Functions concerned with parsing representations of tiddlers
|
Serializers that output tiddlers in a variety of formats.
|
||||||
|
|
||||||
|
store.serializeTiddlers(tiddlers,type)
|
||||||
|
|
||||||
|
tiddlers: An array of tiddler objects
|
||||||
|
type: The target output type as a file extension like `.tid` or a MIME type like `application/x-tiddler`. If `null` or `undefined` then the best type is chosen automatically
|
||||||
|
|
||||||
|
The serializer returns an array of information defining one or more files containing the tiddlers:
|
||||||
|
|
||||||
|
[
|
||||||
|
{name: "title.tid", type: "application/x-tiddler", ext: ".tid", data: "xxxxx"},
|
||||||
|
{name: "title.jpg", type: "image/jpeg", ext: ".jpg", binary: true, data: "xxxxx"},
|
||||||
|
{name: "title.jpg.meta", type: "application/x-tiddler-metadata", ext: ".meta", data: "xxxxx"}
|
||||||
|
]
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
* The `type` field is the type of the file, which is not necessrily the same as the type of the tiddler.
|
||||||
|
* The `binary` field may be omitted if it is not `true`
|
||||||
|
|
||||||
\*/
|
\*/
|
||||||
(function(){
|
(function(){
|
||||||
@ -14,96 +31,105 @@ var utils = require("./Utils.js"),
|
|||||||
|
|
||||||
var tiddlerOutput = exports;
|
var tiddlerOutput = exports;
|
||||||
|
|
||||||
// Utility function to convert a tags string array into a TiddlyWiki-style quoted tags string
|
var outputMetaDataBlock = function(tiddler) {
|
||||||
var stringifyTags = function(tags) {
|
var result = [],
|
||||||
var results = [];
|
fields = tiddler.getFieldStrings(),
|
||||||
for(var t=0; t<tags.length; t++) {
|
t;
|
||||||
if(tags[t].indexOf(" ") !== -1) {
|
for(t=0; t<fields.length; t++) {
|
||||||
results.push("[[" + tags[t] + "]]");
|
result.push(fields[t].name + ": " + fields[t].value);
|
||||||
} else {
|
|
||||||
results.push(tags[t]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return results.join(" ");
|
return result.join("\n");
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Output a tiddler as a .tid file
|
Output tiddlers as separate files in their native formats (ie. `.tid` or `.jpg`/`.jpg.meta`)
|
||||||
*/
|
*/
|
||||||
var outputTiddler = function(tid) {
|
var outputTiddlers = function(tiddlers) {
|
||||||
var result = [],
|
var result = [];
|
||||||
outputAttribute = function(name,value) {
|
for(var t=0; t<tiddlers.length; t++) {
|
||||||
result.push(name + ": " + value + "\n");
|
var tiddler = tiddlers[t],
|
||||||
},
|
extension,
|
||||||
fields = tid.getFields();
|
binary = false;
|
||||||
for(var t in fields) {
|
switch(tiddler.type) {
|
||||||
switch(t) {
|
case "image/jpeg":
|
||||||
case "text":
|
extension = ".jpg";
|
||||||
// Ignore the text field
|
binary = true;
|
||||||
break;
|
break;
|
||||||
case "tags":
|
case "image/gif":
|
||||||
// Output tags as a list
|
extension = ".gif";
|
||||||
outputAttribute(t,stringifyTags(fields.tags));
|
binary = true;
|
||||||
break;
|
break;
|
||||||
case "modified":
|
case "image/png":
|
||||||
case "created":
|
extension = ".png";
|
||||||
// Output dates in YYYYMMDDHHMM
|
binary = true;
|
||||||
outputAttribute(t,utils.convertToYYYYMMDDHHMM(fields[t]));
|
break;
|
||||||
|
case "image/svg+xml":
|
||||||
|
extension = ".svg";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Output other attributes raw
|
extension = ".tid";
|
||||||
outputAttribute(t,fields[t]);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if(extension === ".tid") {
|
||||||
|
result.push({
|
||||||
|
name: tiddler.title + ".tid",
|
||||||
|
type: "application/x-tiddler",
|
||||||
|
extension: ".tid",
|
||||||
|
data: outputMetaDataBlock(tiddler) + "\n\n" + tiddler.text,
|
||||||
|
binary: false
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
result.push({
|
||||||
|
name: tiddler.title,
|
||||||
|
type: tiddler.type,
|
||||||
|
extension: extension,
|
||||||
|
data: tiddler.text,
|
||||||
|
binary: binary
|
||||||
|
});
|
||||||
|
result.push({
|
||||||
|
name: tiddler.title + ".meta",
|
||||||
|
type: "application/x-tiddler-metadata",
|
||||||
|
extension: ".meta",
|
||||||
|
data: outputMetaDataBlock(tiddler),
|
||||||
|
binary: false
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result.push("\n");
|
return result;
|
||||||
result.push(fields.text);
|
|
||||||
return result.join("");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Output a tiddler as an HTML <DIV>
|
Output an array of tiddlers as HTML <DIV>s
|
||||||
out - array to push the output strings
|
out - array to push the output strings
|
||||||
tid - the tiddler to be output
|
tid - the tiddler to be output
|
||||||
The fields are in the order title, creator, modifier, created, modified, tags, followed by any others
|
The fields are in the order title, creator, modifier, created, modified, tags, followed by any others
|
||||||
*/
|
*/
|
||||||
var outputTiddlerDiv = function(tid) {
|
var outputTiddlerDivs = function(tiddlers) {
|
||||||
var result = [],
|
var result = [];
|
||||||
fields = tid.getFields(),
|
for(var t=0; t<tiddlers.length; t++) {
|
||||||
text = fields.text,
|
var tiddler = tiddlers[t],
|
||||||
outputAttribute = function(name,transform) {
|
output = [],
|
||||||
if(name in fields) {
|
fieldStrings = tiddler.getFieldStrings();
|
||||||
var value = fields[name];
|
output.push("<div");
|
||||||
if(transform)
|
for(var f=0; f<fieldStrings.length; f++) {
|
||||||
value = transform(value);
|
output.push(" " + fieldStrings[f].name + "=\"" + fieldStrings[f].value + "\"");
|
||||||
result.push(" " + name + "=\"" + value + "\"");
|
}
|
||||||
delete fields[name];
|
output.push(">\n<pre>");
|
||||||
}
|
output.push(utils.htmlEncode(tiddler.text));
|
||||||
};
|
output.push("</pre>\n</div>");
|
||||||
if(fields.text) {
|
result.push({
|
||||||
delete fields.text;
|
name: tiddler.title,
|
||||||
|
type: "application/x-tiddler-html-div",
|
||||||
|
extension: ".tiddler",
|
||||||
|
data: output.join("")
|
||||||
|
});
|
||||||
}
|
}
|
||||||
result.push("<div");
|
return result;
|
||||||
// Output the standard attributes in the correct order
|
|
||||||
outputAttribute("title");
|
|
||||||
outputAttribute("creator");
|
|
||||||
outputAttribute("modifier");
|
|
||||||
outputAttribute("created", function(v) {return utils.convertToYYYYMMDDHHMM(v);});
|
|
||||||
outputAttribute("modified", function(v) {return utils.convertToYYYYMMDDHHMM(v);});
|
|
||||||
outputAttribute("tags", function(v) {return stringifyTags(v);});
|
|
||||||
// Output any other attributes
|
|
||||||
for(var t in fields) {
|
|
||||||
outputAttribute(t,null,true);
|
|
||||||
}
|
|
||||||
result.push(">\n<pre>");
|
|
||||||
result.push(utils.htmlEncode(text));
|
|
||||||
result.push("</pre>\n</div>");
|
|
||||||
return result.join("");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tiddlerOutput.register = function(store) {
|
tiddlerOutput.register = function(store) {
|
||||||
store.registerTiddlerSerializer(".tid","application/x-tiddler",outputTiddler);
|
store.registerTiddlerSerializer(".tid","application/x-tiddler",outputTiddlers);
|
||||||
store.registerTiddlerSerializer(".tiddler","application/x-tiddler-html-div",outputTiddlerDiv);
|
store.registerTiddlerSerializer(".tiddler","application/x-tiddler-html-div",outputTiddlerDivs);
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -28,6 +28,7 @@ var WikiStore = function WikiStore(options) {
|
|||||||
this.parsers = {}; // Hashmap of parsers by accepted MIME type
|
this.parsers = {}; // Hashmap of parsers by accepted MIME type
|
||||||
this.macros = {}; // Hashmap of macros by macro name
|
this.macros = {}; // Hashmap of macros by macro name
|
||||||
this.caches = {}; // Hashmap of cache objects by tiddler title, each is a hashmap of named caches
|
this.caches = {}; // Hashmap of cache objects by tiddler title, each is a hashmap of named caches
|
||||||
|
this.changeCount = {}; // Hashmap of integer changecount (>1) for each tiddler; persistent across deletions
|
||||||
this.tiddlerSerializers = {}; // Hashmap of serializers by target MIME type
|
this.tiddlerSerializers = {}; // Hashmap of serializers by target MIME type
|
||||||
this.tiddlerDeserializers = {}; // Hashmap of deserializers by accepted MIME type
|
this.tiddlerDeserializers = {}; // Hashmap of deserializers by accepted MIME type
|
||||||
this.eventListeners = []; // Array of {filter:,listener:}
|
this.eventListeners = []; // Array of {filter:,listener:}
|
||||||
@ -38,6 +39,22 @@ var WikiStore = function WikiStore(options) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
WikiStore.prototype.incChangeCount = function(title) {
|
||||||
|
if(this.changeCount.hasOwnProperty(title)) {
|
||||||
|
this.changeCount[title]++;
|
||||||
|
} else {
|
||||||
|
this.changeCount[title] = 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
WikiStore.prototype.getChangeCount = function(title) {
|
||||||
|
if(this.changeCount.hasOwnProperty(title)) {
|
||||||
|
return this.changeCount[title];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
WikiStore.prototype.registerParser = function(type,parser) {
|
WikiStore.prototype.registerParser = function(type,parser) {
|
||||||
if(type instanceof Array) {
|
if(type instanceof Array) {
|
||||||
for(var t=0; t<type.length; t++) {
|
for(var t=0; t<type.length; t++) {
|
||||||
@ -96,6 +113,10 @@ WikiStore.prototype.touchTiddler = function(type,title) {
|
|||||||
this.triggerEvents();
|
this.triggerEvents();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
WikiStore.prototype.clearEvents = function() {
|
||||||
|
this.changedTiddlers = {};
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Trigger the execution of the event dispatcher at the next tick, if it is not already triggered
|
Trigger the execution of the event dispatcher at the next tick, if it is not already triggered
|
||||||
*/
|
*/
|
||||||
@ -133,6 +154,7 @@ WikiStore.prototype.getTiddlerText = function(title,defaultText) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
WikiStore.prototype.deleteTiddler = function(title) {
|
WikiStore.prototype.deleteTiddler = function(title) {
|
||||||
|
this.incChangeCount(title);
|
||||||
delete this.tiddlers[title];
|
delete this.tiddlers[title];
|
||||||
this.clearCache(title);
|
this.clearCache(title);
|
||||||
this.touchTiddler("deleted",title);
|
this.touchTiddler("deleted",title);
|
||||||
@ -153,6 +175,7 @@ WikiStore.prototype.addTiddler = function(tiddler) {
|
|||||||
if(!(tiddler instanceof Tiddler)) {
|
if(!(tiddler instanceof Tiddler)) {
|
||||||
tiddler = new Tiddler(tiddler);
|
tiddler = new Tiddler(tiddler);
|
||||||
}
|
}
|
||||||
|
this.incChangeCount(tiddler.title);
|
||||||
var status = tiddler.title in this.tiddlers ? "modified" : "created";
|
var status = tiddler.title in this.tiddlers ? "modified" : "created";
|
||||||
this.clearCache(tiddler.title);
|
this.clearCache(tiddler.title);
|
||||||
this.tiddlers[tiddler.title] = tiddler;
|
this.tiddlers[tiddler.title] = tiddler;
|
||||||
@ -213,10 +236,11 @@ WikiStore.prototype.getShadowTitles = function() {
|
|||||||
return this.shadows ? this.shadows.getTitles() : [];
|
return this.shadows ? this.shadows.getTitles() : [];
|
||||||
};
|
};
|
||||||
|
|
||||||
WikiStore.prototype.serializeTiddler = function(type,tiddler) {
|
WikiStore.prototype.serializeTiddlers = function(tiddlers,type) {
|
||||||
|
type = type || "application/x-tiddler";
|
||||||
var serializer = this.tiddlerSerializers[type];
|
var serializer = this.tiddlerSerializers[type];
|
||||||
if(serializer) {
|
if(serializer) {
|
||||||
return serializer(tiddler);
|
return serializer(tiddlers);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ exports.macro = {
|
|||||||
for(var t=0; t<story.tiddlers.length; t++) {
|
for(var t=0; t<story.tiddlers.length; t++) {
|
||||||
var storyRecord = story.tiddlers[t];
|
var storyRecord = story.tiddlers[t];
|
||||||
if(storyRecord.title === event.tiddlerTitle && storyRecord.template !== template) {
|
if(storyRecord.title === event.tiddlerTitle && storyRecord.template !== template) {
|
||||||
storyRecord.title = "Draft of " + event.tiddlerTitle + " at " + (new Date());
|
storyRecord.title = "Draft " + (new Date()) + " of " + event.tiddlerTitle;
|
||||||
storyRecord.template = template;
|
storyRecord.template = template;
|
||||||
var tiddler = this.store.getTiddler(event.tiddlerTitle);
|
var tiddler = this.store.getTiddler(event.tiddlerTitle);
|
||||||
this.store.addTiddler(new Tiddler(
|
this.store.addTiddler(new Tiddler(
|
||||||
|
@ -9,7 +9,7 @@ TiddlyWiki command line interface
|
|||||||
|
|
||||||
var App = require("./js/App.js").App,
|
var App = require("./js/App.js").App,
|
||||||
WikiStore = require("./js/WikiStore.js").WikiStore,
|
WikiStore = require("./js/WikiStore.js").WikiStore,
|
||||||
FileStore = require("./js/FileStore.js").FileStore,
|
LocalFileSync = require("./js/LocalFileSync.js").LocalFileSync,
|
||||||
Tiddler = require("./js/Tiddler.js").Tiddler,
|
Tiddler = require("./js/Tiddler.js").Tiddler,
|
||||||
Recipe = require("./js/Recipe.js").Recipe,
|
Recipe = require("./js/Recipe.js").Recipe,
|
||||||
tiddlerInput = require("./js/TiddlerInput.js"),
|
tiddlerInput = require("./js/TiddlerInput.js"),
|
||||||
@ -47,8 +47,9 @@ var parseOptions = function(args,defaultSwitch) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var switches = parseOptions(Array.prototype.slice.call(process.argv,2),"dummy"),
|
var switches = parseOptions(Array.prototype.slice.call(process.argv,2),"dummy"),
|
||||||
|
verbose = false,
|
||||||
recipe = null,
|
recipe = null,
|
||||||
fileStore = null,
|
localFileSync = null,
|
||||||
lastRecipeFilepath = null,
|
lastRecipeFilepath = null,
|
||||||
currSwitch = 0;
|
currSwitch = 0;
|
||||||
|
|
||||||
@ -111,7 +112,7 @@ var commandLineSwitches = {
|
|||||||
store: {
|
store: {
|
||||||
args: {min: 1, max: 1},
|
args: {min: 1, max: 1},
|
||||||
handler: function(args,callback) {
|
handler: function(args,callback) {
|
||||||
fileStore = new FileStore(args[0],app.store,function() {
|
localFileSync = new LocalFileSync(args[0],app.store,function() {
|
||||||
callback(null);
|
callback(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -149,7 +150,7 @@ var commandLineSwitches = {
|
|||||||
recipe = [];
|
recipe = [];
|
||||||
app.store.forEachTiddler(function(title,tiddler) {
|
app.store.forEachTiddler(function(title,tiddler) {
|
||||||
var filename = encodeURIComponent(tiddler.title.replace(/ /g,"_")) + ".tid";
|
var filename = encodeURIComponent(tiddler.title.replace(/ /g,"_")) + ".tid";
|
||||||
fs.writeFileSync(path.resolve(outdir,filename),app.store.serializeTiddler("application/x-tiddler",tiddler),"utf8");
|
fs.writeFileSync(path.resolve(outdir,filename),app.store.serializeTiddlers([tiddler],"application/x-tiddler")[0].data,"utf8");
|
||||||
recipe.push("tiddler: " + filename + "\n");
|
recipe.push("tiddler: " + filename + "\n");
|
||||||
});
|
});
|
||||||
fs.writeFileSync(path.join(args[0],"split.recipe"),recipe.join(""));
|
fs.writeFileSync(path.join(args[0],"split.recipe"),recipe.join(""));
|
||||||
@ -174,11 +175,33 @@ var commandLineSwitches = {
|
|||||||
callback("--servewiki must be preceded by a --recipe");
|
callback("--servewiki must be preceded by a --recipe");
|
||||||
}
|
}
|
||||||
var port = args.length > 0 ? args[0] : 8000;
|
var port = args.length > 0 ? args[0] : 8000;
|
||||||
// Dumbly, this implementation wastes the recipe processing that happened on the --recipe switch
|
|
||||||
http.createServer(function(request, response) {
|
http.createServer(function(request, response) {
|
||||||
response.writeHead(200, {"Content-Type": "text/html"});
|
var path = url.parse(request.url).pathname;
|
||||||
response.end(recipe.cook(), "utf8");
|
switch(request.method) {
|
||||||
|
case "PUT":
|
||||||
|
var data = "";
|
||||||
|
request.on("data",function(chunk) {
|
||||||
|
data += chunk.toString();
|
||||||
|
});
|
||||||
|
request.on("end",function() {
|
||||||
|
var title = decodeURIComponent(path.substr(1));
|
||||||
|
app.store.addTiddler(new Tiddler(JSON.parse(data),{title: title}));
|
||||||
|
response.writeHead(204, "OK");
|
||||||
|
response.end();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "GET":
|
||||||
|
if(path === "/") {
|
||||||
|
response.writeHead(200, {"Content-Type": "text/html"});
|
||||||
|
response.end(recipe.cook(), "utf8");
|
||||||
|
} else {
|
||||||
|
response.writeHead(404);
|
||||||
|
response.end();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}).listen(port);
|
}).listen(port);
|
||||||
|
process.nextTick(function() {callback(null);});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
servetiddlers: {
|
servetiddlers: {
|
||||||
@ -196,11 +219,13 @@ var commandLineSwitches = {
|
|||||||
response.end();
|
response.end();
|
||||||
}
|
}
|
||||||
}).listen(port);
|
}).listen(port);
|
||||||
|
process.nextTick(function() {callback(null);});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
verbose: {
|
verbose: {
|
||||||
args: {min: 0, max: 0},
|
args: {min: 0, max: 0},
|
||||||
handler: function(args,callback) {
|
handler: function(args,callback) {
|
||||||
|
verbose = true;
|
||||||
process.nextTick(function() {callback(null);});
|
process.nextTick(function() {callback(null);});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -245,6 +270,7 @@ var commandLineSwitches = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
process.nextTick(function() {callback(null);});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -259,6 +285,9 @@ var processNextSwitch = function() {
|
|||||||
if(s.args.length > csw.args.max) {
|
if(s.args.length > csw.args.max) {
|
||||||
throw "Command line switch --" + s.switchName + " should have a maximum of " + csw.args.max + " arguments";
|
throw "Command line switch --" + s.switchName + " should have a maximum of " + csw.args.max + " arguments";
|
||||||
}
|
}
|
||||||
|
if(verbose) {
|
||||||
|
console.log("Processing --" + s.switchName + " " + s.args.join(" "));
|
||||||
|
}
|
||||||
csw.handler(s.args,function (err) {
|
csw.handler(s.args,function (err) {
|
||||||
if(err) {
|
if(err) {
|
||||||
throw "Error while executing option '--" + s.switchName + "' was:\n" + err;
|
throw "Error while executing option '--" + s.switchName + "' was:\n" + err;
|
||||||
|
Loading…
Reference in New Issue
Block a user