mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-24 11:54:41 +00:00
Compare commits
240 Commits
word-games
...
external-t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75c1e4b4d8 | ||
|
|
979f079c7a | ||
|
|
d695fca301 | ||
|
|
a0d2392f01 | ||
|
|
23b4e03cd5 | ||
|
|
d5f72cb282 | ||
|
|
5f57bf81cd | ||
|
|
e32c9e4658 | ||
|
|
2a73505508 | ||
|
|
4d87ef4231 | ||
|
|
c543036a0f | ||
|
|
8ae4428332 | ||
|
|
2f133a08aa | ||
|
|
6b17e688da | ||
|
|
8654066f03 | ||
|
|
56dae90425 | ||
|
|
1f6ef07860 | ||
|
|
f30a455ee3 | ||
|
|
03bd99cd11 | ||
|
|
cc389ec82b | ||
|
|
f85678b6dc | ||
|
|
8d7c869072 | ||
|
|
8f592d3f0a | ||
|
|
1f2e0ed189 | ||
|
|
4d6c428ba9 | ||
|
|
d095aa0182 | ||
|
|
15bf850280 | ||
|
|
62b273266e | ||
|
|
1d058177be | ||
|
|
14676b345a | ||
|
|
a50e6eed38 | ||
|
|
073a064ae8 | ||
|
|
e00a3d3cb4 | ||
|
|
68d9200a6b | ||
|
|
2551bb3e3f | ||
|
|
80b18e6315 | ||
|
|
e0561397f1 | ||
|
|
b9c3c38edc | ||
|
|
077ced0d1a | ||
|
|
e5ff84035c | ||
|
|
e18a983209 | ||
|
|
6f61fa07fb | ||
|
|
d5d73e02e9 | ||
|
|
4ba7454d8d | ||
|
|
5192a39830 | ||
|
|
aa5413b942 | ||
|
|
ef284e9bde | ||
|
|
9c41fe1d18 | ||
|
|
e577cf7302 | ||
|
|
ebf563ac70 | ||
|
|
909340c6fe | ||
|
|
df6d38df65 | ||
|
|
59a53e695b | ||
|
|
6d17505f7b | ||
|
|
36dd8ea1d2 | ||
|
|
b965ae926b | ||
|
|
f6eadbd1c9 | ||
|
|
bdbb884be0 | ||
|
|
0be39cfbc2 | ||
|
|
ef2aeac7de | ||
|
|
157afda2fc | ||
|
|
fb4d77ef46 | ||
|
|
575c233597 | ||
|
|
2e59d770f7 | ||
|
|
baf0ee9cde | ||
|
|
af89bb591d | ||
|
|
d0dec741ad | ||
|
|
33a82e395e | ||
|
|
f223896c26 | ||
|
|
de33b365ae | ||
|
|
e9d8547a81 | ||
|
|
dcff318a98 | ||
|
|
f725123690 | ||
|
|
e9e5d37ff0 | ||
|
|
f70cee6907 | ||
|
|
1491339f50 | ||
|
|
8a5ed59ff4 | ||
|
|
a2ca5e4d1e | ||
|
|
fba993502d | ||
|
|
9fae3a932b | ||
|
|
62610f0666 | ||
|
|
7282ec5286 | ||
|
|
9830e0104f | ||
|
|
e6fd0caf6b | ||
|
|
137df37bc7 | ||
|
|
d895706199 | ||
|
|
6ed7d418b5 | ||
|
|
62b8a83741 | ||
|
|
e795b501ac | ||
|
|
03228d8d20 | ||
|
|
c9c5d4cf79 | ||
|
|
f5cc5bc6a1 | ||
|
|
447494ad4d | ||
|
|
c9f178ec87 | ||
|
|
33be326ef6 | ||
|
|
c13f04d838 | ||
|
|
737685149c | ||
|
|
33eef0202d | ||
|
|
a67b1b8bb5 | ||
|
|
124b49456a | ||
|
|
24956087cc | ||
|
|
199ca57f1c | ||
|
|
64d53ac533 | ||
|
|
b3accbf9e0 | ||
|
|
99249a3160 | ||
|
|
f7cd8bad3a | ||
|
|
e9613d7f12 | ||
|
|
97dff042f7 | ||
|
|
32b36fb2af | ||
|
|
41535150dd | ||
|
|
8e69284e8c | ||
|
|
61cfac4eeb | ||
|
|
2720072b23 | ||
|
|
0413c3a38e | ||
|
|
f2b30c1fe0 | ||
|
|
3c86cf7d2e | ||
|
|
451074f7ed | ||
|
|
1e5601ca31 | ||
|
|
75c99cd235 | ||
|
|
bb2c2be9b6 | ||
|
|
53c247b9a1 | ||
|
|
82667d9d16 | ||
|
|
97ed2757f0 | ||
|
|
19fd5ca5f2 | ||
|
|
6ae78a770f | ||
|
|
04962b4cd6 | ||
|
|
f97850dd05 | ||
|
|
2cb3ed3ab9 | ||
|
|
a4421f50c6 | ||
|
|
cb726f40fa | ||
|
|
be026aa308 | ||
|
|
0924ca6365 | ||
|
|
39fec2decf | ||
|
|
dbfd45814d | ||
|
|
d455072f13 | ||
|
|
155525708b | ||
|
|
fdca11dec3 | ||
|
|
f83875331d | ||
|
|
be6deb054e | ||
|
|
b0604a9bf5 | ||
|
|
30925ee7bf | ||
|
|
7204f442cd | ||
|
|
23fec9e390 | ||
|
|
8d9dc0cd29 | ||
|
|
a1d9464011 | ||
|
|
0b71f25f74 | ||
|
|
315464372f | ||
|
|
56068d8215 | ||
|
|
b95f6ca084 | ||
|
|
4a7f078abd | ||
|
|
1b55eb9eee | ||
|
|
3094e06236 | ||
|
|
f87b3bfcdb | ||
|
|
a0a0df9655 | ||
|
|
31c1584b9a | ||
|
|
f1f951e849 | ||
|
|
041c3e817c | ||
|
|
70e60cd93f | ||
|
|
54d8b8a373 | ||
|
|
dd6bd58140 | ||
|
|
a6990128f1 | ||
|
|
338b7c92a2 | ||
|
|
a409536ad0 | ||
|
|
c9af04d0e5 | ||
|
|
076a04fbfb | ||
|
|
83ee363cb4 | ||
|
|
63fa0c4fa4 | ||
|
|
644062fc21 | ||
|
|
021e9b8c4d | ||
|
|
afa653a7aa | ||
|
|
0b56d5fd37 | ||
|
|
2da7ae0b73 | ||
|
|
4c56bd771a | ||
|
|
9c0d6a46cc | ||
|
|
06318b7617 | ||
|
|
8f9e8c1dee | ||
|
|
3cd80de5bb | ||
|
|
f2e26927c1 | ||
|
|
960160b3a2 | ||
|
|
4f33d2f35c | ||
|
|
b5db488438 | ||
|
|
6dd1887f0b | ||
|
|
a70b26cd55 | ||
|
|
219beb13cc | ||
|
|
c18b7527a7 | ||
|
|
2f1806ab6a | ||
|
|
afa4ea3d03 | ||
|
|
2b911ac11f | ||
|
|
c4a7ae3164 | ||
|
|
056e6541a1 | ||
|
|
753bf8fe62 | ||
|
|
4f9dd50382 | ||
|
|
2e695801b1 | ||
|
|
55c522ab8f | ||
|
|
9faaa31299 | ||
|
|
582b156d5f | ||
|
|
8b8f654c9c | ||
|
|
9b247f6d63 | ||
|
|
f342fdc41d | ||
|
|
ca96f7f62b | ||
|
|
2f31eab8f4 | ||
|
|
c8528fd1f7 | ||
|
|
07ac85d9fa | ||
|
|
e84f214280 | ||
|
|
9cd65efad9 | ||
|
|
41200ab6d7 | ||
|
|
62fdaa633a | ||
|
|
79f5e6b498 | ||
|
|
23bd7e7817 | ||
|
|
792171c8fc | ||
|
|
051a468c63 | ||
|
|
894fb1ad35 | ||
|
|
9a3c60173a | ||
|
|
1b226c7556 | ||
|
|
2bd9cc45fa | ||
|
|
2b4619dcbe | ||
|
|
bb20d43cbf | ||
|
|
9c29b15fcd | ||
|
|
994a91001d | ||
|
|
c85c172fe4 | ||
|
|
eeb06a75a6 | ||
|
|
ff9539059a | ||
|
|
5831df9ece | ||
|
|
b7f758bbbe | ||
|
|
36509509bc | ||
|
|
e83d0fb6f5 | ||
|
|
a65e9a7b42 | ||
|
|
9b912f6d65 | ||
|
|
4b45afc11f | ||
|
|
e714693cfe | ||
|
|
dffd4e56b5 | ||
|
|
a0b3e1a564 | ||
|
|
4efd5288d0 | ||
|
|
a2d3778465 | ||
|
|
f2917c3355 | ||
|
|
4fcbaa2b12 | ||
|
|
d29b9c2726 | ||
|
|
97bb1fa8c9 | ||
|
|
2e5035ec2a | ||
|
|
b292985df3 |
@@ -5,7 +5,7 @@
|
||||
# Default to the current version number for building the plugin library
|
||||
|
||||
if [ -z "$TW5_BUILD_VERSION" ]; then
|
||||
TW5_BUILD_VERSION=v5.1.24
|
||||
TW5_BUILD_VERSION=v5.2.0
|
||||
fi
|
||||
|
||||
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
||||
|
||||
103
boot/boot.js
103
boot/boot.js
@@ -256,6 +256,28 @@ $tw.utils.deepDefaults = function(object /*, sourceObjectList */) {
|
||||
return object;
|
||||
};
|
||||
|
||||
/*
|
||||
Convert a URIComponent encoded string to a string safely
|
||||
*/
|
||||
$tw.utils.decodeURIComponentSafe = function(s) {
|
||||
var v = s;
|
||||
try {
|
||||
v = decodeURIComponent(s);
|
||||
} catch(e) {}
|
||||
return v;
|
||||
};
|
||||
|
||||
/*
|
||||
Convert a URI encoded string to a string safely
|
||||
*/
|
||||
$tw.utils.decodeURISafe = function(s) {
|
||||
var v = s;
|
||||
try {
|
||||
v = decodeURI(s);
|
||||
} catch(e) {}
|
||||
return v;
|
||||
};
|
||||
|
||||
/*
|
||||
Convert "&" to &, " " to nbsp, "<" to <, ">" to > and """ to "
|
||||
*/
|
||||
@@ -1212,8 +1234,12 @@ $tw.Wiki = function(options) {
|
||||
index,titlesLength,title;
|
||||
for(index = 0, titlesLength = titles.length; index < titlesLength; index++) {
|
||||
title = titles[index];
|
||||
var shadowInfo = shadowTiddlers[title];
|
||||
callback(shadowInfo.tiddler,title);
|
||||
if(tiddlers[title]) {
|
||||
callback(tiddlers[title],title);
|
||||
} else {
|
||||
var shadowInfo = shadowTiddlers[title];
|
||||
callback(shadowInfo.tiddler,title);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1602,8 +1628,8 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
|
||||
}
|
||||
for(var f in data) {
|
||||
if($tw.utils.hop(data,f)) {
|
||||
// Check field name doesn't contain whitespace or control characters
|
||||
if(typeof(data[f]) !== "string" || /[\x00-\x1F\s]/.test(f)) {
|
||||
// Check field name doesn't contain control characters
|
||||
if(typeof(data[f]) !== "string" || /[\x00-\x1F]/.test(f)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1618,7 +1644,12 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
|
||||
}
|
||||
return true;
|
||||
},
|
||||
data = JSON.parse(text);
|
||||
data = {};
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
} catch(e) {
|
||||
// Ignore JSON parse errors
|
||||
}
|
||||
if($tw.utils.isArray(data) && isTiddlerArrayValid(data)) {
|
||||
return data;
|
||||
} else if(isTiddlerValid(data)) {
|
||||
@@ -1724,13 +1755,20 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/dom","tiddlerdeserializer",{
|
||||
},
|
||||
t,result = [];
|
||||
if(node) {
|
||||
for(t = 0; t < node.childNodes.length; t++) {
|
||||
var type = (node.getAttribute && node.getAttribute("type")) || null;
|
||||
if(type) {
|
||||
// A new-style container with an explicit deserialization type
|
||||
result = $tw.wiki.deserializeTiddlers(type,node.textContent);
|
||||
} else {
|
||||
// An old-style container of classic DIV-based tiddlers
|
||||
for(t = 0; t < node.childNodes.length; t++) {
|
||||
var childNode = node.childNodes[t],
|
||||
tiddlers = extractTextTiddlers(childNode);
|
||||
tiddlers = tiddlers || extractModuleTiddlers(childNode);
|
||||
if(tiddlers) {
|
||||
result.push.apply(result,tiddlers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -1739,17 +1777,23 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/dom","tiddlerdeserializer",{
|
||||
|
||||
$tw.loadTiddlersBrowser = function() {
|
||||
// In the browser, we load tiddlers from certain elements
|
||||
var containerIds = [
|
||||
"libraryModules",
|
||||
"modules",
|
||||
"bootKernelPrefix",
|
||||
"bootKernel",
|
||||
"styleArea",
|
||||
"storeArea",
|
||||
"systemArea"
|
||||
var containerSelectors = [
|
||||
// IDs for old-style v5.1.x tiddler stores
|
||||
"#libraryModules",
|
||||
"#modules",
|
||||
"#bootKernelPrefix",
|
||||
"#bootKernel",
|
||||
"#styleArea",
|
||||
"#storeArea",
|
||||
"#systemArea",
|
||||
// Classes for new-style v5.2.x JSON tiddler stores
|
||||
"script.tiddlywiki-tiddler-store"
|
||||
];
|
||||
for(var t=0; t<containerIds.length; t++) {
|
||||
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById(containerIds[t])));
|
||||
for(var t=0; t<containerSelectors.length; t++) {
|
||||
var nodes = document.querySelectorAll(containerSelectors[t]);
|
||||
for(var n=0; n<nodes.length; n++) {
|
||||
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",nodes[n]));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1872,13 +1916,13 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
value = path.basename(filename);
|
||||
break;
|
||||
case "filename-uri-decoded":
|
||||
value = decodeURIComponent(path.basename(filename));
|
||||
value = $tw.utils.decodeURIComponentSafe(path.basename(filename));
|
||||
break;
|
||||
case "basename":
|
||||
value = path.basename(filename,path.extname(filename));
|
||||
break;
|
||||
case "basename-uri-decoded":
|
||||
value = decodeURIComponent(path.basename(filename,path.extname(filename)));
|
||||
value = $tw.utils.decodeURIComponentSafe(path.basename(filename,path.extname(filename)));
|
||||
break;
|
||||
case "extname":
|
||||
value = path.extname(filename);
|
||||
@@ -1906,6 +1950,20 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
tiddlers.push({tiddlers: fileTiddlers});
|
||||
}
|
||||
};
|
||||
// Helper to recursively search subdirectories
|
||||
var getAllFiles = function(dirPath, recurse, arrayOfFiles) {
|
||||
recurse = recurse || false;
|
||||
arrayOfFiles = arrayOfFiles || [];
|
||||
var files = fs.readdirSync(dirPath);
|
||||
files.forEach(function(file) {
|
||||
if (recurse && fs.statSync(dirPath + path.sep + file).isDirectory()) {
|
||||
arrayOfFiles = getAllFiles(dirPath + path.sep + file, recurse, arrayOfFiles);
|
||||
} else if(fs.statSync(dirPath + path.sep + file).isFile()){
|
||||
arrayOfFiles.push(path.join(dirPath, path.sep, file));
|
||||
}
|
||||
});
|
||||
return arrayOfFiles;
|
||||
}
|
||||
// Process the listed tiddlers
|
||||
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
|
||||
if(tidInfo.prefix && tidInfo.suffix) {
|
||||
@@ -1929,13 +1987,14 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
// Process directory specifier
|
||||
var dirPath = path.resolve(filepath,dirSpec.path);
|
||||
if(fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
|
||||
var files = fs.readdirSync(dirPath),
|
||||
var files = getAllFiles(dirPath, dirSpec.searchSubdirectories),
|
||||
fileRegExp = new RegExp(dirSpec.filesRegExp || "^.*$"),
|
||||
metaRegExp = /^.*\.meta$/;
|
||||
for(var t=0; t<files.length; t++) {
|
||||
var filename = files[t];
|
||||
var thisPath = path.relative(filepath, files[t]),
|
||||
filename = path.basename(thisPath);
|
||||
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
||||
processFile(dirPath + path.sep + filename,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile);
|
||||
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1985,7 +2044,7 @@ $tw.loadPluginFolder = function(filepath,excludeRegExp) {
|
||||
pluginInfo.dependents = pluginInfo.dependents || [];
|
||||
pluginInfo.type = "application/json";
|
||||
// Set plugin text
|
||||
pluginInfo.text = JSON.stringify({tiddlers: pluginInfo.tiddlers},null,4);
|
||||
pluginInfo.text = JSON.stringify({tiddlers: pluginInfo.tiddlers});
|
||||
delete pluginInfo.tiddlers;
|
||||
// Deserialise array fields (currently required for the dependents field)
|
||||
for(var field in pluginInfo) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -22,7 +22,6 @@ All parameters are optional with safe defaults, and can be specified in any orde
|
||||
* ''readers'' - comma-separated list of principals allowed to read from this wiki
|
||||
* ''writers'' - comma-separated list of principals allowed to write to this wiki
|
||||
* ''csrf-disable'' - set to "yes" to disable CSRF checks (defaults to "no")
|
||||
* ''sse-enabled'' - set to "yes" to enable Server-sent events (defaults to "no")
|
||||
* ''root-tiddler'' - the tiddler to serve at the root (defaults to "$:/core/save/all")
|
||||
* ''root-render-type'' - the content type to which the root tiddler should be rendered (defaults to "text/plain")
|
||||
* ''root-serve-type'' - the content type with which the root tiddler should be served (defaults to "text/html")
|
||||
|
||||
13
core/language/en-GB/Help/pipe.tid
Normal file
13
core/language/en-GB/Help/pipe.tid
Normal file
@@ -0,0 +1,13 @@
|
||||
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
|
||||
@@ -3,6 +3,7 @@ title: $:/language/Import/
|
||||
Editor/Import/Heading: Import images and insert them into the editor.
|
||||
Imported/Hint: The following tiddlers were imported:
|
||||
Listing/Cancel/Caption: Cancel
|
||||
Listing/Cancel/Warning: Do you wish to cancel the import?
|
||||
Listing/Hint: These tiddlers are ready to import:
|
||||
Listing/Import/Caption: Import
|
||||
Listing/Select/Caption: Select
|
||||
@@ -29,5 +30,5 @@ Upgrader/System/Warning: Core module tiddler.
|
||||
Upgrader/System/Alert: You are about to import a tiddler that will overwrite a core module tiddler. This is not recommended as it may make the system unstable.
|
||||
Upgrader/ThemeTweaks/Created: Migrated theme tweak from <$text text=<<from>>/>.
|
||||
Upgrader/Tiddler/Disabled: Disabled tiddler.
|
||||
Upgrader/Tiddler/Selected: User selected.
|
||||
Upgrader/Tiddler/Selected: Selected tiddler.
|
||||
Upgrader/Tiddler/Unselected: Unselected tiddler.
|
||||
|
||||
@@ -41,7 +41,6 @@ Error/WhileSaving: Error while saving
|
||||
Error/XMLHttpRequest: XMLHttpRequest error code
|
||||
InternalJavaScriptError/Title: Internal JavaScript Error
|
||||
InternalJavaScriptError/Hint: Well, this is embarrassing. It is recommended that you restart TiddlyWiki by refreshing your browser
|
||||
InvalidFieldName: Illegal characters in field name "<$text text=<<fieldName>>/>". Fields can only contain lowercase letters, digits and the characters underscore (`_`), hyphen (`-`) and period (`.`)
|
||||
LayoutSwitcher/Description: Open the layout switcher
|
||||
LazyLoadingWarning: <p>Trying to load external content from ''<$text text={{!!_canonical_uri}}/>''</p><p>If this message doesn't disappear, either the tiddler content type doesn't match the type of the external content, or you may be using a browser that doesn't support external content for wikis loaded as standalone files. See https://tiddlywiki.com/#ExternalText</p>
|
||||
LoginToTiddlySpace: Login to TiddlySpace
|
||||
|
||||
278
core/modules/commands/pipe.js
Normal file
278
core/modules/commands/pipe.js
Normal file
@@ -0,0 +1,278 @@
|
||||
/*\
|
||||
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;
|
||||
|
||||
})();
|
||||
@@ -8,58 +8,59 @@ Render individual tiddlers and save the results to the specified files
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
exports.info = {
|
||||
name: "render",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing tiddler filter";
|
||||
}
|
||||
var self = this,
|
||||
fs = require("fs"),
|
||||
path = require("path"),
|
||||
wiki = this.commander.wiki,
|
||||
tiddlerFilter = this.params[0],
|
||||
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
|
||||
type = this.params[2] || "text/html",
|
||||
template = this.params[3],
|
||||
variableList = this.params.slice(4),
|
||||
tiddlers = wiki.filterTiddlers(tiddlerFilter),
|
||||
variables = Object.create(null);
|
||||
while(variableList.length >= 2) {
|
||||
variables[variableList[0]] = variableList[1];
|
||||
variableList = variableList.slice(2);
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
exports.info = {
|
||||
name: "render",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing tiddler filter";
|
||||
}
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
var parser = wiki.parseTiddler(template || title);
|
||||
var widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title})}),
|
||||
container = $tw.fakeDocument.createElement("div");
|
||||
widgetNode.render(container,null);
|
||||
var text = type === "text/html" ? container.innerHTML : container.textContent,
|
||||
filepath = path.resolve(self.commander.outputPath,wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]))[0]);
|
||||
if(self.commander.verbose) {
|
||||
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
|
||||
}
|
||||
$tw.utils.createFileDirectories(filepath);
|
||||
fs.writeFileSync(filepath,text,"utf8");
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
var self = this,
|
||||
fs = require("fs"),
|
||||
path = require("path"),
|
||||
wiki = this.commander.wiki,
|
||||
tiddlerFilter = this.params[0],
|
||||
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
|
||||
type = this.params[2] || "text/html",
|
||||
template = this.params[3],
|
||||
variableList = this.params.slice(4),
|
||||
tiddlers = wiki.filterTiddlers(tiddlerFilter),
|
||||
variables = Object.create(null);
|
||||
while(variableList.length >= 2) {
|
||||
variables[variableList[0]] = variableList[1];
|
||||
variableList = variableList.slice(2);
|
||||
}
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
var filepath = path.resolve(self.commander.outputPath,wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]))[0]);
|
||||
if(self.commander.verbose) {
|
||||
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
|
||||
}
|
||||
var parser = wiki.parseTiddler(template || title),
|
||||
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title})}),
|
||||
container = $tw.fakeDocument.createElement("div");
|
||||
widgetNode.render(container,null);
|
||||
var text = type === "text/html" ? container.innerHTML : container.textContent;
|
||||
$tw.utils.createFileDirectories(filepath);
|
||||
fs.writeFileSync(filepath,text,"utf8");
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
|
||||
@@ -12,63 +12,8 @@ Functions to deserialise tiddlers from a block of text
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Utility function to parse an old-style tiddler DIV in a *.tid file. It looks like this:
|
||||
|
||||
<div title="Title" creator="JoeBloggs" modifier="JoeBloggs" created="201102111106" modified="201102111310" tags="myTag [[my long tag]]">
|
||||
<pre>The text of the tiddler (without the expected HTML encoding).
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
Note that the field attributes are HTML encoded, but that the body of the <PRE> tag is not encoded.
|
||||
|
||||
When these tiddler DIVs are encountered within a TiddlyWiki HTML file then the body is encoded in the usual way.
|
||||
*/
|
||||
var parseTiddlerDiv = function(text /* [,fields] */) {
|
||||
// Slot together the default results
|
||||
var result = {};
|
||||
if(arguments.length > 1) {
|
||||
for(var f=1; f<arguments.length; f++) {
|
||||
var fields = arguments[f];
|
||||
for(var t in fields) {
|
||||
result[t] = fields[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Parse the DIV body
|
||||
var startRegExp = /^\s*<div\s+([^>]*)>(\s*<pre>)?/gi,
|
||||
endRegExp,
|
||||
match = startRegExp.exec(text);
|
||||
if(match) {
|
||||
// Old-style DIVs don't have the <pre> tag
|
||||
if(match[2]) {
|
||||
endRegExp = /<\/pre>\s*<\/div>\s*$/gi;
|
||||
} else {
|
||||
endRegExp = /<\/div>\s*$/gi;
|
||||
}
|
||||
var endMatch = endRegExp.exec(text);
|
||||
if(endMatch) {
|
||||
// Extract the text
|
||||
result.text = text.substring(match.index + match[0].length,endMatch.index);
|
||||
// Process the attributes
|
||||
var attrRegExp = /\s*([^=\s]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/gi,
|
||||
attrMatch;
|
||||
do {
|
||||
attrMatch = attrRegExp.exec(match[1]);
|
||||
if(attrMatch) {
|
||||
var name = attrMatch[1];
|
||||
var value = attrMatch[2] !== undefined ? attrMatch[2] : attrMatch[3];
|
||||
result[name] = value;
|
||||
}
|
||||
} while(attrMatch);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
exports["application/x-tiddler-html-div"] = function(text,fields) {
|
||||
return [parseTiddlerDiv(text,fields)];
|
||||
return [deserializeTiddlerDiv(text,fields)];
|
||||
};
|
||||
|
||||
exports["application/json"] = function(text,fields) {
|
||||
@@ -105,30 +50,34 @@ Parse an HTML file into tiddlers. There are three possibilities:
|
||||
# An ordinary HTML file
|
||||
*/
|
||||
exports["text/html"] = function(text,fields) {
|
||||
// Check if we've got a store area
|
||||
var results = [];
|
||||
// Check if we've got an old-style store area
|
||||
var storeAreaMarkerRegExp = /<div id=["']?storeArea['"]?( style=["']?display:none;["']?)?>/gi,
|
||||
match = storeAreaMarkerRegExp.exec(text);
|
||||
if(match) {
|
||||
// If so, it's either a classic TiddlyWiki file or an unencrypted TW5 file
|
||||
// First read the normal tiddlers
|
||||
var results = deserializeTiddlyWikiFile(text,storeAreaMarkerRegExp.lastIndex,!!match[1],fields);
|
||||
// Then any system tiddlers
|
||||
var systemAreaMarkerRegExp = /<div id=["']?systemArea['"]?( style=["']?display:none;["']?)?>/gi,
|
||||
sysMatch = systemAreaMarkerRegExp.exec(text);
|
||||
if(sysMatch) {
|
||||
results.push.apply(results,deserializeTiddlyWikiFile(text,systemAreaMarkerRegExp.lastIndex,!!sysMatch[1],fields));
|
||||
}
|
||||
storeAreaMatch = storeAreaMarkerRegExp.exec(text);
|
||||
if(storeAreaMatch) {
|
||||
// If so, we've got tiddlers in classic TiddlyWiki format or unencrypted old-style TW5 format
|
||||
results.push.apply(results,deserializeStoreArea(text,storeAreaMarkerRegExp.lastIndex,!!storeAreaMatch[1],fields));
|
||||
}
|
||||
// Check for new-style store areas
|
||||
var newStoreAreaMarkerRegExp = /<script class="tiddlywiki-tiddler-store" type="([^"]*)">/gi,
|
||||
newStoreAreaMatch = newStoreAreaMarkerRegExp.exec(text),
|
||||
haveHadNewStoreArea = !!newStoreAreaMatch;
|
||||
while(newStoreAreaMatch) {
|
||||
results.push.apply(results,deserializeNewStoreArea(text,newStoreAreaMarkerRegExp.lastIndex,newStoreAreaMatch[1],fields));
|
||||
newStoreAreaMatch = newStoreAreaMarkerRegExp.exec(text);
|
||||
}
|
||||
// Return if we had either an old-style or a new-style store area
|
||||
if(storeAreaMatch || haveHadNewStoreArea) {
|
||||
return results;
|
||||
}
|
||||
// Otherwise, check whether we've got an encrypted file
|
||||
var encryptedStoreArea = $tw.utils.extractEncryptedStoreArea(text);
|
||||
if(encryptedStoreArea) {
|
||||
// If so, attempt to decrypt it using the current password
|
||||
return $tw.utils.decryptStoreArea(encryptedStoreArea);
|
||||
} else {
|
||||
// Check whether we've got an encrypted file
|
||||
var encryptedStoreArea = $tw.utils.extractEncryptedStoreArea(text);
|
||||
if(encryptedStoreArea) {
|
||||
// If so, attempt to decrypt it using the current password
|
||||
return $tw.utils.decryptStoreArea(encryptedStoreArea);
|
||||
} else {
|
||||
// It's not a TiddlyWiki so we'll return the entire HTML file as a tiddler
|
||||
return deserializeHtmlFile(text,fields);
|
||||
}
|
||||
// It's not a TiddlyWiki so we'll return the entire HTML file as a tiddler
|
||||
return deserializeHtmlFile(text,fields);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -142,7 +91,19 @@ function deserializeHtmlFile(text,fields) {
|
||||
return [result];
|
||||
}
|
||||
|
||||
function deserializeTiddlyWikiFile(text,storeAreaEnd,isTiddlyWiki5,fields) {
|
||||
function deserializeNewStoreArea(text,storeAreaEnd,type,fields) {
|
||||
var endOfScriptRegExp = /<\/script>/gi;
|
||||
endOfScriptRegExp.lastIndex = storeAreaEnd;
|
||||
var match = endOfScriptRegExp.exec(text);
|
||||
if(match) {
|
||||
var scriptContent = text.substring(storeAreaEnd,match.index);
|
||||
return $tw.wiki.deserializeTiddlers(type,scriptContent);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function deserializeStoreArea(text,storeAreaEnd,isTiddlyWiki5,fields) {
|
||||
var results = [],
|
||||
endOfDivRegExp = /(<\/div>\s*)/gi,
|
||||
startPos = storeAreaEnd,
|
||||
@@ -151,7 +112,7 @@ function deserializeTiddlyWikiFile(text,storeAreaEnd,isTiddlyWiki5,fields) {
|
||||
var match = endOfDivRegExp.exec(text);
|
||||
while(match) {
|
||||
var endPos = endOfDivRegExp.lastIndex,
|
||||
tiddlerFields = parseTiddlerDiv(text.substring(startPos,endPos),fields,{type: defaultType});
|
||||
tiddlerFields = deserializeTiddlerDiv(text.substring(startPos,endPos),fields,{type: defaultType});
|
||||
if(!tiddlerFields) {
|
||||
break;
|
||||
}
|
||||
@@ -169,4 +130,59 @@ function deserializeTiddlyWikiFile(text,storeAreaEnd,isTiddlyWiki5,fields) {
|
||||
return results;
|
||||
}
|
||||
|
||||
/*
|
||||
Utility function to parse an old-style tiddler DIV in a *.tid file. It looks like this:
|
||||
|
||||
<div title="Title" creator="JoeBloggs" modifier="JoeBloggs" created="201102111106" modified="201102111310" tags="myTag [[my long tag]]">
|
||||
<pre>The text of the tiddler (without the expected HTML encoding).
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
Note that the field attributes are HTML encoded, but that the body of the <PRE> tag is not encoded.
|
||||
|
||||
When these tiddler DIVs are encountered within a TiddlyWiki HTML file then the body is encoded in the usual way.
|
||||
*/
|
||||
var deserializeTiddlerDiv = function(text /* [,fields] */) {
|
||||
// Slot together the default results
|
||||
var result = {};
|
||||
if(arguments.length > 1) {
|
||||
for(var f=1; f<arguments.length; f++) {
|
||||
var fields = arguments[f];
|
||||
for(var t in fields) {
|
||||
result[t] = fields[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Parse the DIV body
|
||||
var startRegExp = /^\s*<div\s+([^>]*)>(\s*<pre>)?/gi,
|
||||
endRegExp,
|
||||
match = startRegExp.exec(text);
|
||||
if(match) {
|
||||
// Old-style DIVs don't have the <pre> tag
|
||||
if(match[2]) {
|
||||
endRegExp = /<\/pre>\s*<\/div>\s*$/gi;
|
||||
} else {
|
||||
endRegExp = /<\/div>\s*$/gi;
|
||||
}
|
||||
var endMatch = endRegExp.exec(text);
|
||||
if(endMatch) {
|
||||
// Extract the text
|
||||
result.text = text.substring(match.index + match[0].length,endMatch.index);
|
||||
// Process the attributes
|
||||
var attrRegExp = /\s*([^=\s]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/gi,
|
||||
attrMatch;
|
||||
do {
|
||||
attrMatch = attrRegExp.exec(match[1]);
|
||||
if(attrMatch) {
|
||||
var name = attrMatch[1];
|
||||
var value = attrMatch[2] !== undefined ? attrMatch[2] : attrMatch[3];
|
||||
result[name] = value;
|
||||
}
|
||||
} while(attrMatch);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -135,7 +135,11 @@ FramedEngine.prototype.setText = function(text,type) {
|
||||
Update the DomNode with the new text
|
||||
*/
|
||||
FramedEngine.prototype.updateDomNodeText = function(text) {
|
||||
this.domNode.value = text;
|
||||
try {
|
||||
this.domNode.value = text;
|
||||
} catch(e) {
|
||||
// Ignore
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -85,7 +85,11 @@ SimpleEngine.prototype.setText = function(text,type) {
|
||||
Update the DomNode with the new text
|
||||
*/
|
||||
SimpleEngine.prototype.updateDomNodeText = function(text) {
|
||||
this.domNode.value = text;
|
||||
try {
|
||||
this.domNode.value = text;
|
||||
} catch(e) {
|
||||
// Ignore
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -332,7 +332,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
};
|
||||
|
||||
EditTextWidget.prototype.handlePasteEvent = function(event) {
|
||||
if(event.clipboardData.files.length) {
|
||||
if(event.clipboardData && event.clipboardData.files && event.clipboardData.files.length) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.dispatchDOMEvent(this.cloneEvent(event,["clipboardData"]));
|
||||
|
||||
17
core/modules/editor/operations/text/focus-editor.js
Normal file
17
core/modules/editor/operations/text/focus-editor.js
Normal file
@@ -0,0 +1,17 @@
|
||||
/*\
|
||||
title: $:/core/modules/editor/operations/text/focus-editor.js
|
||||
type: application/javascript
|
||||
module-type: texteditoroperation
|
||||
Simply focus the Text editor
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports["focus-editor"] = function(event,operation) {
|
||||
operation = null;
|
||||
};
|
||||
|
||||
})();
|
||||
39
core/modules/filterrunprefixes/map.js
Normal file
39
core/modules/filterrunprefixes/map.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/map.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.map = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
var inputTitles = results.toArray();
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
results.push(filtered[0] || "");
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -253,7 +253,8 @@ exports.compileFilter = function(filterString) {
|
||||
if(operand.indirect) {
|
||||
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
||||
} else if(operand.variable) {
|
||||
operand.value = widget.getVariable(operand.text,{defaultValue: ""});
|
||||
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
||||
operand.value = widget.getVariable(varTree.name,{params:varTree.params,defaultValue: ""});
|
||||
} else {
|
||||
operand.value = operand.text;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ exports.all = function(source,operator,options) {
|
||||
results.pushTop(subop(source,operator.prefix,options));
|
||||
}
|
||||
}
|
||||
return results.toArray();
|
||||
return results.makeTiddlerIterator(options.wiki);
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -16,11 +16,11 @@ Filter operator for returning all the backlinks from a tiddler
|
||||
Export our filter function
|
||||
*/
|
||||
exports.backlinks = function(source,operator,options) {
|
||||
var results = [];
|
||||
var results = new $tw.utils.LinkedList();
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.pushTop(results,options.wiki.getTiddlerBacklinks(title));
|
||||
results.pushTop(options.wiki.getTiddlerBacklinks(title));
|
||||
});
|
||||
return results;
|
||||
return results.makeTiddlerIterator(options.wiki);
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -17,7 +17,7 @@ Export our filter function
|
||||
*/
|
||||
exports.contains = function(source,operator,options) {
|
||||
var results = [],
|
||||
fieldname = (operator.suffix || "list").toLowerCase();
|
||||
fieldname = operator.suffix || "list";
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler) {
|
||||
|
||||
@@ -19,12 +19,7 @@ Export our filter functions
|
||||
exports.decodeuricomponent = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var value = title;
|
||||
try {
|
||||
value = decodeURIComponent(title);
|
||||
} catch(e) {
|
||||
}
|
||||
results.push(value);
|
||||
results.push($tw.utils.decodeURIComponentSafe(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
@@ -40,12 +35,7 @@ exports.encodeuricomponent = function(source,operator,options) {
|
||||
exports.decodeuri = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var value = title;
|
||||
try {
|
||||
value = decodeURI(title);
|
||||
} catch(e) {
|
||||
}
|
||||
results.push(value);
|
||||
results.push($tw.utils.decodeURISafe(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ Export our filter function
|
||||
*/
|
||||
exports.field = function(source,operator,options) {
|
||||
var results = [],indexedResults,
|
||||
fieldname = (operator.suffix || operator.operator || "title").toLowerCase();
|
||||
fieldname = operator.suffix || operator.operator || "title";
|
||||
if(operator.prefix === "!") {
|
||||
if(operator.regexp) {
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -20,7 +20,7 @@ exports.links = function(source,operator,options) {
|
||||
source(function(tiddler,title) {
|
||||
results.pushTop(options.wiki.getTiddlerLinks(title));
|
||||
});
|
||||
return results.toArray();
|
||||
return results.makeTiddlerIterator(options.wiki);
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -165,6 +165,35 @@ exports["standard-deviation"] = makeNumericReducingOperator(
|
||||
}
|
||||
);
|
||||
|
||||
//trigonometry
|
||||
exports.cos = makeNumericBinaryOperator(
|
||||
function(a) {return Math.cos(a)}
|
||||
);
|
||||
|
||||
exports.sin = makeNumericBinaryOperator(
|
||||
function(a) {return Math.sin(a)}
|
||||
);
|
||||
|
||||
exports.tan = makeNumericBinaryOperator(
|
||||
function(a) {return Math.tan(a)}
|
||||
);
|
||||
|
||||
exports.acos = makeNumericBinaryOperator(
|
||||
function(a) {return Math.acos(a)}
|
||||
);
|
||||
|
||||
exports.asin = makeNumericBinaryOperator(
|
||||
function(a) {return Math.asin(a)}
|
||||
);
|
||||
|
||||
exports.atan = makeNumericBinaryOperator(
|
||||
function(a) {return Math.atan(a)}
|
||||
);
|
||||
|
||||
exports.atan2 = makeNumericBinaryOperator(
|
||||
function(a,b) {return Math.atan2(a,b)}
|
||||
);
|
||||
|
||||
//Calculate the variance of a population of numbers in an array given its mean
|
||||
function getVarianceFromArray(values,mean) {
|
||||
var deviationTotal = values.reduce(function(accumulator,value) {
|
||||
|
||||
30
core/modules/filters/moduleproperty.js
Normal file
30
core/modules/filters/moduleproperty.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/moduleproperty.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter [[module-name]moduleproperty[name]] retrieve a module property
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.moduleproperty = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var value = require(title)[operator.operand || ""];
|
||||
if(value !== undefined) {
|
||||
results.push(value);
|
||||
}
|
||||
});
|
||||
results.sort();
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -17,11 +17,23 @@ Export our filter function
|
||||
*/
|
||||
exports.modules = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
|
||||
results.push(moduleName);
|
||||
if(operator.operands.length >= 2) {
|
||||
// Return the modules that have the module property specified in the first operand with the value in the second operand
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
|
||||
if(require(moduleName)[operator.operands[0]] === operator.operands[1]) {
|
||||
results.push(moduleName);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Return all the module names without filtering
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
|
||||
results.push(moduleName);
|
||||
});
|
||||
});
|
||||
}
|
||||
results.sort();
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -17,9 +17,13 @@ Export our filter function
|
||||
*/
|
||||
exports.range = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Split the operand into numbers delimited by these symbols
|
||||
var parts = operator.operand.split(/[,:;]/g),
|
||||
beg, end, inc, i, fixed = 0;
|
||||
// For backwards compatibility, if there is only one operand, try to split it using one of the delimiters
|
||||
var parts = operator.operands || [];
|
||||
if(parts.length === 1) {
|
||||
parts = operator.operand.split(/[,:;]/g);
|
||||
}
|
||||
// Process the parts
|
||||
var beg, end, inc, i, fixed = 0;
|
||||
for (i=0; i<parts.length; i++) {
|
||||
// Validate real number
|
||||
if(!/^\s*[+-]?((\d+(\.\d*)?)|(\.\d+))\s*$/.test(parts[i])) {
|
||||
|
||||
@@ -17,7 +17,7 @@ Export our filter function
|
||||
*/
|
||||
exports.regexp = function(source,operator,options) {
|
||||
var results = [],
|
||||
fieldname = (operator.suffix || "title").toLowerCase(),
|
||||
fieldname = operator.suffix || "title",
|
||||
regexpString, regexp, flags = "", match,
|
||||
getFieldString = function(tiddler,title) {
|
||||
if(tiddler) {
|
||||
|
||||
@@ -119,7 +119,7 @@ exports["search-replace"] = function(source,operator,options) {
|
||||
var results = [],
|
||||
suffixes = operator.suffixes || [],
|
||||
flagSuffix = (suffixes[0] ? (suffixes[0][0] || "") : ""),
|
||||
flags = (flagSuffix.indexOf("g") !== -1 ? "g" : "") + (flagSuffix.indexOf("i") !== -1 ? "i" : ""),
|
||||
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,
|
||||
regExp;
|
||||
@@ -172,4 +172,14 @@ exports.pad = function(source,operator,options) {
|
||||
return results;
|
||||
}
|
||||
|
||||
exports.charcode = function(source,operator,options) {
|
||||
var chars = [];
|
||||
$tw.utils.each(operator.operands,function(operand) {
|
||||
if(operand !== "") {
|
||||
chars.push(String.fromCharCode($tw.utils.parseInt(operand)));
|
||||
}
|
||||
});
|
||||
return [chars.join("")];
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -16,20 +16,13 @@ Filter operator returning all the selected tiddlers that are untagged
|
||||
Export our filter function
|
||||
*/
|
||||
exports.untagged = function(source,operator,options) {
|
||||
var results = [];
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && $tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length > 0) {
|
||||
$tw.utils.pushTop(results,title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(!tiddler || !tiddler.hasField("tags") || ($tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length === 0)) {
|
||||
$tw.utils.pushTop(results,title);
|
||||
}
|
||||
});
|
||||
}
|
||||
var results = [],
|
||||
expected = (operator.prefix === "!");
|
||||
source(function(tiddler,title) {
|
||||
if((tiddler && $tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length > 0) === expected) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ Key descriptors have the following format:
|
||||
ctrl+enter
|
||||
ctrl+shift+alt+A
|
||||
*/
|
||||
KeyboardManager.prototype.parseKeyDescriptor = function(keyDescriptor) {
|
||||
KeyboardManager.prototype.parseKeyDescriptor = function(keyDescriptor,options) {
|
||||
var components = keyDescriptor.split(/\+|\-/),
|
||||
info = {
|
||||
keyCode: 0,
|
||||
@@ -206,6 +206,9 @@ KeyboardManager.prototype.parseKeyDescriptor = function(keyDescriptor) {
|
||||
info.keyCode = this.namedKeys[s];
|
||||
}
|
||||
}
|
||||
if(options.keyDescriptor) {
|
||||
info.keyDescriptor = options.keyDescriptor;
|
||||
}
|
||||
if(info.keyCode) {
|
||||
return info;
|
||||
} else {
|
||||
@@ -237,6 +240,7 @@ KeyboardManager.prototype.parseKeyDescriptors = function(keyDescriptors,options)
|
||||
lookupName = function(configName) {
|
||||
var keyDescriptors = wiki.getTiddlerText("$:/config/" + configName + "/" + name);
|
||||
if(keyDescriptors) {
|
||||
options.keyDescriptor = keyDescriptor;
|
||||
result.push.apply(result,self.parseKeyDescriptors(keyDescriptors,options));
|
||||
}
|
||||
};
|
||||
@@ -245,7 +249,7 @@ KeyboardManager.prototype.parseKeyDescriptors = function(keyDescriptors,options)
|
||||
});
|
||||
}
|
||||
} else {
|
||||
result.push(self.parseKeyDescriptor(keyDescriptor));
|
||||
result.push(self.parseKeyDescriptor(keyDescriptor,options));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
@@ -276,12 +280,16 @@ KeyboardManager.prototype.checkKeyDescriptor = function(event,keyInfo) {
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.checkKeyDescriptors = function(event,keyInfoArray) {
|
||||
return (this.getMatchingKeyDescriptor(event,keyInfoArray) !== null);
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.getMatchingKeyDescriptor = function(event,keyInfoArray) {
|
||||
for(var t=0; t<keyInfoArray.length; t++) {
|
||||
if(this.checkKeyDescriptor(event,keyInfoArray[t])) {
|
||||
return true;
|
||||
return keyInfoArray[t];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.getEventModifierKeyDescriptor = function(event) {
|
||||
@@ -324,7 +332,7 @@ KeyboardManager.prototype.handleKeydownEvent = function(event) {
|
||||
if(key !== undefined) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
$tw.rootWidget.invokeActionString(action,$tw.rootWidget);
|
||||
$tw.rootWidget.invokeActionString(action,$tw.rootWidget,event);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -123,6 +123,19 @@ exports.parseStringLiteral = function(source,pos) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.parseMacroParameters = function(node,source,pos) {
|
||||
// Process parameters
|
||||
var parameter = $tw.utils.parseMacroParameter(source,pos);
|
||||
while(parameter) {
|
||||
node.params.push(parameter);
|
||||
pos = parameter.end;
|
||||
// Get the next parameter
|
||||
parameter = $tw.utils.parseMacroParameter(source,pos);
|
||||
}
|
||||
node.end = pos;
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
Look for a macro invocation parameter. Returns null if not found, or {type: "macro-parameter", name:, value:, start:, end:}
|
||||
*/
|
||||
@@ -187,14 +200,8 @@ exports.parseMacroInvocation = function(source,pos) {
|
||||
}
|
||||
node.name = name.match[1];
|
||||
pos = name.end;
|
||||
// Process parameters
|
||||
var parameter = $tw.utils.parseMacroParameter(source,pos);
|
||||
while(parameter) {
|
||||
node.params.push(parameter);
|
||||
pos = parameter.end;
|
||||
// Get the next parameter
|
||||
parameter = $tw.utils.parseMacroParameter(source,pos);
|
||||
}
|
||||
node = $tw.utils.parseMacroParameters(node,source,pos);
|
||||
pos = node.end;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a double greater than sign
|
||||
@@ -208,6 +215,29 @@ exports.parseMacroInvocation = function(source,pos) {
|
||||
return node;
|
||||
};
|
||||
|
||||
exports.parseFilterVariable = function(source) {
|
||||
var node = {
|
||||
name: "",
|
||||
params: [],
|
||||
},
|
||||
pos = 0,
|
||||
reName = /([^\s"']+)/g;
|
||||
// If there is no whitespace or it is an empty string then there are no macro parameters
|
||||
if(/^\S*$/.test(source)) {
|
||||
node.name = source;
|
||||
return node;
|
||||
}
|
||||
// Get the variable name
|
||||
var nameMatch = $tw.utils.parseTokenRegExp(source,pos,reName);
|
||||
if(nameMatch) {
|
||||
node.name = nameMatch.match[1];
|
||||
pos = nameMatch.end;
|
||||
node = $tw.utils.parseMacroParameters(node,source,pos);
|
||||
delete node.end;
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for an HTML attribute definition. Returns null if not found, otherwise returns {type: "attribute", name:, valueType: "string|indirect|macro", value:, start:, end:,}
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,12 @@ Wiki text block rule for HTML comments. For example:
|
||||
|
||||
```
|
||||
<!-- This is a comment -->
|
||||
\define macroX()
|
||||
<!-- This is a comment -->
|
||||
xxxx
|
||||
\end
|
||||
<!-- This is a comment -->
|
||||
|
||||
```
|
||||
|
||||
Note that the syntax for comments is simplified to an opening "<!--" sequence and a closing "-->" sequence -- HTML itself implements a more complex format (see http://ostermiller.org/findhtmlcomment.html)
|
||||
@@ -19,7 +25,7 @@ Note that the syntax for comments is simplified to an opening "<!--" sequence an
|
||||
"use strict";
|
||||
|
||||
exports.name = "commentblock";
|
||||
exports.types = {block: true};
|
||||
exports.types = {block:true, pragma:true};
|
||||
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
|
||||
@@ -66,7 +66,7 @@ exports.parse = function() {
|
||||
};
|
||||
|
||||
/*
|
||||
Look for an HTML tag. Returns null if not found, otherwise returns {type: "element", name:, attributes: [], isSelfClosing:, start:, end:,}
|
||||
Look for an HTML tag. Returns null if not found, otherwise returns {type: "element", name:, attributes: {}, orderedAttributes: [], isSelfClosing:, start:, end:,}
|
||||
*/
|
||||
exports.parseTag = function(source,pos,options) {
|
||||
options = options || {};
|
||||
@@ -74,7 +74,8 @@ exports.parseTag = function(source,pos,options) {
|
||||
node = {
|
||||
type: "element",
|
||||
start: pos,
|
||||
attributes: {}
|
||||
attributes: {},
|
||||
orderedAttributes: []
|
||||
};
|
||||
// Define our regexps
|
||||
var reTagName = /([a-zA-Z0-9\-\$]+)/g;
|
||||
@@ -106,6 +107,7 @@ exports.parseTag = function(source,pos,options) {
|
||||
// Process attributes
|
||||
var attribute = $tw.utils.parseAttribute(source,pos);
|
||||
while(attribute) {
|
||||
node.orderedAttributes.push(attribute);
|
||||
node.attributes[attribute.name] = attribute;
|
||||
pos = attribute.end;
|
||||
// Get the next attribute
|
||||
|
||||
@@ -231,7 +231,10 @@ WikiParser.prototype.parseBlock = function(terminatorRegExpString) {
|
||||
return nextMatch.rule.parse();
|
||||
}
|
||||
// Treat it as a paragraph if we didn't find a block rule
|
||||
return [{type: "element", tag: "p", children: this.parseInlineRun(terminatorRegExp)}];
|
||||
var start = this.pos;
|
||||
var children = this.parseInlineRun(terminatorRegExp);
|
||||
var end = this.pos;
|
||||
return [{type: "element", tag: "p", children: children, start: start, end: end }];
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -307,7 +310,7 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) {
|
||||
while(this.pos < this.sourceLength && nextMatch) {
|
||||
// Process the text preceding the run rule
|
||||
if(nextMatch.matchIndex > this.pos) {
|
||||
this.pushTextWidget(tree,this.source.substring(this.pos,nextMatch.matchIndex));
|
||||
this.pushTextWidget(tree,this.source.substring(this.pos,nextMatch.matchIndex),this.pos,nextMatch.matchIndex);
|
||||
this.pos = nextMatch.matchIndex;
|
||||
}
|
||||
// Process the run rule
|
||||
@@ -317,7 +320,7 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) {
|
||||
}
|
||||
// Process the remaining text
|
||||
if(this.pos < this.sourceLength) {
|
||||
this.pushTextWidget(tree,this.source.substr(this.pos));
|
||||
this.pushTextWidget(tree,this.source.substr(this.pos),this.pos,this.sourceLength);
|
||||
}
|
||||
this.pos = this.sourceLength;
|
||||
return tree;
|
||||
@@ -337,7 +340,7 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
||||
if(terminatorMatch) {
|
||||
if(!inlineRuleMatch || inlineRuleMatch.matchIndex >= terminatorMatch.index) {
|
||||
if(terminatorMatch.index > this.pos) {
|
||||
this.pushTextWidget(tree,this.source.substring(this.pos,terminatorMatch.index));
|
||||
this.pushTextWidget(tree,this.source.substring(this.pos,terminatorMatch.index),this.pos,terminatorMatch.index);
|
||||
}
|
||||
this.pos = terminatorMatch.index;
|
||||
if(options.eatTerminator) {
|
||||
@@ -350,7 +353,7 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
||||
if(inlineRuleMatch) {
|
||||
// Preceding text
|
||||
if(inlineRuleMatch.matchIndex > this.pos) {
|
||||
this.pushTextWidget(tree,this.source.substring(this.pos,inlineRuleMatch.matchIndex));
|
||||
this.pushTextWidget(tree,this.source.substring(this.pos,inlineRuleMatch.matchIndex),this.pos,inlineRuleMatch.matchIndex);
|
||||
this.pos = inlineRuleMatch.matchIndex;
|
||||
}
|
||||
// Process the inline rule
|
||||
@@ -364,7 +367,7 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
||||
}
|
||||
// Process the remaining text
|
||||
if(this.pos < this.sourceLength) {
|
||||
this.pushTextWidget(tree,this.source.substr(this.pos));
|
||||
this.pushTextWidget(tree,this.source.substr(this.pos),this.pos,this.sourceLength);
|
||||
}
|
||||
this.pos = this.sourceLength;
|
||||
return tree;
|
||||
@@ -373,12 +376,12 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
||||
/*
|
||||
Push a text widget onto an array, respecting the configTrimWhiteSpace setting
|
||||
*/
|
||||
WikiParser.prototype.pushTextWidget = function(array,text) {
|
||||
WikiParser.prototype.pushTextWidget = function(array,text,start,end) {
|
||||
if(this.configTrimWhiteSpace) {
|
||||
text = $tw.utils.trim(text);
|
||||
}
|
||||
if(text) {
|
||||
array.push({type: "text", text: text});
|
||||
array.push({type: "text", text: text, start: start, end: end});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -157,7 +157,8 @@ SaverHandler.prototype.saveWiki = function(options) {
|
||||
return false;
|
||||
}
|
||||
var variables = options.variables || {},
|
||||
template = options.template || "$:/core/save/all",
|
||||
template = (options.template ||
|
||||
this.wiki.getTiddlerText("$:/config/SaveWikiButton/Template","$:/core/save/all")).trim(),
|
||||
downloadType = options.downloadType || "text/plain",
|
||||
text = this.wiki.renderTiddler(downloadType,template,options),
|
||||
callback = function(err) {
|
||||
|
||||
@@ -42,7 +42,7 @@ AndTidWiki.prototype.save = function(text,method,callback,options) {
|
||||
window.twi.saveWiki(text);
|
||||
} else {
|
||||
// Get the pathname of this document
|
||||
var pathname = decodeURIComponent(document.location.toString().split("#")[0]);
|
||||
var pathname = $tw.utils.decodeURIComponentSafe(document.location.toString().split("#")[0]);
|
||||
// Strip the file://
|
||||
if(pathname.indexOf("file://") === 0) {
|
||||
pathname = pathname.substr(7);
|
||||
|
||||
@@ -26,7 +26,7 @@ DownloadSaver.prototype.save = function(text,method,callback,options) {
|
||||
var p = document.location.pathname.lastIndexOf("/");
|
||||
if(p !== -1) {
|
||||
// We decode the pathname because document.location is URL encoded by the browser
|
||||
filename = decodeURIComponent(document.location.pathname.substr(p+1));
|
||||
filename = $tw.utils.decodeURIComponentSafe(document.location.pathname.substr(p+1));
|
||||
}
|
||||
}
|
||||
if(!filename) {
|
||||
|
||||
@@ -72,7 +72,7 @@ GiteaSaver.prototype.save = function(text,method,callback) {
|
||||
}
|
||||
}
|
||||
var data = {
|
||||
message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
content: $tw.utils.base64Encode(text),
|
||||
sha: sha
|
||||
};
|
||||
|
||||
@@ -69,7 +69,7 @@ GitHubSaver.prototype.save = function(text,method,callback) {
|
||||
});
|
||||
}
|
||||
var data = {
|
||||
message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
content: $tw.utils.base64Encode(text),
|
||||
branch: branch,
|
||||
sha: sha
|
||||
|
||||
@@ -67,7 +67,7 @@ GitLabSaver.prototype.save = function(text,method,callback) {
|
||||
});
|
||||
}
|
||||
var data = {
|
||||
commit_message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
commit_message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
content: text,
|
||||
branch: branch,
|
||||
sha: sha
|
||||
|
||||
@@ -43,7 +43,7 @@ TiddlyFoxSaver.prototype.save = function(text,method,callback) {
|
||||
}
|
||||
// Create the message element and put it in the message box
|
||||
var message = document.createElement("div");
|
||||
message.setAttribute("data-tiddlyfox-path",decodeURIComponent(pathname));
|
||||
message.setAttribute("data-tiddlyfox-path",$tw.utils.decodeURIComponentSafe(pathname));
|
||||
message.setAttribute("data-tiddlyfox-content",text);
|
||||
messageBox.appendChild(message);
|
||||
// Add an event handler for when the file has been saved
|
||||
|
||||
@@ -21,7 +21,7 @@ TWEditSaver.prototype.save = function(text,method,callback) {
|
||||
return false;
|
||||
}
|
||||
// Get the pathname of this document
|
||||
var pathname = decodeURIComponent(document.location.pathname);
|
||||
var pathname = $tw.utils.decodeURIComponentSafe(document.location.pathname);
|
||||
// Strip any query or location part
|
||||
var p = pathname.indexOf("?");
|
||||
if(p !== -1) {
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.method = "DELETE";
|
||||
exports.path = /^\/bags\/default\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = decodeURIComponent(state.params[0]);
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
||||
state.wiki.deleteTiddler(title);
|
||||
response.writeHead(204, "OK", {
|
||||
"Content-Type": "text/plain"
|
||||
|
||||
@@ -20,22 +20,29 @@ exports.handler = function(request,response,state) {
|
||||
var path = require("path"),
|
||||
fs = require("fs"),
|
||||
util = require("util"),
|
||||
suppliedFilename = decodeURIComponent(state.params[0]),
|
||||
filename = path.resolve(state.boot.wikiPath,"files",suppliedFilename),
|
||||
suppliedFilename = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
baseFilename = path.resolve(state.boot.wikiPath,"files"),
|
||||
filename = path.resolve(baseFilename,suppliedFilename),
|
||||
extension = path.extname(filename);
|
||||
fs.readFile(filename,function(err,content) {
|
||||
var status,content,type = "text/plain";
|
||||
if(err) {
|
||||
console.log("Error accessing file " + filename + ": " + err.toString());
|
||||
status = 404;
|
||||
content = "File '" + suppliedFilename + "' not found";
|
||||
} else {
|
||||
status = 200;
|
||||
content = content;
|
||||
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
|
||||
}
|
||||
state.sendResponse(status,{"Content-Type": type},content);
|
||||
});
|
||||
// Check that the filename is inside the wiki files folder
|
||||
if(path.relative(baseFilename,filename).indexOf("..") !== 0) {
|
||||
// Send the file
|
||||
fs.readFile(filename,function(err,content) {
|
||||
var status,content,type = "text/plain";
|
||||
if(err) {
|
||||
console.log("Error accessing file " + filename + ": " + err.toString());
|
||||
status = 404;
|
||||
content = "File '" + suppliedFilename + "' not found";
|
||||
} else {
|
||||
status = 200;
|
||||
content = content;
|
||||
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
|
||||
}
|
||||
state.sendResponse(status,{"Content-Type": type},content);
|
||||
});
|
||||
} else {
|
||||
state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
|
||||
}
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
@@ -21,7 +21,6 @@ exports.handler = function(request,response,state) {
|
||||
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
||||
anonymous: !state.authenticatedUsername,
|
||||
read_only: !state.server.isAuthorized("writers",state.authenticatedUsername),
|
||||
sse_enabled: state.server.get("sse-enabled") === "yes",
|
||||
space: {
|
||||
recipe: "default"
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.method = "GET";
|
||||
exports.path = /^\/([^\/]+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = decodeURIComponent(state.params[0]),
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
tiddler = state.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
var renderType = tiddler.getFieldString("_render_type"),
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.method = "GET";
|
||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = decodeURIComponent(state.params[0]),
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
tiddler = state.wiki.getTiddler(title),
|
||||
tiddlerFields = {},
|
||||
knownFields = [
|
||||
|
||||
55
core/modules/server/routes/post-commands.js
Normal file
55
core/modules/server/routes/post-commands.js
Normal file
@@ -0,0 +1,55 @@
|
||||
/*\
|
||||
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
|
||||
};
|
||||
|
||||
}());
|
||||
@@ -17,7 +17,7 @@ exports.method = "PUT";
|
||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = decodeURIComponent(state.params[0]),
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
fields = JSON.parse(state.data);
|
||||
// Pull up any subfields in the `fields` object
|
||||
if(fields.fields) {
|
||||
@@ -30,7 +30,7 @@ exports.handler = function(request,response,state) {
|
||||
if(fields.revision) {
|
||||
delete fields.revision;
|
||||
}
|
||||
state.wiki.addTiddler(new $tw.Tiddler(state.wiki.getCreationFields(),fields,{title: title},state.wiki.getModificationFields()));
|
||||
state.wiki.addTiddler(new $tw.Tiddler(fields,{title: title}));
|
||||
var changeCount = state.wiki.getChangeCount(title).toString();
|
||||
response.writeHead(204, "OK",{
|
||||
Etag: "\"default/" + encodeURIComponent(title) + "/" + changeCount + ":\"",
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/server/server-sent-events.js
|
||||
type: application/javascript
|
||||
module-type: library
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
parameters:
|
||||
prefix - usually the plugin path, such as `plugins/tiddlywiki/tiddlyweb`. The
|
||||
route will match `/events/${prefix}` exactly.
|
||||
|
||||
handler - a function that will be called each time a request comes in with the
|
||||
request and state from the route and an emit function to call.
|
||||
*/
|
||||
|
||||
var ServerSentEvents = function ServerSentEvents(prefix, handler) {
|
||||
this.handler = handler;
|
||||
this.prefix = prefix;
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.getExports = function() {
|
||||
return {
|
||||
bodyFormat: "stream",
|
||||
method: "GET",
|
||||
path: new RegExp("^/events/" + this.prefix + "$"),
|
||||
handler: this.handleEventRequest.bind(this)
|
||||
};
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.handleEventRequest = function(request,response,state) {
|
||||
if(ServerSentEvents.prototype.isEventStreamRequest(request)) {
|
||||
response.writeHead(200, {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
"Connection": "keep-alive"
|
||||
});
|
||||
this.handler(request,state,this.emit.bind(this,response),this.end.bind(this,response));
|
||||
} else {
|
||||
response.writeHead(406,"Not Acceptable",{});
|
||||
response.end();
|
||||
}
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.isEventStreamRequest = function(request) {
|
||||
return request.headers.accept &&
|
||||
request.headers.accept.match(/^text\/event-stream/);
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.emit = function(response,event,data) {
|
||||
if(typeof event !== "string" || event.indexOf("\n") !== -1) {
|
||||
throw new Error("Type must be a single-line string");
|
||||
}
|
||||
if(typeof data !== "string" || data.indexOf("\n") !== -1) {
|
||||
throw new Error("Data must be a single-line string");
|
||||
}
|
||||
response.write("event: " + event + "\ndata: " + data + "\n\n", "utf8");
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.end = function(response) {
|
||||
response.end();
|
||||
};
|
||||
|
||||
exports.ServerSentEvents = ServerSentEvents;
|
||||
|
||||
})();
|
||||
@@ -40,9 +40,10 @@ exports.startup = function() {
|
||||
// Install the tm-focus-selector message
|
||||
$tw.rootWidget.addEventListener("tm-focus-selector",function(event) {
|
||||
var selector = event.param || "",
|
||||
element;
|
||||
element,
|
||||
doc = event.event && event.event.target ? event.event.target.ownerDocument : document;
|
||||
try {
|
||||
element = document.querySelector(selector);
|
||||
element = doc.querySelector(selector);
|
||||
} catch(e) {
|
||||
console.log("Error in selector: ",selector)
|
||||
}
|
||||
|
||||
@@ -120,10 +120,10 @@ function openStartupTiddlers(options) {
|
||||
var hash = $tw.locationHash.substr(1),
|
||||
split = hash.indexOf(":");
|
||||
if(split === -1) {
|
||||
target = decodeURIComponent(hash.trim());
|
||||
target = $tw.utils.decodeURIComponentSafe(hash.trim());
|
||||
} else {
|
||||
target = decodeURIComponent(hash.substr(0,split).trim());
|
||||
storyFilter = decodeURIComponent(hash.substr(split + 1).trim());
|
||||
target = $tw.utils.decodeURIComponentSafe(hash.substr(0,split).trim());
|
||||
storyFilter = $tw.utils.decodeURIComponentSafe(hash.substr(split + 1).trim());
|
||||
}
|
||||
}
|
||||
// If the story wasn't specified use the current tiddlers or a blank story
|
||||
|
||||
@@ -27,7 +27,7 @@ ClassicStoryView.prototype.navigateTo = function(historyInfo) {
|
||||
var listItemWidget = this.listWidget.children[listElementIndex],
|
||||
targetElement = listItemWidget.findFirstDomNode();
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
return;
|
||||
}
|
||||
if(duration) {
|
||||
@@ -43,7 +43,7 @@ ClassicStoryView.prototype.insert = function(widget) {
|
||||
if(duration) {
|
||||
var targetElement = widget.findFirstDomNode();
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
return;
|
||||
}
|
||||
// Get the current height of the tiddler
|
||||
@@ -83,7 +83,7 @@ ClassicStoryView.prototype.remove = function(widget) {
|
||||
widget.removeChildDomNodes();
|
||||
};
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
removeElement();
|
||||
return;
|
||||
}
|
||||
@@ -118,4 +118,4 @@ ClassicStoryView.prototype.remove = function(widget) {
|
||||
|
||||
exports.classic = ClassicStoryView;
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -24,7 +24,7 @@ PopStoryView.prototype.navigateTo = function(historyInfo) {
|
||||
var listItemWidget = this.listWidget.children[listElementIndex],
|
||||
targetElement = listItemWidget.findFirstDomNode();
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
return;
|
||||
}
|
||||
// Scroll the node into view
|
||||
@@ -35,7 +35,7 @@ PopStoryView.prototype.insert = function(widget) {
|
||||
var targetElement = widget.findFirstDomNode(),
|
||||
duration = $tw.utils.getAnimationDuration();
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
return;
|
||||
}
|
||||
// Reset once the transition is over
|
||||
@@ -77,7 +77,7 @@ PopStoryView.prototype.remove = function(widget) {
|
||||
}
|
||||
};
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
removeElement();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ ZoominListView.prototype.navigateTo = function(historyInfo) {
|
||||
var listItemWidget = this.listWidget.children[listElementIndex],
|
||||
targetElement = listItemWidget.findFirstDomNode();
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
return;
|
||||
}
|
||||
// Make the new tiddler be position absolute and visible so that we can measure it
|
||||
@@ -130,7 +130,7 @@ function findTitleDomNode(widget,targetClass) {
|
||||
ZoominListView.prototype.insert = function(widget) {
|
||||
var targetElement = widget.findFirstDomNode();
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
return;
|
||||
}
|
||||
// Make the newly inserted node position absolute and hidden
|
||||
@@ -147,7 +147,7 @@ ZoominListView.prototype.remove = function(widget) {
|
||||
widget.removeChildDomNodes();
|
||||
};
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
removeElement();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ Syncer.prototype.titleIsAnonymous = "$:/status/IsAnonymous";
|
||||
Syncer.prototype.titleIsReadOnly = "$:/status/IsReadOnly";
|
||||
Syncer.prototype.titleUserName = "$:/status/UserName";
|
||||
Syncer.prototype.titleSyncFilter = "$:/config/SyncFilter";
|
||||
Syncer.prototype.titleSyncDisablePolling = "$:/config/SyncDisablePolling";
|
||||
Syncer.prototype.titleSyncPollingInterval = "$:/config/SyncPollingInterval";
|
||||
Syncer.prototype.titleSyncDisableLazyLoading = "$:/config/SyncDisableLazyLoading";
|
||||
Syncer.prototype.titleSavedNotification = "$:/language/Notifications/Save/Done";
|
||||
@@ -90,7 +89,7 @@ function Syncer(options) {
|
||||
if(filteredChanges.length > 0) {
|
||||
self.processTaskQueue();
|
||||
} else {
|
||||
// Look for deletions of tiddlers we're already syncing
|
||||
// Look for deletions of tiddlers we're already syncing
|
||||
var outstandingDeletion = false
|
||||
$tw.utils.each(changes,function(change,title,object) {
|
||||
if(change.deleted && $tw.utils.hop(self.tiddlerInfo,title)) {
|
||||
@@ -122,7 +121,7 @@ function Syncer(options) {
|
||||
self.login(username,password,function() {});
|
||||
} else {
|
||||
// No username and password, so we display a prompt
|
||||
self.handleLoginEvent();
|
||||
self.handleLoginEvent();
|
||||
}
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tm-logout",function() {
|
||||
@@ -131,6 +130,11 @@ 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());
|
||||
});
|
||||
@@ -139,7 +143,7 @@ function Syncer(options) {
|
||||
if(!this.disableUI && this.wiki.getTiddlerText(this.titleSyncDisableLazyLoading) !== "yes") {
|
||||
this.wiki.addEventListener("lazyLoad",function(title) {
|
||||
self.handleLazyLoadEvent(title);
|
||||
});
|
||||
});
|
||||
}
|
||||
// Get the login status
|
||||
this.getStatus(function(err,isLoggedIn) {
|
||||
@@ -174,8 +178,8 @@ Syncer.prototype.getTiddlerRevision = function(title) {
|
||||
if(this.syncadaptor && this.syncadaptor.getTiddlerRevision) {
|
||||
return this.syncadaptor.getTiddlerRevision(title);
|
||||
} else {
|
||||
return this.wiki.getTiddler(title).fields.revision;
|
||||
}
|
||||
return this.wiki.getTiddler(title).fields.revision;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -268,9 +272,9 @@ Syncer.prototype.getStatus = function(callback) {
|
||||
// Mark us as not logged in
|
||||
this.wiki.addTiddler({title: this.titleIsLoggedIn,text: "no"});
|
||||
// Get login status
|
||||
this.syncadaptor.getStatus(function(err,isLoggedIn,username,isReadOnly,isAnonymous,isPollingDisabled) {
|
||||
this.syncadaptor.getStatus(function(err,isLoggedIn,username,isReadOnly,isAnonymous) {
|
||||
if(err) {
|
||||
self.logger.alert(err);
|
||||
self.displayError("Get Status Error",err);
|
||||
} else {
|
||||
// Set the various status tiddlers
|
||||
self.wiki.addTiddler({title: self.titleIsReadOnly,text: isReadOnly ? "yes" : "no"});
|
||||
@@ -279,9 +283,6 @@ Syncer.prototype.getStatus = function(callback) {
|
||||
if(isLoggedIn) {
|
||||
self.wiki.addTiddler({title: self.titleUserName,text: username || ""});
|
||||
}
|
||||
if(isPollingDisabled) {
|
||||
self.wiki.addTiddler({title: self.titleSyncDisablePolling, text: "yes"});
|
||||
}
|
||||
}
|
||||
// Invoke the callback
|
||||
if(callback) {
|
||||
@@ -305,15 +306,12 @@ Syncer.prototype.syncFromServer = function() {
|
||||
}
|
||||
},
|
||||
triggerNextSync = function() {
|
||||
if(pollingEnabled) {
|
||||
self.pollTimerId = setTimeout(function() {
|
||||
self.pollTimerId = null;
|
||||
self.syncFromServer.call(self);
|
||||
},self.pollTimerInterval);
|
||||
}
|
||||
self.pollTimerId = setTimeout(function() {
|
||||
self.pollTimerId = null;
|
||||
self.syncFromServer.call(self);
|
||||
},self.pollTimerInterval);
|
||||
},
|
||||
syncSystemFromServer = (self.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "yes"),
|
||||
pollingEnabled = (self.wiki.getTiddlerText(self.titleSyncDisablePolling) !== "yes");
|
||||
syncSystemFromServer = (self.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "yes" ? true : false);
|
||||
if(this.syncadaptor && this.syncadaptor.getUpdatedTiddlers) {
|
||||
this.logger.log("Retrieving updated tiddler list");
|
||||
cancelNextSync();
|
||||
@@ -336,7 +334,7 @@ Syncer.prototype.syncFromServer = function() {
|
||||
});
|
||||
if(updates.modifications.length > 0 || updates.deletions.length > 0) {
|
||||
self.processTaskQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if(this.syncadaptor && this.syncadaptor.getSkinnyTiddlers) {
|
||||
@@ -479,7 +477,7 @@ Syncer.prototype.handleLogoutEvent = function() {
|
||||
if(this.syncadaptor.logout) {
|
||||
this.syncadaptor.logout(function(err) {
|
||||
if(err) {
|
||||
self.logger.alert(err);
|
||||
self.displayError("Logout Error",err);
|
||||
} else {
|
||||
self.getStatus();
|
||||
}
|
||||
@@ -516,7 +514,7 @@ Syncer.prototype.processTaskQueue = function() {
|
||||
} else {
|
||||
self.updateDirtyStatus();
|
||||
// Process the next task
|
||||
self.processTaskQueue.call(self);
|
||||
self.processTaskQueue.call(self);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -524,11 +522,11 @@ Syncer.prototype.processTaskQueue = function() {
|
||||
this.updateDirtyStatus();
|
||||
// And trigger a timeout if there is a pending task
|
||||
if(task === true) {
|
||||
this.triggerTimeout();
|
||||
this.triggerTimeout();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.updateDirtyStatus();
|
||||
this.updateDirtyStatus();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -562,7 +560,7 @@ Syncer.prototype.chooseNextTask = function() {
|
||||
isReadyToSave = !tiddlerInfo || !tiddlerInfo.timestampLastSaved || tiddlerInfo.timestampLastSaved < thresholdLastSaved;
|
||||
if(hasChanged) {
|
||||
if(isReadyToSave) {
|
||||
return new SaveTiddlerTask(this,title);
|
||||
return new SaveTiddlerTask(this,title);
|
||||
} else {
|
||||
havePending = true;
|
||||
}
|
||||
@@ -601,10 +599,7 @@ SaveTiddlerTask.prototype.run = function(callback) {
|
||||
tiddler = this.syncer.wiki.tiddlerExists(this.title) && this.syncer.wiki.getTiddler(this.title);
|
||||
this.syncer.logger.log("Dispatching 'save' task:",this.title);
|
||||
if(tiddler) {
|
||||
this.syncer.syncadaptor.saveTiddler(tiddler,{
|
||||
changeCount: changeCount,
|
||||
tiddlerInfo: self.syncer.tiddlerInfo[self.title]
|
||||
},function(err,adaptorInfo,revision) {
|
||||
this.syncer.syncadaptor.saveTiddler(tiddler,function(err,adaptorInfo,revision) {
|
||||
// If there's an error, exit without changing any internal state
|
||||
if(err) {
|
||||
return callback(err);
|
||||
@@ -618,6 +613,8 @@ SaveTiddlerTask.prototype.run = function(callback) {
|
||||
};
|
||||
// Invoke the callback
|
||||
callback(null);
|
||||
},{
|
||||
tiddlerInfo: self.syncer.tiddlerInfo[self.title]
|
||||
});
|
||||
} else {
|
||||
this.syncer.logger.log(" Not Dispatching 'save' task:",this.title,"tiddler does not exist");
|
||||
@@ -634,9 +631,7 @@ function DeleteTiddlerTask(syncer,title) {
|
||||
DeleteTiddlerTask.prototype.run = function(callback) {
|
||||
var self = this;
|
||||
this.syncer.logger.log("Dispatching 'delete' task:",this.title);
|
||||
this.syncer.syncadaptor.deleteTiddler(this.title,{
|
||||
tiddlerInfo: self.syncer.tiddlerInfo[this.title]
|
||||
},function(err,adaptorInfo) {
|
||||
this.syncer.syncadaptor.deleteTiddler(this.title,function(err) {
|
||||
// If there's an error, exit without changing any internal state
|
||||
if(err) {
|
||||
return callback(err);
|
||||
@@ -645,6 +640,8 @@ DeleteTiddlerTask.prototype.run = function(callback) {
|
||||
delete self.syncer.tiddlerInfo[self.title];
|
||||
// Invoke the callback
|
||||
callback(null);
|
||||
},{
|
||||
tiddlerInfo: self.syncer.tiddlerInfo[this.title]
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ Browser data transfer utilities, used with the clipboard and drag and drop
|
||||
Options:
|
||||
|
||||
domNode: dom node to make draggable
|
||||
dragImageType: "pill" or "dom"
|
||||
dragImageType: "pill", "blank" or "dom" (the default)
|
||||
dragTiddlerFn: optional function to retrieve the title of tiddler to drag
|
||||
dragFilterFn: optional function to retreive the filter defining a list of tiddlers to drag
|
||||
widget: widget to use as the contect for the filter
|
||||
@@ -73,6 +73,9 @@ exports.makeDraggable = function(options) {
|
||||
if(dataTransfer.setDragImage) {
|
||||
if(dragImageType === "pill") {
|
||||
dataTransfer.setDragImage(dragImage.firstChild,-16,-16);
|
||||
} else if (dragImageType === "blank") {
|
||||
dragImage.removeChild(dragImage.firstChild);
|
||||
dataTransfer.setDragImage(dragImage,0,0);
|
||||
} else {
|
||||
var r = domNode.getBoundingClientRect();
|
||||
dataTransfer.setDragImage(domNode,event.clientX-r.left,event.clientY-r.top);
|
||||
@@ -164,7 +167,7 @@ var importDataTypes = [
|
||||
}},
|
||||
{type: "URL", IECompatible: true, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
||||
// Check for tiddler data URI
|
||||
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
var match = $tw.utils.decodeURIComponentSafe(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
if(match) {
|
||||
return parseJSONTiddlers(match[1],fallbackTitle);
|
||||
} else {
|
||||
@@ -173,7 +176,7 @@ var importDataTypes = [
|
||||
}},
|
||||
{type: "text/x-moz-url", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
||||
// Check for tiddler data URI
|
||||
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
var match = $tw.utils.decodeURIComponentSafe(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
if(match) {
|
||||
return parseJSONTiddlers(match[1],fallbackTitle);
|
||||
} else {
|
||||
|
||||
@@ -34,6 +34,23 @@ exports.httpRequest = function(options) {
|
||||
});
|
||||
return result;
|
||||
},
|
||||
getHeader = function(targetHeader) {
|
||||
return headers[targetHeader] || headers[targetHeader.toLowerCase()];
|
||||
},
|
||||
isSimpleRequest = function(type,headers) {
|
||||
if(["GET","HEAD","POST"].indexOf(type) === -1) {
|
||||
return false;
|
||||
}
|
||||
for(var header in headers) {
|
||||
if(["accept","accept-language","content-language","content-type"].indexOf(header.toLowerCase()) === -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(hasHeader("Content-Type") && ["application/x-www-form-urlencoded","multipart/form-data","text/plain"].indexOf(getHeader["Content-Type"]) === -1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
returnProp = options.returnProp || "responseText",
|
||||
request = new XMLHttpRequest(),
|
||||
data = "",
|
||||
@@ -76,7 +93,7 @@ exports.httpRequest = function(options) {
|
||||
if(data && !hasHeader("Content-Type")) {
|
||||
request.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
|
||||
}
|
||||
if(!hasHeader("X-Requested-With")) {
|
||||
if(!hasHeader("X-Requested-With") && !isSimpleRequest(type,headers)) {
|
||||
request.setRequestHeader("X-Requested-With","TiddlyWiki");
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -243,6 +243,7 @@ Modal.prototype.adjustPageClass = function() {
|
||||
if(windowContainer) {
|
||||
$tw.utils.toggleClass(windowContainer,"tc-modal-displayed",this.modalCount > 0);
|
||||
}
|
||||
$tw.utils.toggleClass(this.srcDocument.body,"tc-modal-prevent-scroll",this.modalCount > 0);
|
||||
};
|
||||
|
||||
exports.Modal = Modal;
|
||||
|
||||
@@ -235,7 +235,7 @@ Object.defineProperty(TW_Element.prototype, "innerHTML", {
|
||||
if(node instanceof TW_Element) {
|
||||
b.push(node.outerHTML);
|
||||
} else if(node instanceof TW_TextNode) {
|
||||
b.push($tw.utils.htmlEncode(node.textContent));
|
||||
b.push($tw.utils.htmlTextEncode(node.textContent));
|
||||
}
|
||||
});
|
||||
return b.join("");
|
||||
|
||||
@@ -228,6 +228,7 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
|
||||
hasUnsafeFields = hasUnsafeFields || /[\x00-\x1F]/mg.test(value);
|
||||
hasUnsafeFields = hasUnsafeFields || ($tw.utils.trim(value) !== value);
|
||||
}
|
||||
hasUnsafeFields = hasUnsafeFields || /:/mg.test(fieldName);
|
||||
});
|
||||
// Check for field values
|
||||
if(hasUnsafeFields) {
|
||||
|
||||
@@ -95,6 +95,15 @@ LinkedList.prototype.toArray = function() {
|
||||
return output;
|
||||
};
|
||||
|
||||
LinkedList.prototype.makeTiddlerIterator = function(wiki) {
|
||||
var self = this;
|
||||
return function(callback) {
|
||||
self.each(function(title) {
|
||||
callback(wiki.getTiddler(title),title);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
function _removeOne(list,value) {
|
||||
var prevEntry = list.prev[value],
|
||||
nextEntry = list.next[value],
|
||||
|
||||
@@ -199,6 +199,8 @@ exports.transliterationPairs = {
|
||||
"Nj":"N",
|
||||
"Ñ":"N",
|
||||
"NJ":"NJ",
|
||||
"ð":"d",
|
||||
"Ð":"D",
|
||||
"Ó":"O",
|
||||
"Ŏ":"O",
|
||||
"Ǒ":"O",
|
||||
@@ -265,6 +267,8 @@ exports.transliterationPairs = {
|
||||
"Ɽ":"R",
|
||||
"Ꜿ":"C",
|
||||
"Ǝ":"E",
|
||||
"ß":"ss",
|
||||
"ẞ":"SS",
|
||||
"Ś":"S",
|
||||
"Ṥ":"S",
|
||||
"Š":"S",
|
||||
@@ -275,6 +279,8 @@ exports.transliterationPairs = {
|
||||
"Ṡ":"S",
|
||||
"Ṣ":"S",
|
||||
"Ṩ":"S",
|
||||
"þ": "th",
|
||||
"Þ": "TH",
|
||||
"Ť":"T",
|
||||
"Ţ":"T",
|
||||
"Ṱ":"T",
|
||||
@@ -907,7 +913,8 @@ exports.transliterationPairs = {
|
||||
"т":"t",
|
||||
"ь":"'",
|
||||
"б":"b",
|
||||
"ю":"yu"
|
||||
"ю":"yu",
|
||||
"…":"..."
|
||||
};
|
||||
|
||||
exports.transliterate = function(str) {
|
||||
|
||||
@@ -223,6 +223,7 @@ exports.removeArrayEntries = function(array,value) {
|
||||
array.splice(p,1);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -382,6 +383,15 @@ exports.formatDateString = function(date,template) {
|
||||
[/^0WW/, function() {
|
||||
return $tw.utils.pad($tw.utils.getWeek(date));
|
||||
}],
|
||||
[/^0ddddd/, function() {
|
||||
return $tw.utils.pad(Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24),3);
|
||||
}],
|
||||
[/^ddddd/, function() {
|
||||
return Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24);
|
||||
}],
|
||||
[/^dddd/, function() {
|
||||
return [7,1,2,3,4,5,6][date.getDay()];
|
||||
}],
|
||||
[/^ddd/, function() {
|
||||
return $tw.language.getString("Date/Short/Day/" + date.getDay());
|
||||
}],
|
||||
@@ -740,9 +750,8 @@ exports.isValidFieldName = function(name) {
|
||||
if(!name || typeof name !== "string") {
|
||||
return false;
|
||||
}
|
||||
name = name.toLowerCase().trim();
|
||||
var fieldValidatorRegEx = /^[a-z0-9\-\._]+$/mg;
|
||||
return fieldValidatorRegEx.test(name);
|
||||
// Since v5.2.x, there are no restrictions on characters in field names
|
||||
return name;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -58,9 +58,10 @@ Invoke the action associated with this widget
|
||||
*/
|
||||
ConfirmWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
var invokeActions = true,
|
||||
handled = true;
|
||||
handled = true,
|
||||
win = event && event.event && event.event.view ? event.event.view : window;
|
||||
if(this.prompt) {
|
||||
invokeActions = confirm(this.message);
|
||||
invokeActions = win.confirm(this.message);
|
||||
}
|
||||
if(invokeActions) {
|
||||
handled = this.invokeActions(triggeringWidget,event);
|
||||
@@ -74,4 +75,4 @@ ConfirmWidget.prototype.allowActionPropagation = function() {
|
||||
|
||||
exports["action-confirm"] = ConfirmWidget;
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -27,8 +27,11 @@ CreateTiddlerWidget.prototype = new Widget();
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
CreateTiddlerWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
// Render children
|
||||
this.renderChildren(parent,nextSibling);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -44,7 +47,8 @@ CreateTiddlerWidget.prototype.execute = function() {
|
||||
this.actionTemplate = this.getAttribute("$template");
|
||||
this.useTemplate = !!this.actionTemplate;
|
||||
this.actionOverwrite = this.getAttribute("$overwrite","no");
|
||||
|
||||
// Construct the child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -86,18 +90,21 @@ CreateTiddlerWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
if (!this.hasBase && this.useTemplate) {
|
||||
title = this.wiki.generateNewTitle(this.actionTemplate);
|
||||
} else if (!this.hasBase && !this.useTemplate) {
|
||||
// If NO $basetitle AND NO $template use initial title
|
||||
// DON'T overwrite any stuff
|
||||
// If no $basetitle and no $template then use initial title
|
||||
title = this.wiki.generateNewTitle(title);
|
||||
}
|
||||
var templateTiddler = this.wiki.getTiddler(this.actionTemplate) || {};
|
||||
var tiddler = this.wiki.addTiddler(new $tw.Tiddler(templateTiddler.fields,creationFields,fields,modificationFields,{title: title}));
|
||||
this.wiki.addTiddler(new $tw.Tiddler(templateTiddler.fields,creationFields,fields,modificationFields,{title: title}));
|
||||
var draftTitle = this.wiki.generateDraftTitle(title);
|
||||
if(this.actionSaveTitle) {
|
||||
this.wiki.setTextReference(this.actionSaveTitle,title,this.getVariable("currentTiddler"));
|
||||
}
|
||||
if(this.actionSaveDraftTitle) {
|
||||
this.wiki.setTextReference(this.actionSaveDraftTitle,this.wiki.generateDraftTitle(title),this.getVariable("currentTiddler"));
|
||||
this.wiki.setTextReference(this.actionSaveDraftTitle,draftTitle,this.getVariable("currentTiddler"));
|
||||
}
|
||||
this.setVariable("createTiddler-title",title);
|
||||
this.setVariable("createTiddler-draftTitle",draftTitle);
|
||||
this.refreshChildren();
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
|
||||
@@ -70,7 +70,18 @@ NavigateWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
navigateFromNode: triggeringWidget,
|
||||
navigateFromClientRect: bounds && { top: bounds.top, left: bounds.left, width: bounds.width, right: bounds.right, bottom: bounds.bottom, height: bounds.height
|
||||
},
|
||||
navigateSuppressNavigation: suppressNavigation
|
||||
navigateFromClientTop: bounds && bounds.top,
|
||||
navigateFromClientLeft: bounds && bounds.left,
|
||||
navigateFromClientWidth: bounds && bounds.width,
|
||||
navigateFromClientRight: bounds && bounds.right,
|
||||
navigateFromClientBottom: bounds && bounds.bottom,
|
||||
navigateFromClientHeight: bounds && bounds.height,
|
||||
navigateSuppressNavigation: suppressNavigation,
|
||||
metaKey: event.metaKey,
|
||||
ctrlKey: event.ctrlKey,
|
||||
altKey: event.altKey,
|
||||
shiftKey: event.shiftKey,
|
||||
event: event
|
||||
});
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
@@ -39,6 +39,8 @@ SendMessageWidget.prototype.execute = function() {
|
||||
this.actionParam = this.getAttribute("$param");
|
||||
this.actionName = this.getAttribute("$name");
|
||||
this.actionValue = this.getAttribute("$value","");
|
||||
this.actionNames = this.getAttribute("$names");
|
||||
this.actionValues = this.getAttribute("$values");
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -59,13 +61,20 @@ Invoke the action associated with this widget
|
||||
SendMessageWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
// Get the string parameter
|
||||
var param = this.actionParam;
|
||||
// Assemble the attributes as a hashmap
|
||||
// Assemble the parameters as a hashmap
|
||||
var paramObject = Object.create(null);
|
||||
var count = 0;
|
||||
// Add names/values pairs if present
|
||||
if(this.actionNames && this.actionValues) {
|
||||
var names = this.wiki.filterTiddlers(this.actionNames,this),
|
||||
values = this.wiki.filterTiddlers(this.actionValues,this);
|
||||
$tw.utils.each(names,function(name,index) {
|
||||
paramObject[name] = values[index] || "";
|
||||
});
|
||||
}
|
||||
// Add raw parameters
|
||||
$tw.utils.each(this.attributes,function(attribute,name) {
|
||||
if(name.charAt(0) !== "$") {
|
||||
paramObject[name] = attribute;
|
||||
count++;
|
||||
}
|
||||
});
|
||||
// Add name/value pair if present
|
||||
@@ -73,14 +82,15 @@ SendMessageWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
paramObject[this.actionName] = this.actionValue;
|
||||
}
|
||||
// Dispatch the message
|
||||
this.dispatchEvent({
|
||||
var params = {
|
||||
type: this.actionMessage,
|
||||
param: param,
|
||||
paramObject: paramObject,
|
||||
tiddlerTitle: this.getVariable("currentTiddler"),
|
||||
navigateFromTitle: this.getVariable("storyTiddler"),
|
||||
event: event
|
||||
});
|
||||
event: event,
|
||||
currentTiddler: this.getVariable("currentTiddler"),
|
||||
navigateFromTitle: this.getVariable("storyTiddler")
|
||||
};
|
||||
this.dispatchEvent(params);
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
|
||||
86
core/modules/widgets/action-setmultiplefields.js
Normal file
86
core/modules/widgets/action-setmultiplefields.js
Normal file
@@ -0,0 +1,86 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/action-setmultiplefields.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Action widget to set multiple fields or indexes on a tiddler
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var SetMultipleFieldsWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
SetMultipleFieldsWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
SetMultipleFieldsWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
SetMultipleFieldsWidget.prototype.execute = function() {
|
||||
this.actionTiddler = this.getAttribute("$tiddler",this.getVariable("currentTiddler"));
|
||||
this.actionFields = this.getAttribute("$fields");
|
||||
this.actionIndexes = this.getAttribute("$indexes");
|
||||
this.actionValues = this.getAttribute("$values");
|
||||
this.actionTimestamp = this.getAttribute("$timestamp","yes") === "yes";
|
||||
};
|
||||
|
||||
/*
|
||||
Refresh the widget by ensuring our attributes are up to date
|
||||
*/
|
||||
SetMultipleFieldsWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes["$tiddler"] || changedAttributes["$fields"] || changedAttributes["$indexes"] || changedAttributes["$values"] || changedAttributes["$timestamp"]) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
/*
|
||||
Invoke the action associated with this widget
|
||||
*/
|
||||
SetMultipleFieldsWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
var tiddler = this.wiki.getTiddler(this.actionTiddler),
|
||||
names, values = this.wiki.filterTiddlers(this.actionValues,this);
|
||||
if(this.actionFields) {
|
||||
var additions = {};
|
||||
names = this.wiki.filterTiddlers(this.actionFields,this);
|
||||
$tw.utils.each(names,function(fieldname,index) {
|
||||
additions[fieldname] = values[index] || "";
|
||||
});
|
||||
var creationFields = this.actionTimestamp ? this.wiki.getCreationFields() : undefined,
|
||||
modificationFields = this.actionTimestamp ? this.wiki.getModificationFields() : undefined;
|
||||
this.wiki.addTiddler(new $tw.Tiddler(creationFields,tiddler,{title: this.actionTiddler},modificationFields,additions));
|
||||
} else if(this.actionIndexes) {
|
||||
var data = this.wiki.getTiddlerData(this.actionTiddler,Object.create(null));
|
||||
names = this.wiki.filterTiddlers(this.actionIndexes,this);
|
||||
$tw.utils.each(names,function(name,index) {
|
||||
data[name] = values[index] || "";
|
||||
});
|
||||
this.wiki.setTiddlerData(this.actionTiddler,data,{},{suppressTimestamp: !this.actionTimestamp});
|
||||
}
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
exports["action-setmultiplefields"] = SetMultipleFieldsWidget;
|
||||
|
||||
})();
|
||||
|
||||
@@ -54,6 +54,7 @@ DraggableWidget.prototype.render = function(parent,nextSibling) {
|
||||
dragFilterFn: function() {return self.getAttribute("filter");},
|
||||
startActions: self.startActions,
|
||||
endActions: self.endActions,
|
||||
dragImageType: self.dragImageType,
|
||||
widget: this
|
||||
});
|
||||
// Insert the link into the DOM and render any children
|
||||
@@ -71,6 +72,7 @@ DraggableWidget.prototype.execute = function() {
|
||||
this.draggableClasses = this.getAttribute("class");
|
||||
this.startActions = this.getAttribute("startactions");
|
||||
this.endActions = this.getAttribute("endactions");
|
||||
this.dragImageType = this.getAttribute("dragimagetype");
|
||||
// Make the child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
@@ -46,7 +46,7 @@ EventWidget.prototype.render = function(parent,nextSibling) {
|
||||
$tw.utils.each(this.types,function(type) {
|
||||
domNode.addEventListener(type,function(event) {
|
||||
var selector = self.getAttribute("selector"),
|
||||
actions = self.getAttribute("actions-"+type),
|
||||
actions = self.getAttribute("$"+type) || self.getAttribute("actions-"+type),
|
||||
stopPropagation = self.getAttribute("stopPropagation","onaction"),
|
||||
selectedNode = event.target,
|
||||
selectedNodeRect,
|
||||
@@ -76,16 +76,22 @@ EventWidget.prototype.render = function(parent,nextSibling) {
|
||||
variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString();
|
||||
variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString();
|
||||
variables["tv-selectednode-height"] = selectedNode.offsetHeight.toString();
|
||||
|
||||
if(event.clientX && event.clientY) {
|
||||
//Add variables for event X and Y position relative to selected node
|
||||
selectedNodeRect = selectedNode.getBoundingClientRect();
|
||||
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
|
||||
variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();
|
||||
|
||||
//Add variables for event X and Y position relative to selected node
|
||||
selectedNodeRect = selectedNode.getBoundingClientRect();
|
||||
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
|
||||
variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();
|
||||
//Add variables for event X and Y position relative to event catcher node
|
||||
catcherNodeRect = self.domNode.getBoundingClientRect();
|
||||
variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
|
||||
variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
|
||||
|
||||
//Add variables for event X and Y position relative to event catcher node
|
||||
catcherNodeRect = self.domNode.getBoundingClientRect();
|
||||
variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
|
||||
variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
|
||||
//Add variables for event X and Y position relative to the viewport
|
||||
variables["event-fromviewport-posx"] = event.clientX.toString();
|
||||
variables["event-fromviewport-posy"] = event.clientY.toString();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
@@ -135,7 +141,15 @@ Compute the internal state of the widget
|
||||
EventWidget.prototype.execute = function() {
|
||||
var self = this;
|
||||
// Get attributes that require a refresh on change
|
||||
this.types = this.getAttribute("events","").split(" ");
|
||||
this.types = [];
|
||||
$tw.utils.each(this.attributes,function(value,key) {
|
||||
if(key.charAt(0) === "$") {
|
||||
self.types.push(key.slice(1));
|
||||
}
|
||||
});
|
||||
if(!this.types.length) {
|
||||
this.types = this.getAttribute("events","").split(" ");
|
||||
}
|
||||
this.elementTag = this.getAttribute("tag");
|
||||
// Make child widgets
|
||||
this.makeChildWidgets();
|
||||
@@ -151,12 +165,13 @@ EventWidget.prototype.assignDomNodeClasses = function() {
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
EventWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes["events"] || changedAttributes["tag"]) {
|
||||
var changedAttributes = this.computeAttributes(),
|
||||
changedAttributesCount = $tw.utils.count(changedAttributes);
|
||||
if(changedAttributesCount === 1 && changedAttributes["class"]) {
|
||||
this.assignDomNodeClasses();
|
||||
} else if(changedAttributesCount > 0) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else if(changedAttributes["class"]) {
|
||||
this.assignDomNodeClasses();
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
@@ -73,26 +73,12 @@ FieldManglerWidget.prototype.handleRemoveFieldEvent = function(event) {
|
||||
FieldManglerWidget.prototype.handleAddFieldEvent = function(event) {
|
||||
var tiddler = this.wiki.getTiddler(this.mangleTitle),
|
||||
addition = this.wiki.getModificationFields(),
|
||||
hadInvalidFieldName = false,
|
||||
addField = function(name,value) {
|
||||
var trimmedName = name.toLowerCase().trim();
|
||||
if(!$tw.utils.isValidFieldName(trimmedName)) {
|
||||
if(!hadInvalidFieldName) {
|
||||
alert($tw.language.getString(
|
||||
"InvalidFieldName",
|
||||
{variables:
|
||||
{fieldName: trimmedName}
|
||||
}
|
||||
));
|
||||
hadInvalidFieldName = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if(!value && tiddler) {
|
||||
value = tiddler.fields[trimmedName];
|
||||
}
|
||||
addition[trimmedName] = value || "";
|
||||
var trimmedName = name.trim();
|
||||
if(!value && tiddler) {
|
||||
value = tiddler.fields[trimmedName];
|
||||
}
|
||||
addition[trimmedName] = value || "";
|
||||
return;
|
||||
};
|
||||
addition.title = this.mangleTitle;
|
||||
|
||||
91
core/modules/widgets/jsontiddler.js
Normal file
91
core/modules/widgets/jsontiddler.js
Normal file
@@ -0,0 +1,91 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/jsontiddler.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Render a tiddler as JSON text
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var JSONTiddlerWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
JSONTiddlerWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
JSONTiddlerWidget.prototype.render = function(parent,nextSibling) {
|
||||
var self = this;
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
// Collect the fields from the optional base tiddler
|
||||
var fields = this.getTiddlerFields();
|
||||
// Add custom fields specified in attributes starting with $
|
||||
$tw.utils.each(this.attributes,function(attribute,name) {
|
||||
if(name.charAt(0) === "$") {
|
||||
fields[name.slice(1)] = attribute;
|
||||
}
|
||||
});
|
||||
// JSONify
|
||||
var json = JSON.stringify(fields);
|
||||
// Escape unsafe script characters
|
||||
if(this.attEscapeUnsafeScriptChars) {
|
||||
json = json.replace(/</g,"\\u003C");
|
||||
}
|
||||
// Update the DOM
|
||||
var textNode = this.document.createTextNode(json);
|
||||
parent.insertBefore(textNode,nextSibling);
|
||||
this.domNodes.push(textNode);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
JSONTiddlerWidget.prototype.execute = function() {
|
||||
this.attTiddler = this.getAttribute("tiddler");
|
||||
this.attExclude = this.getAttribute("exclude","");
|
||||
this.attEscapeUnsafeScriptChars = this.getAttribute("escapeUnsafeScriptChars","no") === "yes";
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
JSONTiddlerWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if($tw.utils.count(changedAttributes) > 0 || (this.attTiddler && changedTiddlers[this.attTiddler])) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
JSONTiddlerWidget.prototype.getTiddlerFields = function() {
|
||||
var fields = {};
|
||||
if(this.attTiddler) {
|
||||
var tiddler = this.wiki.getTiddler(this.attTiddler);
|
||||
if(tiddler) {
|
||||
fields = tiddler.getFieldStrings({exclude: this.attExclude.split(" ")});
|
||||
} else {
|
||||
fields = {title: this.attTiddler};
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
};
|
||||
|
||||
exports.jsontiddler = JSONTiddlerWidget;
|
||||
|
||||
})();
|
||||
@@ -40,9 +40,8 @@ KeyboardWidget.prototype.render = function(parent,nextSibling) {
|
||||
// Create element
|
||||
var domNode = this.document.createElement(tag);
|
||||
// Assign classes
|
||||
var classes = (this["class"] || "").split(" ");
|
||||
classes.push("tc-keyboard");
|
||||
domNode.className = classes.join(" ");
|
||||
this.domNode = domNode;
|
||||
this.assignDomNodeClasses();
|
||||
// Add a keyboard event handler
|
||||
$tw.utils.addEventListeners(domNode,[
|
||||
{name: "keydown", handlerObject: this, handlerMethod: "handleChangeEvent"}
|
||||
@@ -54,7 +53,8 @@ KeyboardWidget.prototype.render = function(parent,nextSibling) {
|
||||
};
|
||||
|
||||
KeyboardWidget.prototype.handleChangeEvent = function(event) {
|
||||
if($tw.keyboardManager.checkKeyDescriptors(event,this.keyInfoArray)) {
|
||||
var keyInfo = $tw.keyboardManager.getMatchingKeyDescriptor(event,this.keyInfoArray);
|
||||
if(keyInfo) {
|
||||
var handled = this.invokeActions(this,event);
|
||||
if(this.actions) {
|
||||
var variables = {
|
||||
@@ -62,6 +62,9 @@ KeyboardWidget.prototype.handleChangeEvent = function(event) {
|
||||
"event-code": event.code,
|
||||
"modifier": $tw.keyboardManager.getEventModifierKeyDescriptor(event)
|
||||
};
|
||||
if(keyInfo.keyDescriptor) {
|
||||
variables["event-key-descriptor"] = keyInfo.keyDescriptor;
|
||||
}
|
||||
this.invokeActionString(this.actions,this,event,variables);
|
||||
}
|
||||
this.dispatchMessage(event);
|
||||
@@ -90,7 +93,6 @@ KeyboardWidget.prototype.execute = function() {
|
||||
this.key = this.getAttribute("key","");
|
||||
this.tag = this.getAttribute("tag","");
|
||||
this.keyInfoArray = $tw.keyboardManager.parseKeyDescriptors(this.key);
|
||||
this["class"] = this.getAttribute("class","");
|
||||
if(this.key.substr(0,2) === "((" && this.key.substr(-2,2) === "))") {
|
||||
this.shortcutTiddlers = [];
|
||||
var name = this.key.substring(2,this.key.length -2);
|
||||
@@ -102,14 +104,22 @@ KeyboardWidget.prototype.execute = function() {
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
KeyboardWidget.prototype.assignDomNodeClasses = function() {
|
||||
var classes = this.getAttribute("class","").split(" ");
|
||||
classes.push("tc-keyboard");
|
||||
this.domNode.className = classes.join(" ");
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
KeyboardWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.message || changedAttributes.param || changedAttributes.key || changedAttributes["class"] || changedAttributes.tag) {
|
||||
if(changedAttributes.message || changedAttributes.param || changedAttributes.key || changedAttributes.tag) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else if(changedAttributes["class"]) {
|
||||
this.assignDomNodeClasses();
|
||||
}
|
||||
// Update the keyInfoArray if one of its shortcut-config-tiddlers has changed
|
||||
if(this.shortcutTiddlers && $tw.utils.hopArray(changedTiddlers,this.shortcutTiddlers)) {
|
||||
|
||||
@@ -154,6 +154,12 @@ LinkWidget.prototype.handleClickEvent = function(event) {
|
||||
navigateFromNode: this,
|
||||
navigateFromClientRect: { top: bounds.top, left: bounds.left, width: bounds.width, right: bounds.right, bottom: bounds.bottom, height: bounds.height
|
||||
},
|
||||
navigateFromClientTop: bounds.top,
|
||||
navigateFromClientLeft: bounds.left,
|
||||
navigateFromClientWidth: bounds.width,
|
||||
navigateFromClientRight: bounds.right,
|
||||
navigateFromClientBottom: bounds.bottom,
|
||||
navigateFromClientHeight: bounds.height,
|
||||
navigateSuppressNavigation: event.metaKey || event.ctrlKey || (event.button === 1),
|
||||
metaKey: event.metaKey,
|
||||
ctrlKey: event.ctrlKey,
|
||||
@@ -201,7 +207,8 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
LinkWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.to || changedTiddlers[this.to] || changedAttributes["aria-label"] || changedAttributes.tooltip) {
|
||||
if(changedAttributes.to || changedTiddlers[this.to] || changedAttributes["aria-label"] || changedAttributes.tooltip ||
|
||||
changedAttributes["class"] || changedAttributes.tabindex || changedAttributes.draggable || changedAttributes.tag) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -236,6 +236,11 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
|
||||
hasRefreshed = hasRefreshed || refreshed;
|
||||
}
|
||||
}
|
||||
// If there are items to remove and we have not refreshed then recreate the item that will now be at the last position
|
||||
if(!hasRefreshed && this.children.length > this.list.length) {
|
||||
this.removeListItem(this.list.length-1);
|
||||
this.insertListItem(this.list.length-1,this.list[this.list.length-1]);
|
||||
}
|
||||
} else {
|
||||
// Cycle through the list, inserting and removing list items as needed
|
||||
for(t=0; t<this.list.length; t++) {
|
||||
|
||||
@@ -33,12 +33,54 @@ MessageCatcherWidget.prototype.render = function(parent,nextSibling) {
|
||||
// Compute attributes and execute state
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
// Add our message handler
|
||||
if(this.messageType) {
|
||||
this.addEventListeners([
|
||||
{type: this.messageType, handler: "handleEvent"}
|
||||
]);
|
||||
// Helper to add an event handler
|
||||
var addEventHandler = function(type,actions) {
|
||||
if(type && actions) {
|
||||
var isActionStringExecuting = false;
|
||||
self.addEventListener(
|
||||
type,
|
||||
function(event) {
|
||||
// Don't trap the event if it came from one of our action handlers
|
||||
if(isActionStringExecuting) {
|
||||
return true;
|
||||
}
|
||||
// Collect all the event properties into variables
|
||||
var collectProps = function(obj,prefix) {
|
||||
prefix = prefix || "";
|
||||
var props = {},
|
||||
names = [];
|
||||
$tw.utils.each(obj,function(value,name) {
|
||||
if(["string","boolean","number"].indexOf(typeof value) !== -1) {
|
||||
names.push(name);
|
||||
props[prefix + "-" + name] = value.toString();
|
||||
}
|
||||
});
|
||||
props["list-" + prefix] = $tw.utils.stringifyList(names);
|
||||
return props;
|
||||
};
|
||||
var variables = $tw.utils.extend(
|
||||
{},
|
||||
collectProps(event.paramObject,"event-paramObject"),
|
||||
collectProps(event,"event"),
|
||||
{
|
||||
modifier: $tw.keyboardManager.getEventModifierKeyDescriptor(event)
|
||||
});
|
||||
isActionStringExecuting = true;
|
||||
self.invokeActionString(actions,self,event,variables);
|
||||
isActionStringExecuting = false;
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
// Add the main event handler
|
||||
addEventHandler(this.getAttribute("type"),this.getAttribute("actions"));
|
||||
// Add any other event handlers
|
||||
$tw.utils.each(this.attributes,function(value,key) {
|
||||
if(key.charAt(0) === "$") {
|
||||
addEventHandler(key.slice(1),value);
|
||||
}
|
||||
});
|
||||
// Render children
|
||||
this.renderChildren(parent,null);
|
||||
};
|
||||
@@ -47,48 +89,16 @@ MessageCatcherWidget.prototype.render = function(parent,nextSibling) {
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
MessageCatcherWidget.prototype.execute = function() {
|
||||
var self = this;
|
||||
// Get attributes that require a refresh on change
|
||||
this.messageType = this.getAttribute("type");
|
||||
this.messageActions = this.getAttribute("actions");
|
||||
// Make child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
/*
|
||||
Handle an event
|
||||
*/
|
||||
MessageCatcherWidget.prototype.handleEvent = function(event) {
|
||||
if(this.messageActions) {
|
||||
// Collect all the event properties into variables
|
||||
var collectProps = function(obj,prefix) {
|
||||
prefix = prefix || "";
|
||||
var props = {};
|
||||
$tw.utils.each(obj,function(value,name) {
|
||||
if(["string","boolean","number"].indexOf(typeof value) !== -1) {
|
||||
props[prefix + name] = value.toString();
|
||||
}
|
||||
});
|
||||
return props;
|
||||
};
|
||||
var variables = $tw.utils.extend(
|
||||
{},
|
||||
collectProps(event.paramObject,"event-paramObject-"),
|
||||
collectProps(event,"event-"),
|
||||
{
|
||||
modifier: $tw.keyboardManager.getEventModifierKeyDescriptor(event)
|
||||
});
|
||||
this.invokeActionString(this.messageActions,this,event,variables);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
MessageCatcherWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes["type"]) {
|
||||
if($tw.utils.count(changedAttributes) > 0) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -160,6 +160,7 @@ NavigatorWidget.prototype.handleNavigateEvent = function(event) {
|
||||
|
||||
// Close a specified tiddler
|
||||
NavigatorWidget.prototype.handleCloseTiddlerEvent = function(event) {
|
||||
event = $tw.hooks.invokeHook("th-closing-tiddler",event);
|
||||
var title = event.param || event.tiddlerTitle,
|
||||
storyList = this.getStoryList();
|
||||
// Look for tiddlers with this title to close
|
||||
@@ -183,7 +184,8 @@ NavigatorWidget.prototype.handleCloseOtherTiddlersEvent = function(event) {
|
||||
|
||||
// Place a tiddler in edit mode
|
||||
NavigatorWidget.prototype.handleEditTiddlerEvent = function(event) {
|
||||
var editTiddler = $tw.hooks.invokeHook("th-editing-tiddler",event);
|
||||
var editTiddler = $tw.hooks.invokeHook("th-editing-tiddler",event),
|
||||
win = event.event && event.event.view ? event.event.view : window;
|
||||
if(!editTiddler) {
|
||||
return false;
|
||||
}
|
||||
@@ -192,7 +194,7 @@ NavigatorWidget.prototype.handleEditTiddlerEvent = function(event) {
|
||||
return self.wiki.isShadowTiddler(title) && !self.wiki.tiddlerExists(title);
|
||||
}
|
||||
function confirmEditShadow(title) {
|
||||
return confirm($tw.language.getString(
|
||||
return win.confirm($tw.language.getString(
|
||||
"ConfirmEditShadowTiddler",
|
||||
{variables:
|
||||
{title: title}
|
||||
@@ -225,7 +227,8 @@ NavigatorWidget.prototype.handleDeleteTiddlerEvent = function(event) {
|
||||
storyList = this.getStoryList(),
|
||||
originalTitle = tiddler ? tiddler.fields["draft.of"] : "",
|
||||
originalTiddler = originalTitle ? this.wiki.getTiddler(originalTitle) : undefined,
|
||||
confirmationTitle;
|
||||
confirmationTitle,
|
||||
win = event.event && event.event.view ? event.event.view : window;
|
||||
if(!tiddler) {
|
||||
return false;
|
||||
}
|
||||
@@ -238,7 +241,7 @@ NavigatorWidget.prototype.handleDeleteTiddlerEvent = function(event) {
|
||||
confirmationTitle = title;
|
||||
}
|
||||
// Seek confirmation
|
||||
if((this.wiki.getTiddler(originalTitle) || (tiddler.fields.text || "") !== "") && !confirm($tw.language.getString(
|
||||
if((this.wiki.getTiddler(originalTitle) || (tiddler.fields.text || "") !== "") && !win.confirm($tw.language.getString(
|
||||
"ConfirmDeleteTiddler",
|
||||
{variables:
|
||||
{title: confirmationTitle}
|
||||
@@ -304,7 +307,8 @@ NavigatorWidget.prototype.generateDraftTitle = function(title) {
|
||||
NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) {
|
||||
var title = event.param || event.tiddlerTitle,
|
||||
tiddler = this.wiki.getTiddler(title),
|
||||
storyList = this.getStoryList();
|
||||
storyList = this.getStoryList(),
|
||||
win = event.event && event.event.view ? event.event.view : window;
|
||||
// Replace the original tiddler with the draft
|
||||
if(tiddler) {
|
||||
var draftTitle = (tiddler.fields["draft.title"] || "").trim(),
|
||||
@@ -313,7 +317,7 @@ NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) {
|
||||
var isRename = draftOf !== draftTitle,
|
||||
isConfirmed = true;
|
||||
if(isRename && this.wiki.tiddlerExists(draftTitle)) {
|
||||
isConfirmed = confirm($tw.language.getString(
|
||||
isConfirmed = win.confirm($tw.language.getString(
|
||||
"ConfirmOverwriteTiddler",
|
||||
{variables:
|
||||
{title: draftTitle}
|
||||
@@ -362,6 +366,7 @@ NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) {
|
||||
// Take a tiddler out of edit mode without saving the changes
|
||||
NavigatorWidget.prototype.handleCancelTiddlerEvent = function(event) {
|
||||
event = $tw.hooks.invokeHook("th-cancelling-tiddler", event);
|
||||
var win = event.event && event.event.view ? event.event.view : window;
|
||||
// Flip the specified tiddler from draft back to the original
|
||||
var draftTitle = event.param || event.tiddlerTitle,
|
||||
draftTiddler = this.wiki.getTiddler(draftTitle),
|
||||
@@ -372,7 +377,7 @@ NavigatorWidget.prototype.handleCancelTiddlerEvent = function(event) {
|
||||
originalTiddler = this.wiki.getTiddler(originalTitle),
|
||||
storyList = this.getStoryList();
|
||||
if(this.wiki.isDraftModified(draftTitle)) {
|
||||
isConfirmed = confirm($tw.language.getString(
|
||||
isConfirmed = win.confirm($tw.language.getString(
|
||||
"ConfirmCancelTiddler",
|
||||
{variables:
|
||||
{title: draftTitle}
|
||||
|
||||
@@ -122,6 +122,7 @@ RadioWidget.prototype.refresh = function(changedTiddlers) {
|
||||
return true;
|
||||
} else if(changedTiddlers[this.radioTitle]) {
|
||||
this.inputDomNode.checked = this.getValue() === this.radioValue;
|
||||
$tw.utils.toggleClass(this.labelDomNode,"tc-radio-selected",this.inputDomNode.checked);
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
} else {
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
|
||||
@@ -226,7 +226,7 @@ RevealWidget.prototype.refresh = function(changedTiddlers) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
} else if(this.type === "popup" && this.updatePopupPosition && (changedTiddlers[this.state] || changedTiddlers[this.stateTitle])) {
|
||||
} else if(this.type === "popup" && this.isOpen && this.updatePopupPosition && (changedTiddlers[this.state] || changedTiddlers[this.stateTitle])) {
|
||||
this.positionPopup(this.domNode);
|
||||
}
|
||||
if(changedAttributes.style) {
|
||||
|
||||
81
core/modules/widgets/setmultiplevariables.js
Normal file
81
core/modules/widgets/setmultiplevariables.js
Normal file
@@ -0,0 +1,81 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/setmultiplevariables.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Widget to set multiple variables at once from a list of names and a list of values
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var SetMultipleVariablesWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
SetMultipleVariablesWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
SetMultipleVariablesWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
this.renderChildren(parent,nextSibling);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
SetMultipleVariablesWidget.prototype.execute = function() {
|
||||
// Setup our variables
|
||||
this.setVariables();
|
||||
// Construct the child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
|
||||
SetMultipleVariablesWidget.prototype.setVariables = function() {
|
||||
// Set the variables
|
||||
var self = this,
|
||||
filterNames = this.getAttribute("$names",""),
|
||||
filterValues = this.getAttribute("$values","");
|
||||
this.variableNames = [];
|
||||
this.variableValues = [];
|
||||
if(filterNames && filterValues) {
|
||||
this.variableNames = this.wiki.filterTiddlers(filterNames,this);
|
||||
this.variableValues = this.wiki.filterTiddlers(filterValues,this);
|
||||
$tw.utils.each(this.variableNames,function(varname,index) {
|
||||
self.setVariable(varname,self.variableValues[index]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Refresh the widget by ensuring our attributes are up to date
|
||||
*/
|
||||
SetMultipleVariablesWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var filterNames = this.getAttribute("$names",""),
|
||||
filterValues = this.getAttribute("$values",""),
|
||||
variableNames = this.wiki.filterTiddlers(filterNames,this),
|
||||
variableValues = this.wiki.filterTiddlers(filterValues,this);
|
||||
if(!$tw.utils.isArrayEqual(this.variableNames,variableNames) || !$tw.utils.isArrayEqual(this.variableValues,variableValues)) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
exports["setmultiplevariables"] = SetMultipleVariablesWidget;
|
||||
|
||||
})();
|
||||
|
||||
@@ -60,6 +60,8 @@ TranscludeWidget.prototype.execute = function() {
|
||||
subTiddler: this.transcludeSubTiddler
|
||||
}),
|
||||
parseTreeNodes = parser ? parser.tree : this.parseTreeNode.children;
|
||||
this.sourceText = parser ? parser.source : null;
|
||||
this.parserType = parser? parser.type : null;
|
||||
// Set context variables for recursion detection
|
||||
var recursionMarker = this.makeRecursionMarker();
|
||||
if(this.recursionMarker === "yes") {
|
||||
@@ -98,12 +100,17 @@ TranscludeWidget.prototype.makeRecursionMarker = function() {
|
||||
return output.join("");
|
||||
};
|
||||
|
||||
TranscludeWidget.prototype.parserNeedsRefresh = function() {
|
||||
var parserInfo = this.wiki.getTextReferenceParserInfo(this.transcludeTitle,this.transcludeField,this.transcludeIndex,{subTiddler:this.transcludeSubTiddler});
|
||||
return (this.sourceText === undefined || parserInfo.sourceText !== this.sourceText || parserInfo.parserType !== this.parserType)
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
TranscludeWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedTiddlers[this.transcludeTitle]) {
|
||||
if(($tw.utils.count(changedAttributes) > 0) || (changedTiddlers[this.transcludeTitle] && this.parserNeedsRefresh())) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -568,10 +568,15 @@ Widget.prototype.invokeActions = function(triggeringWidget,event) {
|
||||
var handled = false;
|
||||
// For each child widget
|
||||
for(var t=0; t<this.children.length; t++) {
|
||||
var child = this.children[t];
|
||||
// Invoke the child if it is an action widget
|
||||
if(child.invokeAction) {
|
||||
var child = this.children[t],
|
||||
childIsActionWidget = !!child.invokeAction,
|
||||
actionRefreshPolicy = child.getVariable("tv-action-refresh-policy"); // Default is "once"
|
||||
// Refresh the child if required
|
||||
if(childIsActionWidget || actionRefreshPolicy === "always") {
|
||||
child.refreshSelf();
|
||||
}
|
||||
// Invoke the child if it is an action widget
|
||||
if(childIsActionWidget) {
|
||||
if(child.invokeAction(triggeringWidget,event)) {
|
||||
handled = true;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ exports.setText = function(title,field,index,value,options) {
|
||||
} else {
|
||||
delete data[index];
|
||||
}
|
||||
this.setTiddlerData(title,data,modificationFields);
|
||||
this.setTiddlerData(title,data,{},{suppressTimestamp: options.suppressTimestamp});
|
||||
} else {
|
||||
var tiddler = this.getTiddler(title),
|
||||
fields = {title: title};
|
||||
@@ -365,47 +365,108 @@ Sort an array of tiddler titles by a specified field
|
||||
*/
|
||||
exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,isNumeric,isAlphaNumeric) {
|
||||
var self = this;
|
||||
titles.sort(function(a,b) {
|
||||
var x,y,
|
||||
compareNumbers = function(x,y) {
|
||||
var result =
|
||||
isNaN(x) && !isNaN(y) ? (isDescending ? -1 : 1) :
|
||||
!isNaN(x) && isNaN(y) ? (isDescending ? 1 : -1) :
|
||||
(isDescending ? y - x : x - y);
|
||||
return result;
|
||||
};
|
||||
if(sortField !== "title") {
|
||||
var tiddlerA = self.getTiddler(a),
|
||||
tiddlerB = self.getTiddler(b);
|
||||
if(tiddlerA) {
|
||||
a = tiddlerA.getFieldString(sortField) || "";
|
||||
if(sortField === "title") {
|
||||
if(!isNumeric && !isAlphaNumeric) {
|
||||
if(isCaseSensitive) {
|
||||
if(isDescending) {
|
||||
titles.sort(function(a,b) {
|
||||
return b.localeCompare(a);
|
||||
});
|
||||
} else {
|
||||
titles.sort(function(a,b) {
|
||||
return a.localeCompare(b);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
a = "";
|
||||
if(isDescending) {
|
||||
titles.sort(function(a,b) {
|
||||
return b.toLowerCase().localeCompare(a.toLowerCase());
|
||||
});
|
||||
} else {
|
||||
titles.sort(function(a,b) {
|
||||
return a.toLowerCase().localeCompare(b.toLowerCase());
|
||||
});
|
||||
}
|
||||
}
|
||||
if(tiddlerB) {
|
||||
b = tiddlerB.getFieldString(sortField) || "";
|
||||
} else {
|
||||
b = "";
|
||||
}
|
||||
}
|
||||
x = Number(a);
|
||||
y = Number(b);
|
||||
if(isNumeric && (!isNaN(x) || !isNaN(y))) {
|
||||
return compareNumbers(x,y);
|
||||
} else if($tw.utils.isDate(a) && $tw.utils.isDate(b)) {
|
||||
return isDescending ? b - a : a - b;
|
||||
} else if(isAlphaNumeric) {
|
||||
return isDescending ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
|
||||
} else {
|
||||
titles.sort(function(a,b) {
|
||||
var x,y;
|
||||
if(isNumeric) {
|
||||
x = Number(a);
|
||||
y = Number(b);
|
||||
if(isNaN(x)) {
|
||||
if(isNaN(y)) {
|
||||
// If neither value is a number then fall through to a textual comparison
|
||||
} else {
|
||||
return isDescending ? -1 : 1;
|
||||
}
|
||||
} else {
|
||||
if(isNaN(y)) {
|
||||
return isDescending ? 1 : -1;
|
||||
} else {
|
||||
return isDescending ? y - x : x - y;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isAlphaNumeric) {
|
||||
return isDescending ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
|
||||
}
|
||||
if(!isCaseSensitive) {
|
||||
a = a.toLowerCase();
|
||||
b = b.toLowerCase();
|
||||
}
|
||||
return isDescending ? b.localeCompare(a) : a.localeCompare(b);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
titles.sort(function(a,b) {
|
||||
var x,y;
|
||||
if(sortField !== "title") {
|
||||
var tiddlerA = self.getTiddler(a),
|
||||
tiddlerB = self.getTiddler(b);
|
||||
if(tiddlerA) {
|
||||
a = tiddlerA.fields[sortField] || "";
|
||||
} else {
|
||||
a = "";
|
||||
}
|
||||
if(tiddlerB) {
|
||||
b = tiddlerB.fields[sortField] || "";
|
||||
} else {
|
||||
b = "";
|
||||
}
|
||||
}
|
||||
if(isNumeric) {
|
||||
x = Number(a);
|
||||
y = Number(b);
|
||||
if(isNaN(x)) {
|
||||
if(isNaN(y)) {
|
||||
// If neither value is a number then fall through to a textual comparison
|
||||
} else {
|
||||
return isDescending ? -1 : 1;
|
||||
}
|
||||
} else {
|
||||
if(isNaN(y)) {
|
||||
return isDescending ? 1 : -1;
|
||||
} else {
|
||||
return isDescending ? y - x : x - y;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(Object.prototype.toString.call(a) === "[object Date]" && Object.prototype.toString.call(b) === "[object Date]") {
|
||||
return isDescending ? b - a : a - b;
|
||||
}
|
||||
a = String(a);
|
||||
b = String(b);
|
||||
if(isAlphaNumeric) {
|
||||
return isDescending ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
|
||||
}
|
||||
if(!isCaseSensitive) {
|
||||
a = a.toLowerCase();
|
||||
b = b.toLowerCase();
|
||||
}
|
||||
return isDescending ? b.localeCompare(a) : a.localeCompare(b);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -795,19 +856,24 @@ Set a tiddlers content to a JavaScript object. Currently this is done by setting
|
||||
title: title of tiddler
|
||||
data: object that can be serialised to JSON
|
||||
fields: optional hashmap of additional tiddler fields to be set
|
||||
options: optional hashmap of options including:
|
||||
suppressTimestamp: if true, don't set the creation/modification timestamps
|
||||
*/
|
||||
exports.setTiddlerData = function(title,data,fields) {
|
||||
exports.setTiddlerData = function(title,data,fields,options) {
|
||||
options = options || {};
|
||||
var existingTiddler = this.getTiddler(title),
|
||||
creationFields = options.suppressTimestamp ? {} : this.getCreationFields(),
|
||||
modificationFields = options.suppressTimestamp ? {} : this.getModificationFields(),
|
||||
newFields = {
|
||||
title: title
|
||||
};
|
||||
};
|
||||
if(existingTiddler && existingTiddler.fields.type === "application/x-tiddler-dictionary") {
|
||||
newFields.text = $tw.utils.makeTiddlerDictionary(data);
|
||||
} else {
|
||||
newFields.type = "application/json";
|
||||
newFields.text = JSON.stringify(data,null,$tw.config.preferences.jsonSpaces);
|
||||
}
|
||||
this.addTiddler(new $tw.Tiddler(this.getCreationFields(),existingTiddler,fields,newFields,this.getModificationFields()));
|
||||
this.addTiddler(new $tw.Tiddler(creationFields,existingTiddler,fields,newFields,modificationFields));
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -844,7 +910,7 @@ exports.clearGlobalCache = function() {
|
||||
exports.getCacheForTiddler = function(title,cacheName,initializer) {
|
||||
this.caches = this.caches || Object.create(null);
|
||||
var caches = this.caches[title];
|
||||
if(caches && caches[cacheName]) {
|
||||
if(caches && caches[cacheName] !== undefined) {
|
||||
return caches[cacheName];
|
||||
} else {
|
||||
if(!caches) {
|
||||
@@ -937,41 +1003,57 @@ exports.parseTiddler = function(title,options) {
|
||||
};
|
||||
|
||||
exports.parseTextReference = function(title,field,index,options) {
|
||||
var tiddler,text;
|
||||
if(options.subTiddler) {
|
||||
tiddler = this.getSubTiddler(title,options.subTiddler);
|
||||
} else {
|
||||
var tiddler,
|
||||
text,
|
||||
parserInfo;
|
||||
if(!options.subTiddler) {
|
||||
tiddler = this.getTiddler(title);
|
||||
if(field === "text" || (!field && !index)) {
|
||||
this.getTiddlerText(title); // Force the tiddler to be lazily loaded
|
||||
return this.parseTiddler(title,options);
|
||||
}
|
||||
}
|
||||
parserInfo = this.getTextReferenceParserInfo(title,field,index,options);
|
||||
if(parserInfo.sourceText !== null) {
|
||||
return this.parseText(parserInfo.parserType,parserInfo.sourceText,options);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
exports.getTextReferenceParserInfo = function(title,field,index,options) {
|
||||
var tiddler,
|
||||
parserInfo = {
|
||||
sourceText : null,
|
||||
parserType : "text/vnd.tiddlywiki"
|
||||
};
|
||||
if(options.subTiddler) {
|
||||
tiddler = this.getSubTiddler(title,options.subTiddler);
|
||||
} else {
|
||||
tiddler = this.getTiddler(title);
|
||||
}
|
||||
if(field === "text" || (!field && !index)) {
|
||||
if(tiddler && tiddler.fields) {
|
||||
return this.parseText(tiddler.fields.type,tiddler.fields.text,options);
|
||||
} else {
|
||||
return null;
|
||||
parserInfo.sourceText = tiddler.fields.text || "";
|
||||
if(tiddler.fields.type) {
|
||||
parserInfo.parserType = tiddler.fields.type;
|
||||
}
|
||||
}
|
||||
} else if(field) {
|
||||
if(field === "title") {
|
||||
text = title;
|
||||
} else {
|
||||
if(!tiddler || !tiddler.hasField(field)) {
|
||||
return null;
|
||||
}
|
||||
text = tiddler.fields[field];
|
||||
parserInfo.sourceText = title;
|
||||
} else if(tiddler && tiddler.fields) {
|
||||
parserInfo.sourceText = tiddler.hasField(field) ? tiddler.fields[field].toString() : null;
|
||||
}
|
||||
return this.parseText("text/vnd.tiddlywiki",text.toString(),options);
|
||||
} else if(index) {
|
||||
this.getTiddlerText(title); // Force the tiddler to be lazily loaded
|
||||
text = this.extractTiddlerDataItem(tiddler,index,undefined);
|
||||
if(text === undefined) {
|
||||
return null;
|
||||
}
|
||||
return this.parseText("text/vnd.tiddlywiki",text,options);
|
||||
parserInfo.sourceText = this.extractTiddlerDataItem(tiddler,index,null);
|
||||
}
|
||||
};
|
||||
if(parserInfo.sourceText === null) {
|
||||
parserInfo.parserType = null;
|
||||
}
|
||||
return parserInfo;
|
||||
}
|
||||
|
||||
/*
|
||||
Make a widget tree for a parse tree
|
||||
|
||||
@@ -4,4 +4,5 @@ title: $:/core/save/all-external-js
|
||||
\define saveTiddlerFilter()
|
||||
[is[tiddler]] -[prefix[$:/state/popup/]] -[prefix[$:/temp/]] -[prefix[$:/HistoryList]] -[status[pending]plugin-type[import]] -[[$:/core]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] +[sort[title]] $(publishFilter)$
|
||||
\end
|
||||
\define coreURL() %24%3A%2Fcore%2Ftemplates%2Ftiddlywiki5.js
|
||||
{{$:/core/templates/tiddlywiki5-external-js.html}}
|
||||
|
||||
8
core/templates/external-js/save-offline-external-js.tid
Normal file
8
core/templates/external-js/save-offline-external-js.tid
Normal file
@@ -0,0 +1,8 @@
|
||||
title: $:/core/save/offline-external-js
|
||||
|
||||
\import [[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]
|
||||
\define saveTiddlerFilter()
|
||||
[is[tiddler]] -[prefix[$:/state/popup/]] -[prefix[$:/temp/]] -[prefix[$:/HistoryList]] -[status[pending]plugin-type[import]] -[[$:/core]] -[[$:/plugins/tiddlywiki/filesystem]] -[[$:/plugins/tiddlywiki/tiddlyweb]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] +[sort[title]] $(publishFilter)$
|
||||
\end
|
||||
\define coreURL() tiddlywikicore-$(version)$.js
|
||||
{{$:/core/templates/tiddlywiki5-external-js.html}}
|
||||
@@ -2,4 +2,8 @@ title: $:/core/templates/tiddlywiki5.js/tiddlers
|
||||
|
||||
`
|
||||
$tw.preloadTiddlerArray(`<$text text=<<jsontiddlers "[[$:/core]]">>/>`);
|
||||
$tw.preloadTiddlerArray([{
|
||||
title: "$:/config/SaveWikiButton/Template",
|
||||
text: "$:/core/save/offline-external-js"
|
||||
}]);
|
||||
`
|
||||
|
||||
@@ -2,7 +2,7 @@ title: $:/core/templates/tiddlywiki5-external-js.html
|
||||
|
||||
\rules only filteredtranscludeinline transcludeinline
|
||||
<!doctype html>
|
||||
{{$:/core/templates/MOTW.html}}<html lang="`<$text text={{{ [{$:/language}get[name]] }}}/>`">
|
||||
{{$:/core/templates/MOTW.html}}<html lang="{{{ [{$:/language}get[name]] }}}">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
||||
<!--~~ Raw markup for the top of the head section ~~-->
|
||||
@@ -43,5 +43,6 @@ title: $:/core/templates/tiddlywiki5-external-js.html
|
||||
<!--~~ Raw markup for the bottom of the body section ~~-->
|
||||
{{{ [all[shadows+tiddlers]tag[$:/tags/RawMarkupWikified/BottomBody]] ||$:/core/templates/raw-static-tiddler}}}
|
||||
</body>
|
||||
<script src="%24%3A%2Fcore%2Ftemplates%2Ftiddlywiki5.js" onerror="alert('Error: Cannot load tiddlywiki.js');"></script>
|
||||
<!--~~ Load external JS ~~-->
|
||||
<script src="{{{ [<coreURL>] }}}" onerror="alert('Error: Cannot load {{{ [<coreURL>] }}}');"></script>
|
||||
</html>
|
||||
|
||||
4
core/templates/html-json-skinny-tiddler.tid
Normal file
4
core/templates/html-json-skinny-tiddler.tid
Normal file
@@ -0,0 +1,4 @@
|
||||
title: $:/core/templates/html-json-skinny-tiddler
|
||||
|
||||
<$list filter="[<numTiddlers>compare:number:gteq[1]] ~[<counter>!match[1]]">`,`<$text text=<<newline>>/></$list>
|
||||
<$jsontiddler tiddler=<<currentTiddler>> exclude="text" escapeUnsafeScriptChars="yes"/>
|
||||
3
core/templates/html-json-tiddler.tid
Normal file
3
core/templates/html-json-tiddler.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/core/templates/html-json-tiddler
|
||||
|
||||
<$list filter="[<counter>!match[1]]">`,`<$text text=<<newline>>/></$list><$jsontiddler tiddler=<<currentTiddler>> escapeUnsafeScriptChars="yes"/>
|
||||
@@ -1,14 +1,37 @@
|
||||
title: $:/core/templates/store.area.template.html
|
||||
|
||||
<$reveal type="nomatch" state="$:/isEncrypted" text="yes">
|
||||
`<div id="storeArea" style="display:none;">`
|
||||
<$list filter=<<saveTiddlerFilter>> template="$:/core/templates/html-div-tiddler"/>
|
||||
<$list filter={{{ [<skinnySaveTiddlerFilter>] }}} template="$:/core/templates/html-div-skinny-tiddler"/>
|
||||
`</div>`
|
||||
</$reveal>
|
||||
<$reveal type="match" state="$:/isEncrypted" text="yes">
|
||||
`<!--~~ Encrypted tiddlers ~~-->`
|
||||
`<pre id="encryptedStoreArea" type="text/plain" style="display:none;">`
|
||||
<$encrypt filter=<<saveTiddlerFilter>>/>
|
||||
`</pre>`
|
||||
</$reveal>
|
||||
\whitespace trim
|
||||
<!-- Unencrypted -->
|
||||
<$list filter="[[$:/isEncrypted]get[text]else[no]match[no]]">
|
||||
<$list filter="[[storeAreaFormat]is[variable]getvariable[]else[json]match[json]]">
|
||||
<!-- New-style JSON store area, with an old-style store area for compatibility with v5.1.x tooling -->
|
||||
`<script class="tiddlywiki-tiddler-store" type="application/json">[`
|
||||
<$vars newline={{{ [charcode[10]] }}}>
|
||||
<$text text=<<newline>>/>
|
||||
<$list filter=<<saveTiddlerFilter>> counter="counter" template="$:/core/templates/html-json-tiddler"/>
|
||||
<$vars numTiddlers={{{ [subfilter<saveTiddlerFilter>count[]] }}}>
|
||||
<$list filter={{{ [<skinnySaveTiddlerFilter>] }}} counter="counter" template="$:/core/templates/html-json-skinny-tiddler"/>
|
||||
</$vars>
|
||||
<$text text=<<newline>>/>
|
||||
</$vars>
|
||||
`]</script>`
|
||||
`<div id="storeArea" style="display:none;">`
|
||||
`</div>`
|
||||
</$list>
|
||||
<$list filter="[[storeAreaFormat]is[variable]getvariable[]else[json]match[div]]">
|
||||
<!-- Old-style DIV/PRE-based store area -->
|
||||
<$reveal type="nomatch" state="$:/isEncrypted" text="yes">
|
||||
`<div id="storeArea" style="display:none;">`
|
||||
<$list filter=<<saveTiddlerFilter>> template="$:/core/templates/html-div-tiddler"/>
|
||||
<$list filter={{{ [<skinnySaveTiddlerFilter>] }}} template="$:/core/templates/html-div-skinny-tiddler"/>
|
||||
`</div>`
|
||||
</$reveal>
|
||||
</$list>
|
||||
</$list>
|
||||
<!-- Encrypted -->
|
||||
<$list filter="[[$:/isEncrypted]get[text]else[no]match[yes]]">
|
||||
`<!--~~ Encrypted tiddlers ~~-->`
|
||||
`<pre id="encryptedStoreArea" type="text/plain" style="display:none;">`
|
||||
<$encrypt filter=<<saveTiddlerFilter>>/>
|
||||
`</pre>`
|
||||
</$list>
|
||||
@@ -19,71 +19,73 @@ $:/config/Plugins/Disabled/$(currentTiddler)$
|
||||
\end
|
||||
|
||||
\define plugin-table-body(type,disabledMessage,default-popup-state)
|
||||
\whitespace trim
|
||||
<div class="tc-plugin-info-chunk tc-plugin-info-toggle">
|
||||
<$reveal type="nomatch" state=<<popup-state>> text="yes" default="""$default-popup-state$""">
|
||||
<$button class="tc-btn-invisible tc-btn-dropdown" set=<<popup-state>> setTo="yes">
|
||||
{{$:/core/images/chevron-right}}
|
||||
</$button>
|
||||
</$reveal>
|
||||
<$reveal type="match" state=<<popup-state>> text="yes" default="""$default-popup-state$""">
|
||||
<$button class="tc-btn-invisible tc-btn-dropdown" set=<<popup-state>> setTo="no">
|
||||
{{$:/core/images/chevron-down}}
|
||||
</$button>
|
||||
</$reveal>
|
||||
<$reveal type="nomatch" state=<<popup-state>> text="yes" default="""$default-popup-state$""">
|
||||
<$button class="tc-btn-invisible tc-btn-dropdown" set=<<popup-state>> setTo="yes">
|
||||
{{$:/core/images/chevron-right}}
|
||||
</$button>
|
||||
</$reveal>
|
||||
<$reveal type="match" state=<<popup-state>> text="yes" default="""$default-popup-state$""">
|
||||
<$button class="tc-btn-invisible tc-btn-dropdown" set=<<popup-state>> setTo="no">
|
||||
{{$:/core/images/chevron-down}}
|
||||
</$button>
|
||||
</$reveal>
|
||||
</div>
|
||||
<div class="tc-plugin-info-chunk tc-plugin-info-icon">
|
||||
<$transclude tiddler=<<currentTiddler>> subtiddler=<<plugin-icon-title>>>
|
||||
<$transclude tiddler="$:/core/images/plugin-generic-$type$"/>
|
||||
</$transclude>
|
||||
<$transclude tiddler=<<currentTiddler>> subtiddler=<<plugin-icon-title>>>
|
||||
<$transclude tiddler="$:/core/images/plugin-generic-$type$"/>
|
||||
</$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> $disabledMessage$
|
||||
</h1>
|
||||
<h2>
|
||||
<$view field="title"/>
|
||||
</h2>
|
||||
<h2>
|
||||
<div><em><$view field="version"/></em></div>
|
||||
</h2>
|
||||
<h1>
|
||||
''<$text text={{{ [<currentTiddler>get[name]] ~[<currentTiddler>split[/]last[1]] }}}/>'': <$view field="description"><$view field="title"/></$view> $disabledMessage$
|
||||
</h1>
|
||||
<h2>
|
||||
<$view field="title"/>
|
||||
</h2>
|
||||
<h2>
|
||||
<div><em><$view field="version"/></em></div>
|
||||
</h2>
|
||||
</div>
|
||||
\end
|
||||
|
||||
\define plugin-info(type,default-popup-state)
|
||||
\whitespace trim
|
||||
<$set name="popup-state" value=<<popup-state-macro>>>
|
||||
<$reveal type="nomatch" state=<<plugin-disable-title>> text="yes">
|
||||
<$link to={{!!title}} class="tc-plugin-info">
|
||||
<<plugin-table-body type:"$type$" default-popup-state:"""$default-popup-state$""">>
|
||||
</$link>
|
||||
</$reveal>
|
||||
<$reveal type="match" state=<<plugin-disable-title>> text="yes">
|
||||
<$link to={{!!title}} class="tc-plugin-info tc-plugin-info-disabled">
|
||||
<<plugin-table-body type:"$type$" default-popup-state:"""$default-popup-state$""" disabledMessage:"<$macrocall $name='lingo' title='Disabled/Status'/>">>
|
||||
</$link>
|
||||
</$reveal>
|
||||
<$reveal type="match" text="yes" state=<<popup-state>> default="""$default-popup-state$""">
|
||||
<div class="tc-plugin-info-dropdown">
|
||||
<div class="tc-plugin-info-dropdown-body">
|
||||
<$list filter="[all[current]] -[[$:/core]]">
|
||||
<div style="float:right;">
|
||||
<$reveal type="nomatch" state=<<plugin-disable-title>> text="yes">
|
||||
<$button set=<<plugin-disable-title>> setTo="yes" tooltip={{$:/language/ControlPanel/Plugins/Disable/Hint}} aria-label={{$:/language/ControlPanel/Plugins/Disable/Caption}}>
|
||||
<<lingo Disable/Caption>>
|
||||
</$button>
|
||||
</$reveal>
|
||||
<$reveal type="match" state=<<plugin-disable-title>> text="yes">
|
||||
<$button set=<<plugin-disable-title>> setTo="no" tooltip={{$:/language/ControlPanel/Plugins/Enable/Hint}} aria-label={{$:/language/ControlPanel/Plugins/Enable/Caption}}>
|
||||
<<lingo Enable/Caption>>
|
||||
</$button>
|
||||
</$reveal>
|
||||
</div>
|
||||
</$list>
|
||||
<$set name="tabsList" filter="[<currentTiddler>list[]] contents">
|
||||
<$macrocall $name="tabs" state=<<tabs-state-macro>> tabsList=<<tabsList>> default={{{ [enlist<tabsList>] }}} template="$:/core/ui/PluginInfo"/>
|
||||
</$set>
|
||||
</div>
|
||||
</div>
|
||||
</$reveal>
|
||||
<$reveal type="nomatch" state=<<plugin-disable-title>> text="yes">
|
||||
<$link to={{!!title}} class="tc-plugin-info">
|
||||
<<plugin-table-body type:"$type$" default-popup-state:"""$default-popup-state$""">>
|
||||
</$link>
|
||||
</$reveal>
|
||||
<$reveal type="match" state=<<plugin-disable-title>> text="yes">
|
||||
<$link to={{!!title}} class="tc-plugin-info tc-plugin-info-disabled">
|
||||
<<plugin-table-body type:"$type$" default-popup-state:"""$default-popup-state$""" disabledMessage:"<$macrocall $name='lingo' title='Disabled/Status'/>">>
|
||||
</$link>
|
||||
</$reveal>
|
||||
<$reveal type="match" text="yes" state=<<popup-state>> default="""$default-popup-state$""">
|
||||
<div class="tc-plugin-info-dropdown">
|
||||
<div class="tc-plugin-info-dropdown-body">
|
||||
<$list filter="[all[current]] -[[$:/core]]">
|
||||
<div style="float:right;">
|
||||
<$reveal type="nomatch" state=<<plugin-disable-title>> text="yes">
|
||||
<$button set=<<plugin-disable-title>> setTo="yes" tooltip={{$:/language/ControlPanel/Plugins/Disable/Hint}} aria-label={{$:/language/ControlPanel/Plugins/Disable/Caption}}>
|
||||
<<lingo Disable/Caption>>
|
||||
</$button>
|
||||
</$reveal>
|
||||
<$reveal type="match" state=<<plugin-disable-title>> text="yes">
|
||||
<$button set=<<plugin-disable-title>> setTo="no" tooltip={{$:/language/ControlPanel/Plugins/Enable Hint}} aria-label={{$:/language/ControlPanel/Plugins/Enable/Caption}}>
|
||||
<<lingo Enable/Caption>>
|
||||
</$button>
|
||||
</$reveal>
|
||||
</div>
|
||||
</$list>
|
||||
<$set name="tabsList" filter="[<currentTiddler>list[]] contents">
|
||||
<$macrocall $name="tabs" state=<<tabs-state-macro>> tabsList=<<tabsList>> default={{{ [enlist<tabsList>] }}} template="$:/core/ui/PluginInfo"/>
|
||||
</$set>
|
||||
</div>
|
||||
</div>
|
||||
</$reveal>
|
||||
</$set>
|
||||
\end
|
||||
|
||||
|
||||
@@ -16,4 +16,4 @@ caption: {{$:/language/ControlPanel/Plugins/Caption}}
|
||||
|
||||
<<lingo Installed/Hint>>
|
||||
|
||||
<$macrocall $name="tabs" tabsList="[[$:/core/ui/ControlPanel/Plugins/Installed/Plugins]] [[$:/core/ui/ControlPanel/Plugins/Installed/Themes]] [[$:/core/ui/ControlPanel/Plugins/Installed/Languages]]" default="$:/core/ui/ControlPanel/Plugins/Installed/Plugins" explicitState="$:/state/tab--86143343"/>
|
||||
<$macrocall $name="tabs" tabsList="[all[tiddlers+shadows]tag[$:/tags/ControlPanel/Plugins]!has[draft.of]]" default="$:/core/ui/ControlPanel/Plugins/Installed/Plugins" explicitState="$:/state/tab--86143343"/>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
title: $:/core/ui/ControlPanel/Plugins/Installed/Languages
|
||||
tags: $:/tags/ControlPanel/Plugins
|
||||
caption: {{$:/language/ControlPanel/Plugins/Languages/Caption}} (<$count filter="[!has[draft.of]plugin-type[language]]"/>)
|
||||
|
||||
<<plugin-table language>>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
title: $:/core/ui/ControlPanel/Plugins/Installed/Plugins
|
||||
tags: $:/tags/ControlPanel/Plugins
|
||||
caption: {{$:/language/ControlPanel/Plugins/Plugins/Caption}} (<$count filter="[!has[draft.of]plugin-type[plugin]]"/>)
|
||||
|
||||
<<plugin-table plugin>>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
title: $:/core/ui/ControlPanel/Plugins/Installed/Themes
|
||||
tags: $:/tags/ControlPanel/Plugins
|
||||
caption: {{$:/language/ControlPanel/Plugins/Themes/Caption}} (<$count filter="[!has[draft.of]plugin-type[theme]]"/>)
|
||||
|
||||
<<plugin-table theme>>
|
||||
|
||||
@@ -13,7 +13,7 @@ title: $:/core/ui/EditorToolbar/link-dropdown
|
||||
<$set name="userInput" value={{{ [<storeTitle>get[text]] }}}><$list filter="[<searchTiddler>get[text]!match<userInput>]" emptyMessage="""<$action-deletetiddler $filter="[<searchTiddler>] [<linkTiddler>] [<storeTitle>] [<searchListState>]"/>"""><$action-setfield $tiddler=<<searchTiddler>> text=<<userInput>>/><$action-setfield $tiddler=<<refreshTitle>> text="yes"/></$list></$set>
|
||||
\end
|
||||
|
||||
\define cancel-search-actions() <$list filter="[<storeTitle>!has[text]] +[<searchTiddler>!has[text]]" emptyMessage="""<<cancel-search-actions-inner>>"""><$action-sendmessage $message="tm-edit-text-operation" $param="wrap-selection" prefix="" suffix=""/></$list>
|
||||
\define cancel-search-actions() <$list filter="[<storeTitle>!has[text]] +[<searchTiddler>!has[text]]" emptyMessage="""<<cancel-search-actions-inner>>"""><$action-sendmessage $message="tm-edit-text-operation" $param="focus-editor"/></$list>
|
||||
|
||||
\define external-link()
|
||||
<$button class="tc-btn-invisible" style="width: auto; display: inline-block; background-colour: inherit;" actions=<<add-link-actions>>>
|
||||
|
||||
53
core/ui/EditorToolbar/stamp-dropdown-item-template.tid
Normal file
53
core/ui/EditorToolbar/stamp-dropdown-item-template.tid
Normal file
@@ -0,0 +1,53 @@
|
||||
title: $:/core/ui/EditorToolbar/StampDropdown/ItemTemplate
|
||||
|
||||
<$linkcatcher actions="""
|
||||
|
||||
<$list filter="[<modifier>!match[ctrl]]" variable="ignore">
|
||||
|
||||
<$list filter="[<currentTiddler>addsuffix[/prefix]!is[tiddler]!is[shadow]removesuffix[/prefix]addsuffix[/suffix]!is[tiddler]!is[shadow]]" variable="ignore">
|
||||
|
||||
<$action-sendmessage
|
||||
$message="tm-edit-text-operation"
|
||||
$param="replace-selection"
|
||||
text={{{ [<currentTiddler>get[text]] }}}
|
||||
/>
|
||||
|
||||
</$list>
|
||||
|
||||
|
||||
<$list filter="[<currentTiddler>addsuffix[/prefix]] [<currentTiddler>addsuffix[/suffix]] +[is[shadow]] :else[is[tiddler]] +[limit[1]]" variable="ignore">
|
||||
|
||||
<$action-sendmessage
|
||||
$message="tm-edit-text-operation"
|
||||
$param="wrap-selection"
|
||||
prefix={{{ [<currentTiddler>addsuffix[/prefix]get[text]] }}}
|
||||
suffix={{{ [<currentTiddler>addsuffix[/suffix]get[text]] }}}
|
||||
/>
|
||||
|
||||
</$list>
|
||||
|
||||
</$list>
|
||||
|
||||
<$list filter="[<modifier>match[ctrl]]" variable="ignore">
|
||||
|
||||
<$action-sendmessage $message="tm-edit-tiddler"/>
|
||||
|
||||
</$list>
|
||||
|
||||
<$action-deletetiddler
|
||||
$tiddler=<<dropdown-state>>
|
||||
/>
|
||||
|
||||
""">
|
||||
|
||||
<$link tooltip={{{ [<currentTiddler>get[description]] }}}>
|
||||
|
||||
<$transclude tiddler=<<currentTiddler>> field="caption" mode="inline">
|
||||
|
||||
<$view tiddler=<<currentTiddler>> field="title" />
|
||||
|
||||
</$transclude>
|
||||
|
||||
</$link>
|
||||
|
||||
</$linkcatcher>
|
||||
@@ -1,48 +1,6 @@
|
||||
title: $:/core/ui/EditorToolbar/stamp-dropdown
|
||||
|
||||
\define toolbar-button-stamp-inner()
|
||||
<$button tag="a">
|
||||
|
||||
<$list filter="[[$(snippetTitle)$]addsuffix[/prefix]is[missing]removesuffix[/prefix]addsuffix[/suffix]is[missing]]">
|
||||
|
||||
<$action-sendmessage
|
||||
$message="tm-edit-text-operation"
|
||||
$param="replace-selection"
|
||||
text={{$(snippetTitle)$}}
|
||||
/>
|
||||
|
||||
</$list>
|
||||
|
||||
|
||||
<$list filter="[[$(snippetTitle)$]addsuffix[/prefix]is[missing]removesuffix[/prefix]addsuffix[/suffix]!is[missing]] [[$(snippetTitle)$]addsuffix[/prefix]!is[missing]removesuffix[/prefix]addsuffix[/suffix]is[missing]] [[$(snippetTitle)$]addsuffix[/prefix]!is[missing]removesuffix[/prefix]addsuffix[/suffix]!is[missing]]">
|
||||
|
||||
<$action-sendmessage
|
||||
$message="tm-edit-text-operation"
|
||||
$param="wrap-selection"
|
||||
prefix={{{ [[$(snippetTitle)$]addsuffix[/prefix]get[text]] }}}
|
||||
suffix={{{ [[$(snippetTitle)$]addsuffix[/suffix]get[text]] }}}
|
||||
/>
|
||||
|
||||
</$list>
|
||||
|
||||
<$action-deletetiddler
|
||||
$tiddler=<<dropdown-state>>
|
||||
/>
|
||||
|
||||
<$transclude tiddler=<<snippetTitle>> field="caption" mode="inline">
|
||||
|
||||
<$view tiddler=<<snippetTitle>> field="title" />
|
||||
|
||||
</$transclude>
|
||||
|
||||
</$button>
|
||||
\end
|
||||
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/TextEditor/Snippet]!has[draft.of]sort[caption]]" variable="snippetTitle">
|
||||
|
||||
<<toolbar-button-stamp-inner>>
|
||||
|
||||
</$list>
|
||||
<$macrocall $name="list-tagged-draggable" tag="$:/tags/TextEditor/Snippet" subFilter="!is[draft]" itemTemplate="$:/core/ui/EditorToolbar/StampDropdown/ItemTemplate"/>
|
||||
|
||||
----
|
||||
|
||||
|
||||
@@ -6,4 +6,5 @@ description: {{$:/language/Buttons/Stamp/Hint}}
|
||||
condition: [<targetTiddler>type[]] [<targetTiddler>get[type]prefix[text/]] [<targetTiddler>get[type]match[application/javascript]] [<targetTiddler>get[type]match[application/json]] [<targetTiddler>get[type]match[application/x-tiddler-dictionary]] [<targetTiddler>get[type]match[image/svg+xml]] +[first[]]
|
||||
shortcuts: ((stamp))
|
||||
dropdown: $:/core/ui/EditorToolbar/stamp-dropdown
|
||||
button-classes: tc-editortoolbar-stamp-button
|
||||
text:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user