1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-27 03:57:21 +00:00

Initial commit

This commit is contained in:
Jeremy Ruston 2011-11-22 14:29:29 +00:00
commit f96708a846
234 changed files with 21127 additions and 0 deletions

15
cook.js Normal file
View File

@ -0,0 +1,15 @@
// Cook a TiddlyWiki recipe and send it to STDOUT
//
// Usage: node cook.js <recipefile>
var sys = require("sys"),
tiddlywiki = require("./js/TiddlyWiki.js"),
recipe = require("./js/Recipe.js");
var filename = process.argv[2];
var store = new tiddlywiki.TiddlyWiki();
var theRecipe = new recipe.Recipe(store,filename);
console.log(theRecipe.cook());

90
js/ArgParser.js Normal file
View File

@ -0,0 +1,90 @@
/*
Parse a space-separated string of name:value parameters
The parameters are returned in a structure that can be referenced like this:
(return).byName["name"][0] - First occurance of parameter with a given name
(return).byPos[0].n - Name of parameter in first position
(return).byPos[0].v - Value of parameter in first position
Options and their defaults are:
defaultName: null,
defaultValue: null,
noNames: false,
cascadeDefaults: false
*/
var ArgParser = function(argString,options) {
var parseToken = function(match,p) {
var n;
if(match[p]) // Double quoted
n = match[p];
else if(match[p+1]) // Single quoted
n = match[p+1];
else if(match[p+2]) // Double-square-bracket quoted
n = match[p+2];
else if(match[p+3]) // Double-brace quoted
n = match[p+3];
else if(match[p+4]) // Unquoted
n = match[p+4];
else if(match[p+5]) // empty quote
n = "";
return n;
};
this.byPos = [];
var dblQuote = "(?:\"((?:(?:\\\\\")|[^\"])+)\")";
var sngQuote = "(?:'((?:(?:\\\\\')|[^'])+)')";
var dblSquare = "(?:\\[\\[((?:\\s|\\S)*?)\\]\\])";
var dblBrace = "(?:\\{\\{((?:\\s|\\S)*?)\\}\\})";
var unQuoted = options.noNames ? "([^\"'\\s]\\S*)" : "([^\"':\\s][^\\s:]*)";
var emptyQuote = "((?:\"\")|(?:''))";
var skipSpace = "(?:\\s*)";
var token = "(?:" + dblQuote + "|" + sngQuote + "|" + dblSquare + "|" + dblBrace + "|" + unQuoted + "|" + emptyQuote + ")";
var re = options.noNames ? new RegExp(token,"mg") : new RegExp(skipSpace + token + skipSpace + "(?:(\\:)" + skipSpace + token + ")?","mg");
do {
var match = re.exec(argString);
if(match) {
var n = parseToken(match,1);
if(options.noNames) {
this.byPos.push({n:"", v:n});
} else {
var v = parseToken(match,8);
if(v === null && options.defaultName) {
v = n;
n = options.defaultName;
} else if(v === null && options.defaultValue) {
v = options.defaultValue;
}
this.byPos.push({n:n, v:v});
if(options.cascadeDefaults) {
options.defaultName = n;
options.defaultValue = v;
}
}
}
} while(match);
this.byName = {};
for(var t=0; t<this.byPos.length; t++) {
var n = this.byPos[t].n;
var v = this.byPos[t].v;
if(n in this.byName)
this.byName[n].push(v);
else
this.byName[n] = [v];
}
}
// Retrieve the first occurance of a named parameter, or the default if missing
ArgParser.prototype.getValueByName = function(n,defaultValue) {
var v = this.byName[n];
return v && v.length > 0 ? v[0] : defaultValue;
}
// Retrieve all the values of a named parameter as an array
ArgParser.prototype.getValuesByName = function(n,defaultValue) {
var v = this.byName[n];
return v && v.length > 0 ? v : defaultValue;
}
exports.ArgParser = ArgParser

205
js/Recipe.js Normal file
View File

@ -0,0 +1,205 @@
/*
Recipe files consist of recipe lines consisting of a marker, a colon and the pathname of an ingredient:
marker: pathname
The pathname is interpreted relative to the directory containing the recipe file.
The special marker "recipe" is used to load a sub-recipe file.
The special marker "template" is used to identify the HTML template. The HTML template contains
markers in two different forms:
<!--@@marker@@-->
&lt;!--@@marker@@--&gt;
Recipe processing is in two parts. First the recipe file is parsed and the referenced files are loaded into tiddlers.
Second, the template is processed by replacing the markers with the text of the tiddlers indicated in the recipe file.
The recipe is parsed into the 'ingredients' hashmap like this:
this.ingredients = {
"marker1": [Tiddler1,Tiddler2,Tiddler3,...],
"marker2": [TiddlerA,TiddlerB,TiddlerC,...],
....
};
*/
var tiddler = require("./Tiddler.js"),
tiddlerUtils = require("./TiddlerUtils.js"),
tiddlywiki = require("./TiddlyWiki.js"),
fs = require("fs"),
path = require("path"),
util = require("util");
// Create a new Recipe object from the specified recipe file, storing the tiddlers in a specified TiddlyWiki store
var Recipe = function(store,filepath) {
this.store = store; // Save a reference to the store
this.ingredients = {}; // Hashmap of array of ingredients
this.readRecipe(filepath); // Read the recipe file
}
// Specialised configuration and handlers for particular ingredient markers
var specialMarkers = {
shadow: {
readIngredientPostProcess: function(fields) {
// Add ".shadow" to the name of shadow tiddlers
fields.title = fields.title + ".shadow";
return fields;
}
}
};
// Process the contents of a recipe file
Recipe.prototype.readRecipe = function(filepath) {
var dirname = path.dirname(filepath),
me = this;
fs.readFileSync(filepath,"utf8").split("\n").forEach(function(line) {
var p = line.indexOf(":");
if(p !== -1) {
var marker = line.substr(0, p).trim(),
value = line.substr(p+1).trim();
if(marker === "recipe") {
me.readRecipe(path.resolve(dirname,value));
} else {
var fields = me.readIngredient(dirname,value),
postProcess = me.readIngredientPostProcess[marker];
if(postProcess)
fields = postProcess(fields);
me.addIngredient(marker,fields);
}
}
});
}
// Special post-processing required for certain ingredient types
Recipe.prototype.readIngredientPostProcess = {
"shadow": function(fields) {
// Add ".shadow" to the name of shadow tiddlers
fields.title = fields.title + ".shadow";
return fields;
}
};
Recipe.prototype.addIngredient = function(marker,tiddlerFields) {
var ingredientTiddler = new tiddler.Tiddler(tiddlerFields);
this.store.addTiddler(ingredientTiddler);
if(marker in this.ingredients) {
this.ingredients[marker].push(ingredientTiddler);
} else {
this.ingredients[marker] = [ingredientTiddler];
}
}
// Read an ingredient file and return it as a hashmap of tiddler fields. Also read the .meta file, if present
Recipe.prototype.readIngredient = function(dirname,filepath) {
var fullpath = path.resolve(dirname,filepath),
extname = path.extname(filepath),
basename = path.basename(filepath,extname),
fields = {
title: basename
};
// Read the tiddler file
fields = tiddlerUtils.parseTiddler(fs.readFileSync(fullpath,"utf8"),extname,fields);
// Check for the .meta file
var metafile = fullpath + ".meta";
if(path.existsSync(metafile)) {
fields = tiddlerUtils.parseMetaDataBlock(fs.readFileSync(metafile,"utf8"),fields);
}
return fields;
}
// Return a string of the cooked recipe
Recipe.prototype.cook = function() {
var template = this.ingredients.template ? this.ingredients.template[0].fields.text : "";
var out = [];
var me = this;
template.split("\n").forEach(function(line) {
var templateRegExp = /^(?:<!--@@(.*)@@-->)|(?:&lt;!--@@(.*)@@--&gt;)$/gi;
var match = templateRegExp.exec(line);
if(match) {
var marker = match[1] === undefined ? match[2] : match[1];
me.outputIngredient(out,marker);
} else {
out.push(line);
}
});
// out.push("\nRecipe:\n" + util.inspect(this.ingredients,false,4));
return out.join("\n");
}
// Output all the tiddlers in the recipe with a particular marker
Recipe.prototype.outputIngredient = function(out,marker) {
var ingredient = this.ingredients[marker];
var outputType = Recipe.ingredientOutputMapper[marker] || "raw";
var outputter = Recipe.ingredientOutputter[outputType];
if(outputter && ingredient) {
outputter(out,ingredient);
}
}
// Allows for specialised processing for certain markers
Recipe.ingredientOutputMapper = {
tiddler: "div",
js: "javascript",
jsdeprecated: "javascript",
jquery: "javascript",
shadow: "shadow"
};
Recipe.ingredientOutputter = {
raw: function(out,ingredient) {
// The default is just to output the raw text of the tiddler, ignoring any metadata
for(var t=0; t<ingredient.length; t++) {
var tid = ingredient[t];
// For compatibility with cook.rb, remove one trailing \n from tiddler
var text = tid.fields.text;
text = text.charAt(text.length-1) === "\n" ? text.substr(0,text.length-1) : text;
out.push(text);
}
},
div: function(out,ingredient) {
// Ordinary tiddlers are output as a <DIV>
for(var t=0; t<ingredient.length; t++) {
var tid = ingredient[t];
tiddlerUtils.outputTiddlerDiv(out,tid);
}
},
javascript: function(out,ingredient) {
// Lines starting with //# are removed from javascript tiddlers
for(var t=0; t<ingredient.length; t++) {
var tid = ingredient[t];
var text = tid.fields.text;
// For compatibility with cook.rb, remove one trailing \n from tiddler
text = text.charAt(text.length-1) === "\n" ? text.substr(0,text.length-1) : text;
var lines = text.split("\n");
for(var line=0; line<lines.length; line++) {
var commentRegExp = /^\s*\/\/#/gi;
if(!commentRegExp.test(lines[line])) {
out.push(lines[line]);
}
}
}
},
shadow: function(out,ingredient) {
// Shadows are output as a <DIV> with the the ".shadow" suffix removed from the title
for(var t=0; t<ingredient.length; t++) {
var tid = ingredient[t];
var title = tid.fields.title;
var tweakedTiddler;
if(title.indexOf(".shadow") === title.length - 7) {
tweakedTiddler = new tiddler.Tiddler(tid,{
title: title.substr(0, title.length-7)
});
} else {
tweakedTiddler = tid;
}
tiddlerUtils.outputTiddlerDiv(out,tweakedTiddler,{omitPrecedingLineFeed: true});
}
}
};
exports.Recipe = Recipe;

34
js/Tiddler.js Normal file
View File

@ -0,0 +1,34 @@
/*
Tiddlers are an immutable dictionary of name:value pairs called fields. Values can be a string, an array
of strings, or a date.
Hardcoded in the system is the knowledge that the 'tags' field is a string array, and that the 'modified'
and 'created' fields are dates. All other fields are strings.
The Tiddler object exposes the following API
new Tiddler(fields) - create a Tiddler given a hashmap of field values
new Tiddler(tiddler,fields) - create a Tiddler from an existing tiddler with a hashmap of modified field values
Tiddler.fields - hashmap of tiddler fields
*/
var Tiddler = function(/* tiddler,fields */) {
var tiddler, fields, c = 0, t;
if(arguments[c] instanceof Tiddler) {
tiddler = arguments[c++];
}
fields = arguments[c++];
this.fields = {};
if(tiddler instanceof Tiddler) {
for(t in tiddler.fields) {
this.fields[t] = tiddler.fields[t]; // Should copy arrays by value
}
}
for(t in fields) {
this.fields[t] = fields[t]; // Should copy arrays by value
}
}
exports.Tiddler = Tiddler;

274
js/TiddlerUtils.js Normal file
View File

@ -0,0 +1,274 @@
/*
Various static utility functions concerned with parsing and generating representations of tiddlers and
other objects.
This file is a bit of a dumping ground; the expectation is that most of these functions will be refactored.
*/
var argParser = require("./ArgParser.js");
var tiddlerUtils = exports;
/*
Parse a tiddler given its mimetype, and merge the results into a hashmap of tiddler fields.
A file extension can be passed as a shortcut for the mimetype, as shown in tiddlerUtils.fileExtensionMappings.
For example ".txt" file extension is mapped to the "text/plain" mimetype.
Special processing to extract embedded metadata is applied to some mimetypes.
*/
tiddlerUtils.parseTiddler = function(text,type,fields) {
if(fields === undefined) {
var fields = {};
}
// Map extensions to mimetpyes
var fileExtensionMapping = tiddlerUtils.fileExtensionMappings[type];
if(fileExtensionMapping)
type = fileExtensionMapping;
// Invoke the parser for the specified mimetype
var parser = tiddlerUtils.parseTiddlerByMimeType[type];
if(parser) {
return parser(text,fields);
}
return fields;
}
tiddlerUtils.fileExtensionMappings = {
".txt": "text/plain",
".html": "text/html",
".tiddler": "application/x-tiddler-html-div",
".tid": "application/x-tiddler",
".js": "application/javascript"
}
tiddlerUtils.parseTiddlerByMimeType = {
"text/plain": function(text,fields) {
fields.text = text;
return fields;
},
"text/html": function(text,fields) {
fields.text = text;
return fields;
},
"application/x-tiddler-html-div": function(text,fields) {
fields = tiddlerUtils.parseTiddlerDiv(text,fields);
return fields;
},
"application/x-tiddler": function(text,fields) {
var split = text.indexOf("\n\n");
if(split === -1) {
split = text.length;
}
fields = tiddlerUtils.parseMetaDataBlock(text.substr(0,split),fields);
fields.text = text.substr(split + 2);
return fields;
},
"application/javascript": function(text,fields) {
fields.text = text;
return fields;
}
}
/*
Parse a block of metadata and merge the results into a hashmap of tiddler fields.
The block consists of newline delimited lines consisting of the field name, a colon, and then the value. For example:
title: Safari
modifier: blaine
created: 20110211110700
modified: 20110211131020
tags: browsers issues
creator: psd
*/
tiddlerUtils.parseMetaDataBlock = function(metaData,fields) {
if(fields === undefined) {
var fields = {};
}
metaData.split("\n").forEach(function(line) {
var p = line.indexOf(":");
if(p !== -1) {
var field = line.substr(0, p).trim();
var value = line.substr(p+1).trim();
fields[field] = tiddlerUtils.parseMetaDataItem(field,value);
}
});
return fields;
}
/*
Parse an old-style tiddler DIV. It looks like this:
<div title="Title" creator="JoeBloggs" modifier="JoeBloggs" created="201102111106" modified="201102111310" tags="myTag [[my long tag]]">
<pre>The text of the tiddler (without the expected HTML encoding).
</pre>
</div>
Note that the field attributes are HTML encoded, but that the body of the <PRE> tag is not.
*/
tiddlerUtils.parseTiddlerDiv = function(text,fields) {
if(fields === undefined) {
var fields = {};
}
var divRegExp = /^\s*<div\s+([^>]*)>((?:.|\n)*)<\/div>\s*$/gi;
var subDivRegExp = /^(?:\s*<pre>)((?:.|\n)*)(?:<\/pre>\s*)$/gi;
var attrRegExp = /\s*([^=\s]+)\s*=\s*"([^"]*)"/gi;
var match = divRegExp.exec(text);
if(match) {
var subMatch = subDivRegExp.exec(match[2]); // Body of the <DIV> tag
if(subMatch) {
fields.text = subMatch[1];
} else {
fields.text = match[2];
}
do {
var attrMatch = attrRegExp.exec(match[1]);
if(attrMatch) {
var name = attrMatch[1];
var value = attrMatch[2];
fields[name] = tiddlerUtils.parseMetaDataItem(name,value);
}
} while(attrMatch);
}
return fields;
}
// Output a tiddler as an HTML <DIV>
// out - array to push the output strings
// tid - the tiddler to be output
// options - options:
// omitPrecedingLineFeed - determines if a linefeed is inserted between the <PRE> tag and the text
tiddlerUtils.outputTiddlerDiv = function(out,tid,options) {
var result = [];
var outputAttribute = function(name,value) {
result.push(" " + name + "=\"" + value + "\"");
};
result.push("<div");
for(var t in tid.fields) {
switch(t) {
case "text":
// Ignore the text field
break;
case "tags":
// Output tags as a list
outputAttribute(t,tiddlerUtils.stringifyTags(tid.fields.tags));
break;
case "modified":
case "created":
// Output dates in YYYYMMDDHHMMSS
outputAttribute(t,tiddlerUtils.convertToYYYYMMDDHHMM(tid.fields[t]));
break;
default:
// Output other attributes raw
outputAttribute(t,tid.fields[t]);
break;
}
}
result.push(">\n<pre>");
if(!(options && options.omitPrecedingLineFeed))
result.push("\n");
result.push(tiddlerUtils.htmlEncode(tid.fields.text));
result.push("</pre>\n</div>");
out.push(result.join(""));
}
tiddlerUtils.stringifyTags = function(tags) {
var results = [];
for(var t=0; t<tags.length; t++) {
if(tags[t].indexOf(" ") !== -1) {
results.push("[[" + tags[t] + "]]");
} else {
results.push(tags[t]);
}
}
return results.join(" ");
}
/*
Parse a single metadata field/value pair and return the value as the appropriate data type
*/
tiddlerUtils.parseMetaDataItem = function(field,value) {
var result;
switch(field) {
case "modified":
case "created":
result = tiddlerUtils.convertFromYYYYMMDDHHMMSS(value);
break;
case "tags":
var parser = new argParser.ArgParser(value,{noNames: true});
result = parser.getValuesByName("","");
break;
default:
result = value;
break;
}
return result;
}
// Pad a string to a certain length with zeros
tiddlerUtils.zeroPad = function(n,d)
{
var s = n.toString();
if(s.length < d)
s = "000000000000000000000000000".substr(0,d-s.length) + s;
return s;
};
// Convert a date to local YYYYMMDDHHMM string format
tiddlerUtils.convertToLocalYYYYMMDDHHMM = function(date)
{
return date.getFullYear() + tiddlerUtils.zeroPad(date.getMonth()+1,2) + tiddlerUtils.zeroPad(date.getDate(),2) + tiddlerUtils.zeroPad(date.getHours(),2) + tiddlerUtils.zeroPad(date.getMinutes(),2);
};
// Convert a date to UTC YYYYMMDDHHMM string format
tiddlerUtils.convertToYYYYMMDDHHMM = function(date)
{
return date.getUTCFullYear() + tiddlerUtils.zeroPad(date.getUTCMonth()+1,2) + tiddlerUtils.zeroPad(date.getUTCDate(),2) + tiddlerUtils.zeroPad(date.getUTCHours(),2) + tiddlerUtils.zeroPad(date.getUTCMinutes(),2);
};
// Convert a date to UTC YYYYMMDD.HHMMSSMMM string format
tiddlerUtils.convertToYYYYMMDDHHMMSSMMM = function(date)
{
return date.getUTCFullYear() + tiddlerUtils.zeroPad(date.getUTCMonth()+1,2) + tiddlerUtils.zeroPad(date.getUTCDate(),2) + "." + tiddlerUtils.zeroPad(date.getUTCHours(),2) + tiddlerUtils.zeroPad(date.getUTCMinutes(),2) + tiddlerUtils.zeroPad(date.getUTCSeconds(),2) + tiddlerUtils.zeroPad(date.getUTCMilliseconds(),3) +"0";
};
// Create a date from a UTC YYYYMMDDHHMM format string
tiddlerUtils.convertFromYYYYMMDDHHMM = function(d)
{
d = d?d.replace(/[^0-9]/g, ""):"";
return tiddlerUtils.convertFromYYYYMMDDHHMMSSMMM(d.substr(0,12));
};
// Create a date from a UTC YYYYMMDDHHMMSS format string
tiddlerUtils.convertFromYYYYMMDDHHMMSS = function(d)
{
d = d?d.replace(/[^0-9]/g, ""):"";
return tiddlerUtils.convertFromYYYYMMDDHHMMSSMMM(d.substr(0,14));
};
// Create a date from a UTC YYYYMMDDHHMMSSMMM format string
tiddlerUtils.convertFromYYYYMMDDHHMMSSMMM = function(d)
{
d = d ? d.replace(/[^0-9]/g, "") : "";
return new Date(Date.UTC(parseInt(d.substr(0,4),10),
parseInt(d.substr(4,2),10)-1,
parseInt(d.substr(6,2),10),
parseInt(d.substr(8,2)||"00",10),
parseInt(d.substr(10,2)||"00",10),
parseInt(d.substr(12,2)||"00",10),
parseInt(d.substr(14,3)||"000",10)));
};
// Convert & to "&amp;", < to "&lt;", > to "&gt;" and " to "&quot;"
tiddlerUtils.htmlEncode = function(s)
{
return s.replace(/&/mg,"&amp;").replace(/</mg,"&lt;").replace(/>/mg,"&gt;").replace(/\"/mg,"&quot;");
};
// Convert "&amp;" to &, "&lt;" to <, "&gt;" to > and "&quot;" to "
tiddlerUtils.htmlDecode = function(s)
{
return s.replace(/&lt;/mg,"<").replace(/&gt;/mg,">").replace(/&quot;/mg,"\"").replace(/&amp;/mg,"&");
};

33
js/TiddlyWiki.js Normal file
View File

@ -0,0 +1,33 @@
var tiddler = require("./Tiddler.js");
var TiddlyWiki = function() {
this.tiddlers = {};
};
TiddlyWiki.prototype.clear = function() {
this.tiddlers = {};
}
TiddlyWiki.prototype.fetchTiddler = function(title) {
var t = this.tiddlers[title];
return t instanceof tiddler.Tiddler ? t : null;
}
TiddlyWiki.prototype.deleteTiddler = function(title) {
delete this.tiddlers[title];
}
TiddlyWiki.prototype.addTiddler = function(tiddler) {
this.tiddlers[tiddler.title] = tiddler;
}
TiddlyWiki.prototype.forEachTiddler = function(callback) {
var t;
for(t in this.tiddlers) {
var tiddler = this.tiddlers[t];
if(tiddler instanceof tiddler.Tiddler)
callback.call(this,t,tiddler);
}
}
exports.TiddlyWiki = TiddlyWiki

21
readme.md Normal file
View File

@ -0,0 +1,21 @@
# cook.js
This is an attempt to modernise TiddlyWiki's build system, which is based on tools written in Ruby called Cook and Ginsu (see https://github.com/TiddlyWiki/cooker for details). This new version is written in JavaScript for node.js, with the intention that it can share code with TiddlyWiki itself.
## Usage
node cook.js <recipefile>
Cooks a recipe file and sends the output to STDOUT
node server.js <recipefile>
Cooks a recipe file and serves it over HTTP port 8000
## Testing
`test.sh` contains a simple test that cooks the main tiddlywiki.com recipe, first with the old Ruby-based tool, and then the new one. It uses OS X's opendiff to display the differences between the two files.
## Current status
As of 22nd November 2011, cook.js can now build a fully functional TiddlyWiki from the existing recipe files. There are still some minor differences in the layout of tiddler attributes, and some whitespace issues that prevent full byte-for-byte compatibility.

22
server.js Normal file
View File

@ -0,0 +1,22 @@
// Cook a TiddlyWiki recipe and serve the result over HTTP
//
// Usage: node server.js <recipefile>
var tiddlywiki = require("./js/TiddlyWiki.js"),
recipe = require("./js/Recipe.js"),
sys = require("sys"),
http = require("http"),
fs = require("fs"),
url = require("url"),
path = require("path");
var filename = process.argv[2];
http.createServer(function (request, response) {
response.writeHead(200, {"Content-Type": "text/html"});
var store = new tiddlywiki.TiddlyWiki();
var theRecipe = new recipe.Recipe(store,filename);
response.end(theRecipe.cook(), "utf-8");
}).listen(8000);
sys.puts("Server running at http://127.0.0.1:8000/");

10
test.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
# cook the recipe with the old cook.rb (assuming you have set it up as described in github.com/TiddlyWiki/cooker)
cook $PWD/test/data/tiddlywiki.com/index.html.recipe -d $PWD -o oldcooked.html
# cook it with cook.js
node cook.js $PWD/test/data/tiddlywiki.com/index.html.recipe > newcooked.html
# compare the two
opendiff oldcooked.html newcooked.html

BIN
test/data/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,3 @@
<div title="Test1">
<pre>This is a testing tiddler.</pre>
</div>

View File

@ -0,0 +1,3 @@
<div title="TestContainsTag">
<pre>This is a testing tiddler with </pre></div> in it.</pre>
</div>

View File

@ -0,0 +1 @@
<div tiddler="TestNoPreTag" modifier="JeremyRuston" modified="200605111124" created="200511301204" tags="">This is a tiddler that hasn't got a {{{<pre>}}} tag</div>

View File

@ -0,0 +1 @@
<div tiddler="TestWithTags" modifier="JeremyRuston" modified="200602241819" created="200602071851" tags="one two [[three and a half]]"><pre>I welcome contributions to the TiddlyWiki core: code, documentation, or anything else that helps to make it a better product.\n\nIn terms of code, I'm happy to accept small snippets inline in emails or group messages. For larger changes, I prefer to receive a modified version of the entire TiddlyWiki HTML file via email; I can then easily analyse the differences.\n\nTo maximise the chances of your work being accepted into the core, you should consider these points:\n* Is the code reasonably short?\n* Is the functionality nearly universally useful?\n* Is the functionality impractical to offer as a plugin?\n* Have you used the same coding conventions as the rest of the core?\n* Have you tested the change on all major browsers?\n</pre></div>

View File

@ -0,0 +1,5 @@
recipe: ../../tiddlywiki.com/index.html.recipe
tiddler: Test1.tiddler
tiddler: TestNoPreTag.tiddler
tiddler: TestWithTags.tiddler
tiddler: TestContainsTag.tiddler

View File

@ -0,0 +1,63 @@
TiddlyWiki
==========
https://github.com/TiddlyWiki/tiddlywiki.com
Description
-----------
This repository contains the tools required to create the site http://tiddlywiki.com/
The content for tiddlywiki.com is obtained from a [TiddlySpace](http://tiddlyspace.com/).
Prerequisites
-------------
Ensure that you have downloaded and installed TiddlyWiki as described at https://github.com/TiddlyWiki/tiddlywiki
You need perl to build tiddlywiki.com. If you do not have it installed, it can be downloaded [here](http://www.perl.org/get.html).
You need to set up `ginsu`. Copy the `ginsu` script file to somewhere that is on your path. Edit this file according to the instructions in the file.
You need to set up the `tiddler2tid`. Copy the `tiddler2tid` script file to somewhere that is on your path.
Building tiddlywiki.com
-----------------------
After downloading and installing TiddlyWiki checkout the version of TiddlyWiki that you wish to use for tiddlywiki.com. Ongoing development occurs in the tiddlywiki repository, so you need to checkout a tagged release version of TiddlyWiki. Change to the tiddlywiki directory and checkout the required version, eg:
git checkout tags/v2.6.5
Change back to the tiddlywiki.com directory.
Pull down the tiddlywiki.com content form TiddlySpace by invoking the `pull.sh` script:
./pull.sh
Edit the build script `bld` setting the correct version number for TiddlyWiki.
Invoke the build script:
./bld
You now need to generate the TiddlyWiki RSS file. To do this open the TiddlyWiki file index.html in Firefox, ensure the AdvancedOption "Generate an RSS feed when saving changes" is set, and then save the TiddlyWiki. Doing this also causes TiddlyWiki to generate some static HTML for display when Javascript is not enabled.
Edit the upload script `upload` setting the correct version number for TiddlyWiki.
Finally you need to upload the TiddlyWiki files to tiddlywiki.com. If this is the first time you are uploading, then you will need to create a `tmp` directory on tiddlywiki.com:
ssh user@tiddlywiki.com
[enter your password when prompted]
mkdir tmp
exit
You can now upload the TiddlyWiki files, run the upload script:
./upload
You will be prompted for your password on several occasions during the upload process. To do this you will of course need an account on tiddlywiki.com. The upload script assumes your remote user name is the same as your local user name, if it is not then you may specify your remote user name as the first parameter to the upload script.
Migrated from http://svn.tiddlywiki.org on 20110719.

17
test/data/tiddlywiki.com/bld Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Usage:
# bld [release]
DEFAULT_RELEASE="2.6.5"
RELEASE=${1:-$DEFAULT_RELEASE}
DEST=$PWD/cooked/tiddlywiki.com
mkdir -p cooked
mkdir -p cooked/tiddlywiki.com
cook $PWD/index.html.recipe -d $DEST -o index.$RELEASE.html
cook $PWD/empty.html.recipe -d $DEST -o empty.$RELEASE.html
cp ../tiddlywiki/java/TiddlySaver.jar $DEST/TiddlySaver.jar
rm $DEST/empty.$RELEASE.zip
cp $DEST/empty.$RELEASE.html tmp/empty.html
zip -j $DEST/empty.$RELEASE.zip tmp/empty.html $DEST/TiddlySaver.jar
rm tmp/empty.html

View File

@ -0,0 +1 @@
recipe: ../tiddlywiki/tiddlywiki.html.recipe

14
test/data/tiddlywiki.com/ginsu Executable file
View File

@ -0,0 +1,14 @@
#!/bin/bash
#
# This is a sample ginsu script to be used with the tiddlywiki.com scripts
# Adjust this script and then install it somewhere on your $PATH, such as ~/bin.
#
# You will need to adjust COOKER_TRUNK below.
#
# Change this to where you have the cooker code installed
COOKER_TRUNK=$HOME/Documents/Code/GitHub/tiddlywiki/cooker
DEFAULT_FILENAME=index
FILENAME=${1:-$DEFAULT_FILENAME}
DEST=$PWD
RECIPE=$PWD/$FILENAME.html
ruby -C $COOKER_TRUNK ginsu.rb $RECIPE -d$DEST $2 $3 $4 $5

View File

@ -0,0 +1,3 @@
recipe: ../tiddlywiki/tiddlywikinonoscript.html.recipe
recipe: tiddlywiki-com-ref/split.recipe
recipe: tiddlywiki-com/split.recipe

View File

@ -0,0 +1,58 @@
#!/bin/sh
#
# this hack pulls down the wikis for each bag, splitting the wiki into tiddlers using ginsu
# long term plan is to use the "fat" JSON for a bag
#
set -e
export space
export dir
mkdir -p tmp
for space in tiddlywiki-com-ref tiddlywiki-com
do
mkdir -p $space
dir=tmp/${space}.html.0
curl -s http://${space}.tiddlyspace.com/bags/${space}_public/tiddlers.wiki > tmp/$space.html
# clear out the space directory so we can see deleted files when we commit
rm -f $space/*
# backup any existing exploded content
mkdir -p backups
[ -d $dir ] && mv $dir backups/$$
# split into tiddlers
(
cd tmp
ginsu $space > /dev/null
)
# convert .tiddler files into .tid files
(
cd "$dir"
tiddler2tid *.tiddler
find . -name \*.tid -o -name \*.js -o -name \*.meta |
while read file
do
sed -e '/^server.*: /d' -e '/^_hash:/d' < "$file" > "../../$space/$file"
done
)
# make recipe based on files in the space directory
(
cd $space
find . -name \*.tid -o -name \*.js |
grep -v '\.jpg\.' |
grep -v 'PageTemplate' |
grep -v 'SplashScreen' |
grep -v 'SiteSubtitle' |
sed 's/^/tiddler: /' > split.recipe
)
done
cook $PWD/index.html.recipe

View File

@ -0,0 +1,53 @@
#!/usr//bin/env perl
#
# convert .tiddler into .tid files
# useful for ginsu a TiddlyWiki, then HTTP PUT them to TiddlyWeb/TiddlySpaces
#
use strict;
sub read_file {
my ($filename) = @_;
undef $/;
local *FILE;
open FILE, "< $filename";
binmode(FILE, ":utf8");
my $c = <FILE>;
close FILE;
return $c;
}
foreach my $file (@ARGV) {
my $tid = $file;
my $text = "";
if ($file =~ /.tiddler$/) {
$tid =~ s/dler$//;
$text = read_file($file, encoding => 'utf8');
my $attrs = $text;
$attrs =~ s/\s*<div([^>]*)>.*$/$1/s;
$attrs =~ s/\s*(\w+)\s*=\s*["']([^"']*)["']\s*/$1: $2\n/gs;
$text =~ s/^\s*<div[^>]*>\s*<\s*pre>\s*(.*)\s*<\/pre\s*>\s*<\/div\s*>\s*$/$1/s;
$text = $attrs . "\n" . $text;
} elsif ($file =~ /.js$/) {
$tid =~ s/.js$/.tid/;
$text = read_file($file . ".meta") . "\n" . read_file($file);
}
if ($text) {
print "$tid\n";
open(FILE, "> $tid");
binmode(FILE, ":utf8");
print FILE $text;
close(FILE);
}
}

70
test/data/tiddlywiki.com/upload Executable file
View File

@ -0,0 +1,70 @@
#!/usr/bin/env bash
# Usage:
# upload [user] [release] [cleanup]
# default values
DEFAULT_RELEASE="2.6.5"
REMOTE_USER=${1:-$USER}
RELEASE=${2:-$DEFAULT_RELEASE}
DEST=$PWD/cooked/tiddlywiki.com
HOST="tiddlywiki.com"
DIR="/var/www/www.tiddlywiki.com/htdocs"
ARCHIVE_DIR="$DIR/archive"
OWNER="www-data:www-data"
PERM="664"
# setPermissions()
# Usage:
# setPermissions file
function setPermissions() {
COMMANDS="$COMMANDS sudo chown $OWNER $1;"
COMMANDS="$COMMANDS sudo chmod $PERM $1;"
}
# upload files to temporary folder
echo
echo "uploading files"
echo
FILES="$DEST/index.$RELEASE.html $DEST/index.$RELEASE.xml $DEST/empty.$RELEASE.html $DEST/TiddlySaver.jar $DEST/empty.$RELEASE.zip"
scp $FILES "$REMOTE_USER@$HOST:./tmp/"
# transfer files to their respective folders
echo
echo "transferring files"
echo
COMMANDS="ssh $REMOTE_USER@$HOST"
# Index
COMMANDS="$COMMANDS sudo cp ./tmp/index.$RELEASE.html $ARCHIVE_DIR/;"
setPermissions "$ARCHIVE_DIR/index.$RELEASE.html"
COMMANDS="$COMMANDS sudo mv ./tmp/index.$RELEASE.html $DIR/index.html;"
setPermissions "$DIR/index.html"
COMMANDS="$COMMANDS sudo mv ./tmp/index.$RELEASE.xml $DIR/index.xml;"
setPermissions "$DIR/index.xml"
# Empty
COMMANDS="$COMMANDS sudo cp ./tmp/empty.$RELEASE.html $ARCHIVE_DIR/;"
setPermissions "$ARCHIVE_DIR/empty.$RELEASE.html"
COMMANDS="$COMMANDS sudo cp ./tmp/empty.$RELEASE.html $DIR/empty.html;"
setPermissions "$DIR/empty.html"
# Upgrade
COMMANDS="$COMMANDS sudo mv ./tmp/empty.$RELEASE.html $DIR/upgrade/index.html;"
setPermissions "$DIR/upgrade/index.html"
# TiddlySaver
COMMANDS="$COMMANDS sudo mv ./tmp/TiddlySaver.jar $DIR/TiddlySaver.jar;"
setPermissions "$DIR/TiddlySaver.jar"
# ZIP package
COMMANDS="$COMMANDS sudo mv ./tmp/empty.$RELEASE.zip $DIR/empty.zip;"
setPermissions "$DIR/empty.zip"
# execute
$COMMANDS
# cleanup
if [ "$3" = "true" ]; then
echo "cleaning up (removing cooked files)"
echo "removing index.$RELEASE.html"
rm "index.$RELEASE.html"
echo "removing empty.$RELEASE.html"
rm "empty.$RELEASE.html"
echo "removing TiddlySaver.jar"
rm "TiddlySaver.jar"
fi

1
test/data/tiddlywiki/ALPHA Executable file
View File

@ -0,0 +1 @@
2.6.6.A1

23
test/data/tiddlywiki/Makefile Executable file
View File

@ -0,0 +1,23 @@
# Start at a Makefile or managing build activities.
# Expects a 'cook' script somewhere on the $PATH.
# See 'cook' in this directory for a sample you can use.
# For now users the OSX specific "open" to run a test file. This
# will need to change.
#
clean:
rm cooked/*.html || true
rm cooked/*.jar || true
rm cooked/*.js || true
rmdir cooked || true
test: clean tests.html
ln -sf test/recipes/sample.txt .
open cooked/tests.html
tests.html:
mkdir -p cooked
cook $(PWD)/test/recipes/tests.html.recipe -d $(PWD)/cooked -o tests.html
alpha:
./bldalpha

75
test/data/tiddlywiki/README.md Executable file
View File

@ -0,0 +1,75 @@
TiddlyWiki
==========
https://github.com/TiddlyWiki/tiddlywiki
Description
-----------
This is the master repository for the core of TiddlyWiki. It is for the development and maintenance of TiddlyWiki.
If you simply wish to use TiddlyWiki, it is easiest to download it from: http://tiddlywiki.com/
This site also gives details about TiddlyWiki.
TiddlyWiki code and issues used to be stored at http://svn.tiddlywiki.org and http://trac.tiddlywiki.org .
Installation
------------
Install the [git](http://git-scm.com/download) version control system, if you do not already have it.
Install the [ruby](http://www.ruby-lang.org/en/downloads/) programming language, if you do not already have it. Ruby is required for some of the TiddlyWiki tools (cook and ginsu).
TiddlyWiki has 4 important parallel repositories:
1. [tiddlywiki](https://github.com/TiddlyWiki/tiddlywiki), this includes the source and test code for TiddlyWiki itself.
2. [cooker](https://github.com/TiddlyWiki/cooker), this includes the tool for building a TiddlyWiki from a set of tiddlers (`cook`) and the tool for splitting a TiddlyWiki into separate tiddlers (`ginsu`). You need to download this repository for any TiddlyWiki development.
3. [translations](https://github.com/TiddlyWiki/translations), this includes the translations of TiddlyWiki into a number of different languages.
4. [tiddlywiki.com](https://github.com/TiddlyWiki/tiddlywiki.com), this includes what is required to build and upload the http://tiddlywiki.com website.
To do any serious work on TiddlyWiki you will probably want to download all four of these repositories. They should be downloaded into parallel directories, since some of the build scripts used relative links to the other repositories:
git clone git@github.com:TiddlyWiki/tiddlywiki.git
git clone git@github.com:TiddlyWiki/cooker.git
git clone git@github.com:TiddlyWiki/tiddlywiki.com.git
git clone git@github.com:TiddlyWiki/translations.git
Next you need to set up `cook`. Copy the `cook` script file to somewhere that is on your path. Edit this file according to the instructions in the file.
Building and testing
--------------------
There is a `Makefile` for managing testing. To build and execute the TiddlyWiki tests, type:
make test
Note that, depending on your machine configuration, the tests may take a while to run (perhaps as long as a 30 seconds to a minute).
To set the version number of the alpha build output files edit the file `ALPHA`. This should normally be set to the same version as in the TiddlyWiki Version.js file.
To build an alpha version of TiddlyWiki incorporating any changes you have made, run the `bldalpha` script by typing:
./bldalpha
Contributing
------------
Pull requests for feature requests/bug fixes are being accepted for this project. Pull requests should be accompanied by tests. If no tests existed for the given functionality previously, please include these in your contribution to ensure that the TiddlyWiki code base is as reliable as possible going forward. Any pull requests without tests will not generally be folded into the core codebase. See https://github.com/TiddlyWiki/tiddlywiki/wiki for more information.
License
-------
TiddlyWiki is Copyright 2011 UneMesa Assocation
It is licensed under a BSD License.

21
test/data/tiddlywiki/bldalpha Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Usage:
# bldalpha [release]
# Requires a cook script on $PATH.
# See 'cook' in this directory for a sample.
DEFAULT_RELEASE=`cat ALPHA`
OUTPUT_DIR=$PWD/cooked
mkdir -p $OUTPUT_DIR
RELEASE=${1:-$DEFAULT_RELEASE}
RECIPE=$PWD/tiddlywiki.html.recipe
RECIPE_EXT_JS=$PWD/tiddlywiki_externaljs.html.recipe
RECIPE_EXT_JS_TS=$PWD/tiddlywiki_externaljs_tiddlyspace_alpha.html.recipe
cook $RECIPE -d $OUTPUT_DIR -o tiddlywiki.$RELEASE.html
cp java/TiddlySaver.jar $OUTPUT_DIR
cook $RECIPE -d $OUTPUT_DIR -o tiddlywiki_compressed.$RELEASE.html -cr -Cr -Dr
cook $RECIPE -d $OUTPUT_DIR -o twcore.$RELEASE.js -j
cook $RECIPE_EXT_JS -d $OUTPUT_DIR -o tiddlywiki_externaljs.$RELEASE.html
cook $RECIPE_EXT_JS_TS -d $OUTPUT_DIR -o tiddlywiki_externaljs_tiddlyspace.$RELEASE.html

18
test/data/tiddlywiki/bldxjs Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Build version of TiddlyWiki with external javascript
# Usage:
# bldxjs [release]
DEFAULT_RELEASE=2.6.3.A2
RELEASE=${1:-$DEFAULT_RELEASE}
DEST=$PWD
RECIPE=$PWD/tiddlywiki.html.recipe
RECIPE_EXT_JS=$PWD/tiddlywiki_externaljs.html.recipe
RECIPE_EXT_JS_TS=$PWD/tiddlywiki_externaljs_tiddlyspace_alpha.html.recipe
ruby -Ku -C ../tools/cooker cook.rb $RECIPE -d$DEST -q -j -o twcore.$RELEASE.js $2 $3 $4 $5
cp -f twcore.$RELEASE.js twcore.js
cp -f jquery/jquery.js jquery.js
cp -f jquery/plugins/jQuery.twStylesheet.js jQuery.twStylesheet.js
ruby -Ku -C ../tools/cooker cook.rb $RECIPE_EXT_JS -d$DEST -q -o tiddlywiki_externaljs.$RELEASE.html$2 $3 $4 $5
ruby -Ku -C ../tools/cooker cook.rb $RECIPE_EXT_JS_TS -d$DEST -q -o tiddlywiki_externaljs_tiddlyspace.$RELEASE.html$2 $3 $4 $5

21
test/data/tiddlywiki/cook Executable file
View File

@ -0,0 +1,21 @@
#!/bin/sh
# This is a sample cook script to be used with the build scripts
# and Makefile for TiddlyWiki. Adjust this script and then install
# it somewhere on your $PATH, such as ~/bin.
#
# You will need to adjust DEFAULT_TRUNK and COOKER_TRUNK below.
# change this to where your tiddlywiki repo lives,
# unless you have TW_TRUNKDIR set.
DEFAULT_TRUNK=$HOME/Documents/Code/Github/tiddlywiki
# Change this to where you have the cooker code installed
COOKER_TRUNK=$HOME/Documents/Code/Github/tiddlywiki/cooker
if [ -z "$TW_TRUNKDIR" ]
then
export TW_TRUNKDIR=$DEFAULT_TRUNK
fi
RECIPE=$1 && shift
ruby -Ku -C $COOKER_TRUNK cook.rb $RECIPE "$@"

View File

@ -0,0 +1,44 @@
//--
//-- Deprecated Crypto functions and associated conversion routines.
//-- Use the jQuery.encoding functions directly instead.
//--
// Crypto 'namespace'
function Crypto() {}
// Convert a string to an array of big-endian 32-bit words
Crypto.strToBe32s = function(str)
{
return jQuery.encoding.strToBe32s(str);
};
// Convert an array of big-endian 32-bit words to a string
Crypto.be32sToStr = function(be)
{
return jQuery.encoding.be32sToStr(be);
};
// Convert an array of big-endian 32-bit words to a hex string
Crypto.be32sToHex = function(be)
{
return jQuery.encoding.be32sToHex(be);
};
// Return, in hex, the SHA-1 hash of a string
Crypto.hexSha1Str = function(str)
{
return jQuery.encoding.digests.hexSha1Str(str);
};
// Return the SHA-1 hash of a string
Crypto.sha1Str = function(str)
{
return jQuery.encoding.digests.sha1Str(str);
};
// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words
Crypto.sha1 = function(x,blen)
{
return jQuery.encoding.digests.sha1(x,blen);
};

View File

@ -0,0 +1,90 @@
//--
//-- Deprecated code
//--
// @Deprecated: Use createElementAndWikify and this.termRegExp instead
config.formatterHelpers.charFormatHelper = function(w)
{
w.subWikify(createTiddlyElement(w.output,this.element),this.terminator);
};
// @Deprecated: Use enclosedTextHelper and this.lookaheadRegExp instead
config.formatterHelpers.monospacedByLineHelper = function(w)
{
var lookaheadRegExp = new RegExp(this.lookahead,"mg");
lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = lookaheadRegExp.exec(w.source);
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var text = lookaheadMatch[1];
if(config.browser.isIE)
text = text.replace(/\n/g,"\r");
createTiddlyElement(w.output,"pre",null,null,text);
w.nextMatch = lookaheadRegExp.lastIndex;
}
};
// @Deprecated: Use <br> or <br /> instead of <<br>>
config.macros.br = {};
config.macros.br.handler = function(place)
{
createTiddlyElement(place,"br");
};
// Find an entry in an array. Returns the array index or null
// @Deprecated: Use indexOf instead
Array.prototype.find = function(item)
{
var i = this.indexOf(item);
return i == -1 ? null : i;
};
// Load a tiddler from an HTML DIV. The caller should make sure to later call Tiddler.changed()
// @Deprecated: Use store.getLoader().internalizeTiddler instead
Tiddler.prototype.loadFromDiv = function(divRef,title)
{
return store.getLoader().internalizeTiddler(store,this,title,divRef);
};
// Format the text for storage in an HTML DIV
// @Deprecated Use store.getSaver().externalizeTiddler instead.
Tiddler.prototype.saveToDiv = function()
{
return store.getSaver().externalizeTiddler(store,this);
};
// @Deprecated: Use store.allTiddlersAsHtml() instead
function allTiddlersAsHtml()
{
return store.allTiddlersAsHtml();
}
// @Deprecated: Use refreshPageTemplate instead
function applyPageTemplate(title)
{
refreshPageTemplate(title);
}
// @Deprecated: Use story.displayTiddlers instead
function displayTiddlers(srcElement,titles,template,unused1,unused2,animate,unused3)
{
story.displayTiddlers(srcElement,titles,template,animate);
}
// @Deprecated: Use story.displayTiddler instead
function displayTiddler(srcElement,title,template,unused1,unused2,animate,unused3)
{
story.displayTiddler(srcElement,title,template,animate);
}
// @Deprecated: Use functions on right hand side directly instead
var createTiddlerPopup = Popup.create;
var scrollToTiddlerPopup = Popup.show;
var hideTiddlerPopup = Popup.remove;
// @Deprecated: Use right hand side directly instead
var regexpBackSlashEn = new RegExp("\\\\n","mg");
var regexpBackSlash = new RegExp("\\\\","mg");
var regexpBackSlashEss = new RegExp("\\\\s","mg");
var regexpNewLine = new RegExp("\n","mg");
var regexpCarriageReturn = new RegExp("\r","mg");

View File

@ -0,0 +1,20 @@
//--
//-- Deprecated FileAdaptor functions
//--
FileAdaptor.loadTiddlyWikiCallback = function(status,context,responseText,url,xhr)
{
context.status = status;
if(!status) {
context.statusText = "Error reading file";
} else {
//# Load the content into a TiddlyWiki() object
context.adaptor.store = new TiddlyWiki();
if(!context.adaptor.store.importTiddlyWiki(responseText)) {
context.statusText = config.messages.invalidFileError.format([url]);
context.status = false;
}
}
context.complete(context,context.userParams);
};

View File

@ -0,0 +1,26 @@
//--
//-- Deprecated HTTP request code
//-- Use the jQuery ajax functions directly instead
//--
//# Load a file over http
//# url - the source url
//# callback - function to call when there is a response
//# params - parameter object that gets passed to the callback for storing it's state
//# Return value is the underlying XMLHttpRequest object, or a string if there was an error
//# Callback function is called like this:
//# callback(status,params,responseText,xhr)
//# status - true if OK, false if error
//# params - the parameter object provided to loadRemoteFile()
//# responseText - the text of the file
//# xhr - the underlying XMLHttpRequest object
function loadRemoteFile(url,callback,params)
{
return httpReq("GET",url,callback,params);
}
function doHttp(type,url,data,contentType,username,password,callback,params,headers,allowCache)
{
return httpReq(type,url,callback,params,headers,data,contentType,username,password,allowCache);
}

View File

@ -0,0 +1,16 @@
//--
//-- Deprecated Number functions
//--
// @Deprecated: no direct replacement, since not used in core code
// Clamp a number to a range
Number.prototype.clamp = function(min,max)
{
var c = this;
if(c < min)
c = min;
if(c > max)
c = max;
return Number(c);
};

View File

@ -0,0 +1,29 @@
//--
//-- Deprecated String functions
//--
// @Deprecated: no direct replacement, since not used in core code
String.prototype.toJSONString = function()
{
// Convert a string to it's JSON representation by encoding control characters, double quotes and backslash. See json.org
var m = {
'\b': '\\b',
'\f': '\\f',
'\n': '\\n',
'\r': '\\r',
'\t': '\\t',
'"' : '\\"',
'\\': '\\\\'
};
var replaceFn = function(a,b) {
var c = m[b];
if(c)
return c;
c = b.charCodeAt();
return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
};
if(/["\\\x00-\x1f]/.test(this))
return '"' + this.replace(/([\x00-\x1f\\"])/g,replaceFn) + '"';
return '"' + this + '"';
};

View File

@ -0,0 +1,22 @@
//--
//-- Deprecated Tiddler code
//--
// @Deprecated: Use tiddlerToRssItem(tiddler,uri) instead
Tiddler.prototype.toRssItem = function(uri)
{
return tiddlerToRssItem(this,uri);
};
// @Deprecated: Use "<item>\n" + tiddlerToRssItem(tiddler,uri) + "\n</item>" instead
Tiddler.prototype.saveToRss = function(uri)
{
return "<item>\n" + tiddlerToRssItem(this,uri) + "\n</item>";
};
// @Deprecated: Use jQuery.encoding.digests.hexSha1Str instead
Tiddler.prototype.generateFingerprint = function()
{
return "0x" + Crypto.hexSha1Str(this.text);
};

View File

@ -0,0 +1,38 @@
//--
//-- Deprecated utility functions
//-- Use the jQuery functions directly instead
//--
// Remove all children of a node
function removeChildren(e)
{
jQuery(e).empty();
}
// Remove a node and all it's children
function removeNode(e)
{
jQuery(e).remove();
}
// Return the content of an element as plain text with no formatting
function getPlainText(e)
{
return jQuery(e).text();
}
function addClass(e,className)
{
jQuery(e).addClass(className);
}
function removeClass(e,className)
{
jQuery(e).removeClass(className);
}
function hasClass(e,className)
{
return jQuery(e).hasClass(className);
}

View File

@ -0,0 +1,16 @@
//--
//-- Deprecated Wikifier code
//--
//# Wikify a named tiddler to plain text
function wikifyPlain(title,theStore,limit)
{
if(!theStore)
theStore = store;
if(theStore.tiddlerExists(title) || theStore.isShadowTiddler(title)) {
return wikifyPlainText(theStore.getTiddlerText(title),limit,tiddler);
} else {
return "";
}
}

View File

@ -0,0 +1,10 @@
jsdeprecated: Crypto.js
jsdeprecated: Deprecated.js
jsdeprecated: FileAdaptor.js
jsdeprecated: Http.js
jsdeprecated: Strings.js
jsdeprecated: Tiddler.js
jsdeprecated: Numbers.js
jsdeprecated: Utilities.js
jsdeprecated: Wikifier.js

View File

@ -0,0 +1,29 @@
TiddlyWiki created by Jeremy Ruston, (jeremy [at] osmosoft [dot] com)
Copyright (c) Jeremy Ruston 2004-2007
Copyright (c) UnaMesa Association 2007-2011
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
Neither the name of the UnaMesa Association nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.

View File

@ -0,0 +1,3 @@
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jQuery.twStylesheet.js"></script>
<script type="text/javascript" src="twcore.js"></script>

View File

@ -0,0 +1,3 @@
<script type="text/javascript" src="/bags/common/tiddlers/jquery.js"></script>
<script type="text/javascript" src="/bags/common/tiddlers/jQuery.twStylesheet.js"></script>
<script type="text/javascript" src="/bags/common/tiddlers/twcore.js"></script>

View File

@ -0,0 +1,3 @@
<script type="text/javascript" src="/bags/common/tiddlers/alpha_jquery.js"></script>
<script type="text/javascript" src="/bags/common/tiddlers/alpha_jQuery.twStylesheet.js"></script>
<script type="text/javascript" src="/bags/common/tiddlers/alpha_twcore.js"></script>

View File

@ -0,0 +1,3 @@
<script type="text/javascript" src="/bags/common/tiddlers/beta_jquery.js"></script>
<script type="text/javascript" src="/bags/common/tiddlers/beta_jQuery.twStylesheet.js"></script>
<script type="text/javascript" src="/bags/common/tiddlers/beta_twcore.js"></script>

View File

@ -0,0 +1,3 @@
<div id="javascriptWarning">
This page requires JavaScript to function properly.<br /><br />If you are using Microsoft Internet Explorer you may need to click on the yellow bar above and select 'Allow Blocked Content'. You must then click 'Yes' on the following security warning.
</div>

View File

@ -0,0 +1 @@
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/>

View File

@ -0,0 +1,5 @@
template: tiddlywiki.template.html
copyright: copyright.txt
style: style.txt
noscript: noscript.txt
jsext: tiddlysaver.txt

View File

@ -0,0 +1,3 @@
template: tiddlywiki.template.html
copyright: copyright.txt
style: style.txt

View File

@ -0,0 +1,7 @@
#saveTest {display:none;}
#messageArea {display:none;}
#copyright {display:none;}
#storeArea {display:none;}
#storeArea div {padding:0.5em; margin:1em 0em 0em 0em; border-color:#fff #666 #444 #ddd; border-style:solid; border-width:2px; overflow:auto;}
#shadowArea {display:none;}
#javascriptWarning {width:100%; text-align:center; font-weight:bold; background-color:#dd1100; color:#fff; padding:1em 0em;}

View File

@ -0,0 +1,6 @@
<script type="text/javascript">
//<![CDATA[
if(useJavaSaver)
document.write("<applet style='position:absolute;left:-1px' name='TiddlySaver' code='TiddlySaver.class' archive='TiddlySaver.jar' width='1' height='1'></applet>");
//]]>
</script>

View File

@ -0,0 +1,86 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script id="versionArea" type="text/javascript">
//<![CDATA[
<!--@@version@@-->
//]]>
</script>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="copyright" content="
&lt;!--@@copyright@@--&gt;
" />
<!--PRE-HEAD-START-->
<!--@@prehead@@-->
<!--PRE-HEAD-END-->
<title>
<!--@@title@@-->
</title>
<style id="styleArea" type="text/css">
<!--@@style@@-->
</style>
<!--POST-HEAD-START-->
<!--@@posthead@@-->
<!--POST-HEAD-END-->
</head>
<body onload="main();" onunload="if(window.unload) unload();">
<!--PRE-BODY-START-->
<!--@@prebody@@-->
<!--PRE-BODY-END-->
<div id="copyright">
Welcome to TiddlyWiki created by Jeremy Ruston; Copyright &copy; 2004-2007 Jeremy Ruston, Copyright &copy; 2007-2011 UnaMesa Association
</div>
<noscript>
<!--@@noscript@@-->
</noscript>
<div id="saveTest"></div>
<div id="backstageCloak"></div>
<div id="backstageButton"></div>
<div id="backstageArea"><div id="backstageToolbar"></div></div>
<div id="backstage">
<div id="backstagePanel"></div>
</div>
<div id="contentWrapper"></div>
<div id="contentStash"></div>
<div id="shadowArea">
<!--@@shadow@@-->
</div>
<!--POST-SHADOWAREA-->
<div id="storeArea">
<!--@@tiddler@@-->
<!--@@plugin@@-->
<!--@@posttiddlers@@-->
</div>
<!--POST-STOREAREA-->
<!--POST-BODY-START-->
<!--@@postbody@@-->
<!--POST-BODY-END-->
<script id="jsArea" type="text/javascript">
//<![CDATA[
<!--@@prejs@@-->
<!--@@js@@-->
<!--@@postjs@@-->
//]]>
</script>
<!--@@jsext@@-->
<script id="jsdeprecatedArea" type="text/javascript">
//<![CDATA[
<!--@@jsdeprecated@@-->
//]]>
</script>
<script id="jslibArea" type="text/javascript">
//<![CDATA[
<!--@@jslib@@-->
//]]>
</script>
<script id="jqueryArea" type="text/javascript">
//<![CDATA[
<!--@@jquery@@-->
//]]>
</script>
<!--POST-SCRIPT-START-->
<!--@@postscript@@-->
<!--POST-SCRIPT-END-->
</body>
</html>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,71 @@
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.security.AccessController;
import java.security.PrivilegedAction;
public class TiddlySaver extends java.applet.Applet {
public String loadFile(final String filename, final String charset) {
return (String)AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
try {
if (charset.length() == 0) {
StringBuffer data = new StringBuffer();
BufferedReader r = new BufferedReader(new FileReader(filename));
String line;
while ((line = r.readLine()) != null) data.append(line).append("\n");
r.close();
return data.toString();
} else {
File f = new File(filename);
FileInputStream i = new FileInputStream(f);
byte[] b = new byte[(f.length() > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)f.length()];
int offset = 0;
int num = 0;
while (offset < b.length && (num = i.read(b, offset, b.length - offset)) >= 0) {
offset += num;
}
i.close();
return new String(b, 0, offset, charset);
}
} catch (Exception x) {
x.printStackTrace();
return null;
}
}
});
}
public int saveFile(final String filename, final String charset, final String data) {
return ((Integer)AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
try {
if (charset.length() == 0) {
int e, s = 0;
BufferedWriter w = new BufferedWriter(new FileWriter(filename));
do {
e = data.indexOf('\n', s);
if (e == -1) e = data.length();
w.write(data, s, e - s);
w.newLine();
s = e + 1;
} while (s < data.length());
w.close();
return new Integer(1);
} else {
FileOutputStream o = new FileOutputStream(filename);
o.write(data.getBytes(charset));
o.close();
return new Integer(1);
}
} catch (Exception x) {
x.printStackTrace();
return new Integer(0);
}
}
})).intValue();
}
}

Binary file not shown.

View File

@ -0,0 +1,38 @@
-----BEGIN PKCS #7 SIGNED DATA-----
MIAGCSqGSIb3DQEHAqCAMIACAQExADALBgkqhkiG9w0BBwGggDCCAyIwggKLoAMC
AQICEEtycpHmJVBWKTR1fltuZYgwDQYJKoZIhvcNAQEFBQAwVTELMAkGA1UEBhMC
WkExJTAjBgNVBAoTHFRoYXd0ZSBDb25zdWx0aW5nIChQdHkpIEx0ZC4xHzAdBgNV
BAMTFlRoYXd0ZSBDb2RlIFNpZ25pbmcgQ0EwHhcNMTAwMzA0MDAwMDAwWhcNMTIw
MzAzMjM1OTU5WjBvMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTES
MBAGA1UEBxMJUGFsbyBBbHRvMRAwDgYDVQQKFAdVbmFNZXNhMRMwEQYDVQQLFApU
aWRkbHlXaWtpMRAwDgYDVQQDFAdVbmFNZXNhMIGfMA0GCSqGSIb3DQEBAQUAA4GN
ADCBiQKBgQDy7syNTVAWoApezeC5oKYWsS19uO87TgHcwqAG2R6U8pBVuHoKpzL9
YpOnwIL3p+l/fHy5T8ghmxdX4d73RtHiHMFIL6ABrSvt/WxUKtyImleBv521pK5P
S0sdBJWgWCSIV76YKxHdHTZfU83rNih1IGzxP+96MflXh4wPsVuvcwIDAQABo4HY
MIHVMAwGA1UdEwEB/wQCMAAwPgYDVR0fBDcwNTAzoDGgL4YtaHR0cDovL2NybC50
aGF3dGUuY29tL1RoYXd0ZUNvZGVTaWduaW5nQ0EuY3JsMB8GA1UdJQQYMBYGCCsG
AQUFBwMDBgorBgEEAYI3AgEWMB0GA1UdBAQWMBQwDjAMBgorBgEEAYI3AgEWAwIH
gDAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnRoYXd0
ZS5jb20wEQYJYIZIAYb4QgEBBAQDAgQQMA0GCSqGSIb3DQEBBQUAA4GBAHgyGc8J
hNHrtizy6e4bWDlYBwVJiGPe1h0qTNrL9qGexHfF9Msik9CYCFHHv0NlatkP0g0L
ZNkR4pTg7QFPBxfV/fh74SxnzadgyX5vsuohC3n7r7XLZy+vh/jeZR2Qt9QTkyxY
AONfQLWpTUvFy6Rqb6KcPmW70s6t7NORkWF1MIIDTjCCAregAwIBAgIBCjANBgkq
hkiG9w0BAQUFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2Fw
ZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGlu
ZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEh
MB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkB
FhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29tMB4XDTAzMDgwNjAwMDAwMFoXDTEz
MDgwNTIzNTk1OVowVTELMAkGA1UEBhMCWkExJTAjBgNVBAoTHFRoYXd0ZSBDb25z
dWx0aW5nIChQdHkpIEx0ZC4xHzAdBgNVBAMTFlRoYXd0ZSBDb2RlIFNpZ25pbmcg
Q0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMa4uSdgrwvjkWll236N7ZHm
qvG+1e3+bdQsf9Fwd/smmVe03T8wuNwh6miNgZL8LkuRNYQg8tpKurT85tqI8iDF
IZIJR5WgCRymeb6xTB388YpuVNJpofFMkzpB/n3UZHtjRfdgYB0xHaTp0w+L+24m
JLOo/+XlkNS0wtxQYK5ZAgMBAAGjgbMwgbAwEgYDVR0TAQH/BAgwBgEB/wIBADBA
BgNVHR8EOTA3MDWgM6Axhi9odHRwOi8vY3JsLnRoYXd0ZS5jb20vVGhhd3RlUHJl
bWl1bVNlcnZlckNBLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwMw
DgYDVR0PAQH/BAQDAgEGMCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFQcml2YXRl
TGFiZWwyLTE0NDANBgkqhkiG9w0BAQUFAAOBgQB2spzuE58b9i00kpRFczTcjmsu
XPxMfYnrw2jx15kPLh0XyLUWi77NigUG8hlJOgNbBckgjm1S4XaBoMNliiJn5BxT
UzdGv7zXL+t7ntAURWxAIQjiXXV2ZjAe9N+Cii+986IMvx3bnxSimnI3TbB3SOhK
PwnOVRks7+YHJOGv7AAAMQAAAAAAAAA=
-----END PKCS #7 SIGNED DATA-----

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,5 @@
javac -source 1.2 -target 1.2 -g:none TiddlySaver.java
jar cf TiddlySaver.jar TiddlySaver*.class
# assume you have UnaMesa.keystore in the same directory
# and Passphrase for keystore
jarsigner -keystore UnaMesa.keystore TiddlySaver.jar BidiX

View File

@ -0,0 +1,323 @@
Readme file for signing TiddlySaver applet
for verifying see verify.readme file
1 - HISTORY
2010 03 06 - BidiX : Signing TiddlySaver.jar with a new Signing Certificate
The files were updated with the new process used for signing (sorry my Macbook was configured in French)
New signed TiddlySaver.jar was tested with Safari 4.0.4 on MacOS 10.6.2
2008 04 06 - BidiX : documentation
2008 04 06 - BidiX : create TiddlySaverVerify.keystore
2008 03 27 - BidiX : Signing TiddlySaver.jar
2008 03 26 - BidiX : obtaining UnaMesa Signing Certificate
2008 03 17 - BidiX : Issuing a certificate request to Thawte with a BidiX CSR
2003 03 12 - BidiX : Create UnaMesa.keystore with BidiX alias and Private key
2 - UNAMESA.KEYSTORE CREATION
Using this command:
----------------
> keytool -genkey -keyalg RSA -alias BidiX -keystore UnaMesa.keystore
Tapez le mot de passe du Keystore :
Ressaisissez le nouveau mot de passe :
Quels sont vos pr?nom et nom ?
[Unknown] : BidiX
Quel est le nom de votre unit? organisationnelle ?
[Unknown] : TiddlyWiki
Quelle est le nom de votre organisation ?
[Unknown] : UnaMesa
Quel est le nom de votre ville de r?sidence ?
[Unknown] : Palo Alto
Quel est le nom de votre ?tat ou province ?
[Unknown] : California
Quel est le code de pays ? deux lettres pour cette unit? ?
[Unknown] : US
Est-ce CN=BidiX, OU=TiddlyWiki, O=UnaMesa, L=Palo Alto, ST=California, C=US ?
[non] : OUI
Sp?cifiez le mot de passe de la cl? pour <BidiX>
(appuyez sur Entr?e s'il s'agit du mot de passe du Keystore) :
Ressaisissez le nouveau mot de passe :
---------------
For security reasons the Keystore is kept in a safe place in BidiX environment (BidiX @ bidix.info)
3 - CERTICATE REQUEST
Using this command :
--------------
> keytool -certreq -alias BidiX -file certreq -keystore UnaMesa.keystore -storepass "???"
> cat certreq
-----BEGIN NEW CERTIFICATE REQUEST-----
MIIBrTCCARYCAQAwbTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcT
...
sxoX+IbLVSs4Ye4HDqFodRkmehWBJsdWpQa/yji72pY+eA3fCgTt57VL+san9pPaLcwPfAiL23cD
R1j/y2RjQYLpE0PH+vQXn26xNeUDo2OONijyG0RLIX57yA==
-----END NEW CERTIFICATE REQUEST-----
---------------
Certificate received
-----BEGIN PKCS #7 SIGNED DATA-----
MIAGCSqGSIb3DQEHAqCAMIACAQExADALBgkqhkiG9w0BBwGggDCCAyIwggKLoAMC
...
PwnOVRks7+YHJOGv7AAAMQAAAAAAAAA=
-----END PKCS #7 SIGNED DATA-----
copied in UnaMesa-2.cer
4 - ADDING CERTICATE TO KEYSTORE
---------------
> keytool -import -alias BidiX -trustcacerts -file UnaMesa-2.cer -keystore UnaMesa.keystore
Tapez le mot de passe du Keystore :
R?ponse de certificat install?e dans le Keystore
---------------
List Keystore
---------------
> keytool -list -v -alias BidiX -keystore UnaMesa.keystore
Tapez le mot de passe du Keystore :
Nom d'alias : BidiX
Date de cr?ation : 6 mars 2010
Type dentr?e?: {0}
Longueur de cha?ne du certificat : 3
Certificat[1]:
Propri?taire?: CN=UnaMesa, OU=TiddlyWiki, O=UnaMesa, L=Palo Alto, ST=California, C=US
?metteur?: CN=Thawte Code Signing CA, O=Thawte Consulting (Pty) Ltd., C=ZA
Num?ro de s?rie?: 4b727291e62550562934757e5b6e6588
Valide du?: Thu Mar 04 01:00:00 CET 2010 au?: Sun Mar 04 00:59:59 CET 2012
Empreintes du certificat?:
MD5?: 1B:79:CE:47:BE:A9:E4:04:2A:DD:04:F5:BA:62:64:AD
SHA1?: 42:A9:6F:4D:C3:20:F8:7F:90:1A:1F:A5:66:92:ED:06:38:19:1E:D4
Nom de lalgorithme de signature?: {7}
Version?: {8}
Extensions?:
#1: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:false
PathLen: undefined
]
#2: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
[accessMethod: 1.3.6.1.5.5.7.48.1
accessLocation: URIName: http://ocsp.thawte.com]
]
#3: ObjectId: 2.5.29.4 Criticality=false
#4: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
[URIName: http://crl.thawte.com/ThawteCodeSigningCA.crl]
]]
#5: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
codeSigning
1.3.6.1.4.1.311.2.1.22
]
#6: ObjectId: 2.16.840.1.113730.1.1 Criticality=false
NetscapeCertType [
Object Signing
]
Certificat[2]:
Propri?taire?: CN=Thawte Code Signing CA, O=Thawte Consulting (Pty) Ltd., C=ZA
?metteur?: EMAILADDRESS=premium-server@thawte.com, CN=Thawte Premium Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA
Num?ro de s?rie?: a
Valide du?: Wed Aug 06 02:00:00 CEST 2003 au?: Tue Aug 06 01:59:59 CEST 2013
Empreintes du certificat?:
MD5?: D4:A7:BF:00:7B:6A:0C:20:D9:23:CD:5B:60:7B:7C:12
SHA1?: A7:06:BA:1E:CA:B6:A2:AB:18:69:9F:C0:D7:DD:8C:7D:E3:6F:29:0F
Nom de lalgorithme de signature?: {7}
Version?: {8}
Extensions?:
#1: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
Key_CertSign
Crl_Sign
]
#2: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:true
PathLen:0
]
#3: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
[URIName: http://crl.thawte.com/ThawtePremiumServerCA.crl]
]]
#4: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
clientAuth
codeSigning
]
#5: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
CN=PrivateLabel2-144
]
Certificat[3]:
Propri?taire?: EMAILADDRESS=premium-server@thawte.com, CN=Thawte Premium Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA
?metteur?: EMAILADDRESS=premium-server@thawte.com, CN=Thawte Premium Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA
Num?ro de s?rie?: 1
Valide du?: Thu Aug 01 02:00:00 CEST 1996 au?: Fri Jan 01 00:59:59 CET 2021
Empreintes du certificat?:
MD5?: 06:9F:69:79:16:66:90:02:1B:8C:8C:A2:C3:07:6F:3A
SHA1?: 62:7F:8D:78:27:65:63:99:D2:7D:7F:90:44:C9:FE:B3:F3:3E:FA:9A
Nom de lalgorithme de signature?: {7}
Version?: {8}
Extensions?:
#1: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:true
PathLen:2147483647
]
---------------
5 - SIGNING TIDDLYSAVER.JAR
Get TiddlySaver.jar from http://trac.tiddlywiki.org/browser/Trunk/core/java/TiddlySaver.jar.
TiddlySaver.jar contained classes compiled on Thu Dec 07 14:48:00 CET 2006
With UnaMesa.keystore in the current directory Signing jar on Sam 6 mar 2010 15:16:04 CET using this command :
---------------
> jarsigner -keystore UnaMesa.keystore TiddlySaver.jar BidiX
Enter Passphrase for keystore:
---------------
6 - VERIFYING SIGNATURE WITHOUT KEYSTORE
---------------
> jarsigner -verify -verbose TiddlySaver.jar
284 Thu Mar 27 07:59:12 CET 2008 META-INF/MANIFEST.MF
395 Sat Mar 06 15:16:04 CET 2010 META-INF/BIDIX.SF
2798 Sat Mar 06 15:16:04 CET 2010 META-INF/BIDIX.RSA
0 Thu Dec 07 14:48:00 CET 2006 META-INF/
sm 1271 Thu Dec 07 14:48:00 CET 2006 TiddlySaver$1.class
sm 1184 Thu Dec 07 14:48:00 CET 2006 TiddlySaver$2.class
sm 775 Thu Dec 07 14:48:00 CET 2006 TiddlySaver.class
s = signature was verified
m = entry is listed in manifest
k = at least one certificate was found in keystore
i = at least one certificate was found in identity scope
jar verified.
---------------
7 - CREATE TiddlySaverVerify.keystore KEYSTORE
export SigningCertificate
---------------
> keytool -export -alias BidiX -file UnaMesa-3.cer -keystore UnaMesa.keystore
Tapez le mot de passe du Keystore :
Certificat enregistr? dans le fichier <UnaMesa-3.cer>
---------------
create keystore "TiddlySaverVerify.keystore" with "tiddlywiki" as password and import SigningCertificate
---------------
> keytool -import -alias BidiX -keystore TiddlySaverVerify.keystore -storepass tiddlywiki -file UnaMesa-3.cer
Propri?taire?: CN=UnaMesa, OU=TiddlyWiki, O=UnaMesa, L=Palo Alto, ST=California, C=US
?metteur?: CN=Thawte Code Signing CA, O=Thawte Consulting (Pty) Ltd., C=ZA
Num?ro de s?rie?: 4b727291e62550562934757e5b6e6588
Valide du?: Thu Mar 04 01:00:00 CET 2010 au?: Sun Mar 04 00:59:59 CET 2012
Empreintes du certificat?:
MD5?: 1B:79:CE:47:BE:A9:E4:04:2A:DD:04:F5:BA:62:64:AD
SHA1?: 42:A9:6F:4D:C3:20:F8:7F:90:1A:1F:A5:66:92:ED:06:38:19:1E:D4
Nom de lalgorithme de signature?: {7}
Version?: {8}
Extensions?:
#1: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:false
PathLen: undefined
]
#2: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
[accessMethod: 1.3.6.1.5.5.7.48.1
accessLocation: URIName: http://ocsp.thawte.com]
]
#3: ObjectId: 2.5.29.4 Criticality=false
#4: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
[URIName: http://crl.thawte.com/ThawteCodeSigningCA.crl]
]]
#5: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
codeSigning
1.3.6.1.4.1.311.2.1.22
]
#6: ObjectId: 2.16.840.1.113730.1.1 Criticality=false
NetscapeCertType [
Object Signing
]
Faire confiance ? ce certificat ? [non] : Y
R?ponse incorrecte, recommencez
Faire confiance ? ce certificat ? [non] : oui
Certificat ajout? au Keystore
---------------
8 - VERIFYING SIGNATURE WITH TiddlySaverVerify.keystore
---------------
> jarsigner -verify -verbose -certs -keystore TiddlySaverVerify.keystore TiddlySaver.jar
284 Thu Mar 27 07:59:12 CET 2008 META-INF/MANIFEST.MF
395 Sat Mar 06 15:16:04 CET 2010 META-INF/BIDIX.SF
2798 Sat Mar 06 15:16:04 CET 2010 META-INF/BIDIX.RSA
0 Thu Dec 07 14:48:00 CET 2006 META-INF/
smk 1271 Thu Dec 07 14:48:00 CET 2006 TiddlySaver$1.class
X.509, CN=UnaMesa, OU=TiddlyWiki, O=UnaMesa, L=Palo Alto, ST=California, C=US (bidix)
[certificate is valid from 04/03/10 01:00 to 04/03/12 00:59]
X.509, CN=Thawte Code Signing CA, O=Thawte Consulting (Pty) Ltd., C=ZA
[certificate is valid from 06/08/03 02:00 to 06/08/13 01:59]
[KeyUsage extension does not support code signing]
X.509, EMAILADDRESS=premium-server@thawte.com, CN=Thawte Premium Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA
[certificate is valid from 01/08/96 02:00 to 01/01/21 00:59]
smk 1184 Thu Dec 07 14:48:00 CET 2006 TiddlySaver$2.class
X.509, CN=UnaMesa, OU=TiddlyWiki, O=UnaMesa, L=Palo Alto, ST=California, C=US (bidix)
[certificate is valid from 04/03/10 01:00 to 04/03/12 00:59]
X.509, CN=Thawte Code Signing CA, O=Thawte Consulting (Pty) Ltd., C=ZA
[certificate is valid from 06/08/03 02:00 to 06/08/13 01:59]
[KeyUsage extension does not support code signing]
X.509, EMAILADDRESS=premium-server@thawte.com, CN=Thawte Premium Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA
[certificate is valid from 01/08/96 02:00 to 01/01/21 00:59]
smk 775 Thu Dec 07 14:48:00 CET 2006 TiddlySaver.class
X.509, CN=UnaMesa, OU=TiddlyWiki, O=UnaMesa, L=Palo Alto, ST=California, C=US (bidix)
[certificate is valid from 04/03/10 01:00 to 04/03/12 00:59]
X.509, CN=Thawte Code Signing CA, O=Thawte Consulting (Pty) Ltd., C=ZA
[certificate is valid from 06/08/03 02:00 to 06/08/13 01:59]
[KeyUsage extension does not support code signing]
X.509, EMAILADDRESS=premium-server@thawte.com, CN=Thawte Premium Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA
[certificate is valid from 01/08/96 02:00 to 01/01/21 00:59]
s = signature was verified
m = entry is listed in manifest
k = at least one certificate was found in keystore
i = at least one certificate was found in identity scope
jar verified.
---------------

View File

@ -0,0 +1,2 @@
# assume TiddlySaverVerify.keystore and TiddlySaver.jar in the current directory
jarsigner -verify -verbose -certs -keystore TiddlySaverVerify.keystore -keypass tiddlywiki TiddlySaver.jar

View File

@ -0,0 +1,46 @@
Above the verifying command and the expected return:
> jarsigner -verify -verbose -certs -keystore TiddlySaverVerify.keystore TiddlySaver.jar
284 Thu Mar 27 07:59:12 CET 2008 META-INF/MANIFEST.MF
395 Sat Mar 06 15:16:04 CET 2010 META-INF/BIDIX.SF
2798 Sat Mar 06 15:16:04 CET 2010 META-INF/BIDIX.RSA
0 Thu Dec 07 14:48:00 CET 2006 META-INF/
smk 1271 Thu Dec 07 14:48:00 CET 2006 TiddlySaver$1.class
X.509, CN=UnaMesa, OU=TiddlyWiki, O=UnaMesa, L=Palo Alto, ST=California, C=US (bidix)
[certificate is valid from 04/03/10 01:00 to 04/03/12 00:59]
X.509, CN=Thawte Code Signing CA, O=Thawte Consulting (Pty) Ltd., C=ZA
[certificate is valid from 06/08/03 02:00 to 06/08/13 01:59]
[KeyUsage extension does not support code signing]
X.509, EMAILADDRESS=premium-server@thawte.com, CN=Thawte Premium Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA
[certificate is valid from 01/08/96 02:00 to 01/01/21 00:59]
smk 1184 Thu Dec 07 14:48:00 CET 2006 TiddlySaver$2.class
X.509, CN=UnaMesa, OU=TiddlyWiki, O=UnaMesa, L=Palo Alto, ST=California, C=US (bidix)
[certificate is valid from 04/03/10 01:00 to 04/03/12 00:59]
X.509, CN=Thawte Code Signing CA, O=Thawte Consulting (Pty) Ltd., C=ZA
[certificate is valid from 06/08/03 02:00 to 06/08/13 01:59]
[KeyUsage extension does not support code signing]
X.509, EMAILADDRESS=premium-server@thawte.com, CN=Thawte Premium Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA
[certificate is valid from 01/08/96 02:00 to 01/01/21 00:59]
smk 775 Thu Dec 07 14:48:00 CET 2006 TiddlySaver.class
X.509, CN=UnaMesa, OU=TiddlyWiki, O=UnaMesa, L=Palo Alto, ST=California, C=US (bidix)
[certificate is valid from 04/03/10 01:00 to 04/03/12 00:59]
X.509, CN=Thawte Code Signing CA, O=Thawte Consulting (Pty) Ltd., C=ZA
[certificate is valid from 06/08/03 02:00 to 06/08/13 01:59]
[KeyUsage extension does not support code signing]
X.509, EMAILADDRESS=premium-server@thawte.com, CN=Thawte Premium Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA
[certificate is valid from 01/08/96 02:00 to 01/01/21 00:59]
s = signature was verified
m = entry is listed in manifest
k = at least one certificate was found in keystore
i = at least one certificate was found in identity scope
jar verified.

4
test/data/tiddlywiki/jquery/jquery.js vendored Executable file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,43 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>jQuery.encoding.digests.sha1</title>
<link rel="stylesheet" type="text/css" href="styles/main.css">
</head>
<body>
<h1>jQuery.encoding.digests.sha1</h1>
<p>
This <a href="http://jquery.com">jQuery</a> plugin implements the SHA-1 cryptographic hash function.
</p>
<h2>Source</h2>
<p>
The source code is currently hosted in TiddlyWiki's
<a href="http://svn.tiddlywiki.org/Trunk/core/jquery/plugins/jQuery.encoding.digests.sha1.js">Subversion repository</a>.
</p>
<p>
<a href="http://groups.google.com/group/TiddlyWikiDev/">Feedback</a> is welcome.
</p>
<h2>API</h2>
<ul>
<li>
<p><code>$.encoding.digests.hexSha1Str(str)</code>: Return, in hex, the SHA-1 hash of a string</p>
</li>
<li>
<p><code>$.encoding.digests.sha1Str(str)</code>: Return the SHA-1 hash of a string</p>
</li>
<li>
<p><code>$.encoding.digests.sha1(x,blen)</code>: Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words</p>
</li>
</ul>
<p>(full documentation in the code comments)</p>
<h2>Demo</h2>
[TBD]
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>TiddlyWiki jQuery plugins</title>
<link rel="stylesheet" type="text/css" href="styles/main.css">
</head>
<body>
<h1>TiddlyWiki jQuery plugins</h1>
<p>
With <a href="http://jquery.com">jQuery</a> being integrated into the
<a href="http://tiddlywiki.com">TiddlyWiki</a> core, the community has
begun extracting TiddlyWiki functionality into generic components in
the form of jQuery plugins:
</p>
<ul>
<li>
<a href="twFile.html">jQuery.twFile</a>
</li>
<li>
<a href="twStylesheet.html">jQuery.twStylesheet</a>
</li>
<li>
<a href="encoding.digests.sha1.html">jQuery.encoding.digests.sha1.html</a>
</li>
</ul>
</body>
</html>

View File

@ -0,0 +1,78 @@
* {
margin: 0;
padding: 0;
}
html {
background-color: #000;
}
body {
width: 50%;
margin: 0 auto;
padding: 10px;
background-color: #FFF;
}
h1,
h2 {
margin-bottom: 10px;
}
h2 {
margin-top: 20px;
}
p,
ul {
margin-bottom: 0.5em;
}
ul {
margin-left: 1em;
}
ul ul {
margin-bottom: 0;
}
li p {
margin-bottom: 0.2em;
}
code {
color: #0A0;
}
fieldset,
legend {
border: 1px solid #AAA;
}
fieldset {
margin: 30px 10px 10px;
padding: 10px 5px 5px 10px;
}
legend,
.editor {
background-color: #EEE;
}
legend {
margin-top: -1em;
border-bottom: none;
padding: 1px 3px 0;
line-height: 1em;
}
fieldset textarea {
display: block;
width: 98%;
}
fieldset input {
width: 5em;
margin: 10px 10px 5px 0;
font-size: 1.1em;
}

View File

@ -0,0 +1,124 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>jQuery.twFile</title>
<link rel="stylesheet" type="text/css" href="styles/main.css">
</head>
<body>
<h1>jQuery.twFile</h1>
<p>
This <a href="http://jquery.com">jQuery</a> plugin provides access to
the local file system (for documents loaded from a <code>file://</code>
URI) to load and save file contents from the browser.
</p>
<p>
The code is based on <a href="http://tiddlywiki.com">TiddlyWiki</a>'s
self-saving capabilities.
</p>
<p id="TiddlySaver">
Note that the <a href="http://www.tiddlywiki.com/TiddlySaver.jar">TiddlySaver</a>
applet is required on Opera and WebKit-based browsers (Safari, Chrome).
The applet has to be present in the same folder as the respective HTML document.
</p>
<h2>Source</h2>
<p>
The source code is currently hosted in TiddlyWiki's
<a href="http://svn.tiddlywiki.org/Trunk/core/jquery/plugins/jQuery.twFile.js">Subversion repository</a>.
</p>
<p>
<a href="http://groups.google.com/group/TiddlyWikiDev/">Feedback</a> is welcome.
</p>
<h2>API Summary</h2>
<ul>
<li>
<p><code>$.twFile.load(filePath)</code>: load contents from file</p>
</li>
<li>
<p><code>$.twFile.save(filePath, content)</code>: save contents to file</p>
</li>
<li>
<p><code>$.twFile.copy(dest, source)</code>: duplicate existing file</p>
<p><strong>N.B.:</strong> This is not supported on all browsers.</p>
</li>
<li>
<p>
<code>$.twFile.convertUriToLocalPath(filePath)</code>:
normalizes specified absolute file path
</p>
</li>
</ul>
<p>
<strong>N.B.:</strong> All file paths must be absolute (e.g.
<code>/tmp/foo.txt</code> or <code>C:\temp\foo.txt</code>).
</p>
<p>(full documentation in the code comments)</p>
<h2>Limitations</h2>
<ul>
<li>
plugin unavailable until
<a href="http://docs.jquery.com/Events/ready">document.ready</a>
handlers have completed
<p>
Since the TiddlySaver applet cannot be injected synchronously
into the document, this is done asynchronously during
<code>document.ready</code> processing.
</p>
<p>
This means that the plugin is not guaranteed to work properly
until after all these handlers have completed.
</p>
</li>
<li>
currently unreliable UTF-8 support on Internet Explorer
<p>
The plugin is designed to work with UTF-8 encoded text files.
However, support in Internet Explorer is broken, and can only
reliably save files that are encoded with the ANSI subset of
UTF-8. In the case of HTML files, this problem can often be
avoided by using HTML entity encodings.
</p>
</li>
</ul>
<h2>Internals</h2>
<p>
Internally, the plugin uses four separate drivers to implement the functionality on different browsers:
<ul>
<li>
<code>activeX</code>: uses the <code>FileSystemObject</code> built into Internet Explorer 5 and above
</li>
<li>
<code>mozilla</code>: uses the XUL libraries built into Firefox
</li>
<li>
<code>tiddlySaver</code>: uses a custom Java applet that works on Safari, Chrome and Opera
</li>
<li>
<code>javaLiveConnect</code>: uses an ancient (and slow) binding technology to call Java runtime library routines directly - only works on Opera
</li>
</ul>
</p>
<h2>Demo</h2>
<p>
Download <a href="twFileDemo.html">this document</a> (and
<a href="#TiddlySaver">TiddlySaver</a> if necessary) and open it from
the local disk.
</p>
<p>
This demo illustrates self-saving capabilities by passing
<code>document.location.href</code> to <code>$.twFile.convertUriToLocalPath</code>,
using the return value in load and save functions.
</p>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,94 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>jQuery.twStylesheet</title>
<link rel="stylesheet" type="text/css" href="styles/main.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript"></script>
<script src="http://svn.tiddlywiki.org/Trunk/core/jquery/plugins/jQuery.twStylesheet.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
var applyCSS = function() {
var css = $("#css_code").val();
$.twStylesheet(css);
};
var resetCSS = function() {
$.twStylesheet.remove();
};
$("#css_apply").click(applyCSS);
$("#css_reset").click(resetCSS);
// initialize
$("#css_code").val(
"html { background-color: #EEE; }\n" +
"body { color: #FFF; background-color: #000; }\n" +
"h1, h2 { font-variant: small-caps; }\n" +
"ul { list-style-type: square; }\n" +
"code { padding: 1px 2px; background-color: #EEE; }\n" +
"#css_editor, #css_editor legend { background-color: #888; }\n"
);
});
</script>
</head>
<body>
<h1>jQuery.twStylesheet</h1>
<p>
This <a href="http://jquery.com">jQuery</a> plugin allows the application
of CSS rule sets to the document.
</p>
<p>
In contrast to jQuery's <a href="http://docs.jquery.com/CSS">CSS methods</a>,
it applies styles to the document rather than to individual elements (just
like defining a static style sheet in the document head).
</p>
<p>
The code is based on <a href="http://tiddlywiki.com">TiddlyWiki</a>'s dynamic
style-sheet capabilities, where it is used to allow users to customize their
documents on the fly.
</p>
<h2>Source</h2>
<p>
The source code is currently hosted in TiddlyWiki's
<a href="http://svn.tiddlywiki.org/Trunk/core/jquery/plugins/jQuery.twStylesheet.js">Subversion repository</a>.
</p>
<p>
<a href="http://groups.google.com/group/TiddlyWikiDev/">Feedback</a> is welcome.
</p>
<h2>API Summary</h2>
<ul>
<li>
<p><code>$.twStylesheet(css[, options])</code>: adds or replaces a style sheet</p>
<p>
<code>css</code> is a string containing the CSS rule sets, while
<code>options.id</code> is an optional name identifying the style sheet, allowing
co-existence of multiple style sheets
</p>
</li>
<li>
<p>
<code>$.twStylesheet.remove([options])</code>: delete an existing style sheet
</p>
<p>
The <code>options</code> argument is identical to <code>$.twStylesheet</code>'s.
</p>
</li>
</ul>
<p>(full documentation in the code comments)</p>
<h2>Demo</h2>
This will apply the CSS rule sets below to the entire document.
<fieldset id="css_editor" class="editor">
<legend>CSS</legend>
<textarea id="css_code" rows="10" cols="70"></textarea>
<input id="css_apply" type="button" value="Apply">
<input id="css_reset" type="button" value="Reset">
</fieldset>
</body>
</html>

View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Usage:
# upload [user]
REMOTE_USER=${1:-$USER}
HOST="jquery.tiddlywiki.org"
DIR="/var/www/www.jquery.tiddlywiki.org/htdocs/"
COMMANDS="ssh $REMOTE_USER@$HOST"
COMMANDS="$COMMANDS cd $DIR;"
COMMANDS="$COMMANDS sudo svn update;"
$COMMANDS

View File

@ -0,0 +1,155 @@
/*
jQuery.encoding.digests.sha1.js
SHA-1 digest and associated utility functions
Copyright (c) UnaMesa Association 2009
Dual licensed under the MIT and GPL licenses:
http://www.opensource.org/licenses/mit-license.php
http://www.gnu.org/licenses/gpl.html
*/
(function($) {
if(!$.encoding)
$.encoding = {};
$.extend($.encoding,{
strToBe32s: function(str) {
// Convert a string to an array of big-endian 32-bit words
var be=[];
var len=Math.floor(str.length/4);
var i, j;
for(i=0, j=0; i<len; i++, j+=4) {
be[i]=((str.charCodeAt(j)&0xff) << 24)|((str.charCodeAt(j+1)&0xff) << 16)|((str.charCodeAt(j+2)&0xff) << 8)|(str.charCodeAt(j+3)&0xff);
}
while(j<str.length) {
be[j>>2] |= (str.charCodeAt(j)&0xff)<<(24-(j*8)%32);
j++;
}
return be;
},
be32sToStr: function(be) {
// Convert an array of big-endian 32-bit words to a string
var str='';
for(var i=0;i<be.length*32;i+=8) {
str += String.fromCharCode((be[i>>5]>>>(24-i%32)) & 0xff);
}
return str;
},
be32sToHex: function(be) {
// Convert an array of big-endian 32-bit words to a hex string
var hex='0123456789ABCDEF';
var str='';
for(var i=0;i<be.length*4;i++) {
str += hex.charAt((be[i>>2]>>((3-i%4)*8+4))&0xF) + hex.charAt((be[i>>2]>>((3-i%4)*8))&0xF);
}
return str;
}
});
})(jQuery);
(function($) {
if(!$.encoding.digests)
$.encoding.digests = {};
$.extend($.encoding.digests,{
hexSha1Str: function(str) {
// Return, in hex, the SHA-1 hash of a string
return $.encoding.be32sToHex($.encoding.digests.sha1Str(str));
},
sha1Str: function(str) {
// Return the SHA-1 hash of a string
return sha1($.encoding.strToBe32s(str),str.length);
},
sha1: function(x,blen) {
// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words
return sha1($.encoding.strToBe32s(str),str.length);
}
});
// Private functions.
function sha1(x,blen) {
// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words
function add32(a,b) {
// Add 32-bit integers, wrapping at 32 bits
// Uses 16-bit operations internally to work around bugs in some JavaScript interpreters.
var lsw=(a&0xFFFF)+(b&0xFFFF);
var msw=(a>>16)+(b>>16)+(lsw>>16);
return (msw<<16)|(lsw&0xFFFF);
}
function AA(a,b,c,d,e) {
// Cryptographic round helper function. Add five 32-bit integers, wrapping at 32 bits, second parameter is rotated left 5 bits before the addition
// Uses 16-bit operations internally to work around bugs in some JavaScript interpreters.
b=(b>>>27)|(b<<5);
var lsw=(a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF);
var msw=(a>>16)+(b>>16)+(c>>16)+(d>>16)+(e>>16)+(lsw>>16);
return (msw<<16)|(lsw&0xFFFF);
}
function RR(w,j) {
// Cryptographic round helper function.
var n=w[j-3]^w[j-8]^w[j-14]^w[j-16];
return (n>>>31)|(n<<1);
}
var len=blen*8;
//# Append padding so length in bits is 448 mod 512
x[len>>5] |= 0x80 << (24-len%32);
//# Append length
x[((len+64>>9)<<4)+15]=len;
var w=new Array(80);
var k1=0x5A827999;
var k2=0x6ED9EBA1;
var k3=0x8F1BBCDC;
var k4=0xCA62C1D6;
var h0=0x67452301;
var h1=0xEFCDAB89;
var h2=0x98BADCFE;
var h3=0x10325476;
var h4=0xC3D2E1F0;
for(var i=0;i<x.length;i+=16) {
var j=0;
var t;
var a=h0;
var b=h1;
var c=h2;
var d=h3;
var e=h4;
while(j<16) {
w[j]=x[i+j];
t=AA(e,a,d^(b&(c^d)),w[j],k1);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
}
while(j<20) {
w[j]=RR(w,j);
t=AA(e,a,d^(b&(c^d)),w[j],k1);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
}
while(j<40) {
w[j]=RR(w,j);
t=AA(e,a,b^c^d,w[j],k2);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
}
while(j<60) {
w[j]=RR(w,j);
t=AA(e,a,(b&c)|(d&(b|c)),w[j],k3);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
}
while(j<80) {
w[j]=RR(w,j);
t=AA(e,a,b^c^d,w[j],k4);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
}
h0=add32(h0,a);
h1=add32(h1,b);
h2=add32(h2,c);
h3=add32(h3,d);
h4=add32(h4,e);
}
return [h0,h1,h2,h3,h4];
}
})(jQuery);

View File

@ -0,0 +1,333 @@
/*
jQuery.twFile.js
jQuery plugin for loading a file and saving data to a file
Copyright (c) UnaMesa Association 2009
Triple licensed under the BSD, MIT and GPL licenses:
http://www.opensource.org/licenses/bsd-license.php
http://www.opensource.org/licenses/mit-license.php
http://www.gnu.org/licenses/gpl.html
*/
(function($) {
if(!$.twFile) {
$.twFile = {};
}
$.extend($.twFile,{
currentDriver: null,
driverList: ["tiddlySaver", "activeX","javaLiveConnect", "mozilla"],
// Loads the contents of a text file from the local file system
// filePath is the path to the file in these formats:
// x:\path\path\path\filename - PC local file
// \\server\share\path\path\path\filename - PC network file
// /path/path/path/filename - Mac/Unix local file
// returns the text of the file, or null if the operation cannot be performed or false if there was an error
load: function(filePath) {
var d = this.getDriver();
return d ? d.loadFile(filePath) : null;
},
// Saves a string to a text file on the local file system
// filePath is the path to the file in the format described above
// content is the string to save
// returns true if the file was saved successfully, or null if the operation cannot be performed or false if there was an error
save: function(filePath,content) {
var d = this.getDriver();
return d ? d.saveFile(filePath,content) : null;
},
// Copies a file on the local file system
// dest is the path to the destination file in the format described above
// source is the path to the source file in the format described above
// returns true if the file was copied successfully, or null if the operation cannot be performed or false if there was an error
copy: function(dest,source) {
var d = this.getDriver();
if(d && d.copyFile)
return d.copyFile(dest,source);
else
return null;
},
// Converts a local file path from the format returned by document.location into the format expected by this plugin
// url is the original URL of the file
// returns the equivalent local file path
convertUriToLocalPath: function (url) {
// Remove any location or query part of the URL
var originalPath = url.split("#")[0].split("?")[0];
// Convert file://localhost/ to file:///
if(originalPath.indexOf("file://localhost/") == 0)
originalPath = "file://" + originalPath.substr(16);
// Convert to a native file format
//# "file:///x:/path/path/path..." - pc local file --> "x:\path\path\path..."
//# "file://///server/share/path/path/path..." - FireFox pc network file --> "\\server\share\path\path\path..."
//# "file:///path/path/path..." - mac/unix local file --> "/path/path/path..."
//# "file://server/share/path/path/path..." - pc network file --> "\\server\share\path\path\path..."
var localPath;
if(originalPath.charAt(9) == ":") // PC local file
localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\\");
else if(originalPath.indexOf("file://///") == 0) // Firefox PC network file
localPath = "\\\\" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\\");
else if(originalPath.indexOf("file:///") == 0) // Mac/UNIX local file
localPath = unescape(originalPath.substr(7));
else if(originalPath.indexOf("file:/") == 0) // Mac/UNIX local file
localPath = unescape(originalPath.substr(5));
else if(originalPath.indexOf("//") == 0) // PC network file
localPath = "\\\\" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\\");
return localPath || originalPath;
},
// Deferred initialization for any drivers that need it
// returns a Deferred object so callback that executes as soon
// as twFile is ready can be attached
initialize: function() {
return $.Deferred(function(dfd) {
for(var t in drivers) {
if(drivers[t].deferredInit)
drivers[t].deferredInit();
}
// Kludge: give the <applet> some time to load
setTimeout(dfd.resolve, 0);
});
},
// Private functions
// Returns a reference to the current driver
getDriver: function() {
if(this.currentDriver === null) {
for(var t=0; t<this.driverList.length; t++) {
if(this.currentDriver === null && drivers[this.driverList[t]].isAvailable && drivers[this.driverList[t]].isAvailable())
this.currentDriver = drivers[this.driverList[t]];
}
}
return this.currentDriver;
}
});
// Automatically initialize on document.ready()
$(function() {
$.twFile.initialize();
});
// Private driver implementations for each browser
var drivers = {};
// Internet Explorer driver
drivers.activeX = {
name: "activeX",
isAvailable: function() {
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
} catch(ex) {
return false;
}
return true;
},
loadFile: function(filePath) {
// Returns null if it can't do it, false if there's an error, or a string of the content if successful
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var file = fso.OpenTextFile(filePath,1);
var content = file.ReadAll();
file.Close();
} catch(ex) {
//# alert("Exception while attempting to load\n\n" + ex.toString());
return null;
}
return content;
},
createPath: function(path) {
//# Remove the filename, if present. Use trailing slash (i.e. "foo\bar\") if no filename.
var pos = path.lastIndexOf("\\");
if(pos!=-1)
path = path.substring(0,pos+1);
//# Walk up the path until we find a folder that exists
var scan = [path];
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var parent = fso.GetParentFolderName(path);
while(parent && !fso.FolderExists(parent)) {
scan.push(parent);
parent = fso.GetParentFolderName(parent);
}
//# Walk back down the path, creating folders
for(i=scan.length-1;i>=0;i--) {
if(!fso.FolderExists(scan[i])) {
fso.CreateFolder(scan[i]);
}
}
return true;
} catch(ex) {
}
return false;
},
copyFile: function(dest,source) {
drivers.activeX.createPath(dest);
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
fso.GetFile(source).Copy(dest);
} catch(ex) {
return false;
}
return true;
},
saveFile: function(filePath,content) {
// Returns null if it can't do it, false if there's an error, true if it saved OK
drivers.activeX.createPath(filePath);
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var file = fso.OpenTextFile(filePath,2,-1,0);
file.Write(content);
file.Close();
} catch (ex) {
return null;
}
return true;
}
};
// Mozilla driver
drivers.mozilla = {
name: "mozilla",
isAvailable: function() {
return !!window.Components;
},
loadFile: function(filePath) {
// Returns null if it can't do it, false if there's an error, or a string of the content if successful
if(window.Components) {
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(filePath);
if(!file.exists())
return null;
var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
inputStream.init(file,0x01,00004,null);
var sInputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
sInputStream.init(inputStream);
var contents = sInputStream.read(sInputStream.available());
sInputStream.close();
inputStream.close();
return contents;
} catch(ex) {
//# alert("Exception while attempting to load\n\n" + ex);
return false;
}
}
return null;
},
saveFile: function(filePath,content) {
// Returns null if it can't do it, false if there's an error, true if it saved OK
if(window.Components) {
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(filePath);
if(!file.exists())
file.create(0,0664);
var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
out.init(file,0x20|0x02,00004,null);
out.write(content,content.length);
out.flush();
out.close();
return true;
} catch(ex) {
alert("Exception while attempting to save\n\n" + ex);
return false;
}
}
return null;
}
};
// TiddlySaver driver
drivers.tiddlySaver = {
name: "tiddlySaver",
deferredInit: function() {
if(!document.applets["TiddlySaver"] && /* !$.browser.mozilla && !$.browser.msie && */ document.location.toString().substr(0,5) == "file:") {
$(document.body).append("<applet style='position:absolute;left:-1px' name='TiddlySaver' code='TiddlySaver.class' archive='TiddlySaver.jar' width='1'height='1'></applet>");
}
},
isAvailable: function() {
var isReady = false;
try {
isReady = !!document.applets["TiddlySaver"] &&
($.browser.msie || document.applets["TiddlySaver"].isActive) &&
( document.applets["TiddlySaver"].isActive() );
} catch (ex) {
isReady = false;
}
return isReady;
},
loadFile: function(filePath) {
var r;
try {
if(document.applets["TiddlySaver"]) {
r = document.applets["TiddlySaver"].loadFile(javaUrlToFilename(filePath),"UTF-8");
return (r === undefined || r === null) ? null : String(r);
}
} catch(ex) {
}
return null;
},
saveFile: function(filePath,content) {
try {
if(document.applets["TiddlySaver"])
return document.applets["TiddlySaver"].saveFile(javaUrlToFilename(filePath),"UTF-8",content);
} catch(ex) {
}
return null;
}
};
// Java LiveConnect driver
drivers.javaLiveConnect = {
name: "javaLiveConnect",
isAvailable: function() {
return !!window.java && !!window.java.io && !!window.java.io.FileReader;
},
loadFile: function(filePath) {
var r;
var content = [];
try {
r = new java.io.BufferedReader(new java.io.FileReader(javaUrlToFilename(filePath)));
var line;
while((line = r.readLine()) != null)
content.push(new String(line));
r.close();
} catch(ex) {
return null;
}
return content.join("\n") + "\n";
},
saveFile: function(filePath,content) {
try {
var s = new java.io.PrintStream(new java.io.FileOutputStream(javaUrlToFilename(filePath)));
s.print(content);
s.close();
} catch(ex) {
return null;
}
return true;
}
};
// Private utilities
function javaUrlToFilename(url) {
var f = "//localhost";
if(url.indexOf(f) == 0)
return url.substring(f.length);
var i = url.indexOf(":");
return i > 0 ? url.substring(i-1) : url;
}
})(jQuery);

View File

@ -0,0 +1,64 @@
/*
jQuery.twStylesheet.js
jQuery plugin to dynamically insert CSS rules into a document
Usage:
jQuery.twStylesheet applies style definitions
jQuery.twStylesheet.remove neutralizes style definitions
Copyright (c) UnaMesa Association 2009
Triple licensed under the BSD, MIT and GPL licenses:
http://www.opensource.org/licenses/bsd-license.php
http://www.opensource.org/licenses/mit-license.php
http://www.gnu.org/licenses/gpl.html
*/
(function($) {
var defaultId = "customStyleSheet"; // XXX: rename to dynamicStyleSheet?
// Add or replace a style sheet
// css argument is a string of CSS rule sets
// options.id is an optional name identifying the style sheet
// options.doc is an optional document reference
// N.B.: Uses DOM methods instead of jQuery to ensure cross-browser comaptibility.
$.twStylesheet = function(css, options) {
options = options || {};
var id = options.id || defaultId;
var doc = options.doc || document;
var el = doc.getElementById(id);
if(doc.createStyleSheet) { // IE-specific handling
if(el) {
el.parentNode.removeChild(el);
}
doc.getElementsByTagName("head")[0].insertAdjacentHTML("beforeEnd",
'&nbsp;<style id="' + id + '" type="text/css">' + css + '</style>'); // fails without &nbsp;
} else { // modern browsers
if(el) {
el.replaceChild(doc.createTextNode(css), el.firstChild);
} else {
el = doc.createElement("style");
el.type = "text/css";
el.id = id;
el.appendChild(doc.createTextNode(css));
doc.getElementsByTagName("head")[0].appendChild(el);
}
}
};
// Remove existing style sheet
// options.id is an optional name identifying the style sheet
// options.doc is an optional document reference
$.twStylesheet.remove = function(options) {
options = options || {};
var id = options.id || defaultId;
var doc = options.doc || document;
var el = doc.getElementById(id);
if(el) {
el.parentNode.removeChild(el);
}
};
})(jQuery);

View File

@ -0,0 +1,139 @@
/**
* gettext for jQuery
*
* Copyright (c) 2008 Sabin Iacob (m0n5t3r) <iacobs@m0n5t3r.info>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* @license http://www.gnu.org/licenses/gpl.html
* @project jquery.gettext
*
* Usage:
*
* This plugin expects its input data to be a JSON object like
* {"": header, "string": "translation", ...}
*
* After getting the server side set up (either as a static file - my choice - or
* as a web service), the client side is simple:
* * add to the head section of the page something like
* <link href="path/to/translation.json" lang="ro" rel="gettext"/>
* * in your script, use $.gt.gettext(string) or _(string); for plural forms, use
* $.gt.ngettext(sg, pl1[, pl2, ...], count) or n_(sg, pl1[, pl2, ...], count)
* * to extract strings to a .po file, you can use standard gettext utilities like
* xgettext and msgfmt; to generate the JSON, one could use the following Python
* snippet, assuming a domain.mo file exists under path/lang/LC_MESSAGES:
*
* import simplejson as enc
*
* def gettext_json(domain, path, lang = [], indent = False):
* try:
* tr = gettext.translation(domain, path, lang)
* return enc.dumps(tr._catalog, ensure_ascii = False, indent = indent)
* except IOError:
* return None
*
* why go through the additional hassle of gettext? well, it's a matter of
* preference, the main advantags I see are:
* * well known editing tools like KBabel, poEdit, gtranslator, Emacs PO mode,
* etc.
* * translation memory, fuzzy matches and other features that get really
* helpful when your application is big and you have hundreds of strings
*/
(function($) {
$.gt = $.gt || {};
$.extend($.gt, {
messages: {},
lang: 'C',
setLang: function(code) { $.gt.lang = typeof code == 'string' && code != ' ' ? code : 'C'; },
pl_re: /^Plural-Forms:\s*nplurals\s*=\s*(\d+);\s*plural\s*=\s*([^a-zA-Z0-9\$]*([a-zA-Z0-9\$]+).+)$/m,
plural: function(n) {return n != 1;},
load: function() {
$('link[rel=gettext]').each(function(){
var lang = this.lang;
$.get(this.href, function(data){
$.gt.messages[lang] = $.gt.messages[lang] || {};
try {
var messages = eval('(' + data + ')');
} catch(e) {
return;
}
$.extend($.gt.messages[lang], messages);
var pl = $.gt.pl_re.exec($.gt.messages[lang]['']);
if(pl){
var expr = pl[2];
var np = pl[1];
var v = pl[3];
try {
var fn = eval('(function(' + v + ') {return ' + expr + ';})');
} catch(e) {
return;
}
$.gt.plural = fn;
}
});
});
$.gt.setLang($('html').attr('lang'));
},
gettext: function(msgstr) {
var lang = $.gt.lang;
if(lang == 'C' || typeof $.gt.messages[lang] == 'undefined') {
return msgstr;
}
var trans = $.gt.messages[lang][msgstr];
if(typeof trans == 'string') { // regular action
return trans;
} else if(typeof trans == 'object' && trans.constructor == Array) { // the translation contains plural(s), yet gettext was called
return trans[0];
}
return msgstr;
},
ngettext: function() {
var lang = $.gt.lang;
var argv = Array.apply(null, arguments);
var cnt = argv[argv.length - 1];
var sg = argv[0];
var pls = argv.slice(0, -1);
var trans = pls;
if(lang != 'C' && typeof $.gt.messages[lang] != 'undefined') {
trans = $.gt.messages[lang][sg];
}
if(typeof trans == 'string') { // called ngettext, but no plural forms available :-?
return trans;
} else if(typeof trans == 'object' && trans.constructor == Array) {
var pl = $.gt.plural(cnt);
if(typeof pl == 'boolean' && pls.length == 2) {
pl = pl ? 1 : 0;
}
if(typeof pl == 'number' && pl < trans.length) {
return trans[pl];
}
}
return sg;
}
});
$('document').ready($.gt.load);
})(jQuery);
if(typeof _ == 'undefined') {
var _ = jQuery.gt.gettext;
}
if(typeof n_ == 'undefined') {
var n_ = jQuery.gt.ngettext;
}

View File

@ -0,0 +1,10 @@
/*
jquery.tw.js
addition of tw 'namespace'
*/
(function($) {
if(!$.tw) {
$.tw = {};
$.tw.extend = $.extend;
}
})(jQuery);

View File

@ -0,0 +1,58 @@
/*
jquery.tw.macro.js
macro parameter expansion
*/
(function($) {
$.tw.extend({
expandMacroParams: function(params) {
// expand the macro parameters into a name:value hash
// all parameters are also given a numeric name, starting at 1
var opts = {};
var unnamed = 1;
var name,val;
var t = $.trim(params);
var s = 0;
var i = findNakedSpace(t,s);
var param = i==-1 ? t.substr(s) : t.substring(s,i);
while(true) {
var ci = param.indexOf(':');
if(ci==-1) {
// parameter is unnamed
name = param ? unnamed++ : null;
val = param;
} else {
name = param.substr(0,ci);
val = param.substr(ci+1);
}
val = $.trim(val);
if(val.charAt(0)=='"' && val.charAt(val.length-1)=='"') {
val = val.substr(1,val.length-2);
}
if(name)
opts[name] = val;
if(i==-1)
break;
s = i+1;
i = findNakedSpace(t,s);
param = i==-1 ? t.substr(s) : t.substring(s,i);
}
return opts;
}
});
// Private functions.
function findNakedSpace(text,start) {
// find the next space not surrounded by quotes
var d = text.indexOf(' ',start);
if(d==-1)
return -1;
var qs = text.indexOf('"',start);
if(qs==-1 || qs > d)
return d;
var qe = text.indexOf('"',qs+1);
if(qe==-1)
return d;
return findNakedSpace(text,qe+1);
}
})(jQuery);

View File

@ -0,0 +1,15 @@
/*
jquery.tw.macro.today.js
jQuery TiddlyWiki <<today>> macro
*/
(function($) {
$.fn.tw_today = function(args) {
args.format = args.format || args[1];
var opts = $.extend({},$.fn.tw_today.defaults,args);
var now = new Date();
var text = now.formatString(opts.format.trim());
this.append("<span>"+text+"</span>");
return this;
};
$.fn.tw_today.defaults = {format:"ddd mmm 0DD 0hh:0mm:0ss YYYY"};
})(jQuery);

View File

@ -0,0 +1,2 @@
jquery: jQuery.encoding.digests.sha1.js
jquery: jQuery.twStylesheet.js

Binary file not shown.

View File

@ -0,0 +1,25 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Tests</title>
<link rel="stylesheet" type="text/css" href="../../../test/qunit/testsuite.css">
<script src="../../jquery-1.3.2.min.js" type="text/javascript"></script>
<!-- test suite -->
<script src="../../../test/qunit/testrunner.js" type="text/javascript"></script>
<script src="../../../test/qunit/raiseAssertion.js" type="text/javascript"></script>
<!-- plugin -->
<script src="../jQuery.twFile.js" type="text/javascript"></script>
<!-- test code -->
<script src="js/jQuery.twFile.js" type="text/javascript"></script>
</head>
<body>
<h2 id="banner"></h2>
<h2 id="userAgent"></h2>
<ol id="tests"></ol>
<div id="main"></div>
</body>
</html>

View File

@ -0,0 +1,25 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Tests</title>
<link rel="stylesheet" type="text/css" href="../../../test/qunit/testsuite.css">
<script src="../../jquery-1.3.2.min.js" type="text/javascript"></script>
<!-- test suite -->
<script src="../../../test/qunit/testrunner.js" type="text/javascript"></script>
<script src="../../../test/qunit/raiseAssertion.js" type="text/javascript"></script>
<!-- plugin -->
<script src="../jQuery.twStylesheet.js" type="text/javascript"></script>
<!-- test code -->
<script src="js/jQuery.twStylesheet.js" type="text/javascript"></script>
</head>
<body>
<h2 id="banner"></h2>
<h2 id="userAgent"></h2>
<ol id="tests"></ol>
<div id="main"></div>
</body>
</html>

View File

@ -0,0 +1,86 @@
jQuery(document).ready(function() {
module("jQuery.twFile");
test("load", function() {
var actual, expected, filepath;
actual = jQuery.twFile.load();
expected = null;
same(actual, expected, "returns null if no argument is specified");
filepath = getDocumentPath() + "/sample.txt";
actual = jQuery.twFile.load(filepath);
expected = "lorem ipsum\n" +
"dolor sit amet\n" +
"\n" +
" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~\n" +
"foo bar baz\n";
same(actual, expected, "returns contents of specified file");
filepath = "/null";
actual = jQuery.twFile.load(filepath);
expected = null;
same(actual, expected, "returns null if the specified file does not exist");
filepath = "sample.txt";
actual = jQuery.twFile.load(filepath);
expected = null;
same(actual, expected, "returns null if specified file path is not absolute");
});
test("save", function() {
var actual, expression, expected, str;
var filepath = getDocumentPath() + "/savetest.txt";
/* disabled as browser-level exceptions cannot be trapped
expression = function() { jQuery.twFile.save(); };
expected = "ReferenceError";
raises(expression, expected, "raises exception if no argument is specified");
*/
/* disabled as browser-level exceptions cannot be trapped
expression = function() { jQuery.twFile.save(filepath); };
expected = "TypeError";
raises(expression, expected, "raises exception if no content argument is specified");
*/
/* disabled as browser-level exceptions cannot be trapped
expression = function() { jQuery.twFile.save("foo.txt", "sample content"); };
expected = "ReferenceError";
raises(expression, expected, "raises exception if specified file path is not absolute");
*/
str = "lorem ipsum\n" +
"dolor sit amet\n" +
"\n" +
" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~\n" +
//"\xa9\u010d\u010c\n" +
"foo bar baz\n" +
(new Date).toString();
saveAndLoadString(filepath, str, "writes given ANSI text content to specified file");
//str = "\xa9\u010d\u010c";
//saveAndLoadString(filepath, str, "writes given UTF-8 text content to specified file");
//jQuery.twFile.save(filepath, ""); // teardown: blank file contents (deletion impossible)
});
// helper function to save and load back a string to a file
var saveAndLoadString = function(filepath,str,desc) {
jQuery.twFile.save(filepath, str);
var actual = jQuery.twFile.load(filepath);
same(actual, str, desc);
}
// helper function to retrieve current document's file path
var getDocumentPath = function() {
var path = document.location.pathname;
var startpos = 0;
var endpos = path.lastIndexOf("/");
if(path.charAt(2) == ":") {
startpos = 1;
path = path.replace(new RegExp("/","g"),"\\")
}
return unescape(path.substring(startpos, endpos));
};
});

View File

@ -0,0 +1,69 @@
jQuery(document).ready(function() {
module("jQuery.twStylesheet");
test("apply", function() {
var actual, expected, el;
el = jQuery('<div />').appendTo(document.body);
jQuery.twStylesheet("div { overflow: hidden; }");
actual = jQuery(el).css("overflow");
expected = "hidden";
same(actual, expected, "applies style definitions to document");
// teardown
jQuery(el).remove();
jQuery.twStylesheet.remove();
el = jQuery('<div />').appendTo(document.body);
jQuery.twStylesheet("div { font-style: italic; }");
actual = jQuery(el).css("font-style");
expected = "italic";
same(actual, expected, "applies style definitions to newly-created elements");
// teardown
jQuery(el).remove();
jQuery.twStylesheet.remove();
jQuery.twStylesheet("", { id: "dummyStyleSheet" });
actual = jQuery("#dummyStyleSheet").length;
expected = 1;
same(actual, expected, "generates style element using given ID");
// teardown
jQuery.twStylesheet.remove({ id: "dummyStyleSheet" });
// TODO: test for options.doc argument
});
test("remove", function() {
var actual, expected;
// setup
el = jQuery('<div />').appendTo(document.body);
jQuery.twStylesheet("div { overflow: hidden; }");
// test
jQuery.twStylesheet.remove();
actual = jQuery(el).css("overflow");
expected = "visible";
same(actual, expected, "neutralizes style definitions");
// teardown
jQuery(el).remove();
// setup
jQuery.twStylesheet("");
// test
jQuery.twStylesheet.remove();
actual = jQuery("#customStyleSheet").length;
expected = 0;
same(actual, expected, "removes default style sheet if no ID is given");
// setup
jQuery.twStylesheet("", { id: "dummyStyleSheet" });
// test
jQuery.twStylesheet.remove({ id: "dummyStyleSheet" });
actual = jQuery("#dummyStyleSheet").length;
expected = 0;
same(actual, expected, "removes style element using given ID");
// TODO: test for options.doc argument
});
});

View File

@ -0,0 +1,5 @@
lorem ipsum
dolor sit amet
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~
foo bar baz

View File

@ -0,0 +1,2 @@
jslib: jquery.js
recipe: plugins/split.recipe

View File

@ -0,0 +1,90 @@
//--
//-- Server adaptor base class
//--
function AdaptorBase()
{
this.host = null;
this.store = null;
return this;
}
AdaptorBase.prototype.close = function()
{
return true;
};
AdaptorBase.prototype.fullHostName = function(host)
{
if(!host)
return '';
host = host.trim();
if(!host.match(/:\/\//))
host = 'http://' + host;
if(host.substr(host.length-1) == '/')
host = host.substr(0,host.length-1);
return host;
};
AdaptorBase.minHostName = function(host)
{
return host;
};
AdaptorBase.prototype.setContext = function(context,userParams,callback)
{
if(!context) context = {};
context.userParams = userParams;
if(callback) context.callback = callback;
context.adaptor = this;
if(!context.host)
context.host = this.host;
context.host = this.fullHostName(context.host);
if(!context.workspace)
context.workspace = this.workspace;
return context;
};
// Open the specified host
//# host - uri of host (eg, "http://www.tiddlywiki.com/" or "www.tiddlywiki.com")
//# context is itself passed on as a parameter to the callback function
//# userParams - user settable object object that is passed on unchanged to the callback function
//# callback - optional function to be called on completion
//# Return value is true if the request was successfully issued, false if this connector doesn't support openHost(),
//# or an error description string if there was a problem
//# The callback parameters are callback(context)
//# context.status - true if OK, string if error
//# context.adaptor - reference to this adaptor object
//# userParams - parameters as originally passed into the openHost function
AdaptorBase.prototype.openHost = function(host,context,userParams,callback)
{
this.host = host;
context = this.setContext(context,userParams,callback);
context.status = true;
if(callback)
window.setTimeout(function() {context.callback(context,userParams);},10);
return true;
};
// Open the specified workspace
//# workspace - name of workspace to open
//# context - passed on as a parameter to the callback function
//# userParams - user settable object object that is passed on unchanged to the callback function
//# callback - function to be called on completion
//# Return value is true if the request was successfully issued
//# or an error description string if there was a problem
//# The callback parameters are callback(context,userParams)
//# context.status - true if OK, false if error
//# context.statusText - error message if there was an error
//# context.adaptor - reference to this adaptor object
//# userParams - parameters as originally passed into the openWorkspace function
AdaptorBase.prototype.openWorkspace = function(workspace,context,userParams,callback)
{
this.workspace = workspace;
context = this.setContext(context,userParams,callback);
context.status = true;
if(callback)
window.setTimeout(function() {callback(context,userParams);},10);
return true;
};

View File

@ -0,0 +1,46 @@
//-
//- Animation engine
//-
function Animator()
{
this.running = 0; // Incremented at start of each animation, decremented afterwards. If zero, the interval timer is disabled
this.timerID = 0; // ID of the timer used for animating
this.animations = []; // List of animations in progress
return this;
}
// Start animation engine
Animator.prototype.startAnimating = function() //# Variable number of arguments
{
var t;
for(t=0; t<arguments.length; t++)
this.animations.push(arguments[t]);
if(this.running == 0) {
var me = this;
this.timerID = window.setInterval(function() {me.doAnimate(me);},10);
}
this.running += arguments.length;
};
// Perform an animation engine tick, calling each of the known animation modules
Animator.prototype.doAnimate = function(me)
{
var a = 0;
while(a < me.animations.length) {
var animation = me.animations[a];
if(animation.tick()) {
a++;
} else {
me.animations.splice(a,1);
if(--me.running == 0)
window.clearInterval(me.timerID);
}
}
};
Animator.slowInSlowOut = function(progress)
{
return(1-((Math.cos(progress * Math.PI)+1)/2));
};

View File

@ -0,0 +1,187 @@
//--
//-- Backstage
//--
// Backstage tasks
config.tasks.save.action = saveChanges;
var backstage = {
area: null,
toolbar: null,
button: null,
showButton: null,
hideButton: null,
cloak: null,
panel: null,
panelBody: null,
panelFooter: null,
currTabName: null,
currTabElem: null,
content: null,
init: function() {
var cmb = config.messages.backstage;
this.area = document.getElementById("backstageArea");
this.toolbar = jQuery("#backstageToolbar").empty()[0];
this.button = jQuery("#backstageButton").empty()[0];
this.button.style.display = "block";
var t = cmb.open.text + " " + glyph("bentArrowLeft");
this.showButton = createTiddlyButton(this.button,t,cmb.open.tooltip,
function(e) {backstage.show(); return false;},null,"backstageShow");
t = glyph("bentArrowRight") + " " + cmb.close.text;
this.hideButton = createTiddlyButton(this.button,t,cmb.close.tooltip,
function(e) {backstage.hide(); return false;},null,"backstageHide");
this.cloak = document.getElementById("backstageCloak");
this.panel = document.getElementById("backstagePanel");
this.panelFooter = createTiddlyElement(this.panel,"div",null,"backstagePanelFooter");
this.panelBody = createTiddlyElement(this.panel,"div",null,"backstagePanelBody");
this.cloak.onmousedown = function(e) {backstage.switchTab(null);};
createTiddlyText(this.toolbar,cmb.prompt);
for(t=0; t<config.backstageTasks.length; t++) {
var taskName = config.backstageTasks[t];
var task = config.tasks[taskName];
var handler = task.action ? this.onClickCommand : this.onClickTab;
var text = task.text + (task.action ? "" : glyph("downTriangle"));
var btn = createTiddlyButton(this.toolbar,text,task.tooltip,handler,"backstageTab");
jQuery(btn).addClass(task.action ? "backstageAction" : "backstageTask");
btn.setAttribute("task", taskName);
}
this.content = document.getElementById("contentWrapper");
if(config.options.chkBackstage)
this.show();
else
this.hide();
},
isVisible: function() {
return this.area ? this.area.style.display == "block" : false;
},
show: function() {
this.area.style.display = "block";
if(anim && config.options.chkAnimate) {
backstage.toolbar.style.left = findWindowWidth() + "px";
var p = [{style: "left", start: findWindowWidth(), end: 0, template: "%0px"}];
anim.startAnimating(new Morpher(backstage.toolbar,config.animDuration,p));
} else {
backstage.area.style.left = "0px";
}
jQuery(this.showButton).hide();
jQuery(this.hideButton).show();
config.options.chkBackstage = true;
saveOption("chkBackstage");
jQuery(this.content).addClass("backstageVisible");
},
hide: function() {
if(this.currTabElem) {
this.switchTab(null);
} else {
backstage.toolbar.style.left = "0px";
if(anim && config.options.chkAnimate) {
var p = [{style: "left", start: 0, end: findWindowWidth(), template: "%0px"}];
var c = function(element,properties) {backstage.area.style.display = "none";};
anim.startAnimating(new Morpher(backstage.toolbar,config.animDuration,p,c));
} else {
this.area.style.display = "none";
}
this.showButton.style.display = "block";
this.hideButton.style.display = "none";
config.options.chkBackstage = false;
saveOption("chkBackstage");
jQuery(this.content).removeClass("backstageVisible");
}
},
onClickCommand: function(e) {
var task = config.tasks[this.getAttribute("task")];
if(task.action) {
backstage.switchTab(null);
task.action();
}
return false;
},
onClickTab: function(e) {
backstage.switchTab(this.getAttribute("task"));
return false;
},
// Switch to a given tab, or none if null is passed
switchTab: function(tabName) {
var tabElem = null;
var e = this.toolbar.firstChild;
while(e) {
if(e.getAttribute && e.getAttribute("task") == tabName)
tabElem = e;
e = e.nextSibling;
}
if(tabName == backstage.currTabName) {
backstage.hidePanel();
return;
}
if(backstage.currTabElem) {
jQuery(this.currTabElem).removeClass("backstageSelTab");
}
if(tabElem && tabName) {
backstage.preparePanel();
jQuery(tabElem).addClass("backstageSelTab");
var task = config.tasks[tabName];
wikify(task.content,backstage.panelBody,null,null);
backstage.showPanel();
} else if(backstage.currTabElem) {
backstage.hidePanel();
}
backstage.currTabName = tabName;
backstage.currTabElem = tabElem;
},
isPanelVisible: function() {
return backstage.panel ? backstage.panel.style.display == "block" : false;
},
preparePanel: function() {
backstage.cloak.style.height = findWindowHeight() + "px";
backstage.cloak.style.display = "block";
jQuery(backstage.panelBody).empty();
return backstage.panelBody;
},
showPanel: function() {
backstage.panel.style.display = "block";
if(anim && config.options.chkAnimate) {
backstage.panel.style.top = (-backstage.panel.offsetHeight) + "px";
var p = [{style: "top", start: -backstage.panel.offsetHeight, end: 0, template: "%0px"}];
anim.startAnimating(new Morpher(backstage.panel,config.animDuration,p),new Scroller(backstage.panel,false));
} else {
backstage.panel.style.top = "0px";
}
return backstage.panelBody;
},
hidePanel: function() {
if(backstage.currTabElem)
jQuery(backstage.currTabElem).removeClass("backstageSelTab");
backstage.currTabElem = null;
backstage.currTabName = null;
if(anim && config.options.chkAnimate) {
var p = [
{style: "top", start: 0, end: -(backstage.panel.offsetHeight), template: "%0px"},
{style: "display", atEnd: "none"}
];
var c = function(element,properties) {backstage.cloak.style.display = "none";};
anim.startAnimating(new Morpher(backstage.panel,config.animDuration,p,c));
} else {
jQuery([backstage.panel,backstage.cloak]).hide();
}
}
};
config.macros.backstage = {};
config.macros.backstage.handler = function(place,macroName,params)
{
var backstageTask = config.tasks[params[0]];
if(backstageTask)
createTiddlyButton(place,backstageTask.text,backstageTask.tooltip,function(e) {backstage.switchTab(params[0]); return false;});
};

View File

@ -0,0 +1,103 @@
//--
//-- Augmented methods for the JavaScript Array() object
//--
// Add indexOf function if browser does not support it
if(!Array.indexOf) {
Array.prototype.indexOf = function(item,from)
{
if(!from)
from = 0;
var i;
for(i=from; i<this.length; i++) {
if(this[i] === item)
return i;
}
return -1;
};}
// Find an entry in a given field of the members of an array
Array.prototype.findByField = function(field,value)
{
var t;
for(t=0; t<this.length; t++) {
if(this[t][field] === value)
return t;
}
return null;
};
// Return whether an entry exists in an array
Array.prototype.contains = function(item)
{
return this.indexOf(item) != -1;
};
// Adds, removes or toggles a particular value within an array
// value - value to add
// mode - +1 to add value, -1 to remove value, 0 to toggle it
Array.prototype.setItem = function(value,mode)
{
var p = this.indexOf(value);
if(mode == 0)
mode = (p == -1) ? +1 : -1;
if(mode == +1) {
if(p == -1)
this.push(value);
} else if(mode == -1) {
if(p != -1)
this.splice(p,1);
}
};
// Return whether one of a list of values exists in an array
Array.prototype.containsAny = function(items)
{
var i;
for(i=0; i<items.length; i++) {
if(this.indexOf(items[i]) != -1)
return true;
}
return false;
};
// Return whether all of a list of values exists in an array
Array.prototype.containsAll = function(items)
{
var i;
for(i = 0; i<items.length; i++) {
if(this.indexOf(items[i]) == -1)
return false;
}
return true;
};
// Push a new value into an array only if it is not already present in the array. If the optional unique parameter is false, it reverts to a normal push
Array.prototype.pushUnique = function(item,unique)
{
if(unique === false) {
this.push(item);
} else {
if(this.indexOf(item) == -1)
this.push(item);
}
};
Array.prototype.remove = function(item)
{
var p = this.indexOf(item);
if(p != -1)
this.splice(p,1);
};
if(!Array.prototype.map) {
Array.prototype.map = function(fn,thisObj)
{
var scope = thisObj || window;
var i,j,a = [];
for(i=0, j=this.length; i < j; ++i) {
a.push(fn.call(scope,this[i],i,this));
}
return a;
};}

View File

@ -0,0 +1,178 @@
//--
//-- Menu and toolbar commands
//--
config.commands.closeTiddler.handler = function(event,src,title)
{
if(story.isDirty(title) && !readOnly) {
if(!confirm(config.commands.cancelTiddler.warning.format([title])))
return false;
}
story.setDirty(title,false);
story.closeTiddler(title,true);
return false;
};
config.commands.closeOthers.handler = function(event,src,title)
{
story.closeAllTiddlers(title);
return false;
};
config.commands.editTiddler.handler = function(event,src,title)
{
clearMessage();
var tiddlerElem = story.getTiddler(title);
var fields = tiddlerElem.getAttribute("tiddlyFields");
story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE,false,null,fields);
var e = story.getTiddlerField(title,config.options.txtEditorFocus||"text");
if(e) {
setCaretPosition(e,0);
}
return false;
};
config.commands.saveTiddler.handler = function(event,src,title)
{
var newTitle = story.saveTiddler(title,event.shiftKey);
if(newTitle)
story.displayTiddler(null,newTitle);
return false;
};
config.commands.cancelTiddler.handler = function(event,src,title)
{
if(story.hasChanges(title) && !readOnly) {
if(!confirm(this.warning.format([title])))
return false;
}
story.setDirty(title,false);
story.displayTiddler(null,title);
return false;
};
config.commands.deleteTiddler.handler = function(event,src,title)
{
var deleteIt = true;
if(config.options.chkConfirmDelete)
deleteIt = confirm(this.warning.format([title]));
if(deleteIt) {
store.removeTiddler(title);
story.closeTiddler(title,true);
autoSaveChanges();
}
return false;
};
config.commands.permalink.handler = function(event,src,title)
{
var t = encodeURIComponent(String.encodeTiddlyLink(title));
if(window.location.hash != t)
window.location.hash = t;
return false;
};
config.commands.references.handlePopup = function(popup,title)
{
var references = store.getReferringTiddlers(title);
var c = false;
var r;
for(r=0; r<references.length; r++) {
if(references[r].title != title && !references[r].isTagged("excludeLists")) {
createTiddlyLink(createTiddlyElement(popup,"li"),references[r].title,true);
c = true;
}
}
if(!c)
createTiddlyElement(popup,"li",null,"disabled",this.popupNone);
};
config.commands.jump.handlePopup = function(popup,title)
{
story.forEachTiddler(function(title,element) {
createTiddlyLink(createTiddlyElement(popup,"li"),title,true,null,false,null,true);
});
};
config.commands.syncing.handlePopup = function(popup,title)
{
var me = config.commands.syncing;
var tiddler = store.fetchTiddler(title);
if(!tiddler)
return;
var serverType = tiddler.getServerType();
var serverHost = tiddler.fields["server.host"];
var serverWorkspace = tiddler.fields["server.workspace"];
if(!serverWorkspace)
serverWorkspace = "";
if(serverType) {
var e = createTiddlyElement(popup,"li",null,"popupMessage");
e.innerHTML = me.currentlySyncing.format([serverType,serverHost,serverWorkspace]);
} else {
createTiddlyElement(popup,"li",null,"popupMessage",me.notCurrentlySyncing);
}
if(serverType) {
createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
var btn = createTiddlyButton(createTiddlyElement(popup,"li"),this.captionUnSync,null,me.onChooseServer);
btn.setAttribute("tiddler",title);
btn.setAttribute("server.type","");
}
createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
createTiddlyElement(popup,"li",null,"popupMessage",me.chooseServer);
var feeds = store.getTaggedTiddlers("systemServer","title");
var t;
for(t=0; t<feeds.length; t++) {
var f = feeds[t];
var feedServerType = store.getTiddlerSlice(f.title,"Type");
if(!feedServerType)
feedServerType = "file";
var feedServerHost = store.getTiddlerSlice(f.title,"URL");
if(!feedServerHost)
feedServerHost = "";
var feedServerWorkspace = store.getTiddlerSlice(f.title,"Workspace");
if(!feedServerWorkspace)
feedServerWorkspace = "";
var caption = f.title;
if(serverType == feedServerType && serverHost == feedServerHost && serverWorkspace == feedServerWorkspace) {
caption = me.currServerMarker + caption;
} else {
caption = me.notCurrServerMarker + caption;
}
btn = createTiddlyButton(createTiddlyElement(popup,"li"),caption,null,me.onChooseServer);
btn.setAttribute("tiddler",title);
btn.setAttribute("server.type",feedServerType);
btn.setAttribute("server.host",feedServerHost);
btn.setAttribute("server.workspace",feedServerWorkspace);
}
};
config.commands.syncing.onChooseServer = function(e)
{
var tiddler = this.getAttribute("tiddler");
var serverType = this.getAttribute("server.type");
if(serverType) {
store.addTiddlerFields(tiddler,{
"server.type": serverType,
"server.host": this.getAttribute("server.host"),
"server.workspace": this.getAttribute("server.workspace")
});
} else {
store.setValue(tiddler,"server",null);
}
return false;
};
config.commands.fields.handlePopup = function(popup,title)
{
var tiddler = store.fetchTiddler(title);
if(!tiddler)
return;
var items = [];
store.forEachField(tiddler,function(tiddler,fieldName,value){items.push({field:fieldName,value:value});},true);
items.sort(function(a,b) {return a.field < b.field ? -1 : (a.field == b.field ? 0 : +1);});
if(items.length > 0)
ListView.create(popup,items,this.listViewTemplate);
else
createTiddlyElement(popup,"div",null,null,this.emptyText);
};

227
test/data/tiddlywiki/js/Config.js Executable file
View File

@ -0,0 +1,227 @@
//--
//-- Configuration repository
//--
// Miscellaneous options
var config = {
numRssItems: 20, // Number of items in the RSS feed
animDuration: 400, // Duration of UI animations in milliseconds
cascadeFast: 20, // Speed for cascade animations (higher == slower)
cascadeSlow: 60, // Speed for EasterEgg cascade animations
cascadeDepth: 5, // Depth of cascade animation
locale: "en" // W3C language tag
};
// Hashmap of alternative parsers for the wikifier
config.parsers = {};
// Adaptors
config.adaptors = {};
config.defaultAdaptor = null;
// Backstage tasks
config.tasks = {};
// Annotations
config.annotations = {};
// Custom fields to be automatically added to new tiddlers
config.defaultCustomFields = {};
// Messages
config.messages = {
messageClose: {},
dates: {},
tiddlerPopup: {}
};
// Options that can be set in the options panel and/or cookies
config.options = {
chkRegExpSearch: false,
chkCaseSensitiveSearch: false,
chkIncrementalSearch: true,
chkAnimate: true,
chkSaveBackups: true,
chkAutoSave: false,
chkGenerateAnRssFeed: false,
chkSaveEmptyTemplate: false,
chkOpenInNewWindow: true,
chkToggleLinks: false,
chkHttpReadOnly: true,
chkForceMinorUpdate: false,
chkConfirmDelete: true,
chkInsertTabs: false,
chkUsePreForStorage: true, // Whether to use <pre> format for storage
chkDisplayInstrumentation: false,
txtBackupFolder: "",
txtEditorFocus: "text",
txtMainTab: "tabTimeline",
txtMoreTab: "moreTabAll",
txtMaxEditRows: "30",
txtFileSystemCharSet: "UTF-8",
txtTheme: ""
};
config.optionsDesc = {};
//# config.optionSource["chkAnimate"] can be:
//# cookie: the option gets stored in a cookie, with the default value coming from SystemSettings
//# volatile: the option isn't persisted at all, and reverts to the default specified in SystemSettings when the document is reloaded
//# setting: the option is stored in the SystemSettings tiddler
//# The default is "setting"
config.optionsSource = {};
// Default tiddler templates
var DEFAULT_VIEW_TEMPLATE = 1;
var DEFAULT_EDIT_TEMPLATE = 2;
config.tiddlerTemplates = {
1: "ViewTemplate",
2: "EditTemplate"
};
// More messages (rather a legacy layout that should not really be like this)
config.views = {
wikified: {
tag: {}
},
editor: {
tagChooser: {}
}
};
// Backstage tasks
config.backstageTasks = ["save","sync","importTask","tweak","upgrade","plugins"];
// Extensions
config.extensions = {};
// Macros; each has a 'handler' member that is inserted later
config.macros = {
today: {},
version: {},
search: {sizeTextbox: 15},
tiddler: {},
tag: {},
tags: {},
tagging: {},
timeline: {},
allTags: {},
list: {
all: {},
missing: {},
orphans: {},
shadowed: {},
touched: {},
filter: {}
},
closeAll: {},
permaview: {},
saveChanges: {},
slider: {},
option: {},
options: {},
newTiddler: {},
newJournal: {},
tabs: {},
gradient: {},
message: {},
view: {defaultView: "text"},
edit: {},
tagChooser: {},
toolbar: {},
plugins: {},
refreshDisplay: {},
importTiddlers: {},
upgrade: {
source: "http://tiddlywiki-releases.tiddlyspace.com/upgrade",
backupExtension: "pre.core.upgrade"
},
sync: {},
annotations: {}
};
// Commands supported by the toolbar macro
config.commands = {
closeTiddler: {},
closeOthers: {},
editTiddler: {},
saveTiddler: {hideReadOnly: true},
cancelTiddler: {},
deleteTiddler: {hideReadOnly: true},
permalink: {},
references: {type: "popup"},
jump: {type: "popup"},
syncing: {type: "popup"},
fields: {type: "popup"}
};
// Control of macro parameter evaluation
config.evaluateMacroParameters = "all";
// Basic regular expressions
config.textPrimitives = {
upperLetter: "[A-Z\u00c0-\u00de\u0150\u0170]",
lowerLetter: "[a-z0-9_\\-\u00df-\u00ff\u0151\u0171]",
anyLetter: "[A-Za-z0-9_\\-\u00c0-\u00de\u00df-\u00ff\u0150\u0170\u0151\u0171]",
anyLetterStrict: "[A-Za-z0-9\u00c0-\u00de\u00df-\u00ff\u0150\u0170\u0151\u0171]"
};
if(!((new RegExp("[\u0150\u0170]","g")).test("\u0150"))) {
config.textPrimitives = {
upperLetter: "[A-Z\u00c0-\u00de]",
lowerLetter: "[a-z0-9_\\-\u00df-\u00ff]",
anyLetter: "[A-Za-z0-9_\\-\u00c0-\u00de\u00df-\u00ff]",
anyLetterStrict: "[A-Za-z0-9\u00c0-\u00de\u00df-\u00ff]"
};
}
config.textPrimitives.sliceSeparator = "::";
config.textPrimitives.sectionSeparator = "##";
config.textPrimitives.urlPattern = "(?:file|http|https|mailto|ftp|irc|news|data):[^\\s'\"]+(?:/|\\b)";
config.textPrimitives.unWikiLink = "~";
config.textPrimitives.wikiLink = "(?:(?:" + config.textPrimitives.upperLetter + "+" +
config.textPrimitives.lowerLetter + "+" +
config.textPrimitives.upperLetter +
config.textPrimitives.anyLetter + "*)|(?:" +
config.textPrimitives.upperLetter + "{2,}" +
config.textPrimitives.lowerLetter + "+))";
config.textPrimitives.cssLookahead = "(?:(" + config.textPrimitives.anyLetter + "+)\\(([^\\)\\|\\n]+)(?:\\):))|(?:(" + config.textPrimitives.anyLetter + "+):([^;\\|\\n]+);)";
config.textPrimitives.cssLookaheadRegExp = new RegExp(config.textPrimitives.cssLookahead,"mg");
config.textPrimitives.brackettedLink = "\\[\\[([^\\]]+)\\]\\]";
config.textPrimitives.titledBrackettedLink = "\\[\\[([^\\[\\]\\|]+)\\|([^\\[\\]\\|]+)\\]\\]";
config.textPrimitives.tiddlerForcedLinkRegExp = new RegExp("(?:" + config.textPrimitives.titledBrackettedLink + ")|(?:" +
config.textPrimitives.brackettedLink + ")|(?:" +
config.textPrimitives.urlPattern + ")","mg");
config.textPrimitives.tiddlerAnyLinkRegExp = new RegExp("("+ config.textPrimitives.wikiLink + ")|(?:" +
config.textPrimitives.titledBrackettedLink + ")|(?:" +
config.textPrimitives.brackettedLink + ")|(?:" +
config.textPrimitives.urlPattern + ")","mg");
config.glyphs = {
currBrowser: null,
browsers: [],
codes: {}
};
//--
//-- Shadow tiddlers
//--
config.shadowTiddlers = {
StyleSheet: "",
MarkupPreHead: "",
MarkupPostHead: "",
MarkupPreBody: "",
MarkupPostBody: "",
TabTimeline: '<<timeline>>',
TabAll: '<<list all>>',
TabTags: '<<allTags excludeLists>>',
TabMoreMissing: '<<list missing>>',
TabMoreOrphans: '<<list orphans>>',
TabMoreShadowed: '<<list shadowed>>',
AdvancedOptions: '<<options>>',
PluginManager: '<<plugins>>',
SystemSettings: '',
ToolbarCommands: '|~ViewToolbar|closeTiddler closeOthers +editTiddler > fields syncing permalink references jump|\n|~EditToolbar|+saveTiddler -cancelTiddler deleteTiddler|',
WindowTitle: '<<tiddler SiteTitle>> - <<tiddler SiteSubtitle>>'
};

View File

@ -0,0 +1,30 @@
// Browser detection... In a very few places, there's nothing else for it but to know what browser we're using.
config.userAgent = navigator.userAgent.toLowerCase();
config.browser = {
isIE: config.userAgent.indexOf("msie") != -1 && config.userAgent.indexOf("opera") == -1,
isGecko: navigator.product == "Gecko" && config.userAgent.indexOf("WebKit") == -1,
ieVersion: /MSIE (\d.\d)/i.exec(config.userAgent), // config.browser.ieVersion[1], if it exists, will be the IE version string, eg "6.0"
isSafari: config.userAgent.indexOf("applewebkit") != -1,
isBadSafari: !((new RegExp("[\u0150\u0170]","g")).test("\u0150")),
firefoxDate: /gecko\/(\d{8})/i.exec(config.userAgent), // config.browser.firefoxDate[1], if it exists, will be Firefox release date as "YYYYMMDD"
isOpera: config.userAgent.indexOf("opera") != -1,
isChrome: config.userAgent.indexOf('chrome') > -1,
isLinux: config.userAgent.indexOf("linux") != -1,
isUnix: config.userAgent.indexOf("x11") != -1,
isMac: config.userAgent.indexOf("mac") != -1,
isWindows: config.userAgent.indexOf("win") != -1
};
merge(config.glyphs,{
browsers: [
function() {return config.browser.isIE;},
function() {return true;}
],
codes: {
downTriangle: ["\u25BC","\u25BE"],
downArrow: ["\u2193","\u2193"],
bentArrowLeft: ["\u2190","\u21A9"],
bentArrowRight: ["\u2192","\u21AA"]
}
});

143
test/data/tiddlywiki/js/Crypto.js Executable file
View File

@ -0,0 +1,143 @@
//--
//-- Crypto functions and associated conversion routines
//--
// Crypto 'namespace'
function Crypto() {}
// Convert a string to an array of big-endian 32-bit words
Crypto.strToBe32s = function(str)
{
var be=[];
var len=Math.floor(str.length/4);
var i, j;
for(i=0, j=0; i<len; i++, j+=4) {
be[i]=((str.charCodeAt(j)&0xff) << 24)|((str.charCodeAt(j+1)&0xff) << 16)|((str.charCodeAt(j+2)&0xff) << 8)|(str.charCodeAt(j+3)&0xff);
}
while(j<str.length) {
be[j>>2] |= (str.charCodeAt(j)&0xff)<<(24-(j*8)%32);
j++;
}
return be;
};
// Convert an array of big-endian 32-bit words to a string
Crypto.be32sToStr = function(be)
{
var str='';
for(var i=0;i<be.length*32;i+=8) {
str += String.fromCharCode((be[i>>5]>>>(24-i%32)) & 0xff);
}
return str;
};
// Convert an array of big-endian 32-bit words to a hex string
Crypto.be32sToHex = function(be)
{
var hex='0123456789ABCDEF';
var str='';
for(var i=0;i<be.length*4;i++) {
str += hex.charAt((be[i>>2]>>((3-i%4)*8+4))&0xF) + hex.charAt((be[i>>2]>>((3-i%4)*8))&0xF);
}
return str;
};
// Return, in hex, the SHA-1 hash of a string
Crypto.hexSha1Str = function(str)
{
return Crypto.be32sToHex(Crypto.sha1Str(str));
};
// Return the SHA-1 hash of a string
Crypto.sha1Str = function(str)
{
return Crypto.sha1(Crypto.strToBe32s(str),str.length);
};
// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words
Crypto.sha1 = function(x,blen)
{
// Add 32-bit integers, wrapping at 32 bits
//# Uses 16-bit operations internally to work around bugs in some JavaScript interpreters.
function add32(a,b)
{
var lsw=(a&0xFFFF)+(b&0xFFFF);
var msw=(a>>16)+(b>>16)+(lsw>>16);
return (msw<<16)|(lsw&0xFFFF);
}
//# Cryptographic round helper function. Add five 32-bit integers, wrapping at 32 bits, second parameter is rotated left 5 bits before the addition
//# Uses 16-bit operations internally to work around bugs in some JavaScript interpreters.
function AA(a,b,c,d,e)
{
b=(b>>>27)|(b<<5);
var lsw=(a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF);
var msw=(a>>16)+(b>>16)+(c>>16)+(d>>16)+(e>>16)+(lsw>>16);
return (msw<<16)|(lsw&0xFFFF);
}
//# Cryptographic round helper function.
function RR(w,j)
{
var n=w[j-3]^w[j-8]^w[j-14]^w[j-16];
return (n>>>31)|(n<<1);
}
var len=blen*8;
//# Append padding so length in bits is 448 mod 512
x[len>>5] |= 0x80 << (24-len%32);
//# Append length
x[((len+64>>9)<<4)+15]=len;
var w=new Array(80);
var k1=0x5A827999;
var k2=0x6ED9EBA1;
var k3=0x8F1BBCDC;
var k4=0xCA62C1D6;
var h0=0x67452301;
var h1=0xEFCDAB89;
var h2=0x98BADCFE;
var h3=0x10325476;
var h4=0xC3D2E1F0;
for(var i=0;i<x.length;i+=16) {
var j=0;
var t;
var a=h0;
var b=h1;
var c=h2;
var d=h3;
var e=h4;
while(j<16) {
w[j]=x[i+j];
t=AA(e,a,d^(b&(c^d)),w[j],k1);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
}
while(j<20) {
w[j]=RR(w,j);
t=AA(e,a,d^(b&(c^d)),w[j],k1);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
}
while(j<40) {
w[j]=RR(w,j);
t=AA(e,a,b^c^d,w[j],k2);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
}
while(j<60) {
w[j]=RR(w,j);
t=AA(e,a,(b&c)|(d&(b|c)),w[j],k3);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
}
while(j<80) {
w[j]=RR(w,j);
t=AA(e,a,b^c^d,w[j],k4);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
}
h0=add32(h0,a);
h1=add32(h1,b);
h2=add32(h2,c);
h3=add32(h3,d);
h4=add32(h4,e);
}
return [h0,h1,h2,h3,h4];
};

119
test/data/tiddlywiki/js/Dates.js Executable file
View File

@ -0,0 +1,119 @@
//--
//-- Augmented methods for the JavaScript Date() object
//--
// Substitute date components into a string
Date.prototype.formatString = function(template)
{
var t = template.replace(/0hh12/g,String.zeroPad(this.getHours12(),2));
t = t.replace(/hh12/g,this.getHours12());
t = t.replace(/0hh/g,String.zeroPad(this.getHours(),2));
t = t.replace(/hh/g,this.getHours());
t = t.replace(/mmm/g,config.messages.dates.shortMonths[this.getMonth()]);
t = t.replace(/0mm/g,String.zeroPad(this.getMinutes(),2));
t = t.replace(/mm/g,this.getMinutes());
t = t.replace(/0ss/g,String.zeroPad(this.getSeconds(),2));
t = t.replace(/ss/g,this.getSeconds());
t = t.replace(/[ap]m/g,this.getAmPm().toLowerCase());
t = t.replace(/[AP]M/g,this.getAmPm().toUpperCase());
t = t.replace(/wYYYY/g,this.getYearForWeekNo());
t = t.replace(/wYY/g,String.zeroPad(this.getYearForWeekNo()-2000,2));
t = t.replace(/YYYY/g,this.getFullYear());
t = t.replace(/YY/g,String.zeroPad(this.getFullYear()-2000,2));
t = t.replace(/MMM/g,config.messages.dates.months[this.getMonth()]);
t = t.replace(/0MM/g,String.zeroPad(this.getMonth()+1,2));
t = t.replace(/MM/g,this.getMonth()+1);
t = t.replace(/0WW/g,String.zeroPad(this.getWeek(),2));
t = t.replace(/WW/g,this.getWeek());
t = t.replace(/DDD/g,config.messages.dates.days[this.getDay()]);
t = t.replace(/ddd/g,config.messages.dates.shortDays[this.getDay()]);
t = t.replace(/0DD/g,String.zeroPad(this.getDate(),2));
t = t.replace(/DDth/g,this.getDate()+this.daySuffix());
t = t.replace(/DD/g,this.getDate());
var tz = this.getTimezoneOffset();
var atz = Math.abs(tz);
t = t.replace(/TZD/g,(tz < 0 ? '+' : '-') + String.zeroPad(Math.floor(atz / 60),2) + ':' + String.zeroPad(atz % 60,2));
t = t.replace(/\\/g,"");
return t;
};
Date.prototype.getWeek = function()
{
var dt = new Date(this.getTime());
var d = dt.getDay();
if(d==0) d=7;// JavaScript Sun=0, ISO Sun=7
dt.setTime(dt.getTime()+(4-d)*86400000);// shift day to Thurs of same week to calculate weekNo
var n = Math.floor((dt.getTime()-new Date(dt.getFullYear(),0,1)+3600000)/86400000);
return Math.floor(n/7)+1;
};
Date.prototype.getYearForWeekNo = function()
{
var dt = new Date(this.getTime());
var d = dt.getDay();
if(d==0) d=7;// JavaScript Sun=0, ISO Sun=7
dt.setTime(dt.getTime()+(4-d)*86400000);// shift day to Thurs of same week
return dt.getFullYear();
};
Date.prototype.getHours12 = function()
{
var h = this.getHours();
return h > 12 ? h-12 : ( h > 0 ? h : 12 );
};
Date.prototype.getAmPm = function()
{
return this.getHours() >= 12 ? config.messages.dates.pm : config.messages.dates.am;
};
Date.prototype.daySuffix = function()
{
return config.messages.dates.daySuffixes[this.getDate()-1];
};
// Convert a date to local YYYYMMDDHHMM string format
Date.prototype.convertToLocalYYYYMMDDHHMM = function()
{
return this.getFullYear() + String.zeroPad(this.getMonth()+1,2) + String.zeroPad(this.getDate(),2) + String.zeroPad(this.getHours(),2) + String.zeroPad(this.getMinutes(),2);
};
// Convert a date to UTC YYYYMMDDHHMM string format
Date.prototype.convertToYYYYMMDDHHMM = function()
{
return this.getUTCFullYear() + String.zeroPad(this.getUTCMonth()+1,2) + String.zeroPad(this.getUTCDate(),2) + String.zeroPad(this.getUTCHours(),2) + String.zeroPad(this.getUTCMinutes(),2);
};
// Convert a date to UTC YYYYMMDD.HHMMSSMMM string format
Date.prototype.convertToYYYYMMDDHHMMSSMMM = function()
{
return this.getUTCFullYear() + String.zeroPad(this.getUTCMonth()+1,2) + String.zeroPad(this.getUTCDate(),2) + "." + String.zeroPad(this.getUTCHours(),2) + String.zeroPad(this.getUTCMinutes(),2) + String.zeroPad(this.getUTCSeconds(),2) + String.zeroPad(this.getUTCMilliseconds(),3) +"0";
};
// Static method to create a date from a UTC YYYYMMDDHHMM format string
Date.convertFromYYYYMMDDHHMM = function(d)
{
d = d?d.replace(/[^0-9]/g, ""):"";
return Date.convertFromYYYYMMDDHHMMSSMMM(d.substr(0,12));
};
// Static method to create a date from a UTC YYYYMMDDHHMMSS format string
Date.convertFromYYYYMMDDHHMMSS = function(d)
{
d = d?d.replace(/[^0-9]/g, ""):"";
return Date.convertFromYYYYMMDDHHMMSSMMM(d.substr(0,14));
};
// Static method to create a date from a UTC YYYYMMDDHHMMSSMMM format string
Date.convertFromYYYYMMDDHHMMSSMMM = function(d)
{
d = d ? d.replace(/[^0-9]/g, "") : "";
return new Date(Date.UTC(parseInt(d.substr(0,4),10),
parseInt(d.substr(4,2),10)-1,
parseInt(d.substr(6,2),10),
parseInt(d.substr(8,2)||"00",10),
parseInt(d.substr(10,2)||"00",10),
parseInt(d.substr(12,2)||"00",10),
parseInt(d.substr(14,3)||"000",10)));
};

264
test/data/tiddlywiki/js/Dom.js Executable file
View File

@ -0,0 +1,264 @@
//--
//-- DOM utilities - many derived from www.quirksmode.org
//--
function drawGradient(place,horiz,locolors,hicolors)
{
if(!hicolors)
hicolors = locolors;
var t;
for(t=0; t<= 100; t+=2) {
var bar = document.createElement("div");
place.appendChild(bar);
bar.style.position = "absolute";
bar.style.left = horiz ? t + "%" : 0;
bar.style.top = horiz ? 0 : t + "%";
bar.style.width = horiz ? (101-t) + "%" : "100%";
bar.style.height = horiz ? "100%" : (101-t) + "%";
bar.style.zIndex = -1;
var p = t/100*(locolors.length-1);
var hc = hicolors[Math.floor(p)];
if(typeof hc == "string")
hc = new RGB(hc);
var lc = locolors[Math.ceil(p)];
if(typeof lc == "string")
lc = new RGB(lc);
bar.style.backgroundColor = hc.mix(lc,p-Math.floor(p)).toString();
}
}
//# Add an event handler
//# Thanks to John Resig, via QuirksMode
function addEvent(obj,type,fn)
{
if(obj.attachEvent) {
obj["e"+type+fn] = fn;
obj[type+fn] = function(){obj["e"+type+fn](window.event);};
obj.attachEvent("on"+type,obj[type+fn]);
} else {
obj.addEventListener(type,fn,false);
}
}
//# Remove an event handler
//# Thanks to John Resig, via QuirksMode
function removeEvent(obj,type,fn)
{
if(obj.detachEvent) {
obj.detachEvent("on"+type,obj[type+fn]);
obj[type+fn] = null;
} else {
obj.removeEventListener(type,fn,false);
}
}
// Find the closest relative with a given property value (property defaults to tagName, relative defaults to parentNode)
function findRelated(e,value,name,relative)
{
name = name || "tagName";
relative = relative || "parentNode";
if(name == "className") {
while(e && !jQuery(e).hasClass(value)) {
e = e[relative];
}
} else {
while(e && e[name] != value) {
e = e[relative];
}
}
return e;
}
// Get the scroll position for window.scrollTo necessary to scroll a given element into view
function ensureVisible(e)
{
var posTop = findPosY(e);
var posBot = posTop + e.offsetHeight;
var winTop = findScrollY();
var winHeight = findWindowHeight();
var winBot = winTop + winHeight;
if(posTop < winTop) {
return posTop;
} else if(posBot > winBot) {
if(e.offsetHeight < winHeight)
return posTop - (winHeight - e.offsetHeight);
else
return posTop;
} else {
return winTop;
}
}
// Get the current width of the display window
function findWindowWidth()
{
return window.innerWidth || document.documentElement.clientWidth;
}
// Get the current height of the display window
function findWindowHeight()
{
return window.innerHeight || document.documentElement.clientHeight;
}
// Get the current horizontal page scroll position
function findScrollX()
{
return window.scrollX || document.documentElement.scrollLeft;
}
// Get the current vertical page scroll position
function findScrollY()
{
return window.scrollY || document.documentElement.scrollTop;
}
function findPosX(obj)
{
var curleft = 0;
while(obj.offsetParent) {
curleft += obj.offsetLeft;
obj = obj.offsetParent;
}
return curleft;
}
function findPosY(obj)
{
var curtop = 0;
while(obj.offsetParent) {
curtop += obj.offsetTop;
obj = obj.offsetParent;
}
return curtop;
}
// Blur a particular element
function blurElement(e)
{
if(e && e.focus && e.blur) {
e.focus();
e.blur();
}
}
// Create a non-breaking space
function insertSpacer(place)
{
var e = document.createTextNode(String.fromCharCode(160));
if(place)
place.appendChild(e);
return e;
}
// Replace the current selection of a textarea or text input and scroll it into view
function replaceSelection(e,text)
{
if(e.setSelectionRange) {
var oldpos = e.selectionStart;
var isRange = e.selectionEnd > e.selectionStart;
e.value = e.value.substr(0,e.selectionStart) + text + e.value.substr(e.selectionEnd);
e.setSelectionRange(isRange ? oldpos : oldpos + text.length,oldpos + text.length);
var linecount = e.value.split("\n").length;
var thisline = e.value.substr(0,e.selectionStart).split("\n").length-1;
e.scrollTop = Math.floor((thisline - e.rows / 2) * e.scrollHeight / linecount);
} else if(document.selection) {
var range = document.selection.createRange();
if(range.parentElement() == e) {
var isCollapsed = range.text == "";
range.text = text;
if(!isCollapsed) {
range.moveStart("character", -text.length);
range.select();
}
}
}
}
// Set the caret position in a text area
function setCaretPosition(e,pos)
{
if(e.selectionStart || e.selectionStart == '0') {
e.selectionStart = pos;
e.selectionEnd = pos;
e.focus();
} else if(document.selection) {
// IE support
e.focus ();
var sel = document.selection.createRange();
sel.moveStart('character', -e.value.length);
sel.moveStart('character',pos);
sel.moveEnd('character',0);
sel.select();
}
}
// Returns the text of the given (text) node, possibly merging subsequent text nodes
function getNodeText(e)
{
var t = "";
while(e && e.nodeName == "#text") {
t += e.nodeValue;
e = e.nextSibling;
}
return t;
}
// Returns true if the element e has a given ancestor element
function isDescendant(e,ancestor)
{
while(e) {
if(e === ancestor)
return true;
e = e.parentNode;
}
return false;
}
// deprecate the following...
// Prevent an event from bubbling
function stopEvent(e)
{
var ev = e || window.event;
ev.cancelBubble = true;
if(ev.stopPropagation) ev.stopPropagation();
return false;
}
// Remove any event handlers or non-primitve custom attributes
function scrubNode(e)
{
if(!config.browser.isIE)
return;
var att = e.attributes;
if(att) {
var t;
for(t=0; t<att.length; t++) {
var n = att[t].name;
if(n !== "style" && (typeof e[n] === "function" || (typeof e[n] === "object" && e[n] != null))) {
try {
e[n] = null;
} catch(ex) {
}
}
}
}
var c = e.firstChild;
while(c) {
scrubNode(c);
c = c.nextSibling;
}
}
function setStylesheet(s,id,doc)
{
jQuery.twStylesheet(s,{id:id,doc:doc});
}
function removeStyleSheet(id)
{
jQuery.twStylesheet.remove({id:id});
}

View File

@ -0,0 +1,185 @@
//--
//-- Server adaptor for talking to static TiddlyWiki files
//--
function FileAdaptor()
{
}
FileAdaptor.prototype = new AdaptorBase();
FileAdaptor.serverType = 'file';
FileAdaptor.serverLabel = 'TiddlyWiki';
FileAdaptor.loadTiddlyWikiSuccess = function(context,jqXHR)
{
context.status = true;
//# Load the content into a TiddlyWiki() object
context.adaptor.store = new TiddlyWiki();
if(!context.adaptor.store.importTiddlyWiki(jqXHR.responseText)) {
context.statusText = config.messages.invalidFileError.format([context.host]);
context.status = false;
}
context.complete(context,context.userParams);
};
FileAdaptor.loadTiddlyWikiError = function(context,jqXHR)
{
context.status = false;
context.statusText = jqXHR.message;
context.complete(context,context.userParams);
};
// Get the list of workspaces on a given server
//# context - passed on as a parameter to the callback function
//# userParams - user settable object object that is passed on unchanged to the callback function
//# callback - function to be called on completion
//# Return value is true if the request was successfully issued, false if this connector doesn't support getWorkspaceList(),
//# or an error description string if there was a problem
//# The callback parameters are callback(context,userParams)
//# context.status - true if OK, false if error
//# context.statusText - error message if there was an error
//# context.adaptor - reference to this adaptor object
//# userParams - parameters as originally passed into the getWorkspaceList function
FileAdaptor.prototype.getWorkspaceList = function(context,userParams,callback)
{
context = this.setContext(context,userParams,callback);
context.workspaces = [{title:"(default)"}];
context.status = true;
if(callback)
window.setTimeout(function() {callback(context,userParams);},10);
return true;
};
// Gets the list of tiddlers within a given workspace
//# context - passed on as a parameter to the callback function
//# userParams - user settable object object that is passed on unchanged to the callback function
//# callback - function to be called on completion
//# filter - filter expression
//# Return value is true if the request was successfully issued,
//# or an error description string if there was a problem
//# The callback parameters are callback(context,userParams)
//# context.status - true if OK, false if error
//# context.statusText - error message if there was an error
//# context.adaptor - reference to this adaptor object
//# context.tiddlers - array of tiddler objects
//# userParams - parameters as originally passed into the getTiddlerList function
FileAdaptor.prototype.getTiddlerList = function(context,userParams,callback,filter)
{
context = this.setContext(context,userParams,callback);
if(!context.filter)
context.filter = filter;
context.complete = FileAdaptor.getTiddlerListComplete;
if(this.store) {
return context.complete(context,context.userParams);
}
var options = {
type:"GET",
url:context.host,
processData:false,
success:function(data,textStatus,jqXHR) {
FileAdaptor.loadTiddlyWikiSuccess(context,jqXHR);
},
error:function(jqXHR,textStatus,errorThrown) {
context.xhr = jqXHR;
FileAdaptor.loadTiddlyWikiError(context,jqXHR);
}
};
return ajaxReq(options);
};
FileAdaptor.getTiddlerListComplete = function(context,userParams)
{
if(context.status) {
if(context.filter) {
context.tiddlers = context.adaptor.store.filterTiddlers(context.filter);
} else {
context.tiddlers = [];
context.adaptor.store.forEachTiddler(function(title,tiddler) {context.tiddlers.push(tiddler);});
}
var i;
for(i=0; i<context.tiddlers.length; i++) {
context.tiddlers[i].fields['server.type'] = FileAdaptor.serverType;
context.tiddlers[i].fields['server.host'] = AdaptorBase.minHostName(context.host);
context.tiddlers[i].fields['server.page.revision'] = context.tiddlers[i].modified.convertToYYYYMMDDHHMM();
}
context.status = true;
}
if(context.callback) {
window.setTimeout(function() {context.callback(context,userParams);},10);
}
return true;
};
FileAdaptor.prototype.generateTiddlerInfo = function(tiddler)
{
var info = {};
info.uri = tiddler.fields['server.host'] + "#" + tiddler.title;
return info;
};
// Retrieve a tiddler from a given workspace on a given server
//# title - title of the tiddler to get
//# context - passed on as a parameter to the callback function
//# userParams - user settable object object that is passed on unchanged to the callback function
//# callback - function to be called on completion
//# Return value is true if the request was successfully issued,
//# or an error description string if there was a problem
//# The callback parameters are callback(context,userParams)
//# context.status - true if OK, false if error
//# context.statusText - error message if there was an error
//# context.adaptor - reference to this adaptor object
//# context.tiddler - the retrieved tiddler, or null if it cannot be found
//# userParams - parameters as originally passed into the getTiddler function
FileAdaptor.prototype.getTiddler = function(title,context,userParams,callback)
{
context = this.setContext(context,userParams,callback);
context.title = title;
context.complete = FileAdaptor.getTiddlerComplete;
if(context.adaptor.store) {
return context.complete(context,context.userParams);
}
var options = {
type:"GET",
url:context.host,
processData:false,
success:function(data,textStatus,jqXHR) {
FileAdaptor.loadTiddlyWikiSuccess(context,jqXHR);
},
error:function(jqXHR,textStatus,errorThrown) {
FileAdaptor.loadTiddlyWikiError(context,jqXHR);
}
};
return ajaxReq(options);
};
FileAdaptor.getTiddlerComplete = function(context,userParams)
{
var t = context.adaptor.store.fetchTiddler(context.title);
if(t) {
t.fields['server.type'] = FileAdaptor.serverType;
t.fields['server.host'] = AdaptorBase.minHostName(context.host);
t.fields['server.page.revision'] = t.modified.convertToYYYYMMDDHHMM();
context.tiddler = t;
context.status = true;
} else { //# tiddler does not exist in document
context.status = false;
}
if(context.allowSynchronous) {
context.isSynchronous = true;
context.callback(context,userParams);
} else {
window.setTimeout(function() {context.callback(context,userParams);},10);
}
return true;
};
FileAdaptor.prototype.close = function()
{
this.store = null;
};
config.adaptors[FileAdaptor.serverType] = FileAdaptor;
config.defaultAdaptor = FileAdaptor.serverType;

View File

@ -0,0 +1,212 @@
//--
//-- Filesystem code
//--
//#
//# This code is designed to be reusable, but please take care,
//# there are some intricacies that make it tricky to use these
//# functions with full UTF-8 files. For more details, see:
//#
//# http://trac.tiddlywiki.org/ticket/99
//#
//#
function copyFile(dest,source)
{
return config.browser.isIE ? ieCopyFile(dest,source) : false;
}
function saveFile(fileUrl,content)
{
var r = mozillaSaveFile(fileUrl,content);
if(!r)
r = ieSaveFile(fileUrl,content);
if(!r)
r = javaSaveFile(fileUrl,content);
return r;
}
function loadFile(fileUrl)
{
var r = mozillaLoadFile(fileUrl);
if((r == null) || (r == false))
r = ieLoadFile(fileUrl);
if((r == null) || (r == false))
r = javaLoadFile(fileUrl);
return r;
}
function ieCreatePath(path)
{
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
} catch(ex) {
return null;
}
//# Remove the filename, if present. Use trailing slash (i.e. "foo\bar\") if no filename.
var pos = path.lastIndexOf("\\");
if(pos==-1)
pos = path.lastIndexOf("/");
if(pos!=-1)
path = path.substring(0,pos+1);
//# Walk up the path until we find a folder that exists
var scan = [path];
var parent = fso.GetParentFolderName(path);
while(parent && !fso.FolderExists(parent)) {
scan.push(parent);
parent = fso.GetParentFolderName(parent);
}
//# Walk back down the path, creating folders
for(i=scan.length-1;i>=0;i--) {
if(!fso.FolderExists(scan[i])) {
fso.CreateFolder(scan[i]);
}
}
return true;
}
// Returns null if it can't do it, false if there's an error, true if it saved OK
function ieSaveFile(filePath,content)
{
ieCreatePath(filePath);
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
} catch(ex) {
//# alert("Exception while attempting to save\n\n" + ex.toString());
return null;
}
var file = fso.OpenTextFile(filePath,2,-1,0);
file.Write(content);
file.Close();
return true;
}
// Returns null if it can't do it, false if there's an error, or a string of the content if successful
function ieLoadFile(filePath)
{
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var file = fso.OpenTextFile(filePath,1);
var content = file.ReadAll();
file.Close();
} catch(ex) {
//# alert("Exception while attempting to load\n\n" + ex.toString());
return null;
}
return content;
}
function ieCopyFile(dest,source)
{
ieCreatePath(dest);
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
fso.GetFile(source).Copy(dest);
} catch(ex) {
return false;
}
return true;
}
// Returns null if it can't do it, false if there's an error, true if it saved OK
function mozillaSaveFile(filePath,content)
{
if(window.Components) {
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(filePath);
if(!file.exists())
file.create(0,0x01B4);// 0x01B4 = 0664
var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
out.init(file,0x22,0x04,null);
out.write(content,content.length);
out.flush();
out.close();
return true;
} catch(ex) {
//# alert("Exception while attempting to save\n\n" + ex);
return false;
}
}
return null;
}
// Returns null if it can't do it, false if there's an error, or a string of the content if successful
function mozillaLoadFile(filePath)
{
if(window.Components) {
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(filePath);
if(!file.exists())
return null;
var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
inputStream.init(file,0x01,0x04,null);
var sInputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
sInputStream.init(inputStream);
var contents = sInputStream.read(sInputStream.available());
sInputStream.close();
inputStream.close();
return contents;
} catch(ex) {
//# alert("Exception while attempting to load\n\n" + ex);
return false;
}
}
return null;
}
function javaUrlToFilename(url)
{
var f = "//localhost";
if(url.indexOf(f) == 0)
return url.substring(f.length);
var i = url.indexOf(":");
return i > 0 ? url.substring(i-1) : url;
}
function javaSaveFile(filePath,content)
{
try {
if(document.applets["TiddlySaver"])
return document.applets["TiddlySaver"].saveFile(javaUrlToFilename(filePath),"UTF-8",content);
} catch(ex) {
}
try {
var s = new java.io.PrintStream(new java.io.FileOutputStream(javaUrlToFilename(filePath)));
s.print(content);
s.close();
} catch(ex2) {
return null;
}
return true;
}
function javaLoadFile(filePath)
{
try {
if(document.applets["TiddlySaver"]) {
var ret = document.applets["TiddlySaver"].loadFile(javaUrlToFilename(filePath),"UTF-8");
if(!ret)
return null;
return String(ret);
}
} catch(ex) {
}
var content = [];
try {
var r = new java.io.BufferedReader(new java.io.FileReader(javaUrlToFilename(filePath)));
var line;
while((line = r.readLine()) != null)
content.push(String(line));
r.close();
} catch(ex2) {
return null;
}
return content.join("\n");
}

View File

@ -0,0 +1,103 @@
//--
//-- Filesystem utilities
//--
function convertUTF8ToUnicode(u)
{
return config.browser.isOpera || !window.netscape ? manualConvertUTF8ToUnicode(u) : mozConvertUTF8ToUnicode(u);
}
//# UTF-8 encoding rules:
//# 0x0000 - 0x007F: 0xxxxxxx
//# 0x0080 - 0x07FF: 110xxxxx 10xxxxxx
//# 0x0800 - 0xFFFF: 1110xxxx 10xxxxxx 10xxxxxx
function manualConvertUTF8ToUnicode(utf)
{
var uni = utf;
var src = 0;
var dst = 0;
var b1, b2, b3;
var c;
while(src < utf.length) {
b1 = utf.charCodeAt(src++);
if(b1 < 0x80) {
dst++;
} else if(b1 < 0xE0) {
b2 = utf.charCodeAt(src++);
c = String.fromCharCode(((b1 & 0x1F) << 6) | (b2 & 0x3F));
uni = uni.substring(0,dst++).concat(c,utf.substr(src));
} else {
b2 = utf.charCodeAt(src++);
b3 = utf.charCodeAt(src++);
c = String.fromCharCode(((b1 & 0xF) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F));
uni = uni.substring(0,dst++).concat(c,utf.substr(src));
}
}
return uni;
}
function mozConvertUTF8ToUnicode(u)
{
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
} catch(ex) {
return manualConvertUTF8ToUnicode(u);
} // fallback
var s = converter.ConvertToUnicode(u);
var fin = converter.Finish();
return fin.length > 0 ? s+fin : s;
}
//# convert unicode string to a format suitable for saving to file
//# this should be UTF8, unless the browser does not support saving non-ASCII characters
function convertUnicodeToFileFormat(s)
{
return config.browser.isOpera || !window.netscape ? (config.browser.isIE ? convertUnicodeToHtmlEntities(s) : s) : mozConvertUnicodeToUTF8(s);
}
function convertUnicodeToHtmlEntities(s)
{
var re = /[^\u0000-\u007F]/g;
return s.replace(re,function($0) {return "&#" + $0.charCodeAt(0).toString() + ";";});
}
function convertUnicodeToUTF8(s)
{
// return convertUnicodeToFileFormat to allow plugin migration
return convertUnicodeToFileFormat(s);
}
function manualConvertUnicodeToUTF8(s)
{
return unescape(encodeURIComponent(s));
}
function mozConvertUnicodeToUTF8(s)
{
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
} catch(ex) {
return manualConvertUnicodeToUTF8(s);
} // fallback
var u = converter.ConvertFromUnicode(s);
var fin = converter.Finish();
return fin.length > 0 ? u + fin : u;
}
function convertUriToUTF8(uri,charSet)
{
if(window.netscape == undefined || charSet == undefined || charSet == "")
return uri;
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var converter = Components.classes["@mozilla.org/intl/utf8converterservice;1"].getService(Components.interfaces.nsIUTF8ConverterService);
} catch(ex) {
return uri;
}
return converter.convertURISpecToUTF8(uri,charSet);
}

Some files were not shown because too many files have changed in this diff Show More