mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-24 20:04:40 +00:00
Compare commits
126 Commits
external-t
...
v5.2.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b73c50adeb | ||
|
|
fdfa45329a | ||
|
|
7b1880404c | ||
|
|
2739b1bafe | ||
|
|
cc782ff518 | ||
|
|
492bfbebe9 | ||
|
|
c9fbff265a | ||
|
|
b0f72d0690 | ||
|
|
6070a2c921 | ||
|
|
cb43b91ab6 | ||
|
|
804bc9e9c0 | ||
|
|
4514a67a1f | ||
|
|
edcba4ee16 | ||
|
|
9e28356047 | ||
|
|
44ad8c770f | ||
|
|
2dd4fa41a5 | ||
|
|
f5389b3859 | ||
|
|
65c8d74218 | ||
|
|
f88e3939e1 | ||
|
|
769778b05b | ||
|
|
f84ff0d778 | ||
|
|
ca1aabe21f | ||
|
|
dd801d1571 | ||
|
|
485730483b | ||
|
|
8b6733d792 | ||
|
|
75aabcce64 | ||
|
|
5dfa6b2bb4 | ||
|
|
3798a3c7d0 | ||
|
|
1c4b2243a6 | ||
|
|
c11493ec37 | ||
|
|
b6c8cdae64 | ||
|
|
b80d079d71 | ||
|
|
6512b038c5 | ||
|
|
6d1d497a63 | ||
|
|
6ea7140e8f | ||
|
|
7b311b0e4a | ||
|
|
be3018fe3b | ||
|
|
68095eb392 | ||
|
|
4bb34e4801 | ||
|
|
1348607c8f | ||
|
|
2f86779a27 | ||
|
|
2af632a46d | ||
|
|
05606f72ad | ||
|
|
6d0701e0fa | ||
|
|
76cdc17f3b | ||
|
|
7b076eadfa | ||
|
|
c5ce2a0a94 | ||
|
|
7fcc84156e | ||
|
|
75bf12db7a | ||
|
|
07de96459e | ||
|
|
be036aa9c8 | ||
|
|
0664895670 | ||
|
|
dde1e4bc0f | ||
|
|
122de63b71 | ||
|
|
e3ba880e18 | ||
|
|
e3be15531f | ||
|
|
5a3ff4e3dc | ||
|
|
f7f32f00a3 | ||
|
|
d7d694b14f | ||
|
|
a6feb6dd66 | ||
|
|
ecf10e41c3 | ||
|
|
481edc1cfe | ||
|
|
ff5817ab50 | ||
|
|
80235bf049 | ||
|
|
ecddd5a7be | ||
|
|
f22fc788e5 | ||
|
|
f828a582c3 | ||
|
|
a94f94f352 | ||
|
|
9f34a01577 | ||
|
|
9cd49ed485 | ||
|
|
4ea1a05af6 | ||
|
|
b6eb6d477b | ||
|
|
cce18d8e2e | ||
|
|
45d469ca5c | ||
|
|
fbee714ffe | ||
|
|
2429dcc2e2 | ||
|
|
4d84422f22 | ||
|
|
d98bfbde58 | ||
|
|
983787a8f2 | ||
|
|
7b83c22e78 | ||
|
|
c8c43b2811 | ||
|
|
7e32e2efcf | ||
|
|
6f8e842105 | ||
|
|
ce99c0aa0f | ||
|
|
3ff165402c | ||
|
|
a350a76a00 | ||
|
|
05b9dd1822 | ||
|
|
5207b1c127 | ||
|
|
267c351735 | ||
|
|
f545418e55 | ||
|
|
97dd832d2e | ||
|
|
d7e7d87581 | ||
|
|
bd2efeaaa3 | ||
|
|
a206bf56b9 | ||
|
|
a33e94c4ee | ||
|
|
e9313b1c9d | ||
|
|
8096935d87 | ||
|
|
dcb083abb0 | ||
|
|
6cc76fe6ab | ||
|
|
4f8de1881c | ||
|
|
9caba544eb | ||
|
|
746a8ca17f | ||
|
|
2475e1b501 | ||
|
|
193628d63f | ||
|
|
b6ce353a7d | ||
|
|
7a50603d9d | ||
|
|
d21fabca4b | ||
|
|
daa9a8ae45 | ||
|
|
d9eb5499a3 | ||
|
|
870c7897ad | ||
|
|
95da1c2907 | ||
|
|
2bfe522b72 | ||
|
|
c099bf9893 | ||
|
|
ab0dda1177 | ||
|
|
4f65953da9 | ||
|
|
d77de61a06 | ||
|
|
3287cf56bb | ||
|
|
b5c81d2721 | ||
|
|
d3522854b6 | ||
|
|
2f3f9de7be | ||
|
|
6890952357 | ||
|
|
71be167592 | ||
|
|
989947b99a | ||
|
|
3d86d62a6e | ||
|
|
0cfe6597d4 | ||
|
|
81b4e99ccc |
File diff suppressed because one or more lines are too long
@@ -27,10 +27,15 @@ Basics/Tiddlers/Prompt: Number of tiddlers
|
||||
Basics/Title/Prompt: Title of this ~TiddlyWiki
|
||||
Basics/Username/Prompt: Username for signing edits
|
||||
Basics/Version/Prompt: ~TiddlyWiki version
|
||||
Cascades/Caption: Cascades
|
||||
Cascades/Hint: These global rules are used to dynamically choose certain templates. The result of the cascade is the result of the first filter in the sequence that returns a result
|
||||
Cascades/TagPrompt: Filters tagged <$macrocall $name="tag" tag=<<currentTiddler>>/>
|
||||
EditorTypes/Caption: Editor Types
|
||||
EditorTypes/Editor/Caption: Editor
|
||||
EditorTypes/Hint: These tiddlers determine which editor is used to edit specific tiddler types.
|
||||
EditorTypes/Type/Caption: Type
|
||||
EditTemplateBody/Caption: Edit Template Body
|
||||
EditTemplateBody/Hint: This rule cascade is used by the default edit template to dynamically choose the template for editing the body of a tiddler.
|
||||
Info/Caption: Info
|
||||
Info/Hint: Information about this TiddlyWiki
|
||||
KeyboardShortcuts/Add/Prompt: Type shortcut here
|
||||
@@ -191,6 +196,8 @@ Settings/TitleLinks/Yes/Description: Display tiddler titles as links
|
||||
Settings/MissingLinks/Caption: Wiki Links
|
||||
Settings/MissingLinks/Hint: Choose whether to link to tiddlers that do not exist yet
|
||||
Settings/MissingLinks/Description: Enable links to missing tiddlers
|
||||
StoryTiddler/Caption: Story Tiddler
|
||||
StoryTiddler/Hint: This rule cascade is used to dynamically choose the template for displaying a tiddler in the story river.
|
||||
StoryView/Caption: Story View
|
||||
StoryView/Prompt: Current view:
|
||||
Stylesheets/Caption: Stylesheets
|
||||
@@ -201,6 +208,10 @@ Theme/Caption: Theme
|
||||
Theme/Prompt: Current theme:
|
||||
TiddlerFields/Caption: Tiddler Fields
|
||||
TiddlerFields/Hint: This is the full set of TiddlerFields in use in this wiki (including system tiddlers but excluding shadow tiddlers).
|
||||
TiddlerColour/Caption: Tiddler Colour
|
||||
TiddlerColour/Hint: This rules cascade is used to dynamically choose the colour for a tiddler (used for the icon and the associated tag pill).
|
||||
TiddlerIcon/Caption: Tiddler Icon
|
||||
TiddlerIcon/Hint: This rules cascade is used to dynamically choose the icon for a tiddler.
|
||||
Toolbars/Caption: Toolbars
|
||||
Toolbars/EditToolbar/Caption: Edit Toolbar
|
||||
Toolbars/EditToolbar/Hint: Choose which buttons are displayed for tiddlers in edit mode. Drag and drop to change the ordering
|
||||
@@ -212,3 +223,7 @@ Toolbars/EditorToolbar/Hint: Choose which buttons are displayed in the editor to
|
||||
Toolbars/ViewToolbar/Caption: View Toolbar
|
||||
Toolbars/ViewToolbar/Hint: Choose which buttons are displayed for tiddlers in view mode. Drag and drop to change the ordering
|
||||
Tools/Download/Full/Caption: Download full wiki
|
||||
ViewTemplateBody/Caption: View Template Body
|
||||
ViewTemplateBody/Hint: This rule cascade is used by the default view template to dynamically choose the template for displaying the body of a tiddler.
|
||||
ViewTemplateTitle/Caption: View Template Title
|
||||
ViewTemplateTitle/Hint: This rule cascade is used by the default view template to dynamically choose the template for displaying the title of a tiddler.
|
||||
@@ -1,13 +0,0 @@
|
||||
title: $:/language/Help/pipe
|
||||
description: Pipe data to/from external processes
|
||||
|
||||
Pipe data to/from external processes.
|
||||
|
||||
```
|
||||
--pipe <pipename> <filter> <incomingTitle> <arguments>...
|
||||
```
|
||||
|
||||
* ''pipename'': identifies the pipe, matching the name defined in the `tiddlywiki.info` file
|
||||
* ''filter'': identifies the tiddlers to be passed to the pipe
|
||||
* ''incomingTitle'': provides a title to be applied to incoming tiddlers for the `raw-text` output format
|
||||
* ''arguments'': passed through to external task pipes, and ignored for other types of pipe
|
||||
@@ -1,278 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/commands/pipe.js
|
||||
type: application/javascript
|
||||
module-type: command
|
||||
|
||||
Command to execute an external task
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.info = {
|
||||
name: "pipe",
|
||||
synchronous: false
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
var self = this;
|
||||
if(this.params.length < 2) {
|
||||
return "Missing parameters";
|
||||
}
|
||||
var name = self.params[0], // External pipe name
|
||||
outgoingFilter = self.params[1], // Filter of tiddlers to write to the pipe
|
||||
incomingTitle = self.params[2],
|
||||
args = self.params.slice(3); // Remaining arguments are passed on as tasks arguments
|
||||
// Find the pipe information
|
||||
var pipeInfo = ($tw.boot.wikiInfo["external-pipes"] || {})[name];
|
||||
if(!pipeInfo) {
|
||||
return this.callback("External pipe \"" + name + "\" not found");
|
||||
}
|
||||
// Create the pipe instance and process a message
|
||||
var pipe = new Pipe({
|
||||
name: name,
|
||||
pipeInfo: pipeInfo,
|
||||
outgoingFilter: outgoingFilter,
|
||||
incomingTitle: incomingTitle,
|
||||
args: args,
|
||||
command: this
|
||||
});
|
||||
pipe.processMessage(this.callback);
|
||||
};
|
||||
|
||||
function Pipe(options) {
|
||||
this.name = options.name;
|
||||
this.pipeInfo = options.pipeInfo;
|
||||
this.outgoingFilter = options.outgoingFilter;
|
||||
this.incomingTitle = options.incomingTitle;
|
||||
this.args = options.args;
|
||||
this.command = options.command;
|
||||
}
|
||||
|
||||
Pipe.prototype.processMessage = function(callback) {
|
||||
// Get the outgoing data
|
||||
var data = this.composeOutgoingData(this.outgoingFilter);
|
||||
// Connect to the pipe
|
||||
switch(this.pipeInfo.type) {
|
||||
case "task":
|
||||
this.pipeExternalTask(data,callback);
|
||||
break;
|
||||
case "socket":
|
||||
this.pipeSocket(data,callback);
|
||||
break;
|
||||
case "socket-erlang":
|
||||
this.pipeSocketErlang(data,callback);
|
||||
break;
|
||||
default:
|
||||
callback("Invalid pipe specifier '" + this.name + "': " + this.pipeInfo.type);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
Pipe.prototype.log = function(args) {
|
||||
this.command.commander.log("Pipe: " + Array.prototype.slice.call(arguments,0).join(" "));
|
||||
};
|
||||
|
||||
Pipe.prototype.pipeExternalTask = function(data,callback) {
|
||||
var self = this,
|
||||
spawn = require("child_process").spawn,
|
||||
path = require("path"),
|
||||
childProcess = spawn(path.resolve($tw.boot.wikiPath,this.pipeInfo.path),this.args,{
|
||||
stdio: ["pipe","pipe",process.stderr],
|
||||
shell: true,
|
||||
env: $tw.utils.extend({},process.env,this.pipeInfo.environment)
|
||||
});
|
||||
// Pass the tiddlers over the outgoing stream
|
||||
childProcess.stdin.on("error",function(err) {
|
||||
self.log("Task stdin error",err)
|
||||
});
|
||||
childProcess.stdin.write(data);
|
||||
childProcess.stdin.end();
|
||||
// Catch the output
|
||||
var chunks = [];
|
||||
childProcess.stdout.on("data",function(chunk) {
|
||||
chunks.push(chunk.toString());
|
||||
});
|
||||
childProcess.stdout.on("close",function() {
|
||||
self.log("Task stdout close");
|
||||
self.processIncomingData(chunks.join(""));
|
||||
});
|
||||
childProcess.stdout.on("error",function(err) {
|
||||
self.log("Task stdout error",err)
|
||||
});
|
||||
// Pick up the output when the process ends
|
||||
childProcess.on("error",function(err) {
|
||||
self.log("Task error",err)
|
||||
});
|
||||
childProcess.on("exit",function(code,signal) {
|
||||
self.log("Task exit",code,signal)
|
||||
if(code !== 0) {
|
||||
return callback("Error executing external task: " + code);
|
||||
}
|
||||
// Exit successfully
|
||||
callback(null);
|
||||
});
|
||||
};
|
||||
|
||||
Pipe.prototype.pipeSocket = function(data,callback) {
|
||||
var self = this,
|
||||
net = require("net"),
|
||||
socket = new net.Socket({
|
||||
allowHalfOpen: true
|
||||
}),
|
||||
chunks = [];
|
||||
socket.connect(this.pipeInfo.port,this.pipeInfo.host || 8081,function() {
|
||||
self.log("Socket connection",this.pipeInfo.port,this.pipeInfo.host);
|
||||
socket.write(data);
|
||||
socket.end();
|
||||
});
|
||||
socket.on("error",function(e) {
|
||||
self.log("Socket error",e)
|
||||
});
|
||||
socket.on("data",function(data) {
|
||||
chunks.push(data.toString());
|
||||
});
|
||||
socket.on("end",function() {
|
||||
self.processIncomingData(chunks.join(""));
|
||||
self.log("Socket end");
|
||||
socket.destroy();
|
||||
});
|
||||
// Add a "close" event handler for the client socket
|
||||
socket.on("close",function() {
|
||||
self.log("Socket closed");
|
||||
return callback(null);
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
Pipe.prototype.pipeSocketErlang = function(data,callback) {
|
||||
var self = this,
|
||||
encoding = this.pipeInfo.encoding || "utf8",
|
||||
net = require("net"),
|
||||
socket = new net.Socket(),
|
||||
accumulator = Buffer.alloc(0);
|
||||
socket.connect(this.pipeInfo.port,this.pipeInfo.host || 8081,function() {
|
||||
self.log("Socket connection",self.pipeInfo.port,self.pipeInfo.host);
|
||||
var dataBytes = Buffer.from(data,encoding);
|
||||
// Write 32-bit big endian message length
|
||||
var lengthBytes = Buffer.alloc(4);
|
||||
lengthBytes.writeUInt32BE(dataBytes.length + 1,0)
|
||||
console.log("Writing bytes",dataBytes.length + 1);
|
||||
socket.write(lengthBytes);
|
||||
// Write 8-bit type
|
||||
var typeByte = Buffer.alloc(1);
|
||||
typeByte.writeUInt8(1,0);
|
||||
socket.write(typeByte);
|
||||
// Write data
|
||||
socket.write(dataBytes);
|
||||
});
|
||||
socket.on("error",function(e) {
|
||||
self.log("Socket error",e)
|
||||
});
|
||||
socket.on("data",function(data) {
|
||||
console.log("Received data",data.length)
|
||||
accumulator = Buffer.concat([accumulator,data]);
|
||||
while(accumulator.length > 4) {
|
||||
var length = accumulator.readInt32BE(0);
|
||||
if(accumulator.length >= (length + 4)) {
|
||||
if(length < 1) {
|
||||
throw "ERROR: Incoming message length field is less than 1";
|
||||
}
|
||||
var type = accumulator.readUInt8(4),
|
||||
dataLength = length - 1,
|
||||
data = accumulator.toString(encoding,5,dataLength + 5);
|
||||
console.log("Got message",length,type)
|
||||
self.processIncomingData(data);
|
||||
accumulator = accumulator.slice(length + 4);
|
||||
socket.end();
|
||||
return callback(null);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
socket.on("end",function() {
|
||||
self.log("Socket end");
|
||||
socket.destroy();
|
||||
});
|
||||
// Add a "close" event handler for the client socket
|
||||
socket.on("close",function() {
|
||||
self.log("Socket closed");
|
||||
return callback(null);
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
Pipe.prototype.composeOutgoingData = function(outgoingFilter) {
|
||||
var self = this,
|
||||
pipeInfoInput = this.pipeInfo.input || {},
|
||||
data;
|
||||
switch(pipeInfoInput.format || "json-raw-tiddlers") {
|
||||
case "rendered-text":
|
||||
var titles = self.command.commander.wiki.filterTiddlers(outgoingFilter),
|
||||
output = [];
|
||||
$tw.utils.each(titles,function(title) {
|
||||
output.push(self.command.commander.wiki.renderTiddler("text/plain",title));
|
||||
});
|
||||
data = output.join("");
|
||||
break;
|
||||
case "json-rendered-text-tiddlers":
|
||||
var titles = self.command.commander.wiki.filterTiddlers(outgoingFilter),
|
||||
tiddlers = [];
|
||||
$tw.utils.each(titles,function(title) {
|
||||
tiddlers.push({
|
||||
title: title,
|
||||
text: self.command.commander.wiki.renderTiddler("text/plain",title)
|
||||
})
|
||||
});
|
||||
data = JSON.stringify(tiddlers);
|
||||
break;
|
||||
case "json-raw-tiddlers":
|
||||
// Intentional fall-through
|
||||
default:
|
||||
data = this.command.commander.wiki.getTiddlersAsJson(outgoingFilter);
|
||||
break;
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
Pipe.prototype.processIncomingData = function(data) {
|
||||
var pipeInfoOutput = this.pipeInfo.output || {},
|
||||
jsonData;
|
||||
switch(pipeInfoOutput.format || "text") {
|
||||
case "json-raw-tiddlers":
|
||||
try {
|
||||
jsonData = JSON.parse(data);
|
||||
} catch(e) {
|
||||
this.log("Error parsing returned JSON: " + e + "\n\n\n->\n" + data);
|
||||
}
|
||||
// Add the tiddlers
|
||||
if(jsonData) {
|
||||
this.command.commander.wiki.addTiddlers(jsonData);
|
||||
}
|
||||
break;
|
||||
case "text":
|
||||
// Intentional fall-through
|
||||
default:
|
||||
console.log("Writing tiddler",pipeInfoOutput.tiddler,{
|
||||
text: data, title: this.incomingTitle
|
||||
})
|
||||
this.command.commander.wiki.addTiddler(new $tw.Tiddler(pipeInfoOutput.tiddler,{
|
||||
text: data, title: this.incomingTitle || pipeInfoOutput.tiddler.title
|
||||
}));
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
@@ -205,7 +205,7 @@ FramedEngine.prototype.handleInputEvent = function(event) {
|
||||
this.widget.saveChanges(this.getText());
|
||||
this.fixHeight();
|
||||
if(this.widget.editInputActions) {
|
||||
this.widget.invokeActionString(this.widget.editInputActions);
|
||||
this.widget.invokeActionString(this.widget.editInputActions,this,event,{actionValue: this.getText()});
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -133,7 +133,7 @@ SimpleEngine.prototype.handleInputEvent = function(event) {
|
||||
this.widget.saveChanges(this.getText());
|
||||
this.fixHeight();
|
||||
if(this.widget.editInputActions) {
|
||||
this.widget.invokeActionString(this.widget.editInputActions);
|
||||
this.widget.invokeActionString(this.widget.editInputActions,this,event,{actionValue: this.getText()});
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -324,7 +324,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
If there are no Files, let the browser handle it.
|
||||
*/
|
||||
EditTextWidget.prototype.handleDropEvent = function(event) {
|
||||
if(event.dataTransfer.files.length) {
|
||||
if($tw.utils.dragEventContainsFiles(event)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.dispatchDOMEvent(this.cloneEvent(event,["dataTransfer"]));
|
||||
|
||||
53
core/modules/filterrunprefixes/cascade.js
Normal file
53
core/modules/filterrunprefixes/cascade.js
Normal file
@@ -0,0 +1,53 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/cascade.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.cascade = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length !== 0) {
|
||||
var filterList = operationSubFunction(source,widget),
|
||||
filterFnList = [];
|
||||
var inputResults = results.toArray();
|
||||
results.clear();
|
||||
$tw.utils.each(inputResults,function(title) {
|
||||
var result = ""; // If no filter matches, we return an empty string
|
||||
$tw.utils.each(filterList,function(filter,index) {
|
||||
if(!filterFnList[index]) {
|
||||
filterFnList[index] = options.wiki.compileFilter(filter);
|
||||
}
|
||||
var output = filterFnList[index](options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler")
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
if(output.length !== 0) {
|
||||
result = output[0];
|
||||
return false;
|
||||
}
|
||||
});
|
||||
results.push(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -16,23 +16,30 @@ Export our filter function
|
||||
exports.filter = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
var resultsToRemove = [];
|
||||
var resultsToRemove = [],
|
||||
index = 0;
|
||||
results.each(function(title) {
|
||||
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name) {
|
||||
switch(name) {
|
||||
case "currentTiddler":
|
||||
return "" + title;
|
||||
case "..currentTiddler":
|
||||
return widget.getVariable("currentTiddler");
|
||||
default:
|
||||
return widget.getVariable(name);
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler"),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (results.length - 1 - index),
|
||||
"length": "" + results.length
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
if(filtered.length === 0) {
|
||||
resultsToRemove.push(title);
|
||||
}
|
||||
++index;
|
||||
});
|
||||
results.remove(resultsToRemove);
|
||||
}
|
||||
|
||||
@@ -15,22 +15,29 @@ Export our filter prefix function
|
||||
exports.map = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
var inputTitles = results.toArray();
|
||||
var inputTitles = results.toArray(),
|
||||
index = 0;
|
||||
results.clear();
|
||||
$tw.utils.each(inputTitles,function(title) {
|
||||
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name) {
|
||||
switch(name) {
|
||||
case "currentTiddler":
|
||||
return "" + title;
|
||||
case "..currentTiddler":
|
||||
return widget.getVariable("currentTiddler");
|
||||
default:
|
||||
return widget.getVariable(name);
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler"),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (inputTitles.length - 1 - index),
|
||||
"length": "" + inputTitles.length
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
results.push(filtered[0] || "");
|
||||
++index;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,26 +15,24 @@ Export our filter prefix function
|
||||
exports.reduce = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
var accumulator = "";
|
||||
var index = 0;
|
||||
var accumulator = "",
|
||||
index = 0;
|
||||
results.each(function(title) {
|
||||
var list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name) {
|
||||
switch(name) {
|
||||
case "currentTiddler":
|
||||
return "" + title;
|
||||
case "..currentTiddler":
|
||||
return widget.getVariable("currentTiddler");
|
||||
case "accumulator":
|
||||
return "" + accumulator;
|
||||
case "index":
|
||||
return "" + index;
|
||||
case "revIndex":
|
||||
return "" + (results.length - 1 - index);
|
||||
case "length":
|
||||
return "" + results.length;
|
||||
default:
|
||||
return widget.getVariable(name);
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler"),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (results.length - 1 - index),
|
||||
"length": "" + results.length,
|
||||
"accumulator": "" + accumulator
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -26,14 +26,16 @@ exports.sort = function(operationSubFunction,options) {
|
||||
compareFn;
|
||||
results.each(function(title) {
|
||||
var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name) {
|
||||
switch(name) {
|
||||
case "currentTiddler":
|
||||
return "" + title;
|
||||
case "..currentTiddler":
|
||||
return widget.getVariable("currentTiddler");
|
||||
default:
|
||||
return widget.getVariable(name);
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler")
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -103,4 +103,16 @@ exports.nth = function(source,operator,options) {
|
||||
return results.slice(count - 1,count);
|
||||
};
|
||||
|
||||
/*
|
||||
The zero based nth member of the list
|
||||
*/
|
||||
exports.zth = function(source,operator,options) {
|
||||
var count = $tw.utils.getInt(operator.operand,0),
|
||||
results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results.slice(count,count + 1);
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -121,21 +121,23 @@ exports["search-replace"] = function(source,operator,options) {
|
||||
flagSuffix = (suffixes[0] ? (suffixes[0][0] || "") : ""),
|
||||
flags = (flagSuffix.indexOf("g") !== -1 ? "g" : "") + (flagSuffix.indexOf("i") !== -1 ? "i" : "") + (flagSuffix.indexOf("m") !== -1 ? "m" : ""),
|
||||
isRegExp = (suffixes[1] && suffixes[1][0] === "regexp") ? true : false,
|
||||
searchTerm,
|
||||
//Escape regexp characters if the operand is not a regular expression
|
||||
searchTerm = isRegExp ? operator.operand : $tw.utils.escapeRegExp(operator.operand),
|
||||
//Escape $ character in replacement string if not in regular expression mode
|
||||
replacement = isRegExp ? operator.operands[1] : (operator.operands[1]||"").replace(/\$/g,"$$$$"),
|
||||
regExp;
|
||||
try {
|
||||
regExp = new RegExp(searchTerm,flags);
|
||||
} catch(ex) {
|
||||
return ["RegExp error: " + ex];
|
||||
}
|
||||
|
||||
source(function(tiddler,title) {
|
||||
if(title && (operator.operands.length > 1)) {
|
||||
//Escape regexp characters if the operand is not a regular expression
|
||||
searchTerm = isRegExp ? operator.operand : $tw.utils.escapeRegExp(operator.operand);
|
||||
try {
|
||||
regExp = new RegExp(searchTerm,flags);
|
||||
} catch(ex) {
|
||||
return ["RegExp error: " + ex];
|
||||
}
|
||||
results.push(
|
||||
title.replace(regExp,operator.operands[1])
|
||||
title.replace(regExp,replacement)
|
||||
);
|
||||
regExp.lastIndex = 0;
|
||||
} else {
|
||||
results.push(title);
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/server/routes/post-commands.js
|
||||
type: application/javascript
|
||||
module-type: route
|
||||
|
||||
POST /commands/
|
||||
|
||||
\*/
|
||||
(function() {
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.method = "POST";
|
||||
|
||||
exports.path = /^\/commands\/$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
// Check we're enabled
|
||||
if(!($tw.boot.wikiInfo.config || {})["allow-remote-commands"]) {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
// Get the job descriptor
|
||||
var jobDescriptor = JSON.parse(state.data);
|
||||
console.log("JOB START:",jobDescriptor)
|
||||
// Respond OK
|
||||
response.writeHead(204, "OK",{
|
||||
"Content-Type": "application/json"
|
||||
});
|
||||
// Maintain status
|
||||
var setStatus = function(status,message) {
|
||||
if(jobDescriptor.statusTitle) {
|
||||
state.wiki.addTiddler(new $tw.Tiddler({title: jobDescriptor.statusTitle,text: status,message: message}));
|
||||
}
|
||||
}
|
||||
setStatus("started");
|
||||
// Initiate the commands
|
||||
var commander = new $tw.Commander(
|
||||
jobDescriptor.commands || [],
|
||||
function(err) {
|
||||
setStatus(err ? "error" : "ok",err ? err : undefined);
|
||||
console.log("JOB END:",err)
|
||||
},
|
||||
state.wiki,
|
||||
{output: process.stdout, error: process.stderr}
|
||||
);
|
||||
commander.execute();
|
||||
// Return results
|
||||
response.end(JSON.stringify({}),"utf8"); // Nothing useful for us to return
|
||||
};
|
||||
|
||||
}());
|
||||
@@ -130,11 +130,6 @@ function Syncer(options) {
|
||||
$tw.rootWidget.addEventListener("tm-server-refresh",function() {
|
||||
self.handleRefreshEvent();
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tm-execute-job",function(event) {
|
||||
if(self.syncadaptor && self.syncadaptor.executeJob) {
|
||||
self.syncadaptor.executeJob(event);
|
||||
}
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tm-copy-syncer-logs-to-clipboard",function() {
|
||||
$tw.utils.copyToClipboard($tw.utils.getSystemInfo() + "\n\nLog:\n" + self.logger.getBuffer());
|
||||
});
|
||||
|
||||
@@ -208,10 +208,10 @@ function parseJSONTiddlers(json,fallbackTitle) {
|
||||
return data;
|
||||
};
|
||||
|
||||
exports.dragEventContainsFiles = function(event) {
|
||||
function dragEventContainsType(event,targetType) {
|
||||
if(event.dataTransfer.types) {
|
||||
for(var i=0; i<event.dataTransfer.types.length; i++) {
|
||||
if(event.dataTransfer.types[i] === "Files") {
|
||||
if(event.dataTransfer.types[i] === targetType) {
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
@@ -220,4 +220,10 @@ exports.dragEventContainsFiles = function(event) {
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.dragEventContainsFiles = function(event) {
|
||||
return (dragEventContainsType(event,"Files") && !dragEventContainsType(event,"text/plain"));
|
||||
};
|
||||
|
||||
exports.dragEventContainsType = dragEventContainsType;
|
||||
|
||||
})();
|
||||
|
||||
@@ -87,7 +87,7 @@ SendMessageWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
param: param,
|
||||
paramObject: paramObject,
|
||||
event: event,
|
||||
currentTiddler: this.getVariable("currentTiddler"),
|
||||
tiddlerTitle: this.getVariable("currentTiddler"),
|
||||
navigateFromTitle: this.getVariable("storyTiddler")
|
||||
};
|
||||
this.dispatchEvent(params);
|
||||
|
||||
@@ -52,7 +52,13 @@ CodeBlockWidget.prototype.execute = function() {
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
CodeBlockWidget.prototype.refresh = function(changedTiddlers) {
|
||||
return false;
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.code || changedAttributes.language) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
exports.codeblock = CodeBlockWidget;
|
||||
|
||||
@@ -198,7 +198,8 @@ DropZoneWidget.prototype.handleDropEvent = function(event) {
|
||||
this.resetState();
|
||||
// Import any files in the drop
|
||||
var numFiles = 0;
|
||||
if(dataTransfer.files) {
|
||||
// If we have type text/vnd.tiddlywiki then skip trying to import files
|
||||
if(dataTransfer.files && !$tw.utils.dragEventContainsType(event,"text/vnd.tiddler")) {
|
||||
numFiles = this.wiki.readFiles(dataTransfer.files,{
|
||||
callback: readFileCallback,
|
||||
deserializer: this.dropzoneDeserializer
|
||||
|
||||
96
core/modules/widgets/let.js
Normal file
96
core/modules/widgets/let.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/let.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
This widget allows defining multiple variables at once, while allowing
|
||||
the later variables to depend upon the earlier ones.
|
||||
|
||||
```
|
||||
\define helloworld() Hello world!
|
||||
<$let currentTiddler="target" value={{!!value}} currentTiddler="different">
|
||||
{{!!value}} will be different from <<value>>
|
||||
</$let>
|
||||
```
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var LetWidget = function(parseTreeNode,options) {
|
||||
// Initialise
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
LetWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
LetWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
this.renderChildren(parent,nextSibling);
|
||||
};
|
||||
|
||||
LetWidget.prototype.computeAttributes = function() {
|
||||
// Before computing attributes, we must make clear that none of the
|
||||
// existing attributes are staged for lookup, even on a refresh
|
||||
var changedAttributes = {},
|
||||
self = this;
|
||||
this.currentValueFor = Object.create(null);
|
||||
$tw.utils.each(this.parseTreeNode.orderedAttributes,function(attribute,index) {
|
||||
var value = self.computeAttribute(attribute),
|
||||
name = attribute.name;
|
||||
if(name.charAt(0) !== "$") {
|
||||
// Now that it's prepped, we're allowed to look this variable up
|
||||
// when defining later variables
|
||||
self.currentValueFor[name] = value;
|
||||
}
|
||||
});
|
||||
// Run through again, setting variables and looking for differences
|
||||
$tw.utils.each(this.currentValueFor,function(value,name) {
|
||||
if (self.attributes[name] !== value) {
|
||||
self.attributes[name] = value;
|
||||
self.setVariable(name,value);
|
||||
changedAttributes[name] = true;
|
||||
}
|
||||
});
|
||||
return changedAttributes;
|
||||
};
|
||||
|
||||
LetWidget.prototype.getVariableInfo = function(name,options) {
|
||||
// Special handling: If this variable exists in this very $let, we can
|
||||
// use it, but only if it's been staged.
|
||||
if ($tw.utils.hop(this.currentValueFor,name)) {
|
||||
return {
|
||||
text: this.currentValueFor[name]
|
||||
};
|
||||
}
|
||||
return Widget.prototype.getVariableInfo.call(this,name,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Refresh the widget by ensuring our attributes are up to date
|
||||
*/
|
||||
LetWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if($tw.utils.count(changedAttributes) > 0) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
exports["let"] = LetWidget;
|
||||
|
||||
})();
|
||||
@@ -29,14 +29,12 @@ var VarsWidget = function(parseTreeNode,options) {
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
VarsWidget.prototype = Object.create(Widget.prototype);
|
||||
VarsWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
VarsWidget.prototype.render = function(parent,nextSibling) {
|
||||
// Call the constructor
|
||||
Widget.call(this);
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
@@ -63,7 +61,7 @@ Refresh the widget by ensuring our attributes are up to date
|
||||
*/
|
||||
VarsWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(Object.keys(changedAttributes).length) {
|
||||
if($tw.utils.count(changedAttributes) > 0) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ Widget.prototype.getVariableInfo = function(name,options) {
|
||||
});
|
||||
// Only substitute variable references if this variable was defined with the \define pragma
|
||||
if(variable.isMacroDefinition) {
|
||||
value = this.substituteVariableReferences(value);
|
||||
value = this.substituteVariableReferences(value,options);
|
||||
}
|
||||
return {
|
||||
text: value,
|
||||
@@ -175,10 +175,10 @@ Widget.prototype.resolveVariableParameters = function(formalParams,actualParams)
|
||||
return results;
|
||||
};
|
||||
|
||||
Widget.prototype.substituteVariableReferences = function(text) {
|
||||
Widget.prototype.substituteVariableReferences = function(text,options) {
|
||||
var self = this;
|
||||
return (text || "").replace(/\$\(([^\)\$]+)\)\$/g,function(match,p1,offset,string) {
|
||||
return self.getVariable(p1,{defaultValue: ""});
|
||||
return options.variables && options.variables[p1] || (self.getVariable(p1,{defaultValue: ""}));
|
||||
});
|
||||
};
|
||||
|
||||
@@ -263,19 +263,9 @@ Compute the current values of the attributes of the widget. Returns a hashmap of
|
||||
*/
|
||||
Widget.prototype.computeAttributes = function() {
|
||||
var changedAttributes = {},
|
||||
self = this,
|
||||
value;
|
||||
self = this;
|
||||
$tw.utils.each(this.parseTreeNode.attributes,function(attribute,name) {
|
||||
if(attribute.type === "filtered") {
|
||||
value = self.wiki.filterTiddlers(attribute.filter,self)[0] || "";
|
||||
} else if(attribute.type === "indirect") {
|
||||
value = self.wiki.getTextReference(attribute.textReference,"",self.getVariable("currentTiddler"));
|
||||
} else if(attribute.type === "macro") {
|
||||
value = self.getVariable(attribute.value.name,{params: attribute.value.params});
|
||||
} else { // String attribute
|
||||
value = attribute.value;
|
||||
}
|
||||
// Check whether the attribute has changed
|
||||
var value = self.computeAttribute(attribute);
|
||||
if(self.attributes[name] !== value) {
|
||||
self.attributes[name] = value;
|
||||
changedAttributes[name] = true;
|
||||
@@ -284,6 +274,20 @@ Widget.prototype.computeAttributes = function() {
|
||||
return changedAttributes;
|
||||
};
|
||||
|
||||
Widget.prototype.computeAttribute = function(attribute) {
|
||||
var value;
|
||||
if(attribute.type === "filtered") {
|
||||
value = this.wiki.filterTiddlers(attribute.filter,this)[0] || "";
|
||||
} else if(attribute.type === "indirect") {
|
||||
value = this.wiki.getTextReference(attribute.textReference,"",this.getVariable("currentTiddler"));
|
||||
} else if(attribute.type === "macro") {
|
||||
value = this.getVariable(attribute.value.name,{params: attribute.value.params});
|
||||
} else { // String attribute
|
||||
value = attribute.value;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
/*
|
||||
Check for the presence of an attribute
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
title: $:/core/ui/Components/tag-link
|
||||
|
||||
<$link>
|
||||
<$set name="backgroundColor" value={{!!color}}>
|
||||
<$set name="backgroundColor" value={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}}>
|
||||
<span style=<<tag-styles>> class="tc-tag-label">
|
||||
<$view field="title" format="text"/>
|
||||
</span>
|
||||
|
||||
9
core/ui/ControlPanel/Cascades.tid
Normal file
9
core/ui/ControlPanel/Cascades.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: $:/core/ui/ControlPanel/Cascades
|
||||
tags: $:/tags/ControlPanel/Advanced
|
||||
caption: {{$:/language/ControlPanel/Cascades/Caption}}
|
||||
|
||||
{{$:/language/ControlPanel/Cascades/Hint}}
|
||||
|
||||
<div class="tc-control-panel">
|
||||
<$macrocall $name="tabs" tabsList="[all[shadows+tiddlers]tag[$:/tags/ControlPanel/Cascades]!has[draft.of]]" default="$:/core/ui/ControlPanel/StoryTiddler"/>
|
||||
</div>
|
||||
9
core/ui/ControlPanel/Cascades/EditTemplateBody.tid
Normal file
9
core/ui/ControlPanel/Cascades/EditTemplateBody.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: $:/core/ui/ControlPanel/EditTemplateBody
|
||||
tags: $:/tags/ControlPanel/Cascades
|
||||
caption: {{$:/language/ControlPanel/EditTemplateBody/Caption}}
|
||||
|
||||
\define lingo-base() $:/language/ControlPanel/EditTemplateBody/
|
||||
|
||||
<<lingo Hint>>
|
||||
|
||||
{{$:/tags/EditTemplateBodyFilter||$:/snippets/ListTaggedCascade}}
|
||||
9
core/ui/ControlPanel/Cascades/StoryTiddler.tid
Normal file
9
core/ui/ControlPanel/Cascades/StoryTiddler.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: $:/core/ui/ControlPanel/StoryTiddler
|
||||
tags: $:/tags/ControlPanel/Cascades
|
||||
caption: {{$:/language/ControlPanel/StoryTiddler/Caption}}
|
||||
|
||||
\define lingo-base() $:/language/ControlPanel/StoryTiddler/
|
||||
|
||||
<<lingo Hint>>
|
||||
|
||||
{{$:/tags/StoryTiddlerTemplateFilter||$:/snippets/ListTaggedCascade}}
|
||||
9
core/ui/ControlPanel/Cascades/TiddlerColour.tid
Normal file
9
core/ui/ControlPanel/Cascades/TiddlerColour.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: $:/core/ui/ControlPanel/TiddlerColour
|
||||
tags: $:/tags/ControlPanel/Cascades
|
||||
caption: {{$:/language/ControlPanel/TiddlerColour/Caption}}
|
||||
|
||||
\define lingo-base() $:/language/ControlPanel/TiddlerColour/
|
||||
|
||||
<<lingo Hint>>
|
||||
|
||||
{{$:/tags/TiddlerColourFilter||$:/snippets/ListTaggedCascade}}
|
||||
9
core/ui/ControlPanel/Cascades/TiddlerIcon.tid
Normal file
9
core/ui/ControlPanel/Cascades/TiddlerIcon.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: $:/core/ui/ControlPanel/TiddlerIcon
|
||||
tags: $:/tags/ControlPanel/Cascades
|
||||
caption: {{$:/language/ControlPanel/TiddlerIcon/Caption}}
|
||||
|
||||
\define lingo-base() $:/language/ControlPanel/TiddlerIcon/
|
||||
|
||||
<<lingo Hint>>
|
||||
|
||||
{{$:/tags/TiddlerIconFilter||$:/snippets/ListTaggedCascade}}
|
||||
9
core/ui/ControlPanel/Cascades/ViewTemplateBody.tid
Normal file
9
core/ui/ControlPanel/Cascades/ViewTemplateBody.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: $:/core/ui/ControlPanel/ViewTemplateBody
|
||||
tags: $:/tags/ControlPanel/Cascades
|
||||
caption: {{$:/language/ControlPanel/ViewTemplateBody/Caption}}
|
||||
|
||||
\define lingo-base() $:/language/ControlPanel/ViewTemplateBody/
|
||||
|
||||
<<lingo Hint>>
|
||||
|
||||
{{$:/tags/ViewTemplateBodyFilter||$:/snippets/ListTaggedCascade}}
|
||||
9
core/ui/ControlPanel/Cascades/ViewTemplateTitle.tid
Normal file
9
core/ui/ControlPanel/Cascades/ViewTemplateTitle.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: $:/core/ui/ControlPanel/ViewTemplateTitle
|
||||
tags: $:/tags/ControlPanel/Cascades
|
||||
caption: {{$:/language/ControlPanel/ViewTemplateTitle/Caption}}
|
||||
|
||||
\define lingo-base() $:/language/ControlPanel/ViewTemplateTitle/
|
||||
|
||||
<<lingo Hint>>
|
||||
|
||||
{{$:/tags/ViewTemplateTitleFilter||$:/snippets/ListTaggedCascade}}
|
||||
@@ -1,54 +1,4 @@
|
||||
title: $:/core/ui/EditTemplate/body
|
||||
tags: $:/tags/EditTemplate
|
||||
|
||||
\define lingo-base() $:/language/EditTemplate/Body/
|
||||
\define config-visibility-title()
|
||||
$:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$
|
||||
\end
|
||||
|
||||
\define importFileActions()
|
||||
<$action-popup $state=<<importState>> $coords="(0,0,0,0)" $floating="yes"/>
|
||||
\end
|
||||
|
||||
<$list filter="[all[current]has[_canonical_uri]]">
|
||||
|
||||
<div class="tc-message-box">
|
||||
|
||||
<<lingo External/Hint>>
|
||||
|
||||
<a href={{!!_canonical_uri}}><$text text={{!!_canonical_uri}}/></a>
|
||||
|
||||
<$edit-text field="_canonical_uri" class="tc-edit-fields" tabindex={{$:/config/EditTabIndex}} cancelPopups="yes"></$edit-text>
|
||||
|
||||
</div>
|
||||
|
||||
</$list>
|
||||
|
||||
<$list filter="[all[current]!has[_canonical_uri]]">
|
||||
<$vars importTitle=<<qualify $:/ImportImage>> importState=<<qualify $:/state/ImportImage>> >
|
||||
<$dropzone importTitle=<<importTitle>> autoOpenOnImport="no" contentTypesFilter={{$:/config/Editor/ImportContentTypesFilter}} class="tc-dropzone-editor" enable={{{ [{$:/config/DragAndDrop/Enable}match[no]] :else[subfilter{$:/config/Editor/EnableImportFilter}then[yes]else[no]] }}} filesOnly="yes" actions=<<importFileActions>> ><$reveal state="$:/state/showeditpreview" type="match" text="yes">
|
||||
<div class="tc-tiddler-preview">
|
||||
|
||||
<$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/>
|
||||
|
||||
<div class="tc-tiddler-preview-preview">
|
||||
|
||||
<$transclude tiddler={{$:/state/editpreviewtype}} mode="inline">
|
||||
|
||||
<$transclude tiddler="$:/core/ui/EditTemplate/body/preview/output" mode="inline"/>
|
||||
|
||||
</$transclude>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</$reveal>
|
||||
|
||||
<$reveal state="$:/state/showeditpreview" type="nomatch" text="yes">
|
||||
|
||||
<$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/>
|
||||
|
||||
</$reveal>
|
||||
</$dropzone>
|
||||
</$vars>
|
||||
</$list>
|
||||
<$transclude tiddler={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/EditTemplateBodyFilter]!is[draft]get[text]] :and[!is[blank]else[$:/core/ui/EditTemplate/body/default]] }}} />
|
||||
|
||||
13
core/ui/EditTemplate/body/canonical-uri.tid
Normal file
13
core/ui/EditTemplate/body/canonical-uri.tid
Normal file
@@ -0,0 +1,13 @@
|
||||
title: $:/core/ui/EditTemplate/body/canonical-uri
|
||||
|
||||
\define lingo-base() $:/language/EditTemplate/Body/
|
||||
|
||||
<div class="tc-message-box">
|
||||
|
||||
<<lingo External/Hint>>
|
||||
|
||||
<a href={{!!_canonical_uri}}><$text text={{!!_canonical_uri}}/></a>
|
||||
|
||||
<$edit-text field="_canonical_uri" class="tc-edit-fields" tabindex={{$:/config/EditTabIndex}} cancelPopups="yes"></$edit-text>
|
||||
|
||||
</div>
|
||||
38
core/ui/EditTemplate/body/default.tid
Normal file
38
core/ui/EditTemplate/body/default.tid
Normal file
@@ -0,0 +1,38 @@
|
||||
title: $:/core/ui/EditTemplate/body/default
|
||||
|
||||
\define config-visibility-title()
|
||||
$:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$
|
||||
\end
|
||||
|
||||
\define importFileActions()
|
||||
<$action-popup $state=<<importState>> $coords="(0,0,0,0)" $floating="yes"/>
|
||||
\end
|
||||
|
||||
<$set name="edit-preview-state" value={{{ [{$:/config/ShowEditPreview/PerTiddler}!match[yes]then[$:/state/showeditpreview]] :else[<qualify "$:/state/showeditpreview">] }}}>
|
||||
<$vars importTitle=<<qualify $:/ImportImage>> importState=<<qualify $:/state/ImportImage>> >
|
||||
<$dropzone importTitle=<<importTitle>> autoOpenOnImport="no" contentTypesFilter={{$:/config/Editor/ImportContentTypesFilter}} class="tc-dropzone-editor" enable={{{ [{$:/config/DragAndDrop/Enable}match[no]] :else[subfilter{$:/config/Editor/EnableImportFilter}then[yes]else[no]] }}} filesOnly="yes" actions=<<importFileActions>> ><$reveal stateTitle=<<edit-preview-state>> type="match" text="yes">
|
||||
<div class="tc-tiddler-preview">
|
||||
|
||||
<$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/>
|
||||
|
||||
<div class="tc-tiddler-preview-preview">
|
||||
|
||||
<$transclude tiddler={{$:/state/editpreviewtype}} mode="inline">
|
||||
|
||||
<$transclude tiddler="$:/core/ui/EditTemplate/body/preview/output" mode="inline"/>
|
||||
|
||||
</$transclude>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</$reveal>
|
||||
|
||||
<$reveal stateTitle=<<edit-preview-state>> type="nomatch" text="yes">
|
||||
|
||||
<$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/>
|
||||
|
||||
</$reveal>
|
||||
</$dropzone>
|
||||
</$vars>
|
||||
</$set>
|
||||
@@ -29,7 +29,7 @@ color:$(foregroundColor)$;
|
||||
\whitespace trim
|
||||
<div class="tc-edit-tags">
|
||||
<$list filter="[list[!!$tagField$]sort[title]]" storyview="pop">
|
||||
<$macrocall $name="tag-body" colour={{!!color}} palette={{$:/palette}} icon={{!!icon}} tagField=<<__tagField__>>/>
|
||||
<$macrocall $name="tag-body" colour={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}} palette={{$:/palette}} icon={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerIconFilter]!is[draft]get[text]] }}} tagField=<<__tagField__>>/>
|
||||
</$list>
|
||||
<$vars tabIndex={{$:/config/EditTabIndex}} cancelPopups="yes">
|
||||
<$macrocall $name="tag-picker" tagField=<<__tagField__>>/>
|
||||
|
||||
@@ -8,11 +8,11 @@ condition: [<targetTiddler>]
|
||||
button-classes: tc-text-editor-toolbar-item-start-group
|
||||
shortcuts: ((preview))
|
||||
|
||||
<$reveal state="$:/state/showeditpreview" type="match" text="yes" tag="span">
|
||||
<$reveal state=<<edit-preview-state>> type="match" text="yes" tag="span">
|
||||
{{$:/core/images/preview-open}}
|
||||
<$action-setfield $tiddler="$:/state/showeditpreview" $value="no"/>
|
||||
<$action-setfield $tiddler=<<edit-preview-state>> $value="no"/>
|
||||
</$reveal>
|
||||
<$reveal state="$:/state/showeditpreview" type="nomatch" text="yes" tag="span">
|
||||
<$reveal state=<<edit-preview-state>> type="nomatch" text="yes" tag="span">
|
||||
{{$:/core/images/preview-closed}}
|
||||
<$action-setfield $tiddler="$:/state/showeditpreview" $value="yes"/>
|
||||
<$action-setfield $tiddler=<<edit-preview-state>> $value="yes"/>
|
||||
</$reveal>
|
||||
|
||||
14
core/ui/ListTaggedCascade.tid
Normal file
14
core/ui/ListTaggedCascade.tid
Normal file
@@ -0,0 +1,14 @@
|
||||
title: $:/snippets/ListTaggedCascade
|
||||
|
||||
{{||$:/language/ControlPanel/Cascades/TagPrompt}}
|
||||
|
||||
<ol>
|
||||
<$list filter="[all[shadows+tiddlers]tag<currentTiddler>]">
|
||||
<li>
|
||||
<div>
|
||||
<$link><$text text=<<currentTiddler>>/></$link>
|
||||
</div>
|
||||
<$codeblock code={{!!text}}/>
|
||||
</li>
|
||||
</$list>
|
||||
</ol>
|
||||
@@ -14,7 +14,7 @@ tags: $:/tags/PageTemplate
|
||||
|
||||
</section>
|
||||
|
||||
<$list filter="[list[$:/StoryList]]" history="$:/HistoryList" template={{$:/config/ui/ViewTemplate}} editTemplate={{$:/config/ui/EditTemplate}} storyview={{$:/view}} emptyMessage={{$:/config/EmptyStoryMessage}}/>
|
||||
<$list filter="[list[$:/StoryList]]" history="$:/HistoryList" template="$:/core/ui/StoryTiddlerTemplate" storyview={{$:/view}} emptyMessage={{$:/config/EmptyStoryMessage}}/>
|
||||
|
||||
<section class="story-frontdrop">
|
||||
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
title: $:/core/ui/PluginListItemTemplate
|
||||
|
||||
<div class="tc-menu-list-item">
|
||||
<$link to={{!!title}}><$view field="description"><$view field="title"/></$view></$link>
|
||||
</div>
|
||||
\whitespace trim
|
||||
<$link to={{!!title}} class="tc-plugin-info">
|
||||
<div class="tc-plugin-info-chunk tc-plugin-info-icon">
|
||||
<$transclude tiddler=<<currentTiddler>> subtiddler={{{ [<currentTiddler>addsuffix[/icon]] }}}>
|
||||
<$transclude tiddler={{{ [<currentTiddler>get[plugin-type]addprefix[$:/core/images/plugin-generic-]] }}}/>
|
||||
</$transclude>
|
||||
</div>
|
||||
<div class="tc-plugin-info-chunk tc-plugin-info-description">
|
||||
<h1>
|
||||
''<$text text={{{ [<currentTiddler>get[name]] ~[<currentTiddler>split[/]last[1]] }}}/>'': <$view field="description"><$view field="title"/></$view>
|
||||
</h1>
|
||||
</div>
|
||||
</$link>
|
||||
|
||||
3
core/ui/StoryTiddlerTemplate.tid
Normal file
3
core/ui/StoryTiddlerTemplate.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/core/ui/StoryTiddlerTemplate
|
||||
|
||||
<$transclude tiddler={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/StoryTiddlerTemplateFilter]!is[draft]get[text]] :and[!is[blank]else{$:/config/ui/ViewTemplate}] }}} />
|
||||
@@ -13,10 +13,10 @@ title: $:/core/ui/TagPickerTagTemplate
|
||||
<$action-setfield $tiddler=<<refreshTitle>> text="yes"/>
|
||||
</$list>
|
||||
<<actions>>
|
||||
<$set name="backgroundColor" value={{!!color}}>
|
||||
<$wikify name="foregroundColor" text="""<$macrocall $name="contrastcolour" target={{!!color}} fallbackTarget=<<fallbackTarget>> colourA=<<colourA>> colourB=<<colourB>>/>""">
|
||||
<$set name="backgroundColor" value={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}}>
|
||||
<$wikify name="foregroundColor" text="""<$macrocall $name="contrastcolour" target=<<backgroundColor>> fallbackTarget=<<fallbackTarget>> colourA=<<colourA>> colourB=<<colourB>>/>""">
|
||||
<span class="tc-tag-label tc-btn-invisible" style=<<tag-pill-styles>>>
|
||||
<$transclude tiddler={{!!icon}}/><$view field="title" format="text"/>
|
||||
{{||$:/core/ui/TiddlerIcon}}<$view field="title" format="text"/>
|
||||
</span>
|
||||
</$wikify>
|
||||
</$set>
|
||||
|
||||
@@ -3,7 +3,7 @@ title: $:/core/ui/TagTemplate
|
||||
\whitespace trim
|
||||
<span class="tc-tag-list-item" data-tag-title=<<currentTiddler>>>
|
||||
<$set name="transclusion" value=<<currentTiddler>>>
|
||||
<$macrocall $name="tag-pill-body" tag=<<currentTiddler>> icon={{!!icon}} colour={{!!color}} palette={{$:/palette}} element-tag="""$button""" element-attributes="""popup=<<qualify "$:/state/popup/tag">> dragFilter='[all[current]tagging[]]' tag='span'"""/>
|
||||
<$macrocall $name="tag-pill-body" tag=<<currentTiddler>> icon={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerIconFilter]!is[draft]get[text]] }}} colour={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}} palette={{$:/palette}} element-tag="""$button""" element-attributes="""popup=<<qualify "$:/state/popup/tag">> dragFilter='[all[current]tagging[]]' tag='span'"""/>
|
||||
<$reveal state=<<qualify "$:/state/popup/tag">> type="popup" position="below" animate="yes" class="tc-drop-down">
|
||||
<$set name="tv-show-missing-links" value="yes">
|
||||
<$transclude tiddler="$:/core/ui/ListItemTemplate"/>
|
||||
|
||||
8
core/ui/TiddlerIcon.tid
Normal file
8
core/ui/TiddlerIcon.tid
Normal file
@@ -0,0 +1,8 @@
|
||||
title: $:/core/ui/TiddlerIcon
|
||||
|
||||
\whitespace trim
|
||||
<$let tiddlerIcon={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerIconFilter]!is[draft]get[text]] }}}>
|
||||
<$list filter="[<tiddlerIcon>!is[blank]]" variable="ignore">
|
||||
<$transclude tiddler=<<tiddlerIcon>>/>
|
||||
</$list>
|
||||
</$let>
|
||||
@@ -3,14 +3,6 @@ tags: $:/tags/ViewTemplate
|
||||
|
||||
<$reveal tag="div" class="tc-tiddler-body" type="nomatch" stateTitle=<<folded-state>> text="hide" retain="yes" animate="yes">
|
||||
|
||||
<$list filter="[all[current]!has[plugin-type]!field:hide-body[yes]]">
|
||||
|
||||
<$transclude>
|
||||
|
||||
<$transclude tiddler="$:/language/MissingTiddler/Hint"/>
|
||||
|
||||
</$transclude>
|
||||
|
||||
</$list>
|
||||
<$transclude tiddler={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/ViewTemplateBodyFilter]!is[draft]get[text]] :and[!is[blank]else[$:/core/ui/ViewTemplate/body/default]] }}} />
|
||||
|
||||
</$reveal>
|
||||
|
||||
3
core/ui/ViewTemplate/body/blank.tid
Normal file
3
core/ui/ViewTemplate/body/blank.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/core/ui/ViewTemplate/body/blank
|
||||
|
||||
<!-- Intentionally blank -->
|
||||
3
core/ui/ViewTemplate/body/code.tid
Normal file
3
core/ui/ViewTemplate/body/code.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/core/ui/ViewTemplate/body/code
|
||||
|
||||
<$codeblock code={{{ [<currentTiddler>get[text]] }}} language={{{ [<currentTiddler>get[type]else[text/vnd.tiddlywiki]] }}}/>
|
||||
7
core/ui/ViewTemplate/body/default.tid
Normal file
7
core/ui/ViewTemplate/body/default.tid
Normal file
@@ -0,0 +1,7 @@
|
||||
title: $:/core/ui/ViewTemplate/body/default
|
||||
|
||||
<$transclude>
|
||||
|
||||
<$transclude tiddler="$:/language/MissingTiddler/Hint"/>
|
||||
|
||||
</$transclude>
|
||||
@@ -1,5 +1,4 @@
|
||||
title: $:/core/ui/ViewTemplate/import
|
||||
tags: $:/tags/ViewTemplate
|
||||
title: $:/core/ui/ViewTemplate/body/import
|
||||
|
||||
\define lingo-base() $:/language/Import/
|
||||
|
||||
10
core/ui/ViewTemplate/body/plugin.tid
Normal file
10
core/ui/ViewTemplate/body/plugin.tid
Normal file
@@ -0,0 +1,10 @@
|
||||
title: $:/core/ui/ViewTemplate/body/plugin
|
||||
|
||||
<div class="tc-tiddler-plugin-info">
|
||||
<$let plugin-type={{!!plugin-type}}
|
||||
default-popup-state="yes"
|
||||
qualified-state=<<qualify "$:/state/plugin-info">>
|
||||
>
|
||||
{{||$:/core/ui/Components/plugin-info}}
|
||||
</$let>
|
||||
</div>
|
||||
@@ -1,15 +0,0 @@
|
||||
title: $:/core/ui/ViewTemplate/plugin
|
||||
tags: $:/tags/ViewTemplate
|
||||
|
||||
<$reveal tag="div" class="tc-tiddler-plugin-info" type="nomatch" stateTitle=<<folded-state>> text="hide" retain="yes" animate="yes">
|
||||
|
||||
<$list filter="[all[current]has[plugin-type]] -[all[current]field:plugin-type[import]]">
|
||||
<$set name="plugin-type" value={{!!plugin-type}}>
|
||||
<$set name="default-popup-state" value="yes">
|
||||
<$set name="qualified-state" value=<<qualify "$:/state/plugin-info">>>
|
||||
{{||$:/core/ui/Components/plugin-info}}
|
||||
</$set>
|
||||
</$set>
|
||||
</$set>
|
||||
</$list>
|
||||
</$reveal>
|
||||
@@ -12,25 +12,12 @@ fill:$(foregroundColor)$;
|
||||
</span>
|
||||
<$set name="tv-wikilinks" value={{$:/config/Tiddlers/TitleLinks}}>
|
||||
<$link>
|
||||
<$set name="foregroundColor" value={{!!color}}>
|
||||
<$list filter="[all[current]has[icon]]~[[$:/config/DefaultTiddlerIcon]has[text]]">
|
||||
<$let foregroundColor={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}}>
|
||||
<span class="tc-tiddler-title-icon" style=<<title-styles>>>
|
||||
<$transclude tiddler={{!!icon}}>
|
||||
<$transclude tiddler={{$:/config/DefaultTiddlerIcon}}/>
|
||||
</$transclude>
|
||||
{{||$:/core/ui/TiddlerIcon}}
|
||||
</span>
|
||||
</$list>
|
||||
</$set>
|
||||
<$list filter="[all[current]removeprefix[$:/]]">
|
||||
<h2 class="tc-title" title={{$:/language/SystemTiddler/Tooltip}}>
|
||||
<span class="tc-system-title-prefix">$:/</span><$text text=<<currentTiddler>>/>
|
||||
</h2>
|
||||
</$list>
|
||||
<$list filter="[all[current]!prefix[$:/]]">
|
||||
<h2 class="tc-title">
|
||||
<$view field="title"/>
|
||||
</h2>
|
||||
</$list>
|
||||
</$let>
|
||||
<$transclude tiddler={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/ViewTemplateTitleFilter]!is[draft]get[text]] :and[!is[blank]else[$:/core/ui/ViewTemplate/title/default]] }}} />
|
||||
</$link>
|
||||
</$set>
|
||||
</div>
|
||||
|
||||
6
core/ui/ViewTemplate/title/default.tid
Normal file
6
core/ui/ViewTemplate/title/default.tid
Normal file
@@ -0,0 +1,6 @@
|
||||
title: $:/core/ui/ViewTemplate/title/default
|
||||
|
||||
\whitespace trim
|
||||
<h2 class="tc-title">
|
||||
<$view field="title"/>
|
||||
</h2>
|
||||
6
core/ui/ViewTemplate/title/system.tid
Normal file
6
core/ui/ViewTemplate/title/system.tid
Normal file
@@ -0,0 +1,6 @@
|
||||
title: $:/core/ui/ViewTemplate/title/system
|
||||
|
||||
\whitespace trim
|
||||
<h2 class="tc-title" title={{$:/language/SystemTiddler/Tooltip}}>
|
||||
<span class="tc-system-title-prefix">$:/</span><$text text={{{ [<currentTiddler>removeprefix[$:/]] }}}/>
|
||||
</h2>
|
||||
5
core/wiki/config/EditTemplateBodyFilters.multids
Normal file
5
core/wiki/config/EditTemplateBodyFilters.multids
Normal file
@@ -0,0 +1,5 @@
|
||||
title: $:/config/EditTemplateBodyFilters/
|
||||
tags: $:/tags/EditTemplateBodyFilter
|
||||
|
||||
canonical-uri: [has[_canonical_uri]then[$:/core/ui/EditTemplate/body/canonical-uri]]
|
||||
default: [[$:/core/ui/EditTemplate/body/default]]
|
||||
@@ -1,6 +1,6 @@
|
||||
title: $:/config/OfficialPluginLibrary
|
||||
tags: $:/tags/PluginLibrary
|
||||
url: https://tiddlywiki.com/library/v5.2.0/index.html
|
||||
url: https://tiddlywiki.com/library/v5.2.1/index.html
|
||||
caption: {{$:/language/OfficialPluginLibrary}}
|
||||
|
||||
{{$:/language/OfficialPluginLibrary/Hint}}
|
||||
|
||||
5
core/wiki/config/StoryTiddlerTemplateFilters.multids
Normal file
5
core/wiki/config/StoryTiddlerTemplateFilters.multids
Normal file
@@ -0,0 +1,5 @@
|
||||
title: $:/config/StoryTiddlerTemplateFilters/
|
||||
tags: $:/tags/StoryTiddlerTemplateFilter
|
||||
|
||||
draft: [is[draft]then{$:/config/ui/EditTemplate}]
|
||||
default: [{$:/config/ui/ViewTemplate}]
|
||||
5
core/wiki/config/TiddlerColourFilters.multids
Normal file
5
core/wiki/config/TiddlerColourFilters.multids
Normal file
@@ -0,0 +1,5 @@
|
||||
title: $:/config/TiddlerColourFilters/
|
||||
tags: $:/tags/TiddlerColourFilter
|
||||
|
||||
color-field: [has[color]then{!!color}]
|
||||
default: [[$:/config/DefaultTiddlerColour]has[text]get[text]trim[]]
|
||||
5
core/wiki/config/TiddlerIconFilters.multids
Normal file
5
core/wiki/config/TiddlerIconFilters.multids
Normal file
@@ -0,0 +1,5 @@
|
||||
title: $:/config/TiddlerIconFilters/
|
||||
tags: $:/tags/TiddlerIconFilter
|
||||
|
||||
icon-field: [has[icon]then{!!icon}]
|
||||
default: [{$:/config/DefaultTiddlerIcon}has[text]]
|
||||
8
core/wiki/config/ViewTemplateBodyFilters.multids
Normal file
8
core/wiki/config/ViewTemplateBodyFilters.multids
Normal file
@@ -0,0 +1,8 @@
|
||||
title: $:/config/ViewTemplateBodyFilters/
|
||||
tags: $:/tags/ViewTemplateBodyFilter
|
||||
|
||||
system: [prefix[$:/boot/]] [prefix[$:/config/]] [prefix[$:/core/]!field:title[$:/core/readme]!field:title[$:/core/icon]] [prefix[$:/info/]] [prefix[$:/language/]] [prefix[$:/languages/]] [prefix[$:/snippets/]] [prefix[$:/state/]] [prefix[$:/status/]] [prefix[$:/info/]] [prefix[$:/temp/]] +[limit[1]then[$:/core/ui/ViewTemplate/body/code]]
|
||||
import: [field:plugin-type[import]then[$:/core/ui/ViewTemplate/body/import]]
|
||||
plugin: [has[plugin-type]then[$:/core/ui/ViewTemplate/body/plugin]]
|
||||
hide-body: [field:hide-body[yes]then[$:/core/ui/ViewTemplate/body/blank]]
|
||||
default: [[$:/core/ui/ViewTemplate/body/default]]
|
||||
5
core/wiki/config/ViewTemplateTitleFilters.multids
Normal file
5
core/wiki/config/ViewTemplateTitleFilters.multids
Normal file
@@ -0,0 +1,5 @@
|
||||
title: $:/config/ViewTemplateTitleFilters/
|
||||
tags: $:/tags/ViewTemplateTitleFilter
|
||||
|
||||
system: [prefix[$:/]then[$:/core/ui/ViewTemplate/title/system]]
|
||||
default: [[$:/core/ui/ViewTemplate/title/default]]
|
||||
9
core/wiki/debugstylesheets.tid
Normal file
9
core/wiki/debugstylesheets.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: $:/snippets/DebugStylesheets
|
||||
|
||||
<style>[test]{list-style:'❌'}</style>
|
||||
<ul>
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/Stylesheet]has[modified]]" counter="n">
|
||||
<style>{{!!text}}[test="<<n>>"]{list-style:disc;}</style>
|
||||
<li test=<<n>>><$link/></li>
|
||||
</$list>
|
||||
</ul>
|
||||
@@ -21,7 +21,9 @@ $actions$<$transclude tiddler="""$icon$"""/><$view tiddler=<<__tag__>> field="ti
|
||||
|
||||
\define tag-pill(tag,element-tag:"span",element-attributes:"",actions:"")
|
||||
<span class="tc-tag-list-item" data-tag-title=<<__tag__>>>
|
||||
<$macrocall $name="tag-pill-body" tag=<<__tag__>> icon={{{ [<__tag__>get[icon]] }}} colour={{{ [<__tag__>get[color]] }}} palette={{$:/palette}} element-tag="""$element-tag$""" element-attributes="""$element-attributes$""" actions="""$actions$"""/>
|
||||
<$let currentTiddler=<<__tag__>>>
|
||||
<$macrocall $name="tag-pill-body" tag=<<__tag__>> icon={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerIconFilter]!is[draft]get[text]] }}} colour={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}} palette={{$:/palette}} element-tag="""$element-tag$""" element-attributes="""$element-attributes$""" actions="""$actions$"""/>
|
||||
</$let>
|
||||
</span>
|
||||
\end
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
title: $:/snippets/peek-stylesheets
|
||||
|
||||
\define expandable-stylesheets-list()
|
||||
\whitespace trim
|
||||
<ol>
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/Stylesheet]!has[draft.of]]">
|
||||
<$vars state=<<qualify "$:/state/peek-stylesheets/open/">>>
|
||||
@@ -38,6 +39,7 @@ title: $:/snippets/peek-stylesheets
|
||||
\end
|
||||
|
||||
\define stylesheets-list()
|
||||
\whitespace trim
|
||||
<ol>
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/Stylesheet]!has[draft.of]]">
|
||||
<li>
|
||||
@@ -57,6 +59,7 @@ title: $:/snippets/peek-stylesheets
|
||||
</$list>
|
||||
</ol>
|
||||
\end
|
||||
\whitespace trim
|
||||
|
||||
<$vars modeState=<<qualify "$:/state/peek-stylesheets/mode/">>>
|
||||
|
||||
|
||||
2
core/wiki/tags/EditTemplateBodyFilter.tid
Normal file
2
core/wiki/tags/EditTemplateBodyFilter.tid
Normal file
@@ -0,0 +1,2 @@
|
||||
title: $:/tags/EditTemplateBodyFilter
|
||||
list: $:/config/EditTemplateBodyFilters/canonical-uri $:/config/EditTemplateBodyFilters/default
|
||||
2
core/wiki/tags/StoryTiddlerTemplateFilter.tid
Normal file
2
core/wiki/tags/StoryTiddlerTemplateFilter.tid
Normal file
@@ -0,0 +1,2 @@
|
||||
title: $:/tags/StoryTiddlerTemplateFilter
|
||||
list: $:/config/StoryTiddlerTemplateFilters/draft $:/config/StoryTiddlerTemplateFilters/default
|
||||
3
core/wiki/tags/TiddlerColourFilter.tid
Normal file
3
core/wiki/tags/TiddlerColourFilter.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/tags/TiddlerColourFilter
|
||||
list: $:/config/TiddlerColourFilters/color-field $:/config/TiddlerColourFilters/default
|
||||
|
||||
3
core/wiki/tags/TiddlerIconFilter.tid
Normal file
3
core/wiki/tags/TiddlerIconFilter.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/tags/TiddlerIconFilter
|
||||
list: $:/config/TiddlerIconFilters/icon-field $:/config/TiddlerIconFilters/default
|
||||
|
||||
3
core/wiki/tags/ViewTemplateBodyFilter.tid
Normal file
3
core/wiki/tags/ViewTemplateBodyFilter.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/tags/ViewTemplateBodyFilter
|
||||
list: $:/config/ViewTemplateBodyFilters/system $:/config/ViewTemplateBodyFilters/import $:/config/ViewTemplateBodyFilters/plugin $:/config/ViewTemplateBodyFilters/hide-body $:/config/ViewTemplateBodyFilters/default
|
||||
|
||||
3
core/wiki/tags/ViewTemplateTitleFilter.tid
Normal file
3
core/wiki/tags/ViewTemplateTitleFilter.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/tags/ViewTemplateTitleFilter
|
||||
list: $:/config/ViewTemplateTitleFilters/system $:/config/ViewTemplateTitleFilters/default
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
created: 20181001171604072
|
||||
modified: 20181001184306738
|
||||
title: External Pipes
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
!! Introduction
|
||||
|
||||
The external pipes mechanism is intended to address the fact that it can be difficult for experienced developers to quickly get started working with TiddlyWiki's code because it requires a good understanding of JavaScript, and some relatively unusual concepts and techniques that are likely to be unfamiliar to most.
|
||||
|
||||
Many software developers are comfortable using and building text-based command line tools that follow the Unix philosophy of using stdin/stdout or TCP sockets for input and output, allowing tools to be chained together in powerful ways.
|
||||
|
||||
External pipes support data transfer with external programs via two techniques:
|
||||
|
||||
* By directly executing the program and communicating with it via stdin and stdout ([[mimic.js|External Pipes mimic.js]] and [[stats.js|External Pipes stats.js]])
|
||||
* By connecting to an existing TCP socket via a host address and port ([[reverser.js|External Pipes reverser.js]])
|
||||
|
||||
Pipes are registered and executed under Node.js. Execution can be triggered via a server command or via a message propagated from the browser.
|
||||
|
||||
Pipes currently support a simple question/response model:
|
||||
|
||||
* TiddlyWiki opens a connection to the host/port, or starts the external task
|
||||
* TiddlyWiki sends the outgoing data through the pipe
|
||||
* TiddlyWiki receives the incoming data through the pipe
|
||||
* The connection is close, or the external task exits
|
||||
|
||||
!! `externalpipesdemo` Edition
|
||||
|
||||
The edition at `editions/externalpipesdemo` in the TiddlyWiki 5 repo contains the example tasks referenced in this documentation.
|
||||
|
||||
!! Configuration
|
||||
|
||||
Pipes must be registered in the `tiddlywiki.info` file of a wiki folder. For example:
|
||||
|
||||
{{External Pipes tiddlywiki.info}}
|
||||
|
||||
!!! Task Configuration Properties
|
||||
|
||||
TBD
|
||||
|
||||
!!! Input Formats
|
||||
|
||||
The available input formats are:
|
||||
|
||||
* `raw-text` - concatenated raw text of the tiddlers
|
||||
* `rendered-text` - concatenated rendered text of the tiddlers
|
||||
* `rendered-html` - concatenated rendered html of the tiddlers
|
||||
* `json-raw-tiddlers` - raw tiddlers in JSON
|
||||
* `json-rendered-text-tiddlers` - rendered tiddlers in JSON
|
||||
|
||||
!!! Output Formats
|
||||
|
||||
The available output formats include:
|
||||
|
||||
* `raw-text` - raw text
|
||||
* `json-raw-tiddlers` - raw tiddlers in JSON
|
||||
|
||||
!! Usage
|
||||
|
||||
Pipes can be invoked via the `--pipe` command, or via a widget message propagated from the browser to the server.
|
||||
|
||||
!!! `--pipe` Command
|
||||
|
||||
The `--pipe` command triggers the invocation of a pipe task. The parameters are:
|
||||
|
||||
```
|
||||
tiddlywiki <wikifolder> --pipe <pipename> <filter> <incomingTitle> <arguments>...
|
||||
```
|
||||
|
||||
The ''pipename'' identifies the pipe, and must match the name defined in the `tiddlywiki.info` file.
|
||||
|
||||
The ''filter'' identifies the tiddlers to be passed to the pipe
|
||||
|
||||
The ''incomingTitle'' provides a title to be applied to incoming tiddlers for the `raw-text` output format
|
||||
|
||||
The remaining ''arguments'' are passed through to external task pipes, and ignored for other types of pipe.
|
||||
|
||||
!!! `tm-exec-task` Message
|
||||
|
||||
TBD
|
||||
|
||||
!! Examples
|
||||
|
||||
The edition `editions/externalpipesdemo` in the TiddlyWiki5 repo contains a demo wiki that invokes sample tasks.
|
||||
|
||||
!!! Mimic
|
||||
|
||||
The `mimic.js` example is a simple command line tool that accepts source text via stdin and outputs a sort of statistical parody of the input text. It is written without any knowledge of TiddlyWiki, and so serves as an example of using an existing text-based tool with TiddlyWiki.
|
||||
|
||||
```
|
||||
tiddlywiki editions/externalpipesdemo/ --verbose --pipe mimic '[[Alice in Wonderland]]' HelloThere 5 4000 --build index
|
||||
```
|
||||
|
||||
View the resulting wiki at `editions/externaltaskdemo/output/index.html`: the tiddler "HelloThere" will contain a garbled version of the "Alice in Wonderland" text.
|
||||
|
||||
!!! Stats
|
||||
|
||||
The `stats.js` example is a simple command line tool that accepts source text via stdin and outputs a sort of statistical parody of the input text. It is written without any knowledge of TiddlyWiki, and so serves as an example of using an existing text-based tool with TiddlyWiki.
|
||||
|
||||
```
|
||||
tiddlywiki editions/externalpipesdemo/ --verbose --pipe stats '[[Alice in Wonderland]]' HelloThere --build index
|
||||
```
|
||||
|
||||
View the resulting wiki at `editions/externaltaskdemo/output/index.html`: the tiddler "HelloThere" will contain statistics about the "Alice in Wonderland" text.
|
||||
|
||||
!!! Reverser
|
||||
|
||||
The `reverser.js` example is an simple command line tool that listens for connections on a host address and port, accepts source text and then returns the same text with the characters reversed.
|
||||
|
||||
Two separate commands are needed to run the sample: one to get the server running, and the second to run TiddlyWiki and invoke the server.
|
||||
|
||||
To run the server, open a command prompt in the `demo-tasks` directory and run:
|
||||
|
||||
```
|
||||
../reverser.js 8081
|
||||
```
|
||||
|
||||
And then in another command prompt in the root of the repo run:
|
||||
|
||||
```
|
||||
tiddlywiki editions/externalpipesdemo/ --verbose --pipe reverser '[[Alice in Wonderland]]' HelloThere --build index
|
||||
```
|
||||
|
||||
View the resulting wiki at `editions/externaltaskdemo/output/index.html`: the tiddler "HelloThere" will contain the reversed text of "Alice in Wonderland".
|
||||
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"tiddlers": [
|
||||
{
|
||||
"file": "../../../../../externalpipesdemo/tiddlywiki.info",
|
||||
"fields": {
|
||||
"type": "text/plain",
|
||||
"title": "External Pipes tiddlywiki.info"
|
||||
}
|
||||
},
|
||||
{
|
||||
"file": "../../../../../externalpipesdemo/demo-tasks/mimic.js",
|
||||
"fields": {
|
||||
"type": "application/javascript",
|
||||
"title": "External Pipes mimic.js"
|
||||
}
|
||||
},
|
||||
{
|
||||
"file": "../../../../../externalpipesdemo/demo-tasks/reverser.js",
|
||||
"fields": {
|
||||
"type": "application/javascript",
|
||||
"title": "External Pipes reverser.js"
|
||||
}
|
||||
},
|
||||
{
|
||||
"file": "../../../../../externalpipesdemo/demo-tasks/stats.js",
|
||||
"fields": {
|
||||
"type": "application/javascript",
|
||||
"title": "External Pipes stats.js"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
A socket server that listens on a host/port for connections and suggests tags for the incoming text
|
||||
|
||||
badtagger.js <port> <host>
|
||||
|
||||
This utility is provided as an example of using an external task that doesn't have any prior knowledge of
|
||||
TiddlyWiki. Like many Unix utilities, it just reads and writes to a socket.
|
||||
|
||||
*/
|
||||
|
||||
var net = require("net"),
|
||||
port = parseInt(process.argv[2] || "",10) || 8081, // Port
|
||||
host = process.argv[3] || "127.0.0.1"; // Host
|
||||
|
||||
var server = net.createServer();
|
||||
|
||||
server.listen(port,host);
|
||||
|
||||
server.on("connection", function(sock) {
|
||||
console.log("CONNECTED: " + sock.remoteAddress +":"+ sock.remotePort);
|
||||
// Trap errors
|
||||
sock.on("error",function(e) {
|
||||
console.log("ERROR: " + e);
|
||||
});
|
||||
// Read data until the end
|
||||
var accumulator = Buffer.alloc(0);
|
||||
sock.on("data",function(data) {
|
||||
console.log("DATA " + sock.remoteAddress + ": " + data.length);
|
||||
accumulator = Buffer.concat([accumulator,Buffer.from(data)]);
|
||||
while(accumulator.length > 4) {
|
||||
var length = accumulator.readInt32BE(0);
|
||||
if(accumulator.length >= (length + 4)) {
|
||||
if(length < 1) {
|
||||
throw "ERROR: Incoming message length field is less than 1";
|
||||
}
|
||||
var type = accumulator.readUInt8(4),
|
||||
dataLength = length - 1,
|
||||
data = accumulator.toString("latin1",5,dataLength + 5);
|
||||
accumulator = accumulator.slice(length + 4);
|
||||
// Recase it
|
||||
console.log("MESSAGE",length,type);
|
||||
var suggestedTags = Buffer.from(suggestTags(data),"latin1");
|
||||
// Send it back
|
||||
var lengthBytes = Buffer.alloc(4);
|
||||
lengthBytes.writeUInt32BE(suggestedTags.length + 1,0)
|
||||
console.log("RESPONSE",1,suggestedTags.length)
|
||||
sock.write(lengthBytes);
|
||||
var typeByte = Buffer.alloc(1);
|
||||
typeByte.writeUInt8(1,0);
|
||||
sock.write(typeByte);
|
||||
sock.write(suggestedTags);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
sock.on("end",function() {
|
||||
console.log("END")
|
||||
sock.end();
|
||||
});
|
||||
sock.on("close", function(data) {
|
||||
console.log("CLOSED: " + sock.remoteAddress +" "+ sock.remotePort);
|
||||
});
|
||||
});
|
||||
|
||||
function suggestTags(str) {
|
||||
var tags = [];
|
||||
if(/e/mi.test(str)) {
|
||||
tags.push("elephant");
|
||||
}
|
||||
if(/s/mi.test(str)) {
|
||||
tags.push("snake");
|
||||
}
|
||||
if(/c/mi.test(str)) {
|
||||
tags.push("cow");
|
||||
}
|
||||
return tags.join("\n");
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
Reads source text from stdin and mimics it to stdout to stdout using a simple statistical analysis of ngram frequency
|
||||
|
||||
mimic.js <ngram-length> <output-length>
|
||||
|
||||
This utility is provided as an example of using an external task that doesn't have any prior knowledge of
|
||||
TiddlyWiki. Like many Unix utilities, it just reads input from stdin and writes its output to stdout.
|
||||
|
||||
*/
|
||||
|
||||
var paramNgramLength = parseInt(process.argv[2] || "",10) || 3, // Size of ngrams for mimicing
|
||||
paramOutputLength = parseInt(process.argv[3] || "",10) || 1000;
|
||||
|
||||
process.stdin.resume();
|
||||
process.stdin.setEncoding("utf8");
|
||||
var inputChunks = [];
|
||||
process.stdin.on("data",function(chunk) {
|
||||
inputChunks.push(chunk);
|
||||
});
|
||||
process.stdin.on("end",function() {
|
||||
// Do the mimicry
|
||||
var output = mimic(inputChunks.join(""),paramNgramLength);
|
||||
// Output the result
|
||||
process.stdout.write(output);
|
||||
});
|
||||
|
||||
function mimic(sourceText,paramNgramLength) {
|
||||
if(!sourceText) {
|
||||
return "";
|
||||
}
|
||||
var tree = {};
|
||||
scanText(tree,sourceText,paramNgramLength);
|
||||
return generateText(tree,sourceText,paramNgramLength,paramOutputLength);
|
||||
}
|
||||
|
||||
/*
|
||||
The source text is scanned to build a tree of the ngram prefixes as follows:
|
||||
|
||||
{
|
||||
"abc": { // The ngram prefix described by this record
|
||||
count: 42, // The number of times the prefix is found in the source text
|
||||
next: [ // An array of information about each subsequent character encountered after the prefix
|
||||
{char: "d", count: 41},
|
||||
{char: " ", count: 1}
|
||||
]
|
||||
},
|
||||
"def": ... etc
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
// Process the source text into the specified tree with the chosen ngram size
|
||||
function scanText(tree,sourceText,size) {
|
||||
var currgram = [],ptr,c,ngram,branch,n;
|
||||
if(sourceText.length <= size*2)
|
||||
return tree;
|
||||
sourceText += sourceText.substring(0,size*2-1); // Wrap the text around
|
||||
for(ptr=0; ptr<size; ptr++) {
|
||||
currgram.push(sourceText.substr(ptr,1));
|
||||
}
|
||||
while(ptr < sourceText.length) {
|
||||
ngram = currgram.join("");
|
||||
c = sourceText.substr(ptr++,1);
|
||||
branch = tree[ngram];
|
||||
if(branch === undefined) {
|
||||
branch = tree[ngram] = {count: 0,next: []};
|
||||
}
|
||||
for(n = 0; n<branch.next.length; n++) {
|
||||
if(branch.next[n].char === c)
|
||||
break;
|
||||
}
|
||||
if(branch.next[n] === undefined) {
|
||||
branch.next[n] = {char: c, count: 1};
|
||||
} else {
|
||||
branch.next[n].count++;
|
||||
}
|
||||
branch.count++;
|
||||
currgram.push(c)
|
||||
currgram.shift();
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
|
||||
// Use the tree to generate mimicry
|
||||
function generateText(tree,sourceText,size,length) {
|
||||
var currgram = [];
|
||||
for(var t=0; t<size; t++) {
|
||||
currgram.push(sourceText.substr(t,1));
|
||||
}
|
||||
var result = [];
|
||||
var c,ngram,branch,r,n;
|
||||
for(t=0; t<length; t++) {
|
||||
ngram = currgram.join("");
|
||||
branch = tree[ngram];
|
||||
n = 0;
|
||||
r = Math.floor(Math.random() * branch.count);
|
||||
while(r >= branch.next[n].count) {
|
||||
r = r - branch.next[n].count;
|
||||
n++;
|
||||
}
|
||||
c = branch.next[n].char;
|
||||
result.push(c);
|
||||
currgram.push(c)
|
||||
currgram.shift();
|
||||
}
|
||||
return result.join("");
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# Sample Processes for TiddlyWiki External Pipes
|
||||
|
||||
"External Pipes" are connections enabling a wiki to communicate with an external process to perform arbitrary processing on a group of tiddlers.
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/usr/bin/env escript
|
||||
|
||||
%% run with sh ./recase_erl.sh
|
||||
|
||||
-mode(compile).
|
||||
|
||||
main(_) ->
|
||||
{ok, Listen} = gen_tcp:listen(8081, [binary,{packet,4},
|
||||
{active,true}]),
|
||||
spawn(fun() -> par_connect(Listen) end),
|
||||
receive after infinity -> void end.
|
||||
|
||||
par_connect(Listen) ->
|
||||
{ok, Socket} = gen_tcp:accept(Listen),
|
||||
io:format("connected ~n"),
|
||||
spawn(fun() -> par_connect(Listen) end),
|
||||
loop(Socket).
|
||||
|
||||
loop(Socket) ->
|
||||
receive
|
||||
{tcp,Socket,Bin} ->
|
||||
io:format("received ~p bytes ~s ~n",[size(Bin), Bin]),
|
||||
Return = recase_binary(Bin),
|
||||
io:format("sending: ~p bytes~n",[size(Return)]),
|
||||
gen_tcp:send(Socket, Return),
|
||||
loop(Socket);
|
||||
Other ->
|
||||
io:format("received ~p~n",[Other])
|
||||
end.
|
||||
|
||||
recase_binary(<<1,B/binary>>) ->
|
||||
L = binary_to_list(B),
|
||||
L1 = [recase(I) || I <- L],
|
||||
B1 = list_to_binary(L1),
|
||||
<<1,B1/binary>>.
|
||||
|
||||
recase(I) when I >= $a, I =< $z -> I - $a + $A;
|
||||
recase(I) when I >= $A, I =< $Z -> I - $A + $a;
|
||||
recase(I) -> I.
|
||||
@@ -1,77 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
A socket server that listens on a host/port for connections and reverses the case of incoming text
|
||||
|
||||
recaser.js <port> <host>
|
||||
|
||||
This utility is provided as an example of using an external task that doesn't have any prior knowledge of
|
||||
TiddlyWiki. Like many Unix utilities, it just reads and writes to a socket.
|
||||
|
||||
*/
|
||||
|
||||
var net = require("net"),
|
||||
port = parseInt(process.argv[2] || "",10) || 8081, // Port
|
||||
host = process.argv[3] || "127.0.0.1"; // Host
|
||||
|
||||
var server = net.createServer();
|
||||
|
||||
server.listen(port,host);
|
||||
|
||||
server.on("connection", function(sock) {
|
||||
console.log("CONNECTED: " + sock.remoteAddress +":"+ sock.remotePort);
|
||||
// Trap errors
|
||||
sock.on("error",function(e) {
|
||||
console.log("ERROR: " + e);
|
||||
});
|
||||
// Read data until the end
|
||||
var accumulator = Buffer.alloc(0);
|
||||
sock.on("data",function(data) {
|
||||
console.log("DATA " + sock.remoteAddress + ": " + data.length);
|
||||
accumulator = Buffer.concat([accumulator,Buffer.from(data)]);
|
||||
while(accumulator.length > 4) {
|
||||
var length = accumulator.readInt32BE(0);
|
||||
if(accumulator.length >= (length + 4)) {
|
||||
if(length < 1) {
|
||||
throw "ERROR: Incoming message length field is less than 1";
|
||||
}
|
||||
var type = accumulator.readUInt8(4),
|
||||
dataLength = length - 1,
|
||||
data = accumulator.toString("latin1",5,dataLength + 5);
|
||||
accumulator = accumulator.slice(length + 4);
|
||||
// Recase it
|
||||
console.log("MESSAGE",length,type);
|
||||
var recasedData = Buffer.from(recase(data),"latin1");
|
||||
// Send it back
|
||||
var lengthBytes = Buffer.alloc(4);
|
||||
lengthBytes.writeUInt32BE(recasedData.length + 1,0)
|
||||
console.log("RESPONSE",1,recasedData.length)
|
||||
sock.write(lengthBytes);
|
||||
var typeByte = Buffer.alloc(1);
|
||||
typeByte.writeUInt8(1,0);
|
||||
sock.write(typeByte);
|
||||
sock.write(recasedData);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
sock.on("end",function() {
|
||||
console.log("END")
|
||||
sock.end();
|
||||
});
|
||||
sock.on("close", function(data) {
|
||||
console.log("CLOSED: " + sock.remoteAddress +" "+ sock.remotePort);
|
||||
});
|
||||
});
|
||||
|
||||
function recase(str) {
|
||||
return str.split("").map(function(char) {
|
||||
if(char >= "A" && char <= "Z") {
|
||||
return char.toLowerCase();
|
||||
} else {
|
||||
return char.toUpperCase();
|
||||
}
|
||||
}).join("");
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
A socket server that listens on a host/port for connections and reverses the order of incoming text
|
||||
|
||||
reverser.js <port> <host>
|
||||
|
||||
This utility is provided as an example of using an external task that doesn't have any prior knowledge of
|
||||
TiddlyWiki. Like many Unix utilities, it just reads and writes to a socket.
|
||||
|
||||
*/
|
||||
|
||||
var net = require("net"),
|
||||
port = parseInt(process.argv[2] || "",10) || 8081, // Port
|
||||
host = process.argv[3] || "127.0.0.1"; // Host
|
||||
|
||||
var server = net.createServer({
|
||||
allowHalfOpen: true
|
||||
});
|
||||
|
||||
server.listen(port,host);
|
||||
|
||||
server.on("connection", function(sock) {
|
||||
console.log("CONNECTED: " + sock.remoteAddress +":"+ sock.remotePort);
|
||||
// Trap errors
|
||||
sock.on("error",function(e) {
|
||||
console.log("ERROR: " + e);
|
||||
});
|
||||
// Read data until the end
|
||||
var chunks = [];
|
||||
sock.on("data",function(data) {
|
||||
console.log("DATA " + sock.remoteAddress + ": " + data);
|
||||
chunks.push(data.toString());
|
||||
});
|
||||
sock.on("end",function() {
|
||||
console.log("END")
|
||||
// Write the data back to the socket
|
||||
sock.write(reverse(chunks.join("")));
|
||||
sock.end();
|
||||
});
|
||||
sock.on("close", function(data) {
|
||||
console.log("CLOSED: " + sock.remoteAddress +" "+ sock.remotePort);
|
||||
});
|
||||
});
|
||||
|
||||
function reverse(str) {
|
||||
return str.split("").reverse().join("");
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
Reads JSON tiddlers from stdin and outputs stats to stdout
|
||||
|
||||
stats.js
|
||||
|
||||
This utility is provided as an example of an external task that understands tiddler objects encoded in JSON.
|
||||
|
||||
It expects to read an array of tiddler objects from stdin in this format:
|
||||
|
||||
[
|
||||
{
|
||||
"title": "Tiddler Title",
|
||||
"text": "Text of tiddler",
|
||||
"tags": "MyTag [[My Other Tag]]"
|
||||
},
|
||||
...
|
||||
]
|
||||
|
||||
The output is in the same format.
|
||||
|
||||
*/
|
||||
|
||||
process.stdin.resume();
|
||||
process.stdin.setEncoding("utf8");
|
||||
var inputChunks = [];
|
||||
process.stdin.on("data",function(chunk) {
|
||||
inputChunks.push(chunk);
|
||||
});
|
||||
process.stdin.on("end",function() {
|
||||
// Read the JSON input
|
||||
var json = inputChunks.join(""),
|
||||
data;
|
||||
try {
|
||||
data = JSON.parse(json);
|
||||
} catch(e) {
|
||||
throw "Malformed JSON: " + e + "\n\n" + json;
|
||||
}
|
||||
// Compute some stats
|
||||
var output = computeStats(data);
|
||||
// Output the result
|
||||
process.stdout.write(JSON.stringify(output));
|
||||
});
|
||||
|
||||
function computeStats(tiddlers) {
|
||||
var numTiddlers = tiddlers.length,
|
||||
wordCount = 0,
|
||||
wordFrequency = {};
|
||||
tiddlers.forEach(function(tiddler) {
|
||||
var matches = (tiddler.text || "").match(/[A-Za-z0-9\u00c0-\u00d6\u00d8-\u00de\u00df-\u00f6\u00f8-\u00ff\u0150\u0170\u0151\u0171]+/g);
|
||||
if(matches) {
|
||||
wordCount += matches.length;
|
||||
matches.forEach(function(word) {
|
||||
word = word.toLowerCase();
|
||||
wordFrequency[word] = wordFrequency[word] || 0;
|
||||
wordFrequency[word] += 1;
|
||||
});
|
||||
}
|
||||
});
|
||||
var sortedWords = Object.keys(wordFrequency).sort(function(a,b) {
|
||||
if(wordFrequency[a] > wordFrequency[b]) {
|
||||
return -1;
|
||||
} else if(wordFrequency[a] < wordFrequency[b]) {
|
||||
return +1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
// Output
|
||||
return [
|
||||
{
|
||||
title: "PipeOutput",
|
||||
text: numTiddlers + " tiddlers in sample.\n" + wordCount + " words in sample.\n" + sortedWords.filter(function(word) {
|
||||
return word.length > 1 && wordFrequency[word] > 1;
|
||||
}).map(function(word) {
|
||||
return word + " " + wordFrequency[word] + "\n";
|
||||
}).join(""),
|
||||
type: "text/plain"
|
||||
}
|
||||
];
|
||||
};
|
||||
@@ -1,360 +0,0 @@
|
||||
title: Alice in Wonderland License
|
||||
tags: text/plain
|
||||
|
||||
End of Project Gutenberg's Alice's Adventures in Wonderland, by Lewis Carroll
|
||||
|
||||
*** END OF THIS PROJECT GUTENBERG EBOOK ALICE'S ADVENTURES IN WONDERLAND ***
|
||||
|
||||
***** This file should be named 11.txt or 11.zip *****
|
||||
This and all associated files of various formats will be found in:
|
||||
http://www.gutenberg.org/1/11/
|
||||
|
||||
Updated editions will replace the previous one--the old editions
|
||||
will be renamed.
|
||||
|
||||
Creating the works from public domain print editions means that no
|
||||
one owns a United States copyright in these works, so the Foundation
|
||||
(and you!) can copy and distribute it in the United States without
|
||||
permission and without paying copyright royalties. Special rules,
|
||||
set forth in the General Terms of Use part of this license, apply to
|
||||
copying and distributing Project Gutenberg-tm electronic works to
|
||||
protect the PROJECT GUTENBERG-tm concept and trademark. Project
|
||||
Gutenberg is a registered trademark, and may not be used if you
|
||||
charge for the eBooks, unless you receive specific permission. If you
|
||||
do not charge anything for copies of this eBook, complying with the
|
||||
rules is very easy. You may use this eBook for nearly any purpose
|
||||
such as creation of derivative works, reports, performances and
|
||||
research. They may be modified and printed and given away--you may do
|
||||
practically ANYTHING with public domain eBooks. Redistribution is
|
||||
subject to the trademark license, especially commercial
|
||||
redistribution.
|
||||
|
||||
*** START: FULL LICENSE ***
|
||||
|
||||
THE FULL PROJECT GUTENBERG LICENSE
|
||||
PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK
|
||||
|
||||
To protect the Project Gutenberg-tm mission of promoting the free
|
||||
distribution of electronic works, by using or distributing this work
|
||||
(or any other work associated in any way with the phrase "Project
|
||||
Gutenberg"), you agree to comply with all the terms of the Full Project
|
||||
Gutenberg-tm License (available with this file or online at
|
||||
http://gutenberg.org/license).
|
||||
|
||||
|
||||
Section 1. General Terms of Use and Redistributing Project Gutenberg-tm
|
||||
electronic works
|
||||
|
||||
1.A. By reading or using any part of this Project Gutenberg-tm
|
||||
electronic work, you indicate that you have read, understand, agree to
|
||||
and accept all the terms of this license and intellectual property
|
||||
(trademark/copyright) agreement. If you do not agree to abide by all
|
||||
the terms of this agreement, you must cease using and return or destroy
|
||||
all copies of Project Gutenberg-tm electronic works in your possession.
|
||||
If you paid a fee for obtaining a copy of or access to a Project
|
||||
Gutenberg-tm electronic work and you do not agree to be bound by the
|
||||
terms of this agreement, you may obtain a refund from the person or
|
||||
entity to whom you paid the fee as set forth in paragraph 1.E.8.
|
||||
|
||||
1.B. "Project Gutenberg" is a registered trademark. It may only be
|
||||
used on or associated in any way with an electronic work by people who
|
||||
agree to be bound by the terms of this agreement. There are a few
|
||||
things that you can do with most Project Gutenberg-tm electronic works
|
||||
even without complying with the full terms of this agreement. See
|
||||
paragraph 1.C below. There are a lot of things you can do with Project
|
||||
Gutenberg-tm electronic works if you follow the terms of this agreement
|
||||
and help preserve free future access to Project Gutenberg-tm electronic
|
||||
works. See paragraph 1.E below.
|
||||
|
||||
1.C. The Project Gutenberg Literary Archive Foundation ("the Foundation"
|
||||
or PGLAF), owns a compilation copyright in the collection of Project
|
||||
Gutenberg-tm electronic works. Nearly all the individual works in the
|
||||
collection are in the public domain in the United States. If an
|
||||
individual work is in the public domain in the United States and you are
|
||||
located in the United States, we do not claim a right to prevent you from
|
||||
copying, distributing, performing, displaying or creating derivative
|
||||
works based on the work as long as all references to Project Gutenberg
|
||||
are removed. Of course, we hope that you will support the Project
|
||||
Gutenberg-tm mission of promoting free access to electronic works by
|
||||
freely sharing Project Gutenberg-tm works in compliance with the terms of
|
||||
this agreement for keeping the Project Gutenberg-tm name associated with
|
||||
the work. You can easily comply with the terms of this agreement by
|
||||
keeping this work in the same format with its attached full Project
|
||||
Gutenberg-tm License when you share it without charge with others.
|
||||
|
||||
1.D. The copyright laws of the place where you are located also govern
|
||||
what you can do with this work. Copyright laws in most countries are in
|
||||
a constant state of change. If you are outside the United States, check
|
||||
the laws of your country in addition to the terms of this agreement
|
||||
before downloading, copying, displaying, performing, distributing or
|
||||
creating derivative works based on this work or any other Project
|
||||
Gutenberg-tm work. The Foundation makes no representations concerning
|
||||
the copyright status of any work in any country outside the United
|
||||
States.
|
||||
|
||||
1.E. Unless you have removed all references to Project Gutenberg:
|
||||
|
||||
1.E.1. The following sentence, with active links to, or other immediate
|
||||
access to, the full Project Gutenberg-tm License must appear prominently
|
||||
whenever any copy of a Project Gutenberg-tm work (any work on which the
|
||||
phrase "Project Gutenberg" appears, or with which the phrase "Project
|
||||
Gutenberg" is associated) is accessed, displayed, performed, viewed,
|
||||
copied or distributed:
|
||||
|
||||
This eBook is for the use of anyone anywhere at no cost and with
|
||||
almost no restrictions whatsoever. You may copy it, give it away or
|
||||
re-use it under the terms of the Project Gutenberg License included
|
||||
with this eBook or online at www.gutenberg.org
|
||||
|
||||
1.E.2. If an individual Project Gutenberg-tm electronic work is derived
|
||||
from the public domain (does not contain a notice indicating that it is
|
||||
posted with permission of the copyright holder), the work can be copied
|
||||
and distributed to anyone in the United States without paying any fees
|
||||
or charges. If you are redistributing or providing access to a work
|
||||
with the phrase "Project Gutenberg" associated with or appearing on the
|
||||
work, you must comply either with the requirements of paragraphs 1.E.1
|
||||
through 1.E.7 or obtain permission for the use of the work and the
|
||||
Project Gutenberg-tm trademark as set forth in paragraphs 1.E.8 or
|
||||
1.E.9.
|
||||
|
||||
1.E.3. If an individual Project Gutenberg-tm electronic work is posted
|
||||
with the permission of the copyright holder, your use and distribution
|
||||
must comply with both paragraphs 1.E.1 through 1.E.7 and any additional
|
||||
terms imposed by the copyright holder. Additional terms will be linked
|
||||
to the Project Gutenberg-tm License for all works posted with the
|
||||
permission of the copyright holder found at the beginning of this work.
|
||||
|
||||
1.E.4. Do not unlink or detach or remove the full Project Gutenberg-tm
|
||||
License terms from this work, or any files containing a part of this
|
||||
work or any other work associated with Project Gutenberg-tm.
|
||||
|
||||
1.E.5. Do not copy, display, perform, distribute or redistribute this
|
||||
electronic work, or any part of this electronic work, without
|
||||
prominently displaying the sentence set forth in paragraph 1.E.1 with
|
||||
active links or immediate access to the full terms of the Project
|
||||
Gutenberg-tm License.
|
||||
|
||||
1.E.6. You may convert to and distribute this work in any binary,
|
||||
compressed, marked up, nonproprietary or proprietary form, including any
|
||||
word processing or hypertext form. However, if you provide access to or
|
||||
distribute copies of a Project Gutenberg-tm work in a format other than
|
||||
"Plain Vanilla ASCII" or other format used in the official version
|
||||
posted on the official Project Gutenberg-tm web site (www.gutenberg.org),
|
||||
you must, at no additional cost, fee or expense to the user, provide a
|
||||
copy, a means of exporting a copy, or a means of obtaining a copy upon
|
||||
request, of the work in its original "Plain Vanilla ASCII" or other
|
||||
form. Any alternate format must include the full Project Gutenberg-tm
|
||||
License as specified in paragraph 1.E.1.
|
||||
|
||||
1.E.7. Do not charge a fee for access to, viewing, displaying,
|
||||
performing, copying or distributing any Project Gutenberg-tm works
|
||||
unless you comply with paragraph 1.E.8 or 1.E.9.
|
||||
|
||||
1.E.8. You may charge a reasonable fee for copies of or providing
|
||||
access to or distributing Project Gutenberg-tm electronic works provided
|
||||
that
|
||||
|
||||
- You pay a royalty fee of 20% of the gross profits you derive from
|
||||
the use of Project Gutenberg-tm works calculated using the method
|
||||
you already use to calculate your applicable taxes. The fee is
|
||||
owed to the owner of the Project Gutenberg-tm trademark, but he
|
||||
has agreed to donate royalties under this paragraph to the
|
||||
Project Gutenberg Literary Archive Foundation. Royalty payments
|
||||
must be paid within 60 days following each date on which you
|
||||
prepare (or are legally required to prepare) your periodic tax
|
||||
returns. Royalty payments should be clearly marked as such and
|
||||
sent to the Project Gutenberg Literary Archive Foundation at the
|
||||
address specified in Section 4, "Information about donations to
|
||||
the Project Gutenberg Literary Archive Foundation."
|
||||
|
||||
- You provide a full refund of any money paid by a user who notifies
|
||||
you in writing (or by e-mail) within 30 days of receipt that s/he
|
||||
does not agree to the terms of the full Project Gutenberg-tm
|
||||
License. You must require such a user to return or
|
||||
destroy all copies of the works possessed in a physical medium
|
||||
and discontinue all use of and all access to other copies of
|
||||
Project Gutenberg-tm works.
|
||||
|
||||
- You provide, in accordance with paragraph 1.F.3, a full refund of any
|
||||
money paid for a work or a replacement copy, if a defect in the
|
||||
electronic work is discovered and reported to you within 90 days
|
||||
of receipt of the work.
|
||||
|
||||
- You comply with all other terms of this agreement for free
|
||||
distribution of Project Gutenberg-tm works.
|
||||
|
||||
1.E.9. If you wish to charge a fee or distribute a Project Gutenberg-tm
|
||||
electronic work or group of works on different terms than are set
|
||||
forth in this agreement, you must obtain permission in writing from
|
||||
both the Project Gutenberg Literary Archive Foundation and Michael
|
||||
Hart, the owner of the Project Gutenberg-tm trademark. Contact the
|
||||
Foundation as set forth in Section 3 below.
|
||||
|
||||
1.F.
|
||||
|
||||
1.F.1. Project Gutenberg volunteers and employees expend considerable
|
||||
effort to identify, do copyright research on, transcribe and proofread
|
||||
public domain works in creating the Project Gutenberg-tm
|
||||
collection. Despite these efforts, Project Gutenberg-tm electronic
|
||||
works, and the medium on which they may be stored, may contain
|
||||
"Defects," such as, but not limited to, incomplete, inaccurate or
|
||||
corrupt data, transcription errors, a copyright or other intellectual
|
||||
property infringement, a defective or damaged disk or other medium, a
|
||||
computer virus, or computer codes that damage or cannot be read by
|
||||
your equipment.
|
||||
|
||||
1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the "Right
|
||||
of Replacement or Refund" described in paragraph 1.F.3, the Project
|
||||
Gutenberg Literary Archive Foundation, the owner of the Project
|
||||
Gutenberg-tm trademark, and any other party distributing a Project
|
||||
Gutenberg-tm electronic work under this agreement, disclaim all
|
||||
liability to you for damages, costs and expenses, including legal
|
||||
fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT
|
||||
LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE
|
||||
PROVIDED IN PARAGRAPH F3. YOU AGREE THAT THE FOUNDATION, THE
|
||||
TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE
|
||||
LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR
|
||||
INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a
|
||||
defect in this electronic work within 90 days of receiving it, you can
|
||||
receive a refund of the money (if any) you paid for it by sending a
|
||||
written explanation to the person you received the work from. If you
|
||||
received the work on a physical medium, you must return the medium with
|
||||
your written explanation. The person or entity that provided you with
|
||||
the defective work may elect to provide a replacement copy in lieu of a
|
||||
refund. If you received the work electronically, the person or entity
|
||||
providing it to you may choose to give you a second opportunity to
|
||||
receive the work electronically in lieu of a refund. If the second copy
|
||||
is also defective, you may demand a refund in writing without further
|
||||
opportunities to fix the problem.
|
||||
|
||||
1.F.4. Except for the limited right of replacement or refund set forth
|
||||
in paragraph 1.F.3, this work is provided to you 'AS-IS' WITH NO OTHER
|
||||
WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
WARRANTIES OF MERCHANTIBILITY OR FITNESS FOR ANY PURPOSE.
|
||||
|
||||
1.F.5. Some states do not allow disclaimers of certain implied
|
||||
warranties or the exclusion or limitation of certain types of damages.
|
||||
If any disclaimer or limitation set forth in this agreement violates the
|
||||
law of the state applicable to this agreement, the agreement shall be
|
||||
interpreted to make the maximum disclaimer or limitation permitted by
|
||||
the applicable state law. The invalidity or unenforceability of any
|
||||
provision of this agreement shall not void the remaining provisions.
|
||||
|
||||
1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the
|
||||
trademark owner, any agent or employee of the Foundation, anyone
|
||||
providing copies of Project Gutenberg-tm electronic works in accordance
|
||||
with this agreement, and any volunteers associated with the production,
|
||||
promotion and distribution of Project Gutenberg-tm electronic works,
|
||||
harmless from all liability, costs and expenses, including legal fees,
|
||||
that arise directly or indirectly from any of the following which you do
|
||||
or cause to occur: (a) distribution of this or any Project Gutenberg-tm
|
||||
work, (b) alteration, modification, or additions or deletions to any
|
||||
Project Gutenberg-tm work, and (c) any Defect you cause.
|
||||
|
||||
|
||||
Section 2. Information about the Mission of Project Gutenberg-tm
|
||||
|
||||
Project Gutenberg-tm is synonymous with the free distribution of
|
||||
electronic works in formats readable by the widest variety of computers
|
||||
including obsolete, old, middle-aged and new computers. It exists
|
||||
because of the efforts of hundreds of volunteers and donations from
|
||||
people in all walks of life.
|
||||
|
||||
Volunteers and financial support to provide volunteers with the
|
||||
assistance they need, is critical to reaching Project Gutenberg-tm's
|
||||
goals and ensuring that the Project Gutenberg-tm collection will
|
||||
remain freely available for generations to come. In 2001, the Project
|
||||
Gutenberg Literary Archive Foundation was created to provide a secure
|
||||
and permanent future for Project Gutenberg-tm and future generations.
|
||||
To learn more about the Project Gutenberg Literary Archive Foundation
|
||||
and how your efforts and donations can help, see Sections 3 and 4
|
||||
and the Foundation web page at http://www.pglaf.org.
|
||||
|
||||
|
||||
Section 3. Information about the Project Gutenberg Literary Archive
|
||||
Foundation
|
||||
|
||||
The Project Gutenberg Literary Archive Foundation is a non profit
|
||||
501(c)(3) educational corporation organized under the laws of the
|
||||
state of Mississippi and granted tax exempt status by the Internal
|
||||
Revenue Service. The Foundation's EIN or federal tax identification
|
||||
number is 64-6221541. Its 501(c)(3) letter is posted at
|
||||
http://pglaf.org/fundraising. Contributions to the Project Gutenberg
|
||||
Literary Archive Foundation are tax deductible to the full extent
|
||||
permitted by U.S. federal laws and your state's laws.
|
||||
|
||||
The Foundation's principal office is located at 4557 Melan Dr. S.
|
||||
Fairbanks, AK, 99712., but its volunteers and employees are scattered
|
||||
throughout numerous locations. Its business office is located at
|
||||
809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887, email
|
||||
business@pglaf.org. Email contact links and up to date contact
|
||||
information can be found at the Foundation's web site and official
|
||||
page at http://pglaf.org
|
||||
|
||||
For additional contact information:
|
||||
Dr. Gregory B. Newby
|
||||
Chief Executive and Director
|
||||
gbnewby@pglaf.org
|
||||
|
||||
|
||||
Section 4. Information about Donations to the Project Gutenberg
|
||||
Literary Archive Foundation
|
||||
|
||||
Project Gutenberg-tm depends upon and cannot survive without wide
|
||||
spread public support and donations to carry out its mission of
|
||||
increasing the number of public domain and licensed works that can be
|
||||
freely distributed in machine readable form accessible by the widest
|
||||
array of equipment including outdated equipment. Many small donations
|
||||
($1 to $5,000) are particularly important to maintaining tax exempt
|
||||
status with the IRS.
|
||||
|
||||
The Foundation is committed to complying with the laws regulating
|
||||
charities and charitable donations in all 50 states of the United
|
||||
States. Compliance requirements are not uniform and it takes a
|
||||
considerable effort, much paperwork and many fees to meet and keep up
|
||||
with these requirements. We do not solicit donations in locations
|
||||
where we have not received written confirmation of compliance. To
|
||||
SEND DONATIONS or determine the status of compliance for any
|
||||
particular state visit http://pglaf.org
|
||||
|
||||
While we cannot and do not solicit contributions from states where we
|
||||
have not met the solicitation requirements, we know of no prohibition
|
||||
against accepting unsolicited donations from donors in such states who
|
||||
approach us with offers to donate.
|
||||
|
||||
International donations are gratefully accepted, but we cannot make
|
||||
any statements concerning tax treatment of donations received from
|
||||
outside the United States. U.S. laws alone swamp our small staff.
|
||||
|
||||
Please check the Project Gutenberg Web pages for current donation
|
||||
methods and addresses. Donations are accepted in a number of other
|
||||
ways including checks, online payments and credit card donations.
|
||||
To donate, please visit: http://pglaf.org/donate
|
||||
|
||||
|
||||
Section 5. General Information About Project Gutenberg-tm electronic
|
||||
works.
|
||||
|
||||
Professor Michael S. Hart is the originator of the Project Gutenberg-tm
|
||||
concept of a library of electronic works that could be freely shared
|
||||
with anyone. For thirty years, he produced and distributed Project
|
||||
Gutenberg-tm eBooks with only a loose network of volunteer support.
|
||||
|
||||
|
||||
Project Gutenberg-tm eBooks are often created from several printed
|
||||
editions, all of which are confirmed as Public Domain in the U.S.
|
||||
unless a copyright notice is included. Thus, we do not necessarily
|
||||
keep eBooks in compliance with any particular paper edition.
|
||||
|
||||
|
||||
Most people start at our Web site which has the main PG search facility:
|
||||
|
||||
http://www.gutenberg.org
|
||||
|
||||
This Web site includes information about Project Gutenberg-tm,
|
||||
including how to make donations to the Project Gutenberg Literary
|
||||
Archive Foundation, how to help produce our new eBooks, and how to
|
||||
subscribe to our email newsletter to hear about new eBooks.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +0,0 @@
|
||||
title: $:/plugins/tiddlywiki/externaltasksdemo/EditorToolbar/SuggestTags
|
||||
tags: $:/tags/EditorToolbar
|
||||
icon: $:/core/images/tag-button
|
||||
caption: Suggest Tags
|
||||
description: Invoke external programme to suggest tags for this tiddler
|
||||
condition: [<targetTiddler>!has[type]] [<targetTiddler>type[text/vnd.tiddlywiki]]
|
||||
button-classes: tc-text-editor-toolbar-item-start-group
|
||||
shortcuts: ((suggest-tags))
|
||||
dropdown: $:/plugins/tiddlywiki/externaltasksdemo/EditorToolbar/SuggestTagsDropdown
|
||||
|
||||
<$set name="inputFilter" filter="[<targetTiddler>]">
|
||||
<$action-sendmessage $message="tm-execute-job" 1="--pipe" 2="badtagger" 3=<<inputFilter>> 4="PipeOutput" statusTitle="JobStatus"/>
|
||||
</$set>
|
||||
Suggest Tags - <$text text=<<targetTiddler>>/>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
title: $:/plugins/tiddlywiki/externaltasksdemo/EditorToolbar/SuggestTagsDropdown
|
||||
|
||||
<$button message="tm-server-refresh">Refresh</$button>
|
||||
|
||||
Status: {{JobStatus}} {{JobStatus!!message}}
|
||||
|
||||
Results: {{PipeOutput}}
|
||||
@@ -1,6 +0,0 @@
|
||||
title: Sample Text
|
||||
|
||||
Aliquo déditum habet huius, non tempora. Affectus captet declarant retinere támque. Desiderabile dolor posuit státim uterque.
|
||||
|
||||
Arbitraretur civium epicureum extremo, gerendarum málá pacuvii. Accumsan alteram amaret conclusionémqué definitiones événiunt firmám homo noctesque quibus refert triá utens. Chóró egestas fugiamus fuissent, impénsa littéras magna ménté quia scientiam sensibus tibi. Bonas eas fieri i, lacinia legantur oratione urbes.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
title: $:/DefaultTiddlers
|
||||
|
||||
HelloThere
|
||||
@@ -1,54 +0,0 @@
|
||||
title: HelloThere
|
||||
|
||||
! External Pipe Demos
|
||||
|
||||
Note that the browser polls the server every {{$:/config/SyncPollingInterval}}ms. You can trigger an instaneous poll: <$button message="tm-server-refresh">Refresh</$button>
|
||||
|
||||
Status: {{JobStatus}} {{JobStatus!!message}}
|
||||
|
||||
!! Reverser
|
||||
|
||||
This demo requires the example task `reverser.js 8081` to be running in a separate command window. You can edit the [[Sample Text]].
|
||||
|
||||
<$button>
|
||||
<$action-sendmessage $message="tm-execute-job" 1="--pipe" 2="reverser" 3="[[Sample Text]]" 4="PipeOutput" statusTitle="JobStatus"/>
|
||||
Reverser
|
||||
</$button>
|
||||
|
||||
!! Recaser
|
||||
|
||||
This demo requires the example task `./recaser.js 8081` or `./recase_erl.sh` to be running in a separate command window. You can edit the [[Sample Text]].
|
||||
|
||||
<$button>
|
||||
<$action-sendmessage $message="tm-execute-job" 1="--pipe" 2="recaser" 3="[[Sample Text]]" 4="PipeOutput" statusTitle="JobStatus"/>
|
||||
Recaser
|
||||
</$button>
|
||||
|
||||
!! Tagger
|
||||
|
||||
This demo requires the example task `./badtagger.js 8081` to be running in a separate command window. You can edit the [[Sample Text]].
|
||||
|
||||
<$button>
|
||||
<$action-sendmessage $message="tm-execute-job" 1="--pipe" 2="badtagger" 3="[[Sample Text]]" 4="PipeOutput" statusTitle="JobStatus"/>
|
||||
Tagger
|
||||
</$button>
|
||||
|
||||
!! Mimic
|
||||
|
||||
<$button>
|
||||
<$action-sendmessage $message="tm-execute-job" 1="--pipe" 2="mimic" 3="[[Alice in Wonderland]]" 4="PipeOutput" 5="5" 6="5000" statusTitle="JobStatus"/>
|
||||
Mimic
|
||||
</$button>
|
||||
|
||||
!! Stats
|
||||
|
||||
<$button>
|
||||
<$action-sendmessage $message="tm-execute-job" 1="--pipe" 2="stats" 3="[[Alice in Wonderland]]" 4="PipeOutput" statusTitle="JobStatus"/>
|
||||
Stats
|
||||
</$button>
|
||||
|
||||
!! Demo Output
|
||||
|
||||
The output generated by the demos appears here:
|
||||
|
||||
{{PipeOutput}}
|
||||
@@ -1,2 +0,0 @@
|
||||
title: $:/config/SyncPollingInterval
|
||||
text: 5000
|
||||
@@ -1,119 +0,0 @@
|
||||
{
|
||||
"description": "Edition demonstrating external pipes",
|
||||
"plugins": [
|
||||
"tiddlywiki/tiddlyweb"
|
||||
],
|
||||
"themes": [
|
||||
"tiddlywiki/vanilla",
|
||||
"tiddlywiki/snowwhite"
|
||||
],
|
||||
"build": {
|
||||
"index": [
|
||||
"--rendertiddler","$:/core/save/all","index.html","text/plain"]
|
||||
},
|
||||
"config": {
|
||||
"allow-remote-commands": true
|
||||
},
|
||||
"external-pipes": {
|
||||
"reverser": {
|
||||
"type": "socket",
|
||||
"host": "127.0.0.1",
|
||||
"port": 8081,
|
||||
"input": {
|
||||
"format": "rendered-text"
|
||||
},
|
||||
"output": {
|
||||
"format": "text",
|
||||
"tiddler": {
|
||||
"title": "PipeOutput",
|
||||
"type": "text/plain"
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
"MY_VARIABLE": "value"
|
||||
},
|
||||
"timeout": 100
|
||||
},
|
||||
"stats": {
|
||||
"type": "task",
|
||||
"path": "./demo-tasks/stats.js",
|
||||
"input": {
|
||||
"format": "json-raw-tiddlers"
|
||||
},
|
||||
"output": {
|
||||
"format": "json-raw-tiddlers"
|
||||
},
|
||||
"error": {
|
||||
"format": "text",
|
||||
"tiddler": {
|
||||
"title": "PipeOutput",
|
||||
"type": "text/plain",
|
||||
"result": "error"
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
"MY_VARIABLE": "value"
|
||||
},
|
||||
"timeout": 100
|
||||
},
|
||||
"mimic": {
|
||||
"type": "task",
|
||||
"path": "./demo-tasks/mimic.js",
|
||||
"arguments": ["ngram-length"],
|
||||
"input": {
|
||||
"format": "rendered-text"
|
||||
},
|
||||
"output": {
|
||||
"format": "text",
|
||||
"tiddler": {
|
||||
"title": "PipeOutput",
|
||||
"type": "text/plain"
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
"MY_VARIABLE": "value"
|
||||
},
|
||||
"timeout": 100
|
||||
},
|
||||
"recaser": {
|
||||
"type": "socket-erlang",
|
||||
"host": "127.0.0.1",
|
||||
"port": 8081,
|
||||
"encoding": "latin1",
|
||||
"input": {
|
||||
"format": "rendered-text"
|
||||
},
|
||||
"output": {
|
||||
"format": "text",
|
||||
"tiddler": {
|
||||
"title": "PipeOutput",
|
||||
"type": "text/plain"
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
"MY_VARIABLE": "value"
|
||||
},
|
||||
"timeout": 100
|
||||
},
|
||||
"badtagger": {
|
||||
"type": "socket-erlang",
|
||||
"host": "127.0.0.1",
|
||||
"port": 8081,
|
||||
"encoding": "latin1",
|
||||
"input": {
|
||||
"format": "rendered-text"
|
||||
},
|
||||
"output": {
|
||||
"format": "text",
|
||||
"tiddler": {
|
||||
"title": "PipeOutput",
|
||||
"type": "text/plain"
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
"MY_VARIABLE": "value"
|
||||
},
|
||||
"timeout": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ caption: Quoi de neuf dans <<version>>
|
||||
color: #fff
|
||||
created: 20160603124050989
|
||||
fr-title: BonjourLaVignette - Dernière Version
|
||||
image: New Release Banner.png
|
||||
image: New Release Banner
|
||||
link: Releases
|
||||
modified: 20160603124131122
|
||||
tags: HelloThumbnail
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
caption: 5.2.1
|
||||
created: 20211003152250369
|
||||
modified: 20211003152250369
|
||||
caption: 5.2.2
|
||||
created: 20211208115905247
|
||||
modified: 20211208115905247
|
||||
tags: ReleaseNotes
|
||||
title: Release 5.2.1
|
||||
title: Release 5.2.2
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
\define contributor(username)
|
||||
<a href="https://github.com/$username$" style="text-decoration:none;font-size:24px;" class="tc-tiddlylink-external" target="_blank" rel="noopener noreferrer"><img src="https://github.com/$username$.png?size=32" width="32" height="32"/> @<$text text=<<__username__>>/></a>
|
||||
\end
|
||||
|
||||
//[[See GitHub for detailed change history of this release|https://github.com/Jermolene/TiddlyWiki5/compare/v5.2.0...master]]//
|
||||
//[[See GitHub for detailed change history of this release|https://github.com/Jermolene/TiddlyWiki5/compare/v5.2.1...master]]//
|
||||
|
||||
! Highlights
|
||||
|
||||
! Performance Improvements
|
||||
|
||||
*
|
||||
|
||||
! Bug Fixes
|
||||
|
||||
*
|
||||
|
||||
! Usability Improvements
|
||||
|
||||
*
|
||||
@@ -33,7 +35,7 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
*
|
||||
|
||||
! Client-server Improvements
|
||||
! Developer Improvements
|
||||
|
||||
*
|
||||
|
||||
@@ -41,20 +43,10 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
*
|
||||
|
||||
! Plugin Improvements
|
||||
|
||||
! Developer Experience Improvements
|
||||
|
||||
*
|
||||
|
||||
! Translation improvements
|
||||
|
||||
*
|
||||
|
||||
! Other Bug Fixes
|
||||
|
||||
*
|
||||
|
||||
! Acknowledgements
|
||||
|
||||
[[@Jermolene|https://github.com/Jermolene]] would like to thank the contributors to this release who have generously given their time to help improve TiddlyWiki:
|
||||
@@ -815,6 +815,10 @@ Tests the filtering mechanism.
|
||||
expect(wiki.filterTiddlers("[[Unlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data]search-replace:g:regexp<myregexp2>,[]]",anchorWidget).join(",")).toBe("conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data");
|
||||
expect(wiki.filterTiddlers("[[Unlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data]search-replace:gm:regexp<myregexp2>,[]]",anchorWidget).join(",")).toBe("conventional online services, TiddlyWiki lets you choose where to keep your data\nconventional online services, TiddlyWiki lets you choose where to keep your data\nconventional online services, TiddlyWiki lets you choose where to keep your data\nconventional online services, TiddlyWiki lets you choose where to keep your data");
|
||||
expect(wiki.filterTiddlers("[[Hello There\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\nguaranteeing that in the decades to come you will still be able to use the notes you take today.]search-replace:gm:regexp<myregexp3>,[]]",anchorWidget).join(",")).toBe("\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\n");
|
||||
expect(wiki.filterTiddlers("[[This is equation $$x$$ end.]search-replace[equation $$x$$ end.],[relation $$x$$ finish.]]").join(",")).toBe("This is relation $$x$$ finish.");
|
||||
expect(wiki.filterTiddlers("[[This is an amazing TiddlyWiki]] [[How old is TiddlyWiki?. TiddlyWiki is great]] [[My TiddlyWiki is so fast.]] +[search-replace:g:regexp[TiddlyWiki],[TW]]").join(",")).toBe("This is an amazing TW,How old is TW?. TW is great,My TW is so fast.");
|
||||
expect(wiki.filterTiddlers("[[This is an amazing TiddlyWiki]] [[How old is TiddlyWiki?. TiddlyWiki is great]] [[My TiddlyWiki is so fast.]] +[search-replace::regexp[TiddlyWiki],[TW]]").join(",")).toBe("This is an amazing TW,How old is TW?. TiddlyWiki is great,My TW is so fast.");
|
||||
expect(wiki.filterTiddlers("[[This is an amazing TiddlyWiki]] [[How old is TiddlyWiki?. TiddlyWiki is great]] [[My TiddlyWiki is so fast.]] +[search-replace:g[TiddlyWiki],[TW]]").join(",")).toBe("This is an amazing TW,How old is TW?. TW is great,My TW is so fast.");
|
||||
});
|
||||
|
||||
it("should handle the pad operator", function() {
|
||||
|
||||
@@ -288,6 +288,38 @@ describe("'reduce' and 'intersection' filter prefix tests", function() {
|
||||
tags: ["cakes","with tea"],
|
||||
text: "Does anyone eat pound cake?"
|
||||
});
|
||||
wiki.addTiddler({
|
||||
title: "$:/filter1",
|
||||
text: "[tag[cakes]then[It is customary]]",
|
||||
tags: "$:/tags/Filter $:/tags/SecondFilter"
|
||||
});
|
||||
wiki.addTiddler({
|
||||
title: "$:/filter2",
|
||||
text: "[<currentTiddler>tag[shopping]then[It is not customary]]",
|
||||
tags: "$:/tags/Filter $:/tags/SecondFilter"
|
||||
});
|
||||
wiki.addTiddler({
|
||||
title: "$:/filter3",
|
||||
text: "[[Just a default]]",
|
||||
tags: "$:/tags/Filter"
|
||||
});
|
||||
wiki.addTiddler({
|
||||
title: "$:/tags/Filter",
|
||||
list: "$:/filter1 $:/filter2 $:/filter3"
|
||||
});
|
||||
wiki.addTiddler({
|
||||
title: "$:/tags/SecondFilter",
|
||||
list: "$:/filter1 $:/filter2"
|
||||
});
|
||||
|
||||
it("should handle the :cascade filter prefix", function() {
|
||||
expect(wiki.filterTiddlers("[[Rice Pudding]] :cascade[all[shadows+tiddlers]tag[$:/tags/Filter]get[text]]").join(",")).toBe("It is not customary");
|
||||
expect(wiki.filterTiddlers("[[chocolate cake]] :cascade[all[shadows+tiddlers]tag[$:/tags/Filter]get[text]]").join(",")).toBe("It is customary");
|
||||
expect(wiki.filterTiddlers("[[Sparkling water]] :cascade[all[shadows+tiddlers]tag[$:/tags/Filter]get[text]]").join(",")).toBe("Just a default");
|
||||
expect(wiki.filterTiddlers("[[Rice Pudding]] :cascade[all[shadows+tiddlers]tag[$:/tags/SecondFilter]get[text]]").join(",")).toBe("It is not customary");
|
||||
expect(wiki.filterTiddlers("[[chocolate cake]] :cascade[all[shadows+tiddlers]tag[$:/tags/SecondFilter]get[text]]").join(",")).toBe("It is customary");
|
||||
expect(wiki.filterTiddlers("[[Sparkling water]] :cascade[all[shadows+tiddlers]tag[$:/tags/SecondFilter]get[text]]").join(",")).toBe("");
|
||||
});
|
||||
|
||||
it("should handle the :reduce filter prefix", function() {
|
||||
expect(wiki.filterTiddlers("[tag[shopping]] :reduce[get[quantity]add<accumulator>]").join(",")).toBe("22");
|
||||
@@ -384,6 +416,24 @@ describe("'reduce' and 'intersection' filter prefix tests", function() {
|
||||
expect(wiki.filterTiddlers("[tag[shopping]] :map[get[description]else{!!title}]").join(",")).toBe("A square of rich chocolate cake,a round yellow seed,Milk,Rice Pudding");
|
||||
// Return the first title from :map if the filter returns more than one result
|
||||
expect(wiki.filterTiddlers("[tag[shopping]] :map[tags[]]").join(",")).toBe("shopping,shopping,shopping,shopping");
|
||||
// Prepend the position in the list using the index and length variables
|
||||
expect(wiki.filterTiddlers("[tag[shopping]] :map[get[title]addprefix[-]addprefix<length>addprefix[of]addprefix<index>]").join(",")).toBe("0of4-Brownies,1of4-Chick Peas,2of4-Milk,3of4-Rice Pudding");
|
||||
});
|
||||
|
||||
it("should handle macro parameters for filter run prefixes",function() {
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
var rootWidget = new widget.widget({ type:"widget", children:[ {type:"widget", children:[]} ] },
|
||||
{ wiki:wiki, document:$tw.document});
|
||||
rootWidget.makeChildWidgets();
|
||||
var anchorWidget = rootWidget.children[0];
|
||||
rootWidget.setVariable("greet","Hello $name$",[{name:"name"}],true);
|
||||
rootWidget.setVariable("echo","$text$",[{name:"text"}],true);
|
||||
// :map prefix
|
||||
expect(wiki.filterTiddlers("1 :map[subfilter<greet Tom>join[ ]]",anchorWidget).join(",")).toBe("Hello Tom");
|
||||
expect(wiki.filterTiddlers('[tag[shopping]] :map[<echo "$(index)$ $(currentTiddler)$">]',anchorWidget).join(",")).toBe("0 Brownies,1 Chick Peas,2 Milk,3 Rice Pudding");
|
||||
// :reduce prefix
|
||||
expect(wiki.filterTiddlers("1 :reduce[subfilter<greet Tom>join[ ]]",anchorWidget).join(",")).toBe("Hello Tom");
|
||||
expect(wiki.filterTiddlers('[tag[shopping]] :reduce[<echo "$(accumulator)$ $(index)$ $(currentTiddler)$,">]',anchorWidget).join(",")).toBe(" 0 Brownies, 1 Chick Peas, 2 Milk, 3 Rice Pudding,");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -247,6 +247,40 @@ describe("Widget module", function() {
|
||||
expect(wrapper.children[0].children[2].sequenceNumber).toBe(4);
|
||||
});
|
||||
|
||||
it("should deal with the let widget", function() {
|
||||
var wiki = new $tw.Wiki();
|
||||
wiki.addTiddlers([
|
||||
{title: "TiddlerOne", text: "lookup"},
|
||||
{title: "TiddlerTwo", lookup: "value", newlookup: "value", wrong: "wrong"},
|
||||
{title: "TiddlerThree", text: "wrong", value: "Happy Result", wrong: "ALL WRONG!!"}
|
||||
]);
|
||||
var text="\\define macro() TiddlerThree\n"+
|
||||
"\\define currentTiddler() TiddlerOne\n"+
|
||||
"<$let "+
|
||||
"field={{!!text}} "+
|
||||
"currentTiddler='TiddlerTwo' "+
|
||||
"field={{{ [all[current]get<field>] }}} "+
|
||||
"currentTiddler=<<macro>>>"+
|
||||
"<$transclude field=<<field>>/></$let>";
|
||||
var widgetNode = createWidgetNode(parseText(text,wiki),wiki);
|
||||
var wrapper = renderWidgetNode(widgetNode);
|
||||
expect(wrapper.innerHTML).toBe("<p>Happy Result</p>");
|
||||
|
||||
// This is important. $Let needs to be aware enough not to let its
|
||||
// own variables interfere with its ability to recognize no change.
|
||||
// Doesn't matter that nothing has changed, we just need to make sure
|
||||
// it recognizes that that its outward facing variables are unchanged
|
||||
// EVEN IF some intermediate variables did change, there's no need to
|
||||
// refresh.
|
||||
wiki.addTiddler({title: "TiddlerOne", text: "newlookup"});
|
||||
expect(widgetNode.refresh({})).toBe(false);
|
||||
|
||||
// But if we make a change that might result in different outfacing
|
||||
// variables, then it should refresh
|
||||
wiki.addTiddler({title: "TiddlerOne", text: "badlookup"});
|
||||
expect(widgetNode.refresh({})).toBe(true);
|
||||
});
|
||||
|
||||
it("should deal with attributes specified as macro invocations", function() {
|
||||
var wiki = new $tw.Wiki();
|
||||
// Construct the widget node
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
created: 20210322152203906
|
||||
list: [[Documentation Macros]] HelloThere GettingStarted Community
|
||||
modified: 20210322152237613
|
||||
created: 20211126104006194
|
||||
list: [[Page and tiddler layout customisation]] [[Creating new buttons for the ViewToolbar and page controls]] [[Structuring TiddlyWiki]] Tagging [[Introduction to Lists]] [[Icon Gallery]] [[How to widen tiddlers (aka storyriver)]] [[How to turn off camel case linking]] [[How to put the last modification date in a banner]] [[How to hide the author's and other fields with CSS]] [[How to export tiddlers]] [[How to Customize TiddlyDesktop]] [[Editing Tiddlers with Vim]] [[Concatenating text and variables using macro substitution]] [[Demonstration: keyboard-driven-input Macro]] HelloThere GettingStarted Community
|
||||
modified: 20211126111221917
|
||||
title: $:/StoryList
|
||||
type: text/vnd.tiddlywiki
|
||||
@@ -1,24 +0,0 @@
|
||||
caption: tm-execute-job
|
||||
created: 20181017140932589
|
||||
modified: 20181017171440568
|
||||
tags: Messages
|
||||
title: WidgetMessage: tm-execute-job
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.1.18">> The "execute job" message triggers the execution of [[remote commands|Using remote commands]]. It uses the message parameters as follows:
|
||||
|
||||
|!Name |!Description |
|
||||
|$param |Not used |
|
||||
|commands |Command string to be executed |
|
||||
|0...n |Command tokens to be executed |
|
||||
|statusTitle |Optional title of tiddler in which to store status updates as the commands are executed |
|
||||
|
||||
Note that the command string to be executed can either be passed as a single string, or as a sequence of tokens:
|
||||
|
||||
* A single string:
|
||||
*> `<$action-sendmessage $message="tm-execute-job" commands="--version"/>`
|
||||
* Separate command tokens with numeric indices:
|
||||
*> `<$action-sendmessage $message="tm-execute-job" 0="--version" 1="--version"/>`
|
||||
** Note that the numeric indices must be non-negative integers with no leading zeros
|
||||
|
||||
The "execute job" message is handled by the TiddlyWiki core SyncMechanism which invokes the current [[SyncAdaptorModule|SyncAdaptorModules]] (typically the ''tiddlywiki/tiddlywebadaptor'' plugin).
|
||||
@@ -1,6 +1,6 @@
|
||||
created: 20180626122427188
|
||||
modified: 20180626134639673
|
||||
tags: [[Using TiddlyWiki on Node.js]]
|
||||
modified: 20211117234223960
|
||||
tags: [[TiddlyWiki on Node.js]]
|
||||
title: NamedCommandParameters
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
created: 20131101111400000
|
||||
modified: 20210402095728684
|
||||
modified: 20211115092001000
|
||||
tags: Community
|
||||
title: Contributing
|
||||
type: text/vnd.tiddlywiki
|
||||
@@ -45,7 +45,7 @@ PR titles may also include a short prefix to indicate the subsystem to which the
|
||||
|
||||
! Commenting on Pull Requests
|
||||
|
||||
One of the principles of open source is that many pairs of eyes on the code can improve quality. So, we welcome comments and critiques of pending PRs. [[Conventional Comments|https://conventionalcomments.org]] has some techcniques to help make comments as constructive and actionable as possible. Notably, they recommend prefixing a comment with a label to clarify the intention:
|
||||
One of the principles of open source is that many pairs of eyes on the code can improve quality. So, we welcome comments and critiques of pending PRs. [[Conventional Comments|https://conventionalcomments.org]] has some techniques to help make comments as constructive and actionable as possible. Notably, they recommend prefixing a comment with a label to clarify the intention:
|
||||
|
||||
|praise |Praises highlight something positive. Try to leave at least one of these comments per review. Do not leave false praise (which can actually be damaging). Do look for something to sincerely praise |
|
||||
|nitpick |Nitpicks are small, trivial, but necessary changes. Distinguishing nitpick comments significantly helps direct the reader's attention to comments requiring more involvement |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
created: 20210204010508263
|
||||
modified: 20210204010941713
|
||||
tags: Images SVG Icons
|
||||
modified: 20211113225941563
|
||||
tags: Images SVG Icons [[Other Resources]]
|
||||
title: "TW Icons" by morosanuae
|
||||
type: text/vnd.tiddlywiki
|
||||
url: https://morosanuae.github.io/tw-icons
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
created: 20130823091700000
|
||||
modified: 20140912150339263
|
||||
modified: 20211124214214045
|
||||
tags: Community Videos
|
||||
title: TiddlyWiki Hangouts
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
The TiddlyWiki community holds regular Google Hangouts, usually every Tuesday from 4pm to 6pm (UK time). They are announced in the [[TiddlyWiki Google group|https://groups.google.com/d/forum/tiddlywiki]] and on the [[TiddlyWiki Twitter account|https://twitter.com/TiddlyWiki]].
|
||||
The TiddlyWiki community has held many Google Hangouts over the years. They are announced in the [[TiddlyWiki Google group|https://groups.google.com/d/forum/tiddlywiki]] and on the [[TiddlyWiki Twitter account|https://twitter.com/TiddlyWiki]].
|
||||
|
||||
Past Hangouts are archived in this ~YouTube playlist:
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ created: 20141122093837330
|
||||
delivery: Web Service
|
||||
description: Free online service that you can also host yourself
|
||||
method: sync
|
||||
modified: 20210106151027179
|
||||
tags: Android Chrome Firefox [[Internet Explorer]] Linux Mac Opera PHP [[Other resources]] Safari Saving Windows iOS Edge [[Community Editions]]
|
||||
modified: 20211113010826610
|
||||
tags: Android Chrome Firefox [[Internet Explorer]] Linux Mac Opera PHP Safari Saving Windows iOS Edge [[Community Editions]] [[Other Resources]]
|
||||
title: "Noteself" by Danielo Rodríguez
|
||||
type: text/vnd.tiddlywiki
|
||||
url: https://noteself.github.io/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user