mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-24 03:44:41 +00:00
Compare commits
406 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
384e5b7b63 | ||
|
|
5e317161f6 | ||
|
|
39e8a83c4c | ||
|
|
7890440569 | ||
|
|
02331365f0 | ||
|
|
48fe208f0c | ||
|
|
a613ffb6a3 | ||
|
|
c0f7f18f0a | ||
|
|
e18b6bf5c4 | ||
|
|
31523a1e7b | ||
|
|
4b780899a5 | ||
|
|
04f402b974 | ||
|
|
aa2f240936 | ||
|
|
d99e0c9f97 | ||
|
|
2a1fb964d5 | ||
|
|
5050829e63 | ||
|
|
6c4c1a984b | ||
|
|
53181d2ab8 | ||
|
|
f22547fa3a | ||
|
|
3693b4786d | ||
|
|
cd16573f20 | ||
|
|
0aaebe9757 | ||
|
|
379e780e80 | ||
|
|
0a2c3d0c3c | ||
|
|
202ffd9c51 | ||
|
|
2e0c119d5b | ||
|
|
f03feb69a9 | ||
|
|
40a61ff2e7 | ||
|
|
b9a8c3c01d | ||
|
|
c25a44756b | ||
|
|
83497c13d9 | ||
|
|
ec0fa2f932 | ||
|
|
773ef6adfb | ||
|
|
b1e0fa4a34 | ||
|
|
aa1a8cf2eb | ||
|
|
8802015f1a | ||
|
|
50268d9231 | ||
|
|
b37178dda1 | ||
|
|
1e106a8f3d | ||
|
|
f3cab3753e | ||
|
|
303f255fcd | ||
|
|
af45d509eb | ||
|
|
d3fe4f600a | ||
|
|
0276b69244 | ||
|
|
4891732481 | ||
|
|
d9ed01b621 | ||
|
|
0493208a23 | ||
|
|
0efed8335d | ||
|
|
1f860bd04e | ||
|
|
8744d77f88 | ||
|
|
24f29ac605 | ||
|
|
b1ed77d6b8 | ||
|
|
8f1114960a | ||
|
|
3a00d2eea3 | ||
|
|
5ed7ade44f | ||
|
|
bea33efd63 | ||
|
|
f4656b0f25 | ||
|
|
9bad99d14e | ||
|
|
3197f9a639 | ||
|
|
eba1c3c160 | ||
|
|
c2391c5250 | ||
|
|
5b3bb1974c | ||
|
|
39cdaeb34d | ||
|
|
d778bc9a21 | ||
|
|
fe5670663d | ||
|
|
8804278e6e | ||
|
|
b9fbe12118 | ||
|
|
779e62a30f | ||
|
|
d65fd771e7 | ||
|
|
73e1724fdf | ||
|
|
595072b2bc | ||
|
|
66d5e2650e | ||
|
|
bb81f00161 | ||
|
|
5dbc1b7163 | ||
|
|
28b861451b | ||
|
|
796e59e0dc | ||
|
|
e30330d4be | ||
|
|
52a414959c | ||
|
|
b9a835b879 | ||
|
|
6343c39bd6 | ||
|
|
35b327e336 | ||
|
|
63b3d88604 | ||
|
|
a71e27386f | ||
|
|
9a67a90a30 | ||
|
|
d53d6e7921 | ||
|
|
b90600580f | ||
|
|
d0594e4a45 | ||
|
|
b5360db375 | ||
|
|
da0c244a51 | ||
|
|
ad1c2a6571 | ||
|
|
617ec82a22 | ||
|
|
7c2d519d4f | ||
|
|
f246b93a38 | ||
|
|
31a803626f | ||
|
|
88a65f038e | ||
|
|
6085936475 | ||
|
|
cd2bc88658 | ||
|
|
b1ecf81b0c | ||
|
|
eee18aab40 | ||
|
|
9fc2086b71 | ||
|
|
8307f7c3ca | ||
|
|
b26e138503 | ||
|
|
16da00fe3e | ||
|
|
7086c41b6c | ||
|
|
6a172363da | ||
|
|
75b501f681 | ||
|
|
daf703b67f | ||
|
|
0d0ece6377 | ||
|
|
74b0da065e | ||
|
|
6f93ce6ea7 | ||
|
|
91b341e8e0 | ||
|
|
f0ff1f993e | ||
|
|
d0c20435cd | ||
|
|
6505e6f448 | ||
|
|
a6b538b308 | ||
|
|
467bf17dd8 | ||
|
|
95f565878e | ||
|
|
d6f5b3cacd | ||
|
|
d5b04c2688 | ||
|
|
7b251df989 | ||
|
|
a51f62bc40 | ||
|
|
6397ce8997 | ||
|
|
de9bb2fa40 | ||
|
|
b5482d8dba | ||
|
|
3708f6c8e4 | ||
|
|
1961db6732 | ||
|
|
36c0af0fd4 | ||
|
|
9e08aed8ad | ||
|
|
075d7d76df | ||
|
|
3d8249dc7a | ||
|
|
97e995e0c7 | ||
|
|
2397f0aa6f | ||
|
|
6b2ab90721 | ||
|
|
73ded6a82a | ||
|
|
9bc523fdef | ||
|
|
f4a015f120 | ||
|
|
d9fd722e50 | ||
|
|
112a8d95c5 | ||
|
|
ef1c47c3aa | ||
|
|
6282fe43af | ||
|
|
db056a84a5 | ||
|
|
a14b8a94df | ||
|
|
e20682dcfd | ||
|
|
bc61f7eebf | ||
|
|
6c65aa2a6d | ||
|
|
ced9f315a1 | ||
|
|
1563f207b3 | ||
|
|
9a01e9ab71 | ||
|
|
3527379468 | ||
|
|
abb9f262c3 | ||
|
|
b5059c612a | ||
|
|
56b6781715 | ||
|
|
4bf626d741 | ||
|
|
8dc971a11e | ||
|
|
f914f0a6a2 | ||
|
|
0b14a0c24e | ||
|
|
3e40403d11 | ||
|
|
1b339e17bc | ||
|
|
2b90d0ab96 | ||
|
|
d632e47ffe | ||
|
|
0e37e0cd78 | ||
|
|
190d4881bf | ||
|
|
c3833d0232 | ||
|
|
ac3b67b819 | ||
|
|
dbcda815fa | ||
|
|
74bdbb9be8 | ||
|
|
b152d0a727 | ||
|
|
00669e87da | ||
|
|
d4db283d61 | ||
|
|
2f21cbc971 | ||
|
|
18280249f4 | ||
|
|
da6149cdde | ||
|
|
c16f96626e | ||
|
|
56131e4563 | ||
|
|
f9b4f747a1 | ||
|
|
79ae3f8cb7 | ||
|
|
c60fd4c0c6 | ||
|
|
a37137d426 | ||
|
|
a2b465ee75 | ||
|
|
241f901d85 | ||
|
|
7a6cbb1629 | ||
|
|
94d460ef20 | ||
|
|
5b5b25dd16 | ||
|
|
0c2734f181 | ||
|
|
60c6f039e4 | ||
|
|
0e83fad837 | ||
|
|
b1a5afbf15 | ||
|
|
28b7493c3c | ||
|
|
ab1b1f2cde | ||
|
|
eac449e8ff | ||
|
|
f495df6386 | ||
|
|
2945c9abc1 | ||
|
|
bbcc367e5a | ||
|
|
0383b98555 | ||
|
|
f143164cbe | ||
|
|
a1a4bf0f9d | ||
|
|
ba9d6187af | ||
|
|
cec5522b72 | ||
|
|
a20da9f530 | ||
|
|
daad0ec142 | ||
|
|
ed1a7e73cd | ||
|
|
352d7d664c | ||
|
|
74107b9b8a | ||
|
|
7d1e3f4c35 | ||
|
|
15c7d24eaa | ||
|
|
e1053bf014 | ||
|
|
66a13cb915 | ||
|
|
1530b3e2d8 | ||
|
|
a2fe101848 | ||
|
|
50d25e24f9 | ||
|
|
e5b432a86b | ||
|
|
d6d3aab36a | ||
|
|
424b8a1f68 | ||
|
|
9c3a6976f0 | ||
|
|
52d32fe3fd | ||
|
|
2319c9269e | ||
|
|
a393705cef | ||
|
|
4d3d7de3b5 | ||
|
|
4a45e9d2dc | ||
|
|
28591965b1 | ||
|
|
7a71a87ed0 | ||
|
|
3c005a153f | ||
|
|
24ccb215b2 | ||
|
|
b4dc730575 | ||
|
|
e8bb897e26 | ||
|
|
1bba9dc315 | ||
|
|
ad9769451d | ||
|
|
74def9e080 | ||
|
|
25b2e846ce | ||
|
|
fbd689368e | ||
|
|
db00c699f4 | ||
|
|
2fedd8dcd3 | ||
|
|
f32d05ae4b | ||
|
|
487dab57e6 | ||
|
|
ee486b2863 | ||
|
|
b3a8780044 | ||
|
|
7736e6e4e4 | ||
|
|
b43b89f44a | ||
|
|
0c6b2311ae | ||
|
|
12ecb1fd08 | ||
|
|
b29c9cf829 | ||
|
|
16bb65d17f | ||
|
|
2f2ddf6c0e | ||
|
|
f07e0f981a | ||
|
|
9a38642141 | ||
|
|
a3dc3b4b98 | ||
|
|
c02c3a06e0 | ||
|
|
cf28eeb2a1 | ||
|
|
b759d82f4c | ||
|
|
c65d08240b | ||
|
|
c460cc03a4 | ||
|
|
b2260c9d7e | ||
|
|
4e0aea288d | ||
|
|
a9b54d6fce | ||
|
|
a85d034015 | ||
|
|
96708ecf65 | ||
|
|
940aafe2e0 | ||
|
|
ca179cc904 | ||
|
|
58e12139de | ||
|
|
f67777161d | ||
|
|
251619189e | ||
|
|
117bf0a0de | ||
|
|
e5af022bd3 | ||
|
|
766bc7acee | ||
|
|
b00c1c7290 | ||
|
|
8e033eb0d4 | ||
|
|
0b4669621a | ||
|
|
1a2ec12831 | ||
|
|
9418538104 | ||
|
|
14293d1b6b | ||
|
|
e98d324e66 | ||
|
|
3bceb98119 | ||
|
|
d1121787c0 | ||
|
|
b3273bcbda | ||
|
|
b86d142408 | ||
|
|
5bf238fc86 | ||
|
|
0e57ce4090 | ||
|
|
3c715c5e0d | ||
|
|
c8f7573a23 | ||
|
|
0f85ca3478 | ||
|
|
997029a78f | ||
|
|
3a70ddb235 | ||
|
|
903cdc09cc | ||
|
|
a485eb8588 | ||
|
|
f7d81a00c2 | ||
|
|
632e062749 | ||
|
|
b8cbc07c54 | ||
|
|
8ed91f2f90 | ||
|
|
fc483abfc8 | ||
|
|
62adfba68c | ||
|
|
0d0764b6ce | ||
|
|
975d5346fb | ||
|
|
87fbd07728 | ||
|
|
d204688f35 | ||
|
|
dd8f660c4e | ||
|
|
5c8844a51a | ||
|
|
8d35178bc4 | ||
|
|
52f02717a8 | ||
|
|
56640b90bb | ||
|
|
664225f6fd | ||
|
|
5685724774 | ||
|
|
cedb953f83 | ||
|
|
54d0cb2021 | ||
|
|
5a361bdadc | ||
|
|
8de4583d6c | ||
|
|
e9470169d8 | ||
|
|
9c50a223b8 | ||
|
|
fb07992fa8 | ||
|
|
7108e0d861 | ||
|
|
c72a0b7a67 | ||
|
|
3259b80114 | ||
|
|
cd5366087c | ||
|
|
0b76c327c2 | ||
|
|
6dc90718f0 | ||
|
|
a292a2be44 | ||
|
|
c415af13f1 | ||
|
|
030c51b1f8 | ||
|
|
7f11c151f0 | ||
|
|
5ec7250621 | ||
|
|
28a25be5f7 | ||
|
|
8e02bde938 | ||
|
|
5aba7292e7 | ||
|
|
52cef1394c | ||
|
|
7b535b8f31 | ||
|
|
22c1b04ee7 | ||
|
|
7a6d7e2a15 | ||
|
|
87fa7f972c | ||
|
|
b4b77d1681 | ||
|
|
b35544bf49 | ||
|
|
d9f301f755 | ||
|
|
2f590a365e | ||
|
|
8fbcfaa79b | ||
|
|
accd4a1b65 | ||
|
|
537cfcbf79 | ||
|
|
1b41b44684 | ||
|
|
d7b6917638 | ||
|
|
892a1f560e | ||
|
|
da298f037d | ||
|
|
f97c1226aa | ||
|
|
989cee5059 | ||
|
|
e724bc6120 | ||
|
|
ffcbcbfa82 | ||
|
|
f1090d749e | ||
|
|
b9299309cc | ||
|
|
bf253a603b | ||
|
|
f575389d89 | ||
|
|
994432e28e | ||
|
|
6079563ff8 | ||
|
|
ff6b0bd5dc | ||
|
|
23060f92f0 | ||
|
|
d038e0bc1b | ||
|
|
3486acaec6 | ||
|
|
be574b713e | ||
|
|
808587f1c1 | ||
|
|
c7b31b0242 | ||
|
|
641eeaf611 | ||
|
|
c4e13bc94a | ||
|
|
ee66d1a1af | ||
|
|
e4f3d56bdc | ||
|
|
20daaae7e8 | ||
|
|
b867b7487e | ||
|
|
4be5f0abe8 | ||
|
|
292d653880 | ||
|
|
d86e4043c2 | ||
|
|
0409151801 | ||
|
|
e1cc285151 | ||
|
|
ffc0899f52 | ||
|
|
2d9aa12aa8 | ||
|
|
fc898ae64a | ||
|
|
975bc30079 | ||
|
|
06b7de415c | ||
|
|
3ad8cf59bd | ||
|
|
5f0a1dd967 | ||
|
|
0788145cb5 | ||
|
|
03db25cf38 | ||
|
|
4d74f52202 | ||
|
|
05b32728bc | ||
|
|
3a2ea9b98b | ||
|
|
da1905b789 | ||
|
|
845e8294cd | ||
|
|
f079b31334 | ||
|
|
ee9d19d299 | ||
|
|
ffae85140f | ||
|
|
ba2f831d8c | ||
|
|
7bc7f643b6 | ||
|
|
18dd8d4433 | ||
|
|
118b2ffe2f | ||
|
|
4be6efdb4e | ||
|
|
e20bce5450 | ||
|
|
12e3e8b489 | ||
|
|
b7c416d340 | ||
|
|
8b60dbb81d | ||
|
|
9bd002e41d | ||
|
|
10d5aecf3f | ||
|
|
4eed18496f | ||
|
|
959a7ac485 | ||
|
|
8f6abf534f | ||
|
|
b96377099a | ||
|
|
486b326ea9 | ||
|
|
7326a3a4cc | ||
|
|
08cfa88249 | ||
|
|
82694e1426 | ||
|
|
570c1b20f0 | ||
|
|
1da8a32837 | ||
|
|
8ec8c5103e | ||
|
|
a5d380006e |
@@ -5,7 +5,7 @@
|
||||
# Optional parameter is the username for signing edits
|
||||
|
||||
node ./tiddlywiki.js \
|
||||
editions/server \
|
||||
editions/tw5.com-server \
|
||||
--verbose \
|
||||
--server 8080 $:/core/save/lazy-images text/plain text/html $1 $2\
|
||||
|| exit 1
|
||||
|
||||
239
boot/boot.js
239
boot/boot.js
@@ -251,29 +251,35 @@ $tw.utils.parseDate = function(value) {
|
||||
|
||||
// Stringify an array of tiddler titles into a list string
|
||||
$tw.utils.stringifyList = function(value) {
|
||||
var result = [];
|
||||
for(var t=0; t<value.length; t++) {
|
||||
if(value[t].indexOf(" ") !== -1) {
|
||||
result.push("[[" + value[t] + "]]");
|
||||
} else {
|
||||
result.push(value[t]);
|
||||
if($tw.utils.isArray(value)) {
|
||||
var result = [];
|
||||
for(var t=0; t<value.length; t++) {
|
||||
var entry = value[t] || "";
|
||||
if(entry.indexOf(" ") !== -1) {
|
||||
result.push("[[" + entry + "]]");
|
||||
} else {
|
||||
result.push(entry);
|
||||
}
|
||||
}
|
||||
return result.join(" ");
|
||||
} else {
|
||||
return value || "";
|
||||
}
|
||||
return result.join(" ");
|
||||
};
|
||||
|
||||
// Parse a string array from a bracketted list. For example "OneTiddler [[Another Tiddler]] LastOne"
|
||||
$tw.utils.parseStringArray = function(value) {
|
||||
if(typeof value === "string") {
|
||||
var memberRegExp = /(?:^|[^\S\xA0])(?:\[\[(.*?)\]\])(?=[^\S\xA0]|$)|([\S\xA0]+)/mg,
|
||||
results = [],
|
||||
results = [], names = {},
|
||||
match;
|
||||
do {
|
||||
match = memberRegExp.exec(value);
|
||||
if(match) {
|
||||
var item = match[1] || match[2];
|
||||
if(item !== undefined && results.indexOf(item) === -1) {
|
||||
if(item !== undefined && !$tw.utils.hop(names,item)) {
|
||||
results.push(item);
|
||||
names[item] = true;
|
||||
}
|
||||
}
|
||||
} while(match);
|
||||
@@ -514,6 +520,9 @@ $tw.utils.PasswordPrompt.prototype.createPrompt = function(options) {
|
||||
if(options.canCancel) {
|
||||
children.push(dm("button",{
|
||||
text: $tw.language.getString("Encryption/Cancel"),
|
||||
attributes: {
|
||||
type: "button"
|
||||
},
|
||||
eventListeners: [{
|
||||
name: "click",
|
||||
handlerFunction: function(event) {
|
||||
@@ -635,9 +644,25 @@ $tw.utils.Crypto = function() {
|
||||
Execute the module named 'moduleName'. The name can optionally be relative to the module named 'moduleRoot'
|
||||
*/
|
||||
$tw.modules.execute = function(moduleName,moduleRoot) {
|
||||
var name = moduleName[0] === "." ? $tw.utils.resolvePath(moduleName,moduleRoot) : moduleName,
|
||||
moduleInfo = $tw.modules.titles[name] || $tw.modules.titles[name + ".js"] || $tw.modules.titles[moduleName] || $tw.modules.titles[moduleName + ".js"] ,
|
||||
tiddler = $tw.wiki.getTiddler(name) || $tw.wiki.getTiddler(name + ".js") || $tw.wiki.getTiddler(moduleName) || $tw.wiki.getTiddler(moduleName + ".js") ,
|
||||
var name = moduleName;
|
||||
if(moduleName.charAt(0) === ".") {
|
||||
name = $tw.utils.resolvePath(moduleName,moduleRoot)
|
||||
}
|
||||
if(!$tw.modules.titles[name]) {
|
||||
if($tw.modules.titles[name + ".js"]) {
|
||||
name = name + ".js";
|
||||
} else if($tw.modules.titles[name + "/index.js"]) {
|
||||
name = name + "/index.js";
|
||||
} else if($tw.modules.titles[moduleName]) {
|
||||
name = moduleName;
|
||||
} else if($tw.modules.titles[moduleName + ".js"]) {
|
||||
name = moduleName + ".js";
|
||||
} else if($tw.modules.titles[moduleName + "/index.js"]) {
|
||||
name = moduleName + "/index.js";
|
||||
}
|
||||
}
|
||||
var moduleInfo = $tw.modules.titles[name],
|
||||
tiddler = $tw.wiki.getTiddler(name),
|
||||
_exports = {},
|
||||
sandbox = {
|
||||
module: {exports: _exports},
|
||||
@@ -648,7 +673,7 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
|
||||
clearInterval: clearInterval,
|
||||
setTimeout: setTimeout,
|
||||
clearTimeout: clearTimeout,
|
||||
Buffer: $tw.browser ? {} : Buffer,
|
||||
Buffer: $tw.browser ? undefined : Buffer,
|
||||
$tw: $tw,
|
||||
require: function(title) {
|
||||
return $tw.modules.execute(title, name);
|
||||
@@ -802,6 +827,7 @@ taking precedence to the right
|
||||
*/
|
||||
$tw.Tiddler = function(/* [fields,] fields */) {
|
||||
this.fields = Object.create(null);
|
||||
this.cache = Object.create(null);
|
||||
for(var c=0; c<arguments.length; c++) {
|
||||
var arg = arguments[c],
|
||||
src = (arg instanceof $tw.Tiddler) ? arg.fields : arg;
|
||||
@@ -902,7 +928,7 @@ $tw.Wiki = function(options) {
|
||||
// Delete a tiddler
|
||||
this.deleteTiddler = function(title) {
|
||||
// Uncomment the following line for detailed logs of all tiddler deletions
|
||||
// console.log("Deleting",title,tiddler)
|
||||
// console.log("Deleting",title)
|
||||
if($tw.utils.hop(tiddlers,title)) {
|
||||
delete tiddlers[title];
|
||||
this.clearCache(title);
|
||||
@@ -1261,15 +1287,15 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/tids","tiddlerdeserializer",{
|
||||
for(var t=0; t<lines.length; t++) {
|
||||
var line = lines[t];
|
||||
if(line.charAt(0) !== "#") {
|
||||
var colonPos= line.indexOf(": ");
|
||||
var colonPos= line.indexOf(":");
|
||||
if(colonPos !== -1) {
|
||||
var tiddler = $tw.utils.extend(Object.create(null),fields);
|
||||
tiddler.title = (tiddler.title || "") + line.substr(0,colonPos);
|
||||
tiddler.title = (tiddler.title || "") + line.substr(0,colonPos).trim();
|
||||
if(titles.indexOf(tiddler.title) !== -1) {
|
||||
console.log("Warning: .multids file contains multiple definitions for " + tiddler.title);
|
||||
}
|
||||
titles.push(tiddler.title);
|
||||
tiddler.text = line.substr(colonPos + 2);
|
||||
tiddler.text = line.substr(colonPos + 2).trim();
|
||||
tiddlers.push(tiddler);
|
||||
}
|
||||
}
|
||||
@@ -1294,8 +1320,8 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/html","tiddlerdeserializer",{
|
||||
});
|
||||
$tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
|
||||
"application/json": function(text,fields) {
|
||||
var tiddlers = JSON.parse(text);
|
||||
return tiddlers;
|
||||
var data = JSON.parse(text);
|
||||
return $tw.utils.isArray(data) ? data : [data];
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1448,17 +1474,26 @@ $tw.loadTiddlersFromFile = function(filepath,fields) {
|
||||
typeInfo = type ? $tw.config.contentTypeInfo[type] : null,
|
||||
data = fs.readFileSync(filepath,typeInfo ? typeInfo.encoding : "utf8"),
|
||||
tiddlers = $tw.wiki.deserializeTiddlers(ext,data,fields),
|
||||
metafile = filepath + ".meta",
|
||||
metadata;
|
||||
if(ext !== ".json" && tiddlers.length === 1 && fs.existsSync(metafile)) {
|
||||
metadata = fs.readFileSync(metafile,"utf8");
|
||||
if(metadata) {
|
||||
tiddlers = [$tw.utils.parseFields(metadata,tiddlers[0])];
|
||||
}
|
||||
if(ext !== ".json" && tiddlers.length === 1) {
|
||||
metadata = $tw.loadMetadataForFile(filepath);
|
||||
tiddlers = [$tw.utils.extend({},tiddlers[0],metadata)];
|
||||
}
|
||||
return {filepath: filepath, type: type, tiddlers: tiddlers, hasMetaFile: !!metadata};
|
||||
};
|
||||
|
||||
/*
|
||||
Load the metadata fields in the .meta file corresponding to a particular file
|
||||
*/
|
||||
$tw.loadMetadataForFile = function(filepath) {
|
||||
var metafilename = filepath + ".meta";
|
||||
if(fs.existsSync(metafilename)) {
|
||||
return $tw.utils.parseFields(fs.readFileSync(metafilename,"utf8") || "");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
A default set of files for TiddlyWiki to ignore during load.
|
||||
This matches what NPM ignores, and adds "*.meta" to ignore tiddler
|
||||
@@ -1478,44 +1513,7 @@ $tw.loadTiddlersFromPath = function(filepath,excludeRegExp) {
|
||||
var files = fs.readdirSync(filepath);
|
||||
// Look for a tiddlywiki.files file
|
||||
if(files.indexOf("tiddlywiki.files") !== -1) {
|
||||
// If so, process the files it describes
|
||||
var filesInfo = JSON.parse(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"));
|
||||
// First the tiddlers
|
||||
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
|
||||
var type = tidInfo.fields.type || "text/plain",
|
||||
typeInfo = $tw.config.contentTypeInfo[type],
|
||||
pathname = path.resolve(filepath,tidInfo.file),
|
||||
text = fs.readFileSync(pathname,typeInfo ? typeInfo.encoding : "utf8");
|
||||
if(tidInfo.isTiddlerFile) {
|
||||
var fileTiddlers = $tw.wiki.deserializeTiddlers(path.extname(pathname),text) || [];
|
||||
$tw.utils.each(fileTiddlers,function(tiddler) {
|
||||
$tw.utils.extend(tiddler,tidInfo.fields);
|
||||
if(tidInfo.prefix) {
|
||||
tiddler.text = tidInfo.prefix + tiddler.text;
|
||||
}
|
||||
if(tidInfo.suffix) {
|
||||
tiddler.text = tiddler.text + tidInfo.suffix;
|
||||
}
|
||||
});
|
||||
tiddlers.push({tiddlers: fileTiddlers});
|
||||
} else {
|
||||
if(tidInfo.prefix) {
|
||||
text = tidInfo.prefix + text;
|
||||
}
|
||||
if(tidInfo.suffix) {
|
||||
text = text + tidInfo.suffix;
|
||||
}
|
||||
tidInfo.fields.text = text;
|
||||
tiddlers.push({tiddlers: [tidInfo.fields]});
|
||||
}
|
||||
});
|
||||
// Then any recursive directories
|
||||
$tw.utils.each(filesInfo.directories,function(dirPath) {
|
||||
var pathname = path.resolve(filepath,dirPath);
|
||||
if(fs.existsSync(pathname) && fs.statSync(pathname).isDirectory()) {
|
||||
tiddlers.push.apply(tiddlers,$tw.loadTiddlersFromPath(pathname,excludeRegExp));
|
||||
}
|
||||
});
|
||||
Array.prototype.push.apply(tiddlers,$tw.loadTiddlersFromSpecification(filepath,excludeRegExp));
|
||||
} else {
|
||||
// If not, read all the files in the directory
|
||||
$tw.utils.each(files,function(file) {
|
||||
@@ -1531,6 +1529,106 @@ $tw.loadTiddlersFromPath = function(filepath,excludeRegExp) {
|
||||
return tiddlers;
|
||||
};
|
||||
|
||||
/*
|
||||
Load all the tiddlers defined by a `tiddlywiki.files` specification file
|
||||
filepath: pathname of the directory containing the specification file
|
||||
*/
|
||||
$tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
var tiddlers = [];
|
||||
// Read the specification
|
||||
var filesInfo = JSON.parse(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"));
|
||||
// Helper to process a file
|
||||
var processFile = function(filename,isTiddlerFile,fields) {
|
||||
var extInfo = $tw.config.fileExtensionInfo[path.extname(filename)],
|
||||
type = (extInfo || {}).type || fields.type || "text/plain",
|
||||
typeInfo = $tw.config.contentTypeInfo[type] || {},
|
||||
pathname = path.resolve(filepath,filename),
|
||||
text = fs.readFileSync(pathname,typeInfo.encoding || "utf8"),
|
||||
metadata = $tw.loadMetadataForFile(pathname) || {},
|
||||
fileTiddlers;
|
||||
if(isTiddlerFile) {
|
||||
fileTiddlers = $tw.wiki.deserializeTiddlers(path.extname(pathname),text,metadata) || [];
|
||||
} else {
|
||||
fileTiddlers = [$tw.utils.extend({text: text},metadata)];
|
||||
}
|
||||
var combinedFields = $tw.utils.extend({},fields,metadata);
|
||||
$tw.utils.each(fileTiddlers,function(tiddler) {
|
||||
$tw.utils.each(combinedFields,function(fieldInfo,name) {
|
||||
if(typeof fieldInfo === "string" || $tw.utils.isArray(fieldInfo)) {
|
||||
tiddler[name] = fieldInfo;
|
||||
} else {
|
||||
var value = tiddler[name];
|
||||
switch(fieldInfo.source) {
|
||||
case "filename":
|
||||
value = path.basename(filename);
|
||||
break;
|
||||
case "filename-uri-decoded":
|
||||
value = decodeURIComponent(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)));
|
||||
break;
|
||||
case "extname":
|
||||
value = path.extname(filename);
|
||||
break;
|
||||
case "created":
|
||||
value = new Date(fs.statSync(pathname).birthtime);
|
||||
break;
|
||||
case "modified":
|
||||
value = new Date(fs.statSync(pathname).mtime);
|
||||
break;
|
||||
}
|
||||
if(fieldInfo.prefix) {
|
||||
value = fieldInfo.prefix + value;
|
||||
}
|
||||
if(fieldInfo.suffix) {
|
||||
value = value + fieldInfo.suffix;
|
||||
}
|
||||
tiddler[name] = value;
|
||||
}
|
||||
});
|
||||
});
|
||||
tiddlers.push({tiddlers: fileTiddlers});
|
||||
};
|
||||
// Process the listed tiddlers
|
||||
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
|
||||
if(tidInfo.prefix && tidInfo.suffix) {
|
||||
tidInfo.fields.text = {prefix: tidInfo.prefix,suffix: tidInfo.suffix};
|
||||
} else if(tidInfo.prefix) {
|
||||
tidInfo.fields.text = {prefix: tidInfo.prefix};
|
||||
} else if(tidInfo.suffix) {
|
||||
tidInfo.fields.text = {suffix: tidInfo.suffix};
|
||||
}
|
||||
processFile(tidInfo.file,tidInfo.isTiddlerFile,tidInfo.fields);
|
||||
});
|
||||
// Process any listed directories
|
||||
$tw.utils.each(filesInfo.directories,function(dirSpec) {
|
||||
// Read literal directories directly
|
||||
if(typeof dirSpec === "string") {
|
||||
var pathname = path.resolve(filepath,dirSpec);
|
||||
if(fs.existsSync(pathname) && fs.statSync(pathname).isDirectory()) {
|
||||
tiddlers.push.apply(tiddlers,$tw.loadTiddlersFromPath(pathname,excludeRegExp));
|
||||
}
|
||||
} else {
|
||||
// Process directory specifier
|
||||
var dirPath = path.resolve(filepath,dirSpec.path),
|
||||
files = fs.readdirSync(dirPath),
|
||||
fileRegExp = new RegExp(dirSpec.filesRegExp || "^.*$"),
|
||||
metaRegExp = /^.*\.meta$/;
|
||||
for(var t=0; t<files.length; t++) {
|
||||
var filename = files[t];
|
||||
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
||||
processFile(dirPath + path.sep + filename,dirSpec.isTiddlerFile,dirSpec.fields);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return tiddlers;
|
||||
};
|
||||
|
||||
/*
|
||||
Load the tiddlers from a plugin folder, and package them up into a proper JSON plugin tiddler
|
||||
*/
|
||||
@@ -1853,8 +1951,14 @@ $tw.boot.startup = function(options) {
|
||||
$tw.utils.registerFileType("video/mp4","base64",".mp4");
|
||||
$tw.utils.registerFileType("audio/mp3","base64",".mp3");
|
||||
$tw.utils.registerFileType("audio/mp4","base64",[".mp4",".m4a"]);
|
||||
$tw.utils.registerFileType("text/markdown","utf8",[".md",".markdown"],{deserializerType:"text/x-markdown"});
|
||||
$tw.utils.registerFileType("text/x-markdown","utf8",[".md",".markdown"]);
|
||||
$tw.utils.registerFileType("application/enex+xml","utf8",".enex");
|
||||
$tw.utils.registerFileType("application/enex+xml","utf8",".enex");
|
||||
$tw.utils.registerFileType("application/vnd.openxmlformats-officedocument.wordprocessingml.document","base64",".docx");
|
||||
$tw.utils.registerFileType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","base64",".xlsx");
|
||||
$tw.utils.registerFileType("application/vnd.openxmlformats-officedocument.presentationml.presentation","base64",".pptx");
|
||||
$tw.utils.registerFileType("application/x-bibtex","utf8",".bib");
|
||||
$tw.utils.registerFileType("application/epub+zip","base64",".epub");
|
||||
// Create the wiki store for the app
|
||||
$tw.wiki = new $tw.Wiki();
|
||||
// Install built in tiddler fields modules
|
||||
@@ -2041,13 +2145,14 @@ $tw.hooks.addHook = function(hookName,definition) {
|
||||
/*
|
||||
Invoke the hook by key
|
||||
*/
|
||||
$tw.hooks.invokeHook = function(hookName, value) {
|
||||
$tw.hooks.invokeHook = function(hookName /*, value,... */) {
|
||||
var args = Array.prototype.slice.call(arguments,1);
|
||||
if($tw.utils.hop($tw.hooks.names,hookName)) {
|
||||
for (var i = 0; i < $tw.hooks.names[hookName].length; i++) {
|
||||
value = $tw.hooks.names[hookName][i](value);
|
||||
args[0] = $tw.hooks.names[hookName][i].apply(null,args);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
return args[0];
|
||||
};
|
||||
|
||||
/////////////////////////// Main boot function to decrypt tiddlers and then startup
|
||||
|
||||
100
boot/sjcl.js
100
boot/sjcl.js
@@ -1,42 +1,60 @@
|
||||
"use strict";var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a},notReady:function(a){this.toString=function(){return"NOT READY: "+this.message};this.message=a}}};
|
||||
if(typeof module!="undefined"&&module.exports)module.exports=sjcl;
|
||||
sjcl.cipher.aes=function(a){this.h[0][0][0]||this.z();var b,c,d,e,f=this.h[0][4],g=this.h[1];b=a.length;var h=1;if(b!==4&&b!==6&&b!==8)throw new sjcl.exception.invalid("invalid aes key size");this.a=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(a%b===0||b===8&&a%b===4){c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255];if(a%b===0){c=c<<8^c>>>24^h<<24;h=h<<1^(h>>7)*283}}d[a]=d[a-b]^c}for(b=0;a;b++,a--){c=d[b&3?a:a-4];e[b]=a<=4||b<4?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^
|
||||
g[3][f[c&255]]}};
|
||||
sjcl.cipher.aes.prototype={encrypt:function(a){return this.I(a,0)},decrypt:function(a){return this.I(a,1)},h:[[[],[],[],[],[]],[[],[],[],[],[]]],z:function(){var a=this.h[0],b=this.h[1],c=a[4],d=b[4],e,f,g,h=[],i=[],k,j,l,m;for(e=0;e<0x100;e++)i[(h[e]=e<<1^(e>>7)*283)^e]=e;for(f=g=0;!c[f];f^=k||1,g=i[g]||1){l=g^g<<1^g<<2^g<<3^g<<4;l=l>>8^l&255^99;c[f]=l;d[l]=f;j=h[e=h[k=h[f]]];m=j*0x1010101^e*0x10001^k*0x101^f*0x1010100;j=h[l]*0x101^l*0x1010100;for(e=0;e<4;e++){a[e][f]=j=j<<24^j>>>8;b[e][l]=m=m<<24^m>>>8}}for(e=
|
||||
0;e<5;e++){a[e]=a[e].slice(0);b[e]=b[e].slice(0)}},I:function(a,b){if(a.length!==4)throw new sjcl.exception.invalid("invalid aes block size");var c=this.a[b],d=a[0]^c[0],e=a[b?3:1]^c[1],f=a[2]^c[2];a=a[b?1:3]^c[3];var g,h,i,k=c.length/4-2,j,l=4,m=[0,0,0,0];g=this.h[b];var n=g[0],o=g[1],p=g[2],q=g[3],r=g[4];for(j=0;j<k;j++){g=n[d>>>24]^o[e>>16&255]^p[f>>8&255]^q[a&255]^c[l];h=n[e>>>24]^o[f>>16&255]^p[a>>8&255]^q[d&255]^c[l+1];i=n[f>>>24]^o[a>>16&255]^p[d>>8&255]^q[e&255]^c[l+2];a=n[a>>>24]^o[d>>16&
|
||||
255]^p[e>>8&255]^q[f&255]^c[l+3];l+=4;d=g;e=h;f=i}for(j=0;j<4;j++){m[b?3&-j:j]=r[d>>>24]<<24^r[e>>16&255]<<16^r[f>>8&255]<<8^r[a&255]^c[l++];g=d;d=e;e=f;f=a;a=g}return m}};
|
||||
sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.P(a.slice(b/32),32-(b&31)).slice(1);return c===undefined?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<<c)-1},concat:function(a,b){if(a.length===0||b.length===0)return a.concat(b);var c=a[a.length-1],d=sjcl.bitArray.getPartial(c);return d===32?a.concat(b):sjcl.bitArray.P(b,d,c|0,a.slice(0,a.length-1))},bitLength:function(a){var b=a.length;
|
||||
if(b===0)return 0;return(b-1)*32+sjcl.bitArray.getPartial(a[b-1])},clamp:function(a,b){if(a.length*32<b)return a;a=a.slice(0,Math.ceil(b/32));var c=a.length;b&=31;if(c>0&&b)a[c-1]=sjcl.bitArray.partial(b,a[c-1]&2147483648>>b-1,1);return a},partial:function(a,b,c){if(a===32)return b;return(c?b|0:b<<32-a)+a*0x10000000000},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return false;var c=0,d;for(d=0;d<a.length;d++)c|=
|
||||
a[d]^b[d];return c===0},P:function(a,b,c,d){var e;e=0;if(d===undefined)d=[];for(;b>=32;b-=32){d.push(c);c=0}if(b===0)return d.concat(a);for(e=0;e<a.length;e++){d.push(c|a[e]>>>b);c=a[e]<<32-b}e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,b+a>32?c:d.pop(),1));return d},k:function(a,b){return[a[0]^b[0],a[1]^b[1],a[2]^b[2],a[3]^b[3]]}};
|
||||
sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d<c/8;d++){if((d&3)===0)e=a[d/4];b+=String.fromCharCode(e>>>24);e<<=8}return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c<a.length;c++){d=d<<8|a.charCodeAt(c);if((c&3)===3){b.push(d);d=0}}c&3&&b.push(sjcl.bitArray.partial(8*(c&3),d));return b}};
|
||||
sjcl.codec.hex={fromBits:function(a){var b="",c;for(c=0;c<a.length;c++)b+=((a[c]|0)+0xf00000000000).toString(16).substr(4);return b.substr(0,sjcl.bitArray.bitLength(a)/4)},toBits:function(a){var b,c=[],d;a=a.replace(/\s|0x/g,"");d=a.length;a+="00000000";for(b=0;b<a.length;b+=8)c.push(parseInt(a.substr(b,8),16)^0);return sjcl.bitArray.clamp(c,d*4)}};
|
||||
sjcl.codec.base64={F:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fromBits:function(a,b,c){var d="",e=0,f=sjcl.codec.base64.F,g=0,h=sjcl.bitArray.bitLength(a);if(c)f=f.substr(0,62)+"-_";for(c=0;d.length*6<h;){d+=f.charAt((g^a[c]>>>e)>>>26);if(e<6){g=a[c]<<6-e;e+=26;c++}else{g<<=6;e-=6}}for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d=0,e=sjcl.codec.base64.F,f=0,g;if(b)e=e.substr(0,62)+"-_";for(b=0;b<a.length;b++){g=e.indexOf(a.charAt(b));
|
||||
if(g<0)throw new sjcl.exception.invalid("this isn't base64!");if(d>26){d-=26;c.push(f^g>>>d);f=g<<32-d}else{d+=6;f^=g<<32-d}}d&56&&c.push(sjcl.bitArray.partial(d&56,f,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.a[0]||this.z();if(a){this.n=a.n.slice(0);this.i=a.i.slice(0);this.e=a.e}else this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};
|
||||
sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.n=this.N.slice(0);this.i=[];this.e=0;return this},update:function(a){if(typeof a==="string")a=sjcl.codec.utf8String.toBits(a);var b,c=this.i=sjcl.bitArray.concat(this.i,a);b=this.e;a=this.e=b+sjcl.bitArray.bitLength(a);for(b=512+b&-512;b<=a;b+=512)this.D(c.splice(0,16));return this},finalize:function(){var a,b=this.i,c=this.n;b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.e/
|
||||
4294967296));for(b.push(this.e|0);b.length;)this.D(b.splice(0,16));this.reset();return c},N:[],a:[],z:function(){function a(e){return(e-Math.floor(e))*0x100000000|0}var b=0,c=2,d;a:for(;b<64;c++){for(d=2;d*d<=c;d++)if(c%d===0)continue a;if(b<8)this.N[b]=a(Math.pow(c,0.5));this.a[b]=a(Math.pow(c,1/3));b++}},D:function(a){var b,c,d=a.slice(0),e=this.n,f=this.a,g=e[0],h=e[1],i=e[2],k=e[3],j=e[4],l=e[5],m=e[6],n=e[7];for(a=0;a<64;a++){if(a<16)b=d[a];else{b=d[a+1&15];c=d[a+14&15];b=d[a&15]=(b>>>7^b>>>18^
|
||||
b>>>3^b<<25^b<<14)+(c>>>17^c>>>19^c>>>10^c<<15^c<<13)+d[a&15]+d[a+9&15]|0}b=b+n+(j>>>6^j>>>11^j>>>25^j<<26^j<<21^j<<7)+(m^j&(l^m))+f[a];n=m;m=l;l=j;j=k+b|0;k=i;i=h;h=g;g=b+(h&i^k&(h^i))+(h>>>2^h>>>13^h>>>22^h<<30^h<<19^h<<10)|0}e[0]=e[0]+g|0;e[1]=e[1]+h|0;e[2]=e[2]+i|0;e[3]=e[3]+k|0;e[4]=e[4]+j|0;e[5]=e[5]+l|0;e[6]=e[6]+m|0;e[7]=e[7]+n|0}};
|
||||
sjcl.mode.ccm={name:"ccm",encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,i=h.bitLength(c)/8,k=h.bitLength(g)/8;e=e||64;d=d||[];if(i<7)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;f<4&&k>>>8*f;f++);if(f<15-i)f=15-i;c=h.clamp(c,8*(15-f));b=sjcl.mode.ccm.H(a,b,c,d,e,f);g=sjcl.mode.ccm.J(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),i=f.clamp(b,h-e),k=f.bitSlice(b,
|
||||
h-e);h=(h-e)/8;if(g<7)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;b<4&&h>>>8*b;b++);if(b<15-g)b=15-g;c=f.clamp(c,8*(15-b));i=sjcl.mode.ccm.J(a,i,c,k,e,b);a=sjcl.mode.ccm.H(a,i.data,c,d,e,b);if(!f.equal(i.tag,a))throw new sjcl.exception.corrupt("ccm: tag doesn't match");return i.data},H:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,i=h.k;e/=8;if(e%2||e<4||e>16)throw new sjcl.exception.invalid("ccm: invalid tag length");if(d.length>0xffffffff||b.length>0xffffffff)throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data");
|
||||
f=[h.partial(8,(d.length?64:0)|e-2<<2|f-1)];f=h.concat(f,c);f[3]|=h.bitLength(b)/8;f=a.encrypt(f);if(d.length){c=h.bitLength(d)/8;if(c<=65279)g=[h.partial(16,c)];else if(c<=0xffffffff)g=h.concat([h.partial(16,65534)],[c]);g=h.concat(g,d);for(d=0;d<g.length;d+=4)f=a.encrypt(i(f,g.slice(d,d+4).concat([0,0,0])))}for(d=0;d<b.length;d+=4)f=a.encrypt(i(f,b.slice(d,d+4).concat([0,0,0])));return h.clamp(f,e*8)},J:function(a,b,c,d,e,f){var g,h=sjcl.bitArray;g=h.k;var i=b.length,k=h.bitLength(b);c=h.concat([h.partial(8,
|
||||
f-1)],c).concat([0,0,0]).slice(0,4);d=h.bitSlice(g(d,a.encrypt(c)),0,e);if(!i)return{tag:d,data:[]};for(g=0;g<i;g+=4){c[3]++;e=a.encrypt(c);b[g]^=e[0];b[g+1]^=e[1];b[g+2]^=e[2];b[g+3]^=e[3]}return{tag:d,data:h.clamp(b,k)}}};
|
||||
sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){if(sjcl.bitArray.bitLength(c)!==128)throw new sjcl.exception.invalid("ocb iv must be 128 bits");var g,h=sjcl.mode.ocb2.B,i=sjcl.bitArray,k=i.k,j=[0,0,0,0];c=h(a.encrypt(c));var l,m=[];d=d||[];e=e||64;for(g=0;g+4<b.length;g+=4){l=b.slice(g,g+4);j=k(j,l);m=m.concat(k(c,a.encrypt(k(c,l))));c=h(c)}l=b.slice(g);b=i.bitLength(l);g=a.encrypt(k(c,[0,0,0,b]));l=i.clamp(k(l.concat([0,0,0]),g),b);j=k(j,k(l.concat([0,0,0]),g));j=a.encrypt(k(j,k(c,h(c))));
|
||||
if(d.length)j=k(j,f?d:sjcl.mode.ocb2.pmac(a,d));return m.concat(i.concat(l,i.clamp(j,e)))},decrypt:function(a,b,c,d,e,f){if(sjcl.bitArray.bitLength(c)!==128)throw new sjcl.exception.invalid("ocb iv must be 128 bits");e=e||64;var g=sjcl.mode.ocb2.B,h=sjcl.bitArray,i=h.k,k=[0,0,0,0],j=g(a.encrypt(c)),l,m,n=sjcl.bitArray.bitLength(b)-e,o=[];d=d||[];for(c=0;c+4<n/32;c+=4){l=i(j,a.decrypt(i(j,b.slice(c,c+4))));k=i(k,l);o=o.concat(l);j=g(j)}m=n-c*32;l=a.encrypt(i(j,[0,0,0,m]));l=i(l,h.clamp(b.slice(c),
|
||||
m).concat([0,0,0]));k=i(k,l);k=a.encrypt(i(k,i(j,g(j))));if(d.length)k=i(k,f?d:sjcl.mode.ocb2.pmac(a,d));if(!h.equal(h.clamp(k,e),h.bitSlice(b,n)))throw new sjcl.exception.corrupt("ocb: tag doesn't match");return o.concat(h.clamp(l,m))},pmac:function(a,b){var c,d=sjcl.mode.ocb2.B,e=sjcl.bitArray,f=e.k,g=[0,0,0,0],h=a.encrypt([0,0,0,0]);h=f(h,d(d(h)));for(c=0;c+4<b.length;c+=4){h=d(h);g=f(g,a.encrypt(f(h,b.slice(c,c+4))))}b=b.slice(c);if(e.bitLength(b)<128){h=f(h,d(h));b=e.concat(b,[2147483648|0,0,
|
||||
0,0])}g=f(g,b);return a.encrypt(f(d(f(h,d(h))),g))},B:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^(a[0]>>>31)*135]}};sjcl.misc.hmac=function(a,b){this.M=b=b||sjcl.hash.sha256;var c=[[],[]],d=b.prototype.blockSize/32;this.l=[new b,new b];if(a.length>d)a=b.hash(a);for(b=0;b<d;b++){c[0][b]=a[b]^909522486;c[1][b]=a[b]^1549556828}this.l[0].update(c[0]);this.l[1].update(c[1])};
|
||||
sjcl.misc.hmac.prototype.encrypt=sjcl.misc.hmac.prototype.mac=function(a,b){a=(new this.M(this.l[0])).update(a,b).finalize();return(new this.M(this.l[1])).update(a).finalize()};
|
||||
sjcl.misc.pbkdf2=function(a,b,c,d,e){c=c||1E3;if(d<0||c<0)throw sjcl.exception.invalid("invalid params to pbkdf2");if(typeof a==="string")a=sjcl.codec.utf8String.toBits(a);e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,i,k=[],j=sjcl.bitArray;for(i=1;32*k.length<(d||1);i++){e=f=a.encrypt(j.concat(b,[i]));for(g=1;g<c;g++){f=a.encrypt(f);for(h=0;h<f.length;h++)e[h]^=f[h]}k=k.concat(e)}if(d)k=j.clamp(k,d);return k};
|
||||
sjcl.random={randomWords:function(a,b){var c=[];b=this.isReady(b);var d;if(b===0)throw new sjcl.exception.notReady("generator isn't seeded");else b&2&&this.U(!(b&1));for(b=0;b<a;b+=4){(b+1)%0x10000===0&&this.L();d=this.w();c.push(d[0],d[1],d[2],d[3])}this.L();return c.slice(0,a)},setDefaultParanoia:function(a){this.t=a},addEntropy:function(a,b,c){c=c||"user";var d,e,f=(new Date).valueOf(),g=this.q[c],h=this.isReady(),i=0;d=this.G[c];if(d===undefined)d=this.G[c]=this.R++;if(g===undefined)g=this.q[c]=
|
||||
0;this.q[c]=(this.q[c]+1)%this.b.length;switch(typeof a){case "number":if(b===undefined)b=1;this.b[g].update([d,this.u++,1,b,f,1,a|0]);break;case "object":c=Object.prototype.toString.call(a);if(c==="[object Uint32Array]"){e=[];for(c=0;c<a.length;c++)e.push(a[c]);a=e}else{if(c!=="[object Array]")i=1;for(c=0;c<a.length&&!i;c++)if(typeof a[c]!="number")i=1}if(!i){if(b===undefined)for(c=b=0;c<a.length;c++)for(e=a[c];e>0;){b++;e>>>=1}this.b[g].update([d,this.u++,2,b,f,a.length].concat(a))}break;case "string":if(b===
|
||||
undefined)b=a.length;this.b[g].update([d,this.u++,3,b,f,a.length]);this.b[g].update(a);break;default:i=1}if(i)throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");this.j[g]+=b;this.f+=b;if(h===0){this.isReady()!==0&&this.K("seeded",Math.max(this.g,this.f));this.K("progress",this.getProgress())}},isReady:function(a){a=this.C[a!==undefined?a:this.t];return this.g&&this.g>=a?this.j[0]>80&&(new Date).valueOf()>this.O?3:1:this.f>=a?2:0},getProgress:function(a){a=
|
||||
this.C[a?a:this.t];return this.g>=a?1:this.f>a?1:this.f/a},startCollectors:function(){if(!this.m){if(window.addEventListener){window.addEventListener("load",this.o,false);window.addEventListener("mousemove",this.p,false)}else if(document.attachEvent){document.attachEvent("onload",this.o);document.attachEvent("onmousemove",this.p)}else throw new sjcl.exception.bug("can't attach event");this.m=true}},stopCollectors:function(){if(this.m){if(window.removeEventListener){window.removeEventListener("load",
|
||||
this.o,false);window.removeEventListener("mousemove",this.p,false)}else if(window.detachEvent){window.detachEvent("onload",this.o);window.detachEvent("onmousemove",this.p)}this.m=false}},addEventListener:function(a,b){this.r[a][this.Q++]=b},removeEventListener:function(a,b){var c;a=this.r[a];var d=[];for(c in a)a.hasOwnProperty(c)&&a[c]===b&&d.push(c);for(b=0;b<d.length;b++){c=d[b];delete a[c]}},b:[new sjcl.hash.sha256],j:[0],A:0,q:{},u:0,G:{},R:0,g:0,f:0,O:0,a:[0,0,0,0,0,0,0,0],d:[0,0,0,0],s:undefined,
|
||||
t:6,m:false,r:{progress:{},seeded:{}},Q:0,C:[0,48,64,96,128,192,0x100,384,512,768,1024],w:function(){for(var a=0;a<4;a++){this.d[a]=this.d[a]+1|0;if(this.d[a])break}return this.s.encrypt(this.d)},L:function(){this.a=this.w().concat(this.w());this.s=new sjcl.cipher.aes(this.a)},T:function(a){this.a=sjcl.hash.sha256.hash(this.a.concat(a));this.s=new sjcl.cipher.aes(this.a);for(a=0;a<4;a++){this.d[a]=this.d[a]+1|0;if(this.d[a])break}},U:function(a){var b=[],c=0,d;this.O=b[0]=(new Date).valueOf()+3E4;for(d=
|
||||
0;d<16;d++)b.push(Math.random()*0x100000000|0);for(d=0;d<this.b.length;d++){b=b.concat(this.b[d].finalize());c+=this.j[d];this.j[d]=0;if(!a&&this.A&1<<d)break}if(this.A>=1<<this.b.length){this.b.push(new sjcl.hash.sha256);this.j.push(0)}this.f-=c;if(c>this.g)this.g=c;this.A++;this.T(b)},p:function(a){sjcl.random.addEntropy([a.x||a.clientX||a.offsetX||0,a.y||a.clientY||a.offsetY||0],2,"mouse")},o:function(){sjcl.random.addEntropy((new Date).valueOf(),2,"loadtime")},K:function(a,b){var c;a=sjcl.random.r[a];
|
||||
var d=[];for(c in a)a.hasOwnProperty(c)&&d.push(a[c]);for(c=0;c<d.length;c++)d[c](b)}};try{var s=new Uint32Array(32);crypto.getRandomValues(s);sjcl.random.addEntropy(s,1024,"crypto['getRandomValues']")}catch(t){}
|
||||
sjcl.json={defaults:{v:1,iter:1E3,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},encrypt:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.c({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.c(f,c);c=f.adata;if(typeof f.salt==="string")f.salt=sjcl.codec.base64.toBits(f.salt);if(typeof f.iv==="string")f.iv=sjcl.codec.base64.toBits(f.iv);if(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||typeof a==="string"&&f.iter<=100||f.ts!==64&&f.ts!==96&&f.ts!==128||f.ks!==128&&f.ks!==192&&f.ks!==0x100||f.iv.length<
|
||||
2||f.iv.length>4)throw new sjcl.exception.invalid("json encrypt: invalid parameters");if(typeof a==="string"){g=sjcl.misc.cachedPbkdf2(a,f);a=g.key.slice(0,f.ks/32);f.salt=g.salt}if(typeof b==="string")b=sjcl.codec.utf8String.toBits(b);if(typeof c==="string")c=sjcl.codec.utf8String.toBits(c);g=new sjcl.cipher[f.cipher](a);e.c(d,f);d.key=a;f.ct=sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return e.encode(f)},decrypt:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.c(e.c(e.c({},e.defaults),e.decode(b)),
|
||||
c,true);var f;c=b.adata;if(typeof b.salt==="string")b.salt=sjcl.codec.base64.toBits(b.salt);if(typeof b.iv==="string")b.iv=sjcl.codec.base64.toBits(b.iv);if(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||typeof a==="string"&&b.iter<=100||b.ts!==64&&b.ts!==96&&b.ts!==128||b.ks!==128&&b.ks!==192&&b.ks!==0x100||!b.iv||b.iv.length<2||b.iv.length>4)throw new sjcl.exception.invalid("json decrypt: invalid parameters");if(typeof a==="string"){f=sjcl.misc.cachedPbkdf2(a,b);a=f.key.slice(0,b.ks/32);b.salt=f.salt}if(typeof c===
|
||||
"string")c=sjcl.codec.utf8String.toBits(c);f=new sjcl.cipher[b.cipher](a);c=sjcl.mode[b.mode].decrypt(f,b.ct,b.iv,c,b.ts);e.c(d,b);d.key=a;return sjcl.codec.utf8String.fromBits(c)},encode:function(a){var b,c="{",d="";for(b in a)if(a.hasOwnProperty(b)){if(!b.match(/^[a-z0-9]+$/i))throw new sjcl.exception.invalid("json encode: invalid property name");c+=d+'"'+b+'":';d=",";switch(typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';break;case "object":c+='"'+
|
||||
sjcl.codec.base64.fromBits(a[b],1)+'"';break;default:throw new sjcl.exception.bug("json encode: unsupported type");}}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");if(!a.match(/^\{.*\}$/))throw new sjcl.exception.invalid("json decode: this isn't json!");a=a.replace(/^\{|\}$/g,"").split(/,/);var b={},c,d;for(c=0;c<a.length;c++){if(!(d=a[c].match(/^(?:(["']?)([a-z][a-z0-9]*)\1):(?:(\d+)|"([a-z0-9+\/%*_.@=\-]*)")$/i)))throw new sjcl.exception.invalid("json decode: this isn't json!");b[d[2]]=
|
||||
d[3]?parseInt(d[3],10):d[2].match(/^(ct|salt|iv)$/)?sjcl.codec.base64.toBits(d[4]):unescape(d[4])}return b},c:function(a,b,c){if(a===undefined)a={};if(b===undefined)return a;var d;for(d in b)if(b.hasOwnProperty(d)){if(c&&a[d]!==undefined&&a[d]!==b[d])throw new sjcl.exception.invalid("required parameter overridden");a[d]=b[d]}return a},W:function(a,b){var c={},d;for(d in a)if(a.hasOwnProperty(d)&&a[d]!==b[d])c[d]=a[d];return c},V:function(a,b){var c={},d;for(d=0;d<b.length;d++)if(a[b[d]]!==undefined)c[b[d]]=
|
||||
a[b[d]];return c}};sjcl.encrypt=sjcl.json.encrypt;sjcl.decrypt=sjcl.json.decrypt;sjcl.misc.S={};sjcl.misc.cachedPbkdf2=function(a,b){var c=sjcl.misc.S,d;b=b||{};d=b.iter||1E3;c=c[a]=c[a]||{};d=c[d]=c[d]||{firstSalt:b.salt&&b.salt.length?b.salt.slice(0):sjcl.random.randomWords(2,0)};c=b.salt===undefined?d.firstSalt:b.salt;d[c]=d[c]||sjcl.misc.pbkdf2(a,c,b.iter);return{key:d[c].slice(0),salt:c.slice(0)}};
|
||||
sjcl.cipher.aes=function(a){this.s[0][0][0]||this.O();var b,c,d,e,f=this.s[0][4],g=this.s[1];b=a.length;var h=1;if(4!==b&&6!==b&&8!==b)throw new sjcl.exception.invalid("invalid aes key size");this.b=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(0===a%b||8===b&&4===a%b)c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255],0===a%b&&(c=c<<8^c>>>24^h<<24,h=h<<1^283*(h>>7));d[a]=d[a-b]^c}for(b=0;a;b++,a--)c=d[b&3?a:a-4],e[b]=4>=a||4>b?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^g[3][f[c&
|
||||
255]]};
|
||||
sjcl.cipher.aes.prototype={encrypt:function(a){return t(this,a,0)},decrypt:function(a){return t(this,a,1)},s:[[[],[],[],[],[]],[[],[],[],[],[]]],O:function(){var a=this.s[0],b=this.s[1],c=a[4],d=b[4],e,f,g,h=[],k=[],l,n,m,p;for(e=0;0x100>e;e++)k[(h[e]=e<<1^283*(e>>7))^e]=e;for(f=g=0;!c[f];f^=l||1,g=k[g]||1)for(m=g^g<<1^g<<2^g<<3^g<<4,m=m>>8^m&255^99,c[f]=m,d[m]=f,n=h[e=h[l=h[f]]],p=0x1010101*n^0x10001*e^0x101*l^0x1010100*f,n=0x101*h[m]^0x1010100*m,e=0;4>e;e++)a[e][f]=n=n<<24^n>>>8,b[e][m]=p=p<<24^p>>>8;for(e=
|
||||
0;5>e;e++)a[e]=a[e].slice(0),b[e]=b[e].slice(0)}};
|
||||
function t(a,b,c){if(4!==b.length)throw new sjcl.exception.invalid("invalid aes block size");var d=a.b[c],e=b[0]^d[0],f=b[c?3:1]^d[1],g=b[2]^d[2];b=b[c?1:3]^d[3];var h,k,l,n=d.length/4-2,m,p=4,r=[0,0,0,0];h=a.s[c];a=h[0];var q=h[1],v=h[2],w=h[3],x=h[4];for(m=0;m<n;m++)h=a[e>>>24]^q[f>>16&255]^v[g>>8&255]^w[b&255]^d[p],k=a[f>>>24]^q[g>>16&255]^v[b>>8&255]^w[e&255]^d[p+1],l=a[g>>>24]^q[b>>16&255]^v[e>>8&255]^w[f&255]^d[p+2],b=a[b>>>24]^q[e>>16&255]^v[f>>8&255]^w[g&255]^d[p+3],p+=4,e=h,f=k,g=l;for(m=
|
||||
0;4>m;m++)r[c?3&-m:m]=x[e>>>24]<<24^x[f>>16&255]<<16^x[g>>8&255]<<8^x[b&255]^d[p++],h=e,e=f,f=g,g=b,b=h;return r}
|
||||
sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.$(a.slice(b/32),32-(b&31)).slice(1);return void 0===c?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<<c)-1},concat:function(a,b){if(0===a.length||0===b.length)return a.concat(b);var c=a[a.length-1],d=sjcl.bitArray.getPartial(c);return 32===d?a.concat(b):sjcl.bitArray.$(b,d,c|0,a.slice(0,a.length-1))},bitLength:function(a){var b=a.length;return 0===
|
||||
b?0:32*(b-1)+sjcl.bitArray.getPartial(a[b-1])},clamp:function(a,b){if(32*a.length<b)return a;a=a.slice(0,Math.ceil(b/32));var c=a.length;b=b&31;0<c&&b&&(a[c-1]=sjcl.bitArray.partial(b,a[c-1]&2147483648>>b-1,1));return a},partial:function(a,b,c){return 32===a?b:(c?b|0:b<<32-a)+0x10000000000*a},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return!1;var c=0,d;for(d=0;d<a.length;d++)c|=a[d]^b[d];return 0===
|
||||
c},$:function(a,b,c,d){var e;e=0;for(void 0===d&&(d=[]);32<=b;b-=32)d.push(c),c=0;if(0===b)return d.concat(a);for(e=0;e<a.length;e++)d.push(c|a[e]>>>b),c=a[e]<<32-b;e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,32<b+a?c:d.pop(),1));return d},i:function(a,b){return[a[0]^b[0],a[1]^b[1],a[2]^b[2],a[3]^b[3]]},byteswapM:function(a){var b,c;for(b=0;b<a.length;++b)c=a[b],a[b]=c>>>24|c>>>8&0xff00|(c&0xff00)<<8|c<<24;return a}};
|
||||
sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d<c/8;d++)0===(d&3)&&(e=a[d/4]),b+=String.fromCharCode(e>>>24),e<<=8;return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c<a.length;c++)d=d<<8|a.charCodeAt(c),3===(c&3)&&(b.push(d),d=0);c&3&&b.push(sjcl.bitArray.partial(8*(c&3),d));return b}};
|
||||
sjcl.codec.hex={fromBits:function(a){var b="",c;for(c=0;c<a.length;c++)b+=((a[c]|0)+0xf00000000000).toString(16).substr(4);return b.substr(0,sjcl.bitArray.bitLength(a)/4)},toBits:function(a){var b,c=[],d;a=a.replace(/\s|0x/g,"");d=a.length;a=a+"00000000";for(b=0;b<a.length;b+=8)c.push(parseInt(a.substr(b,8),16)^0);return sjcl.bitArray.clamp(c,4*d)}};
|
||||
sjcl.codec.base32={B:"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",X:"0123456789ABCDEFGHIJKLMNOPQRSTUV",BITS:32,BASE:5,REMAINING:27,fromBits:function(a,b,c){var d=sjcl.codec.base32.BASE,e=sjcl.codec.base32.REMAINING,f="",g=0,h=sjcl.codec.base32.B,k=0,l=sjcl.bitArray.bitLength(a);c&&(h=sjcl.codec.base32.X);for(c=0;f.length*d<l;)f+=h.charAt((k^a[c]>>>g)>>>e),g<d?(k=a[c]<<d-g,g+=e,c++):(k<<=d,g-=d);for(;f.length&7&&!b;)f+="=";return f},toBits:function(a,b){a=a.replace(/\s|=/g,"").toUpperCase();var c=sjcl.codec.base32.BITS,
|
||||
d=sjcl.codec.base32.BASE,e=sjcl.codec.base32.REMAINING,f=[],g,h=0,k=sjcl.codec.base32.B,l=0,n,m="base32";b&&(k=sjcl.codec.base32.X,m="base32hex");for(g=0;g<a.length;g++){n=k.indexOf(a.charAt(g));if(0>n){if(!b)try{return sjcl.codec.base32hex.toBits(a)}catch(p){}throw new sjcl.exception.invalid("this isn't "+m+"!");}h>e?(h-=e,f.push(l^n>>>h),l=n<<c-h):(h+=d,l^=n<<c-h)}h&56&&f.push(sjcl.bitArray.partial(h&56,l,1));return f}};
|
||||
sjcl.codec.base32hex={fromBits:function(a,b){return sjcl.codec.base32.fromBits(a,b,1)},toBits:function(a){return sjcl.codec.base32.toBits(a,1)}};
|
||||
sjcl.codec.base64={B:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fromBits:function(a,b,c){var d="",e=0,f=sjcl.codec.base64.B,g=0,h=sjcl.bitArray.bitLength(a);c&&(f=f.substr(0,62)+"-_");for(c=0;6*d.length<h;)d+=f.charAt((g^a[c]>>>e)>>>26),6>e?(g=a[c]<<6-e,e+=26,c++):(g<<=6,e-=6);for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d,e=0,f=sjcl.codec.base64.B,g=0,h;b&&(f=f.substr(0,62)+"-_");for(d=0;d<a.length;d++){h=f.indexOf(a.charAt(d));
|
||||
if(0>h)throw new sjcl.exception.invalid("this isn't base64!");26<e?(e-=26,c.push(g^h>>>e),g=h<<32-e):(e+=6,g^=h<<32-e)}e&56&&c.push(sjcl.bitArray.partial(e&56,g,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.b[0]||this.O();a?(this.F=a.F.slice(0),this.A=a.A.slice(0),this.l=a.l):this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};
|
||||
sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.F=this.Y.slice(0);this.A=[];this.l=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.A=sjcl.bitArray.concat(this.A,a);b=this.l;a=this.l=b+sjcl.bitArray.bitLength(a);if(0x1fffffffffffff<a)throw new sjcl.exception.invalid("Cannot hash more than 2^53 - 1 bits");if("undefined"!==typeof Uint32Array){var d=new Uint32Array(c),e=0;for(b=512+b-(512+b&0x1ff);b<=a;b+=512)u(this,d.subarray(16*e,
|
||||
16*(e+1))),e+=1;c.splice(0,16*e)}else for(b=512+b-(512+b&0x1ff);b<=a;b+=512)u(this,c.splice(0,16));return this},finalize:function(){var a,b=this.A,c=this.F,b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.l/0x100000000));for(b.push(this.l|0);b.length;)u(this,b.splice(0,16));this.reset();return c},Y:[],b:[],O:function(){function a(a){return 0x100000000*(a-Math.floor(a))|0}for(var b=0,c=2,d,e;64>b;c++){e=!0;for(d=2;d*d<=c;d++)if(0===c%d){e=
|
||||
!1;break}e&&(8>b&&(this.Y[b]=a(Math.pow(c,.5))),this.b[b]=a(Math.pow(c,1/3)),b++)}}};
|
||||
function u(a,b){var c,d,e,f=a.F,g=a.b,h=f[0],k=f[1],l=f[2],n=f[3],m=f[4],p=f[5],r=f[6],q=f[7];for(c=0;64>c;c++)16>c?d=b[c]:(d=b[c+1&15],e=b[c+14&15],d=b[c&15]=(d>>>7^d>>>18^d>>>3^d<<25^d<<14)+(e>>>17^e>>>19^e>>>10^e<<15^e<<13)+b[c&15]+b[c+9&15]|0),d=d+q+(m>>>6^m>>>11^m>>>25^m<<26^m<<21^m<<7)+(r^m&(p^r))+g[c],q=r,r=p,p=m,m=n+d|0,n=l,l=k,k=h,h=d+(k&l^n&(k^l))+(k>>>2^k>>>13^k>>>22^k<<30^k<<19^k<<10)|0;f[0]=f[0]+h|0;f[1]=f[1]+k|0;f[2]=f[2]+l|0;f[3]=f[3]+n|0;f[4]=f[4]+m|0;f[5]=f[5]+p|0;f[6]=f[6]+r|0;f[7]=
|
||||
f[7]+q|0}
|
||||
sjcl.mode.ccm={name:"ccm",G:[],listenProgress:function(a){sjcl.mode.ccm.G.push(a)},unListenProgress:function(a){a=sjcl.mode.ccm.G.indexOf(a);-1<a&&sjcl.mode.ccm.G.splice(a,1)},fa:function(a){var b=sjcl.mode.ccm.G.slice(),c;for(c=0;c<b.length;c+=1)b[c](a)},encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,k=h.bitLength(c)/8,l=h.bitLength(g)/8;e=e||64;d=d||[];if(7>k)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;4>f&&l>>>8*f;f++);f<15-k&&(f=15-k);c=h.clamp(c,
|
||||
8*(15-f));b=sjcl.mode.ccm.V(a,b,c,d,e,f);g=sjcl.mode.ccm.C(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),k=f.clamp(b,h-e),l=f.bitSlice(b,h-e),h=(h-e)/8;if(7>g)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);c=f.clamp(c,8*(15-b));k=sjcl.mode.ccm.C(a,k,c,l,e,b);a=sjcl.mode.ccm.V(a,k.data,c,d,e,b);if(!f.equal(k.tag,a))throw new sjcl.exception.corrupt("ccm: tag doesn't match");
|
||||
return k.data},na:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,k=h.i;d=[h.partial(8,(b.length?64:0)|d-2<<2|f-1)];d=h.concat(d,c);d[3]|=e;d=a.encrypt(d);if(b.length)for(c=h.bitLength(b)/8,65279>=c?g=[h.partial(16,c)]:0xffffffff>=c&&(g=h.concat([h.partial(16,65534)],[c])),g=h.concat(g,b),b=0;b<g.length;b+=4)d=a.encrypt(k(d,g.slice(b,b+4).concat([0,0,0])));return d},V:function(a,b,c,d,e,f){var g=sjcl.bitArray,h=g.i;e/=8;if(e%2||4>e||16<e)throw new sjcl.exception.invalid("ccm: invalid tag length");
|
||||
if(0xffffffff<d.length||0xffffffff<b.length)throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data");c=sjcl.mode.ccm.na(a,d,c,e,g.bitLength(b)/8,f);for(d=0;d<b.length;d+=4)c=a.encrypt(h(c,b.slice(d,d+4).concat([0,0,0])));return g.clamp(c,8*e)},C:function(a,b,c,d,e,f){var g,h=sjcl.bitArray;g=h.i;var k=b.length,l=h.bitLength(b),n=k/50,m=n;c=h.concat([h.partial(8,f-1)],c).concat([0,0,0]).slice(0,4);d=h.bitSlice(g(d,a.encrypt(c)),0,e);if(!k)return{tag:d,data:[]};for(g=0;g<k;g+=4)g>n&&(sjcl.mode.ccm.fa(g/
|
||||
k),n+=m),c[3]++,e=a.encrypt(c),b[g]^=e[0],b[g+1]^=e[1],b[g+2]^=e[2],b[g+3]^=e[3];return{tag:d,data:h.clamp(b,l)}}};
|
||||
sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){if(128!==sjcl.bitArray.bitLength(c))throw new sjcl.exception.invalid("ocb iv must be 128 bits");var g,h=sjcl.mode.ocb2.S,k=sjcl.bitArray,l=k.i,n=[0,0,0,0];c=h(a.encrypt(c));var m,p=[];d=d||[];e=e||64;for(g=0;g+4<b.length;g+=4)m=b.slice(g,g+4),n=l(n,m),p=p.concat(l(c,a.encrypt(l(c,m)))),c=h(c);m=b.slice(g);b=k.bitLength(m);g=a.encrypt(l(c,[0,0,0,b]));m=k.clamp(l(m.concat([0,0,0]),g),b);n=l(n,l(m.concat([0,0,0]),g));n=a.encrypt(l(n,l(c,h(c))));
|
||||
d.length&&(n=l(n,f?d:sjcl.mode.ocb2.pmac(a,d)));return p.concat(k.concat(m,k.clamp(n,e)))},decrypt:function(a,b,c,d,e,f){if(128!==sjcl.bitArray.bitLength(c))throw new sjcl.exception.invalid("ocb iv must be 128 bits");e=e||64;var g=sjcl.mode.ocb2.S,h=sjcl.bitArray,k=h.i,l=[0,0,0,0],n=g(a.encrypt(c)),m,p,r=sjcl.bitArray.bitLength(b)-e,q=[];d=d||[];for(c=0;c+4<r/32;c+=4)m=k(n,a.decrypt(k(n,b.slice(c,c+4)))),l=k(l,m),q=q.concat(m),n=g(n);p=r-32*c;m=a.encrypt(k(n,[0,0,0,p]));m=k(m,h.clamp(b.slice(c),p).concat([0,
|
||||
0,0]));l=k(l,m);l=a.encrypt(k(l,k(n,g(n))));d.length&&(l=k(l,f?d:sjcl.mode.ocb2.pmac(a,d)));if(!h.equal(h.clamp(l,e),h.bitSlice(b,r)))throw new sjcl.exception.corrupt("ocb: tag doesn't match");return q.concat(h.clamp(m,p))},pmac:function(a,b){var c,d=sjcl.mode.ocb2.S,e=sjcl.bitArray,f=e.i,g=[0,0,0,0],h=a.encrypt([0,0,0,0]),h=f(h,d(d(h)));for(c=0;c+4<b.length;c+=4)h=d(h),g=f(g,a.encrypt(f(h,b.slice(c,c+4))));c=b.slice(c);128>e.bitLength(c)&&(h=f(h,d(h)),c=e.concat(c,[-2147483648,0,0,0]));g=f(g,c);
|
||||
return a.encrypt(f(d(f(h,d(h))),g))},S:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^135*(a[0]>>>31)]}};
|
||||
sjcl.mode.gcm={name:"gcm",encrypt:function(a,b,c,d,e){var f=b.slice(0);b=sjcl.bitArray;d=d||[];a=sjcl.mode.gcm.C(!0,a,f,d,c,e||128);return b.concat(a.data,a.tag)},decrypt:function(a,b,c,d,e){var f=b.slice(0),g=sjcl.bitArray,h=g.bitLength(f);e=e||128;d=d||[];e<=h?(b=g.bitSlice(f,h-e),f=g.bitSlice(f,0,h-e)):(b=f,f=[]);a=sjcl.mode.gcm.C(!1,a,f,d,c,e);if(!g.equal(a.tag,b))throw new sjcl.exception.corrupt("gcm: tag doesn't match");return a.data},ka:function(a,b){var c,d,e,f,g,h=sjcl.bitArray.i;e=[0,0,
|
||||
0,0];f=b.slice(0);for(c=0;128>c;c++){(d=0!==(a[Math.floor(c/32)]&1<<31-c%32))&&(e=h(e,f));g=0!==(f[3]&1);for(d=3;0<d;d--)f[d]=f[d]>>>1|(f[d-1]&1)<<31;f[0]>>>=1;g&&(f[0]^=-0x1f000000)}return e},j:function(a,b,c){var d,e=c.length;b=b.slice(0);for(d=0;d<e;d+=4)b[0]^=0xffffffff&c[d],b[1]^=0xffffffff&c[d+1],b[2]^=0xffffffff&c[d+2],b[3]^=0xffffffff&c[d+3],b=sjcl.mode.gcm.ka(b,a);return b},C:function(a,b,c,d,e,f){var g,h,k,l,n,m,p,r,q=sjcl.bitArray;m=c.length;p=q.bitLength(c);r=q.bitLength(d);h=q.bitLength(e);
|
||||
g=b.encrypt([0,0,0,0]);96===h?(e=e.slice(0),e=q.concat(e,[1])):(e=sjcl.mode.gcm.j(g,[0,0,0,0],e),e=sjcl.mode.gcm.j(g,e,[0,0,Math.floor(h/0x100000000),h&0xffffffff]));h=sjcl.mode.gcm.j(g,[0,0,0,0],d);n=e.slice(0);d=h.slice(0);a||(d=sjcl.mode.gcm.j(g,h,c));for(l=0;l<m;l+=4)n[3]++,k=b.encrypt(n),c[l]^=k[0],c[l+1]^=k[1],c[l+2]^=k[2],c[l+3]^=k[3];c=q.clamp(c,p);a&&(d=sjcl.mode.gcm.j(g,h,c));a=[Math.floor(r/0x100000000),r&0xffffffff,Math.floor(p/0x100000000),p&0xffffffff];d=sjcl.mode.gcm.j(g,d,a);k=b.encrypt(e);
|
||||
d[0]^=k[0];d[1]^=k[1];d[2]^=k[2];d[3]^=k[3];return{tag:q.bitSlice(d,0,f),data:c}}};sjcl.misc.hmac=function(a,b){this.W=b=b||sjcl.hash.sha256;var c=[[],[]],d,e=b.prototype.blockSize/32;this.w=[new b,new b];a.length>e&&(a=b.hash(a));for(d=0;d<e;d++)c[0][d]=a[d]^909522486,c[1][d]=a[d]^1549556828;this.w[0].update(c[0]);this.w[1].update(c[1]);this.R=new b(this.w[0])};
|
||||
sjcl.misc.hmac.prototype.encrypt=sjcl.misc.hmac.prototype.mac=function(a){if(this.aa)throw new sjcl.exception.invalid("encrypt on already updated hmac called!");this.update(a);return this.digest(a)};sjcl.misc.hmac.prototype.reset=function(){this.R=new this.W(this.w[0]);this.aa=!1};sjcl.misc.hmac.prototype.update=function(a){this.aa=!0;this.R.update(a)};sjcl.misc.hmac.prototype.digest=function(){var a=this.R.finalize(),a=(new this.W(this.w[1])).update(a).finalize();this.reset();return a};
|
||||
sjcl.misc.pbkdf2=function(a,b,c,d,e){c=c||1E4;if(0>d||0>c)throw new sjcl.exception.invalid("invalid params to pbkdf2");"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,k,l=[],n=sjcl.bitArray;for(k=1;32*l.length<(d||1);k++){e=f=a.encrypt(n.concat(b,[k]));for(g=1;g<c;g++)for(f=a.encrypt(f),h=0;h<f.length;h++)e[h]^=f[h];l=l.concat(e)}d&&(l=n.clamp(l,d));return l};
|
||||
sjcl.prng=function(a){this.c=[new sjcl.hash.sha256];this.m=[0];this.P=0;this.H={};this.N=0;this.U={};this.Z=this.f=this.o=this.ha=0;this.b=[0,0,0,0,0,0,0,0];this.h=[0,0,0,0];this.L=void 0;this.M=a;this.D=!1;this.K={progress:{},seeded:{}};this.u=this.ga=0;this.I=1;this.J=2;this.ca=0x10000;this.T=[0,48,64,96,128,192,0x100,384,512,768,1024];this.da=3E4;this.ba=80};
|
||||
sjcl.prng.prototype={randomWords:function(a,b){var c=[],d;d=this.isReady(b);var e;if(d===this.u)throw new sjcl.exception.notReady("generator isn't seeded");if(d&this.J){d=!(d&this.I);e=[];var f=0,g;this.Z=e[0]=(new Date).valueOf()+this.da;for(g=0;16>g;g++)e.push(0x100000000*Math.random()|0);for(g=0;g<this.c.length&&(e=e.concat(this.c[g].finalize()),f+=this.m[g],this.m[g]=0,d||!(this.P&1<<g));g++);this.P>=1<<this.c.length&&(this.c.push(new sjcl.hash.sha256),this.m.push(0));this.f-=f;f>this.o&&(this.o=
|
||||
f);this.P++;this.b=sjcl.hash.sha256.hash(this.b.concat(e));this.L=new sjcl.cipher.aes(this.b);for(d=0;4>d&&(this.h[d]=this.h[d]+1|0,!this.h[d]);d++);}for(d=0;d<a;d+=4)0===(d+1)%this.ca&&y(this),e=z(this),c.push(e[0],e[1],e[2],e[3]);y(this);return c.slice(0,a)},setDefaultParanoia:function(a,b){if(0===a&&"Setting paranoia=0 will ruin your security; use it only for testing"!==b)throw new sjcl.exception.invalid("Setting paranoia=0 will ruin your security; use it only for testing");this.M=a},addEntropy:function(a,
|
||||
b,c){c=c||"user";var d,e,f=(new Date).valueOf(),g=this.H[c],h=this.isReady(),k=0;d=this.U[c];void 0===d&&(d=this.U[c]=this.ha++);void 0===g&&(g=this.H[c]=0);this.H[c]=(this.H[c]+1)%this.c.length;switch(typeof a){case "number":void 0===b&&(b=1);this.c[g].update([d,this.N++,1,b,f,1,a|0]);break;case "object":c=Object.prototype.toString.call(a);if("[object Uint32Array]"===c){e=[];for(c=0;c<a.length;c++)e.push(a[c]);a=e}else for("[object Array]"!==c&&(k=1),c=0;c<a.length&&!k;c++)"number"!==typeof a[c]&&
|
||||
(k=1);if(!k){if(void 0===b)for(c=b=0;c<a.length;c++)for(e=a[c];0<e;)b++,e=e>>>1;this.c[g].update([d,this.N++,2,b,f,a.length].concat(a))}break;case "string":void 0===b&&(b=a.length);this.c[g].update([d,this.N++,3,b,f,a.length]);this.c[g].update(a);break;default:k=1}if(k)throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");this.m[g]+=b;this.f+=b;h===this.u&&(this.isReady()!==this.u&&A("seeded",Math.max(this.o,this.f)),A("progress",this.getProgress()))},
|
||||
isReady:function(a){a=this.T[void 0!==a?a:this.M];return this.o&&this.o>=a?this.m[0]>this.ba&&(new Date).valueOf()>this.Z?this.J|this.I:this.I:this.f>=a?this.J|this.u:this.u},getProgress:function(a){a=this.T[a?a:this.M];return this.o>=a?1:this.f>a?1:this.f/a},startCollectors:function(){if(!this.D){this.a={loadTimeCollector:B(this,this.ma),mouseCollector:B(this,this.oa),keyboardCollector:B(this,this.la),accelerometerCollector:B(this,this.ea),touchCollector:B(this,this.qa)};if(window.addEventListener)window.addEventListener("load",
|
||||
this.a.loadTimeCollector,!1),window.addEventListener("mousemove",this.a.mouseCollector,!1),window.addEventListener("keypress",this.a.keyboardCollector,!1),window.addEventListener("devicemotion",this.a.accelerometerCollector,!1),window.addEventListener("touchmove",this.a.touchCollector,!1);else if(document.attachEvent)document.attachEvent("onload",this.a.loadTimeCollector),document.attachEvent("onmousemove",this.a.mouseCollector),document.attachEvent("keypress",this.a.keyboardCollector);else throw new sjcl.exception.bug("can't attach event");
|
||||
this.D=!0}},stopCollectors:function(){this.D&&(window.removeEventListener?(window.removeEventListener("load",this.a.loadTimeCollector,!1),window.removeEventListener("mousemove",this.a.mouseCollector,!1),window.removeEventListener("keypress",this.a.keyboardCollector,!1),window.removeEventListener("devicemotion",this.a.accelerometerCollector,!1),window.removeEventListener("touchmove",this.a.touchCollector,!1)):document.detachEvent&&(document.detachEvent("onload",this.a.loadTimeCollector),document.detachEvent("onmousemove",
|
||||
this.a.mouseCollector),document.detachEvent("keypress",this.a.keyboardCollector)),this.D=!1)},addEventListener:function(a,b){this.K[a][this.ga++]=b},removeEventListener:function(a,b){var c,d,e=this.K[a],f=[];for(d in e)e.hasOwnProperty(d)&&e[d]===b&&f.push(d);for(c=0;c<f.length;c++)d=f[c],delete e[d]},la:function(){C(this,1)},oa:function(a){var b,c;try{b=a.x||a.clientX||a.offsetX||0,c=a.y||a.clientY||a.offsetY||0}catch(d){c=b=0}0!=b&&0!=c&&this.addEntropy([b,c],2,"mouse");C(this,0)},qa:function(a){a=
|
||||
a.touches[0]||a.changedTouches[0];this.addEntropy([a.pageX||a.clientX,a.pageY||a.clientY],1,"touch");C(this,0)},ma:function(){C(this,2)},ea:function(a){a=a.accelerationIncludingGravity.x||a.accelerationIncludingGravity.y||a.accelerationIncludingGravity.z;if(window.orientation){var b=window.orientation;"number"===typeof b&&this.addEntropy(b,1,"accelerometer")}a&&this.addEntropy(a,2,"accelerometer");C(this,0)}};
|
||||
function A(a,b){var c,d=sjcl.random.K[a],e=[];for(c in d)d.hasOwnProperty(c)&&e.push(d[c]);for(c=0;c<e.length;c++)e[c](b)}function C(a,b){"undefined"!==typeof window&&window.performance&&"function"===typeof window.performance.now?a.addEntropy(window.performance.now(),b,"loadtime"):a.addEntropy((new Date).valueOf(),b,"loadtime")}function y(a){a.b=z(a).concat(z(a));a.L=new sjcl.cipher.aes(a.b)}function z(a){for(var b=0;4>b&&(a.h[b]=a.h[b]+1|0,!a.h[b]);b++);return a.L.encrypt(a.h)}
|
||||
function B(a,b){return function(){b.apply(a,arguments)}}sjcl.random=new sjcl.prng(6);
|
||||
a:try{var D,E,F,G;if(G="undefined"!==typeof module&&module.exports){var H;try{H=require("crypto")}catch(a){H=null}G=E=H}if(G&&E.randomBytes)D=E.randomBytes(128),D=new Uint32Array((new Uint8Array(D)).buffer),sjcl.random.addEntropy(D,1024,"crypto['randomBytes']");else if("undefined"!==typeof window&&"undefined"!==typeof Uint32Array){F=new Uint32Array(32);if(window.crypto&&window.crypto.getRandomValues)window.crypto.getRandomValues(F);else if(window.msCrypto&&window.msCrypto.getRandomValues)window.msCrypto.getRandomValues(F);
|
||||
else break a;sjcl.random.addEntropy(F,1024,"crypto['getRandomValues']")}}catch(a){"undefined"!==typeof window&&window.console&&(console.log("There was an error collecting entropy from the browser:"),console.log(a))}
|
||||
sjcl.json={defaults:{v:1,iter:1E4,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},ja:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.g({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.g(f,c);c=f.adata;"string"===typeof f.salt&&(f.salt=sjcl.codec.base64.toBits(f.salt));"string"===typeof f.iv&&(f.iv=sjcl.codec.base64.toBits(f.iv));if(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||"string"===typeof a&&100>=f.iter||64!==f.ts&&96!==f.ts&&128!==f.ts||128!==f.ks&&192!==f.ks&&0x100!==f.ks||2>f.iv.length||
|
||||
4<f.iv.length)throw new sjcl.exception.invalid("json encrypt: invalid parameters");"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,f),a=g.key.slice(0,f.ks/32),f.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.publicKey&&(g=a.kem(),f.kemtag=g.tag,a=g.key.slice(0,f.ks/32));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));"string"===typeof c&&(f.adata=c=sjcl.codec.utf8String.toBits(c));g=new sjcl.cipher[f.cipher](a);e.g(d,f);d.key=a;f.ct="ccm"===f.mode&&sjcl.arrayBuffer&&sjcl.arrayBuffer.ccm&&
|
||||
b instanceof ArrayBuffer?sjcl.arrayBuffer.ccm.encrypt(g,b,f.iv,c,f.ts):sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return f},encrypt:function(a,b,c,d){var e=sjcl.json,f=e.ja.apply(e,arguments);return e.encode(f)},ia:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.g(e.g(e.g({},e.defaults),b),c,!0);var f,g;f=b.adata;"string"===typeof b.salt&&(b.salt=sjcl.codec.base64.toBits(b.salt));"string"===typeof b.iv&&(b.iv=sjcl.codec.base64.toBits(b.iv));if(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||"string"===
|
||||
typeof a&&100>=b.iter||64!==b.ts&&96!==b.ts&&128!==b.ts||128!==b.ks&&192!==b.ks&&0x100!==b.ks||!b.iv||2>b.iv.length||4<b.iv.length)throw new sjcl.exception.invalid("json decrypt: invalid parameters");"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,b),a=g.key.slice(0,b.ks/32),b.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.secretKey&&(a=a.unkem(sjcl.codec.base64.toBits(b.kemtag)).slice(0,b.ks/32));"string"===typeof f&&(f=sjcl.codec.utf8String.toBits(f));g=new sjcl.cipher[b.cipher](a);f="ccm"===
|
||||
b.mode&&sjcl.arrayBuffer&&sjcl.arrayBuffer.ccm&&b.ct instanceof ArrayBuffer?sjcl.arrayBuffer.ccm.decrypt(g,b.ct,b.iv,b.tag,f,b.ts):sjcl.mode[b.mode].decrypt(g,b.ct,b.iv,f,b.ts);e.g(d,b);d.key=a;return 1===c.raw?f:sjcl.codec.utf8String.fromBits(f)},decrypt:function(a,b,c,d){var e=sjcl.json;return e.ia(a,e.decode(b),c,d)},encode:function(a){var b,c="{",d="";for(b in a)if(a.hasOwnProperty(b)){if(!b.match(/^[a-z0-9]+$/i))throw new sjcl.exception.invalid("json encode: invalid property name");c+=d+'"'+
|
||||
b+'":';d=",";switch(typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';break;case "object":c+='"'+sjcl.codec.base64.fromBits(a[b],0)+'"';break;default:throw new sjcl.exception.bug("json encode: unsupported type");}}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");if(!a.match(/^\{.*\}$/))throw new sjcl.exception.invalid("json decode: this isn't json!");a=a.replace(/^\{|\}$/g,"").split(/,/);var b={},c,d;for(c=0;c<a.length;c++){if(!(d=a[c].match(/^\s*(?:(["']?)([a-z][a-z0-9]*)\1)\s*:\s*(?:(-?\d+)|"([a-z0-9+\/%*_.@=\-]*)"|(true|false))$/i)))throw new sjcl.exception.invalid("json decode: this isn't json!");
|
||||
null!=d[3]?b[d[2]]=parseInt(d[3],10):null!=d[4]?b[d[2]]=d[2].match(/^(ct|adata|salt|iv)$/)?sjcl.codec.base64.toBits(d[4]):unescape(d[4]):null!=d[5]&&(b[d[2]]="true"===d[5])}return b},g:function(a,b,c){void 0===a&&(a={});if(void 0===b)return a;for(var d in b)if(b.hasOwnProperty(d)){if(c&&void 0!==a[d]&&a[d]!==b[d])throw new sjcl.exception.invalid("required parameter overridden");a[d]=b[d]}return a},sa:function(a,b){var c={},d;for(d in a)a.hasOwnProperty(d)&&a[d]!==b[d]&&(c[d]=a[d]);return c},ra:function(a,
|
||||
b){var c={},d;for(d=0;d<b.length;d++)void 0!==a[b[d]]&&(c[b[d]]=a[b[d]]);return c}};sjcl.encrypt=sjcl.json.encrypt;sjcl.decrypt=sjcl.json.decrypt;sjcl.misc.pa={};sjcl.misc.cachedPbkdf2=function(a,b){var c=sjcl.misc.pa,d;b=b||{};d=b.iter||1E3;c=c[a]=c[a]||{};d=c[d]=c[d]||{firstSalt:b.salt&&b.salt.length?b.salt.slice(0):sjcl.random.randomWords(2,0)};c=void 0===b.salt?d.firstSalt:b.salt;d[c]=d[c]||sjcl.misc.pbkdf2(a,c,b.iter);return{key:d[c].slice(0),salt:c.slice(0)}};
|
||||
"undefined"!==typeof module&&module.exports&&(module.exports=sjcl);"function"===typeof define&&define([],function(){return sjcl});
|
||||
|
||||
@@ -3,30 +3,31 @@ type: text/plain
|
||||
|
||||
TiddlyWiki created by Jeremy Ruston, (jeremy [at] jermolene [dot] com)
|
||||
|
||||
Copyright © Jeremy Ruston 2004-2007
|
||||
Copyright © UnaMesa Association 2007-2016
|
||||
Copyright (c) 2004-2007, Jeremy Ruston
|
||||
Copyright (c) 2007-2017, UnaMesa Association
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
Neither the name of the UnaMesa Association nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
15
core/images/copy-clipboard.tid
Normal file
15
core/images/copy-clipboard.tid
Normal file
@@ -0,0 +1,15 @@
|
||||
title: $:/core/images/copy-clipboard
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tc-image-copy-clipboard tc-image-button" width="22pt" height="22pt" viewBox="0 0 128 128">
|
||||
<g fill-rule="evenodd">
|
||||
<rect x="40" y="40" width="33" height="8" rx="4"></rect>
|
||||
<rect x="40" y="82" width="17" height="8" rx="4"></rect>
|
||||
<rect x="40" y="54" width="17" height="8" rx="4"></rect>
|
||||
<rect x="40" y="96" width="33" height="8" rx="4"></rect>
|
||||
<rect x="40" y="68" width="12" height="8" rx="4"></rect>
|
||||
<path d="M40,16 L23.9992458,16 C19.5813843,16 16,19.5907123 16,24 C16,24.0016363 16.0000005,24.0032725 16.0000015,24.0049086 C16.0000005,24.0065441 16,24.0081803 16,24.0098166 L16,119.990183 C16,119.99182 16.0000005,119.993456 16.0000015,119.995092 C16.0000005,119.996727 16,119.998364 16,120 C16,124.409288 19.5813843,128 23.9992458,128 L104.000754,128 C106.205061,128 108.203844,127.105595 109.652065,125.659342 C111.102424,124.21251 112,122.214511 112,120.007595 L112,103.992405 C112,99.5776607 108.418278,96 104,96 C99.5907123,96 96,99.5783218 96,103.992405 L96,112 L32,112 L32,32 L96,32 L96,40.0075946 C96,44.4223393 99.581722,48 104,48 C108.409288,48 112,44.4216782 112,40.0075946 L112,23.9924054 C112,21.7851587 111.104671,19.7871591 109.657101,18.3409203 C108.203844,16.8944047 106.205061,16 104.000754,16 L88,16 C88,11.5907123 84.4151006,8 79.9929031,8 L48.0070969,8 C43.5881712,8 40,11.581722 40,16 Z M44,14.9958262 C44,12.7889923 45.7964248,11 48.0000255,11 L79.9999745,11 C82.2091276,11 84,12.7965212 84,14.9958262 L84,19.0041738 C84,21.2110077 82.2035752,23 79.9999745,23 L48.0000255,23 C45.7908724,23 44,21.2034788 44,19.0041738 L44,14.9958262 Z"></path>
|
||||
<rect x="62" y="64" width="66" height="16" rx="8"></rect>
|
||||
<path d="M60.6568542,85.6568542 L76.6568542,69.6568543 L65.3431458,69.6568542 L81.3431458,85.6568542 C84.4673401,88.7810486 89.5326599,88.7810486 92.6568542,85.6568542 C95.7810486,82.5326599 95.7810486,77.4673401 92.6568542,74.3431458 L76.6568542,58.3431458 C73.5326599,55.2189514 68.4673401,55.2189514 65.3431458,58.3431457 L49.3431458,74.3431457 C46.2189514,77.4673401 46.2189514,82.5326599 49.3431457,85.6568542 C52.4673401,88.7810486 57.5326599,88.7810486 60.6568542,85.6568542 L60.6568542,85.6568542 Z" transform="translate(71.000000, 72.000000) rotate(-90.000000) translate(-71.000000, -72.000000) "></path>
|
||||
</g>
|
||||
</svg>
|
||||
9
core/images/list.tid
Normal file
9
core/images/list.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: $:/core/images/list
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tc-image-list tc-image-button" width="22pt" height="22pt" viewBox="0 0 128 128">
|
||||
<g fill-rule="evenodd">
|
||||
<path d="M0.719999312,185.568543 C2.21955287,181.862817 3.0452019,177.812144 3.0452019,173.568542 C3.0452019,155.891545 -11.2816707,141.568542 -28.9547636,141.568542 L-60.9548326,141.568542 C-78.6344937,141.568542 -92.9547981,155.895431 -92.9547981,173.568542 C-92.9547981,191.24554 -78.6279255,205.568542 -60.9548326,205.568542 L-28.9547636,205.568542 C-27.593228,205.568542 -26.2516158,205.483573 -24.9349335,205.31865 C-31.5207556,201.78951 -36.8809788,196.272192 -40.2126959,189.568542 L-60.9493786,189.568542 C-69.7889277,189.568542 -76.9547981,182.407041 -76.9547981,173.568542 C-76.9547981,164.731986 -69.7994766,157.568542 -60.9493786,157.568542 L-28.9602176,157.568542 C-20.1206685,157.568542 -12.9547981,164.730044 -12.9547981,173.568542 C-12.9547981,176.946528 -14.0004297,180.080016 -15.7866505,182.6623 C-13.6856165,184.473592 -10.949961,185.568542 -7.9585771,185.568542 L0.720002586,185.568542 Z" transform="translate(-44.954798, 173.568542) rotate(-225.000000) translate(44.954798, -173.568542) "></path>
|
||||
<path d="M87.7480315,128 L23.9992458,128 C19.5813843,128 16,124.409247 16,119.993027 L16,8.00697327 C16,3.58484404 19.5881049,0 23.9992458,0 L104.000754,0 C108.418616,0 112,3.59075293 112,8.00697327 L112,104 L91.2492027,104 C90.2848199,104 89.410573,104.391703 88.7768998,105.025201 C88.1373658,105.661376 87.7480315,106.53563 87.7480315,107.501171 L87.7480315,128 Z M95.7480315,127.879386 L111.627417,112 L95.7480315,112 L95.7480315,127.879386 Z M40,15.5089165 C40,13.5709954 41.5636015,12 43.4998101,12 L98.5001899,12 C100.433082,12 102,13.5614718 102,15.5089165 L102,16.4910835 C102,18.4290046 100.436399,20 98.5001899,20 L43.4998101,20 C41.5669183,20 40,18.4385282 40,16.4910835 L40,15.5089165 Z M32,22 C35.3137085,22 38,19.3137085 38,16 C38,12.6862915 35.3137085,10 32,10 C28.6862915,10 26,12.6862915 26,16 C26,19.3137085 28.6862915,22 32,22 Z M40,31.5089165 C40,29.5709954 41.5636015,28 43.4998101,28 L98.5001899,28 C100.433082,28 102,29.5614718 102,31.5089165 L102,32.4910835 C102,34.4290046 100.436399,36 98.5001899,36 L43.4998101,36 C41.5669183,36 40,34.4385282 40,32.4910835 L40,31.5089165 Z M40,47.5089165 C40,45.5709954 41.5636015,44 43.4998101,44 L98.5001899,44 C100.433082,44 102,45.5614718 102,47.5089165 L102,48.4910835 C102,50.4290046 100.436399,52 98.5001899,52 L43.4998101,52 C41.5669183,52 40,50.4385282 40,48.4910835 L40,47.5089165 Z M40,63.5089165 C40,61.5709954 41.5636015,60 43.4998101,60 L98.5001899,60 C100.433082,60 102,61.5614718 102,63.5089165 L102,64.4910835 C102,66.4290046 100.436399,68 98.5001899,68 L43.4998101,68 C41.5669183,68 40,66.4385282 40,64.4910835 L40,63.5089165 Z M40,79.5089165 C40,77.5709954 41.5636015,76 43.4998101,76 L98.5001899,76 C100.433082,76 102,77.5614718 102,79.5089165 L102,80.4910835 C102,82.4290046 100.436399,84 98.5001899,84 L43.4998101,84 C41.5669183,84 40,82.4385282 40,80.4910835 L40,79.5089165 Z M40,95.5089165 C40,93.5709954 41.5636015,92 43.4998101,92 L98.5001899,92 C100.433082,92 102,93.5614718 102,95.5089165 L102,96.4910835 C102,98.4290046 100.436399,100 98.5001899,100 L43.4998101,100 C41.5669183,100 40,98.4385282 40,96.4910835 L40,95.5089165 Z M40,111.508916 C40,109.570995 41.5680474,108 43.4972017,108 L76.5027983,108 C78.4342495,108 80,109.561472 80,111.508916 L80,112.491084 C80,114.429005 78.4319526,116 76.5027983,116 L43.4972017,116 C41.5657505,116 40,114.438528 40,112.491084 L40,111.508916 Z M32,38 C35.3137085,38 38,35.3137085 38,32 C38,28.6862915 35.3137085,26 32,26 C28.6862915,26 26,28.6862915 26,32 C26,35.3137085 28.6862915,38 32,38 Z M32,54 C35.3137085,54 38,51.3137085 38,48 C38,44.6862915 35.3137085,42 32,42 C28.6862915,42 26,44.6862915 26,48 C26,51.3137085 28.6862915,54 32,54 Z M32,70 C35.3137085,70 38,67.3137085 38,64 C38,60.6862915 35.3137085,58 32,58 C28.6862915,58 26,60.6862915 26,64 C26,67.3137085 28.6862915,70 32,70 Z M32,86 C35.3137085,86 38,83.3137085 38,80 C38,76.6862915 35.3137085,74 32,74 C28.6862915,74 26,76.6862915 26,80 C26,83.3137085 28.6862915,86 32,86 Z M32,102 C35.3137085,102 38,99.3137085 38,96 C38,92.6862915 35.3137085,90 32,90 C28.6862915,90 26,92.6862915 26,96 C26,99.3137085 28.6862915,102 32,102 Z M32,118 C35.3137085,118 38,115.313708 38,112 C38,108.686292 35.3137085,106 32,106 C28.6862915,106 26,108.686292 26,112 C26,115.313708 28.6862915,118 32,118 Z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
12
core/images/print-button.tid
Normal file
12
core/images/print-button.tid
Normal file
@@ -0,0 +1,12 @@
|
||||
title: $:/core/images/print-button
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tc-image-print-button tc-image-button" viewBox="0 0 128 128" width="22pt" height="22pt">
|
||||
<g fill-rule="evenodd">
|
||||
<path d="M112,71 L112,30.5 L111.96811,30.5 L111.96811,30.5 C111.932942,28.4998414 111.151676,26.510538 109.625176,24.9840387 L86.9982489,2.35711116 C85.3482153,0.707077645 83.1589869,-0.071534047 81,0.0201838424 L81,0 L23.9992458,0 C19.5808867,0 16,3.58213437 16,8.00092105 L16,71 L24,71 L24,8 L81,8 L81,22.4996539 C81,26.9216269 84.5818769,30.5 89.0003461,30.5 L104,30.5 L104,71 L112,71 Z"></path>
|
||||
<rect x="32" y="36" width="64" height="8" rx="4"></rect>
|
||||
<rect x="32" y="52" width="64" height="8" rx="4"></rect>
|
||||
<rect x="32" y="20" width="40" height="8" rx="4"></rect>
|
||||
<path d="M0,80.0054195 C0,71.1658704 7.15611005,64 16.0008841,64 L111.999116,64 C120.83616,64 128,71.1553215 128,80.0054195 L128,111.99458 C128,120.83413 120.84389,128 111.999116,128 L16.0008841,128 C7.16383982,128 0,120.844679 0,111.99458 L0,80.0054195 Z M104,96 C108.418278,96 112,92.418278 112,88 C112,83.581722 108.418278,80 104,80 C99.581722,80 96,83.581722 96,88 C96,92.418278 99.581722,96 104,96 Z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
8
core/images/timestamp-off.tid
Normal file
8
core/images/timestamp-off.tid
Normal file
@@ -0,0 +1,8 @@
|
||||
title: $:/core/images/timestamp-off
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tc-image-timestamp-off tc-image-button" width="22pt" height="22pt" viewBox="0 0 128 128">
|
||||
<g fill-rule="evenodd">
|
||||
<path d="M58.25 11C26.08 11 0 37.082 0 69.25s26.08 58.25 58.25 58.25c32.175 0 58.25-26.082 58.25-58.25S90.425 11 58.25 11zm0 100.5C34.914 111.5 16 92.586 16 69.25 16 45.92 34.914 27 58.25 27s42.25 18.92 42.25 42.25c0 23.336-18.914 42.25-42.25 42.25zM49.704 10c-2.762 0-5-2.24-5-5-.004-2.756 2.238-5 5-5H66.69c2.762 0 5.002 2.24 5 5 .006 2.757-2.238 5-5 5H49.705z"/><path d="M58.25 35.88c-18.777 0-33.998 15.224-33.998 33.998 0 18.773 15.22 34.002 33.998 34.002 18.784 0 34.002-15.23 34.002-34.002 0-18.774-15.218-33.998-34.002-33.998zm-3.03 50.123H44.196v-34H55.22v34zm16.976 0H61.17v-34h11.025v34z"/>
|
||||
</g>
|
||||
</svg>
|
||||
8
core/images/timestamp-on.tid
Normal file
8
core/images/timestamp-on.tid
Normal file
@@ -0,0 +1,8 @@
|
||||
title: $:/core/images/timestamp-on
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tc-image-timestamp-on tc-image-button" width="22pt" height="22pt" viewBox="0 0 128 128">
|
||||
<g fill-rule="evenodd">
|
||||
<path d="M58.25 11C26.08 11 0 37.082 0 69.25s26.08 58.25 58.25 58.25c32.175 0 58.25-26.082 58.25-58.25S90.425 11 58.25 11zm0 100.5C34.914 111.5 16 92.586 16 69.25 16 45.92 34.914 27 58.25 27s42.25 18.92 42.25 42.25c0 23.336-18.914 42.25-42.25 42.25zM49.704 10c-2.762 0-5-2.24-5-5-.004-2.756 2.238-5 5-5H66.69c2.762 0 5.002 2.24 5 5 .006 2.757-2.238 5-5 5H49.705z"/><path d="M13.41 27.178c-2.116 1.775-5.27 1.498-7.045-.613-1.772-2.11-1.498-5.27.616-7.047l9.95-8.348c2.115-1.774 5.27-1.5 7.045.618 1.775 2.108 1.498 5.27-.616 7.043l-9.95 8.348zM102.983 27.178c2.116 1.775 5.27 1.498 7.045-.613 1.772-2.11 1.498-5.27-.616-7.047l-9.95-8.348c-2.114-1.774-5.27-1.5-7.044.618-1.775 2.108-1.498 5.27.616 7.043l9.95 8.348zM65.097 71.072c0 3.826-3.09 6.928-6.897 6.928-3.804.006-6.9-3.102-6.903-6.928 0 0 4.76-39.072 6.903-39.072s6.897 39.072 6.897 39.072z"/>
|
||||
</g>
|
||||
</svg>
|
||||
@@ -54,6 +54,8 @@ Home/Caption: home
|
||||
Home/Hint: Open the default tiddlers
|
||||
Language/Caption: language
|
||||
Language/Hint: Choose the user interface language
|
||||
Manager/Caption: tiddler manager
|
||||
Manager/Hint: Open tiddler manager
|
||||
More/Caption: more
|
||||
More/Hint: More actions
|
||||
NewHere/Caption: new here
|
||||
@@ -76,6 +78,8 @@ Permalink/Caption: permalink
|
||||
Permalink/Hint: Set browser address bar to a direct link to this tiddler
|
||||
Permaview/Caption: permaview
|
||||
Permaview/Hint: Set browser address bar to a direct link to all the tiddlers in this story
|
||||
Print/Caption: print page
|
||||
Print/Hint: Print the current page
|
||||
Refresh/Caption: refresh
|
||||
Refresh/Hint: Perform a full refresh of the wiki
|
||||
Save/Caption: ok
|
||||
@@ -90,6 +94,12 @@ ShowSideBar/Caption: show sidebar
|
||||
ShowSideBar/Hint: Show sidebar
|
||||
TagManager/Caption: tag manager
|
||||
TagManager/Hint: Open tag manager
|
||||
Timestamp/Caption: timestamps
|
||||
Timestamp/Hint: Choose whether modifications update timestamps
|
||||
Timestamp/On/Caption: timestamps are on
|
||||
Timestamp/On/Hint: Update timestamps when tiddlers are modified
|
||||
Timestamp/Off/Caption: timestamps are off
|
||||
Timestamp/Off/Hint: Don't update timestamps when tiddlers are modified
|
||||
Theme/Caption: theme
|
||||
Theme/Hint: Choose the display theme
|
||||
Bold/Caption: bold
|
||||
|
||||
@@ -11,6 +11,7 @@ Basics/DefaultTiddlers/Prompt: Default tiddlers:
|
||||
Basics/DefaultTiddlers/TopHint: Choose which tiddlers are displayed at startup:
|
||||
Basics/Language/Prompt: Hello! Current language:
|
||||
Basics/NewJournal/Title/Prompt: Title of new journal tiddlers
|
||||
Basics/NewJournal/Text/Prompt: Text for new journal tiddlers
|
||||
Basics/NewJournal/Tags/Prompt: Tags for new journal tiddlers
|
||||
Basics/OverriddenShadowTiddlers/Prompt: Number of overridden shadow tiddlers:
|
||||
Basics/ShadowTiddlers/Prompt: Number of shadow tiddlers:
|
||||
@@ -52,7 +53,7 @@ Palette/HideEditor/Caption: hide editor
|
||||
Palette/Prompt: Current palette:
|
||||
Palette/ShowEditor/Caption: show editor
|
||||
Parsing/Caption: Parsing
|
||||
Parsing/Hint: Here you can globally disable individual wiki parser rules. Take care as disabling some parser rules can prevent ~TiddlyWiki functioning correctly (you can restore normal operation with [[safe mode|http://tiddlywiki.com/#SafeMode]] )
|
||||
Parsing/Hint: Here you can globally disable/enable wiki parser rules. For changes to take effect, save and reload your wiki. Disabling certain parser rules can prevent <$text text="TiddlyWiki"/> from functioning correctly. Use [[safe mode|http://tiddlywiki.com/#SafeMode]] to restore normal operation.
|
||||
Parsing/Block/Caption: Block Parse Rules
|
||||
Parsing/Inline/Caption: Inline Parse Rules
|
||||
Parsing/Pragma/Caption: Pragma Parse Rules
|
||||
@@ -74,16 +75,24 @@ Plugins/NoInfoFound/Hint: No ''"<$text text=<<currentTab>>/>"'' found
|
||||
Plugins/NoInformation/Hint: No information provided
|
||||
Plugins/NotInstalled/Hint: This plugin is not currently installed
|
||||
Plugins/OpenPluginLibrary: open plugin library
|
||||
Plugins/ClosePluginLibrary: close plugin library
|
||||
Plugins/Plugins/Caption: Plugins
|
||||
Plugins/Plugins/Hint: Plugins
|
||||
Plugins/Reinstall/Caption: reinstall
|
||||
Plugins/Themes/Caption: Themes
|
||||
Plugins/Themes/Hint: Theme plugins
|
||||
Saving/Caption: Saving
|
||||
Saving/Heading: Saving
|
||||
Saving/DownloadSaver/AutoSave/Description: Permit automatic saving for the download saver
|
||||
Saving/DownloadSaver/AutoSave/Hint: Enable Autosave for Download Saver
|
||||
Saving/DownloadSaver/Caption: Download Saver
|
||||
Saving/DownloadSaver/Hint: These settings apply to the HTML5-compatible download saver
|
||||
Saving/General/Caption: General
|
||||
Saving/General/Hint: These settings apply to all the loaded savers
|
||||
Saving/Hint: Settings used for saving the entire TiddlyWiki as a single file via a saver module
|
||||
Saving/TiddlySpot/Advanced/Heading: Advanced Settings
|
||||
Saving/TiddlySpot/BackupDir: Backup Directory
|
||||
Saving/TiddlySpot/Backups: Backups
|
||||
Saving/TiddlySpot/Caption: ~TiddlySpot Saver
|
||||
Saving/TiddlySpot/Description: These settings are only used when saving to http://tiddlyspot.com or a compatible remote server
|
||||
Saving/TiddlySpot/Filename: Upload Filename
|
||||
Saving/TiddlySpot/Heading: ~TiddlySpot
|
||||
@@ -95,7 +104,7 @@ Saving/TiddlySpot/UserName: Wiki Name
|
||||
Settings/AutoSave/Caption: Autosave
|
||||
Settings/AutoSave/Disabled/Description: Do not save changes automatically
|
||||
Settings/AutoSave/Enabled/Description: Save changes automatically
|
||||
Settings/AutoSave/Hint: Automatically save changes during editing
|
||||
Settings/AutoSave/Hint: Attempt to automatically save changes during editing when using a supporting saver
|
||||
Settings/CamelCase/Caption: Camel Case Wiki Links
|
||||
Settings/CamelCase/Hint: You can globally disable automatic linking of ~CamelCase phrases. Requires reload to take effect
|
||||
Settings/CamelCase/Description: Enable automatic ~CamelCase linking
|
||||
@@ -103,6 +112,10 @@ Settings/Caption: Settings
|
||||
Settings/EditorToolbar/Caption: Editor Toolbar
|
||||
Settings/EditorToolbar/Hint: Enable or disable the editor toolbar:
|
||||
Settings/EditorToolbar/Description: Show editor toolbar
|
||||
Settings/InfoPanelMode/Caption: Tiddler Info Panel Mode
|
||||
Settings/InfoPanelMode/Hint: Control when the tiddler info panel closes:
|
||||
Settings/InfoPanelMode/Popup/Description: Tiddler info panel closes automatically
|
||||
Settings/InfoPanelMode/Sticky/Description: Tiddler info panel stays open until explicitly closed
|
||||
Settings/Hint: These settings let you customise the behaviour of TiddlyWiki.
|
||||
Settings/NavigationAddressBar/Caption: Navigation Address Bar
|
||||
Settings/NavigationAddressBar/Hint: Behaviour of the browser address bar when navigating to a tiddler:
|
||||
@@ -149,12 +162,12 @@ TiddlerFields/Caption: Tiddler Fields
|
||||
TiddlerFields/Hint: This is the full set of TiddlerFields in use in this wiki (including system tiddlers but excluding shadow tiddlers).
|
||||
Toolbars/Caption: Toolbars
|
||||
Toolbars/EditToolbar/Caption: Edit Toolbar
|
||||
Toolbars/EditToolbar/Hint: Choose which buttons are displayed for tiddlers in edit mode
|
||||
Toolbars/EditToolbar/Hint: Choose which buttons are displayed for tiddlers in edit mode. Drag and drop to change the ordering
|
||||
Toolbars/Hint: Select which toolbar buttons are displayed
|
||||
Toolbars/PageControls/Caption: Page Toolbar
|
||||
Toolbars/PageControls/Hint: Choose which buttons are displayed on the main page toolbar
|
||||
Toolbars/PageControls/Hint: Choose which buttons are displayed on the main page toolbar. Drag and drop to change the ordering
|
||||
Toolbars/EditorToolbar/Caption: Editor Toolbar
|
||||
Toolbars/EditorToolbar/Hint: Choose which buttons are displayed in the editor toolbar. Note that some buttons will only appear when editing tiddlers of a certain type
|
||||
Toolbars/EditorToolbar/Hint: Choose which buttons are displayed in the editor toolbar. Note that some buttons will only appear when editing tiddlers of a certain type. Drag and drop to change the ordering
|
||||
Toolbars/ViewToolbar/Caption: View Toolbar
|
||||
Toolbars/ViewToolbar/Hint: Choose which buttons are displayed for tiddlers in view mode
|
||||
Toolbars/ViewToolbar/Hint: Choose which buttons are displayed for tiddlers in view mode. Drag and drop to change the ordering
|
||||
Tools/Download/Full/Caption: Download full wiki
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
title: $:/language/Docs/ModuleTypes/
|
||||
|
||||
allfilteroperator: A sub-operator for the ''all'' filter operator.
|
||||
animation: Animations that may be used with the RevealWidget.
|
||||
bitmapeditoroperation: A bitmap editor toolbar operation.
|
||||
command: Commands that can be executed under Node.js.
|
||||
config: Data to be inserted into `$tw.config`.
|
||||
filteroperator: Individual filter operator methods.
|
||||
global: Global data to be inserted into `$tw`.
|
||||
info: Publishes system information via the [[$:/temp/info-plugin]] pseudo-plugin.
|
||||
isfilteroperator: Operands for the ''is'' filter operator.
|
||||
library: Generic module type for general purpose JavaScript modules.
|
||||
macro: JavaScript macro definitions.
|
||||
parser: Parsers for different content types.
|
||||
saver: Savers handle different methods for saving files from the browser.
|
||||
startup: Startup functions.
|
||||
storyview: Story views customise the animation and behaviour of list widgets.
|
||||
texteditoroperation: A text editor toolbar operation.
|
||||
tiddlerdeserializer: Converts different content types into tiddlers.
|
||||
tiddlerfield: Defines the behaviour of an individual tiddler field.
|
||||
tiddlermethod: Adds methods to the `$tw.Tiddler` prototype.
|
||||
|
||||
@@ -18,6 +18,8 @@ Tags/Add/Placeholder: tag name
|
||||
Tags/Dropdown/Caption: tag list
|
||||
Tags/Dropdown/Hint: Show tag list
|
||||
Title/BadCharacterWarning: Warning: avoid using any of the characters <<bad-chars>> in tiddler titles
|
||||
Title/Exists/Prompt: Target tiddler already exists
|
||||
Title/Relink/Prompt: Update ''<$text text=<<fromTitle>>/>'' to ''<$text text=<<toTitle>>/>'' in the //tags// and //list// fields of other tiddlers
|
||||
Type/Dropdown/Caption: content type list
|
||||
Type/Dropdown/Hint: Show content type list
|
||||
Type/Delete/Caption: delete content type
|
||||
|
||||
@@ -11,4 +11,5 @@ SystemTiddlers: System tiddlers
|
||||
ShadowTiddlers: Shadow tiddlers
|
||||
OverriddenShadowTiddlers: Overridden shadow tiddlers
|
||||
SystemTags: System tags
|
||||
StoryList: Tiddlers in the story river, excluding <$text text="$:/AdvancedSearch"/>
|
||||
TypedTiddlers: Non wiki-text tiddlers
|
||||
28
core/language/en-GB/Help/fetch.tid
Normal file
28
core/language/en-GB/Help/fetch.tid
Normal file
@@ -0,0 +1,28 @@
|
||||
title: $:/language/Help/fetch
|
||||
description: Fetch tiddlers from wiki by URL
|
||||
|
||||
Fetch one or more files over HTTP/HTTPS, and import the tiddlers matching a filter, optionally transforming the incoming titles.
|
||||
|
||||
```
|
||||
--fetch file <url> <import-filter> <transform-filter>
|
||||
--fetch files <url-filter> <import-filter> <transform-filter>
|
||||
```
|
||||
|
||||
With the "file" variant only a single file is fetched and the first parameter is the URL of the file to read.
|
||||
|
||||
With the "files" variant, multiple files are fetched and the first parameter is a filter yielding a list of URLs of the files to read. For example, given a set of tiddlers tagged "remote-server" that have a field "url" the filter `[tag[remote-server]get[url]]` will retrieve all the available URLs.
|
||||
|
||||
The `<import-filter>` parameter specifies a filter determining which tiddlers are imported. It defaults to `[all[tiddlers]]` if not provided.
|
||||
|
||||
The `<transform-filter>` parameter specifies an optional filter that transforms the titles of the imported tiddlers. For example, `[addprefix[$:/myimports/]]` would add the prefix `$:/myimports/` to each title.
|
||||
|
||||
Preceding the `--fetch` command with `--verbose` will output progress information during the import.
|
||||
|
||||
Note that TiddlyWiki will not fetch an older version of an already loaded plugin.
|
||||
|
||||
The following example retrieves all the non-system tiddlers from http://tiddlywiki.com and saves them to a JSON file:
|
||||
|
||||
```
|
||||
tiddlywiki --verbose --fetch file "http://tiddlywiki.com/" "[!is[system]]" "" --rendertiddler "$:/core/templates/exporters/JsonFile" output.json text/plain "" exportFilter "[!is[system]]"
|
||||
```
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
title: $:/language/Help/rendertiddler
|
||||
description: Render an individual tiddler as a specified ContentType
|
||||
|
||||
Render an individual tiddler as a specified ContentType, defaulting to `text/html` and save it to the specified filename. Optionally a template can be specified, in which case the template tiddler is rendered with the "currentTiddler" variable set to the tiddler that is being rendered (the first parameter value).
|
||||
Render an individual tiddler as a specified ContentType, defaulting to `text/html` and save it to the specified filename.
|
||||
|
||||
Optionally the title of a template tiddler can be specified, in which case the template tiddler is rendered with the "currentTiddler" variable set to the tiddler that is being rendered (the first parameter value).
|
||||
|
||||
A name and value for an additional variable may optionally also be specified.
|
||||
|
||||
```
|
||||
--rendertiddler <title> <filename> [<type>] [<template>]
|
||||
--rendertiddler <title> <filename> [<type>] [<template>] [<name>] [<value>]
|
||||
```
|
||||
|
||||
By default, the filename is resolved relative to the `output` subdirectory of the edition directory. The `--output` command can be used to direct output to a different directory.
|
||||
|
||||
Any missing directories in the path to the filename are automatically created.
|
||||
|
||||
For example, the following command saves all tiddlers matching the filter `[tag[done]]` to a JSON file titled `output.json` by employing the core template `$:/core/templates/exporters/JsonFile`.
|
||||
|
||||
```
|
||||
--rendertiddler "$:/core/templates/exporters/JsonFile" output.json text/plain "" exportFilter "[tag[done]]"
|
||||
```
|
||||
|
||||
@@ -22,6 +22,7 @@ Encryption/RepeatPassword: Repeat password
|
||||
Encryption/PasswordNoMatch: Passwords do not match
|
||||
Encryption/SetPassword: Set password
|
||||
Error/Caption: Error
|
||||
Error/EditConflict: File changed on server
|
||||
Error/Filter: Filter error
|
||||
Error/FilterSyntax: Syntax error in filter expression
|
||||
Error/IsFilterOperator: Filter Error: Unknown operand for the 'is' filter operator
|
||||
@@ -36,6 +37,23 @@ InternalJavaScriptError/Hint: Well, this is embarrassing. It is recommended that
|
||||
InvalidFieldName: Illegal characters in field name "<$text text=<<fieldName>>/>". Fields can only contain lowercase letters, digits and the characters underscore (`_`), hyphen (`-`) and period (`.`)
|
||||
LazyLoadingWarning: <p>Loading external text from ''<$text text={{!!_canonical_uri}}/>''</p><p>If this message doesn't disappear you may be using a browser that doesn't support external text in this configuration. See http://tiddlywiki.com/#ExternalText</p>
|
||||
LoginToTiddlySpace: Login to TiddlySpace
|
||||
Manager/Controls/FilterByTag/None: (none)
|
||||
Manager/Controls/FilterByTag/Prompt: Filter by tag:
|
||||
Manager/Controls/Order/Prompt: Reverse order
|
||||
Manager/Controls/Search/Placeholder: Search
|
||||
Manager/Controls/Search/Prompt: Search:
|
||||
Manager/Controls/Show/Option/Tags: tags
|
||||
Manager/Controls/Show/Option/Tiddlers: tiddlers
|
||||
Manager/Controls/Show/Prompt: Show:
|
||||
Manager/Controls/Sort/Prompt: Sort by:
|
||||
Manager/Item/Colour: Colour
|
||||
Manager/Item/Fields: Fields
|
||||
Manager/Item/Icon/None: (none)
|
||||
Manager/Item/Icon: Icon
|
||||
Manager/Item/RawText: Raw text
|
||||
Manager/Item/Tags: Tags
|
||||
Manager/Item/Tools: Tools
|
||||
Manager/Item/WikifiedText: Wikified text
|
||||
MissingTiddler/Hint: Missing tiddler "<$text text=<<currentTiddler>>/>" - click {{$:/core/images/edit-button}} to create
|
||||
No: No
|
||||
OfficialPluginLibrary: Official ~TiddlyWiki Plugin Library
|
||||
@@ -43,6 +61,7 @@ OfficialPluginLibrary/Hint: The official ~TiddlyWiki plugin library at tiddlywik
|
||||
PluginReloadWarning: Please save {{$:/core/ui/Buttons/save-wiki}} and reload {{$:/core/ui/Buttons/refresh}} to allow changes to plugins to take effect
|
||||
RecentChanges/DateFormat: DDth MMM YYYY
|
||||
SystemTiddler/Tooltip: This is a system tiddler
|
||||
SystemTiddlers/Include/Prompt: Include system tiddlers
|
||||
TagManager/Colour/Heading: Colour
|
||||
TagManager/Count/Heading: Count
|
||||
TagManager/Icon/Heading: Icon
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
title: $:/config/NewJournal/
|
||||
|
||||
Title: DDth MMM YYYY
|
||||
Text:
|
||||
Tags: Journal
|
||||
|
||||
@@ -8,6 +8,7 @@ Matches: //<small><<resultCount>> matches</small>//
|
||||
Matches/All: All matches:
|
||||
Matches/Title: Title matches:
|
||||
Search: Search
|
||||
Search/TooShort: Search text too short
|
||||
Shadows/Caption: Shadows
|
||||
Shadows/Hint: Search for shadow tiddlers
|
||||
Shadows/Matches: //<small><<resultCount>> matches</small>//
|
||||
|
||||
@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/application/javascript
|
||||
description: JavaScript code
|
||||
name: application/javascript
|
||||
group: Developer
|
||||
group-sort: 2
|
||||
|
||||
@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/application/json
|
||||
description: JSON data
|
||||
name: application/json
|
||||
group: Developer
|
||||
group-sort: 2
|
||||
|
||||
@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/application/x-tiddler-dictionary
|
||||
description: Data dictionary
|
||||
name: application/x-tiddler-dictionary
|
||||
group: Developer
|
||||
group-sort: 2
|
||||
|
||||
@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/image/gif
|
||||
description: GIF image
|
||||
name: image/gif
|
||||
group: Image
|
||||
group-sort: 1
|
||||
|
||||
@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/image/jpeg
|
||||
description: JPEG image
|
||||
name: image/jpeg
|
||||
group: Image
|
||||
group-sort: 1
|
||||
|
||||
@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/image/png
|
||||
description: PNG image
|
||||
name: image/png
|
||||
group: Image
|
||||
group-sort: 1
|
||||
|
||||
@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/image/svg+xml
|
||||
description: Structured Vector Graphics image
|
||||
name: image/svg+xml
|
||||
group: Image
|
||||
group-sort: 1
|
||||
|
||||
@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/image/x-icon
|
||||
description: ICO format icon file
|
||||
name: image/x-icon
|
||||
group: Image
|
||||
group-sort: 1
|
||||
|
||||
@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/text/css
|
||||
description: Static stylesheet
|
||||
name: text/css
|
||||
group: Developer
|
||||
group-sort: 2
|
||||
|
||||
@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/text/html
|
||||
description: HTML markup
|
||||
name: text/html
|
||||
group: Text
|
||||
group-sort: 0
|
||||
|
||||
@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/text/plain
|
||||
description: Plain text
|
||||
name: text/plain
|
||||
group: Text
|
||||
group-sort: 0
|
||||
|
||||
@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/text/vnd.tiddlywiki
|
||||
description: TiddlyWiki 5
|
||||
name: text/vnd.tiddlywiki
|
||||
group: Text
|
||||
group-sort: 0
|
||||
|
||||
@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/text/x-tiddlywiki
|
||||
description: TiddlyWiki Classic
|
||||
name: text/x-tiddlywiki
|
||||
group: Text
|
||||
group-sort: 0
|
||||
|
||||
@@ -29,6 +29,24 @@ var Commander = function(commandTokens,callback,wiki,streams) {
|
||||
this.outputPath = path.resolve($tw.boot.wikiPath,$tw.config.wikiOutputSubDir);
|
||||
};
|
||||
|
||||
/*
|
||||
Log a string if verbose flag is set
|
||||
*/
|
||||
Commander.prototype.log = function(str) {
|
||||
if(this.verbose) {
|
||||
this.streams.output.write(str + "\n");
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Write a string if verbose flag is set
|
||||
*/
|
||||
Commander.prototype.write = function(str) {
|
||||
if(this.verbose) {
|
||||
this.streams.output.write(str);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Add a string of tokens to the command queue
|
||||
*/
|
||||
|
||||
145
core/modules/commands/fetch.js
Normal file
145
core/modules/commands/fetch.js
Normal file
@@ -0,0 +1,145 @@
|
||||
/*\
|
||||
title: $:/core/modules/commands/fetch.js
|
||||
type: application/javascript
|
||||
module-type: command
|
||||
|
||||
Commands to fetch external tiddlers
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.info = {
|
||||
name: "fetch",
|
||||
synchronous: false
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 2) {
|
||||
return "Missing subcommand and url";
|
||||
}
|
||||
var subcommand = this.params[0],
|
||||
url = this.params[1],
|
||||
importFilter = this.params[2] || "[all[tiddlers]]",
|
||||
transformFilter = this.params[3] || "";
|
||||
switch(subcommand) {
|
||||
case "file":
|
||||
return this.fetchFiles({
|
||||
url: url,
|
||||
importFilter: importFilter,
|
||||
transformFilter: transformFilter,
|
||||
callback: this.callback
|
||||
});
|
||||
break;
|
||||
case "files":
|
||||
return this.fetchFiles({
|
||||
urlFilter: url,
|
||||
importFilter: importFilter,
|
||||
transformFilter: transformFilter,
|
||||
callback: this.callback
|
||||
});
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Command.prototype.fetchFiles = function(options) {
|
||||
var self = this;
|
||||
// Get the list of URLs
|
||||
var urls;
|
||||
if(options.url) {
|
||||
urls = [options.url]
|
||||
} else if(options.urlFilter) {
|
||||
urls = $tw.wiki.filterTiddlers(options.urlFilter);
|
||||
} else {
|
||||
return "Missing URL";
|
||||
}
|
||||
// Process each URL in turn
|
||||
var next = 0;
|
||||
var getNextFile = function(err) {
|
||||
if(err) {
|
||||
return options.callback(err);
|
||||
}
|
||||
if(next < urls.length) {
|
||||
self.fetchFile(urls[next++],options,getNextFile);
|
||||
} else {
|
||||
options.callback(null);
|
||||
}
|
||||
};
|
||||
getNextFile(null);
|
||||
// Success
|
||||
return null;
|
||||
};
|
||||
|
||||
Command.prototype.fetchFile = function(url,options,callback) {
|
||||
var self = this,
|
||||
lib = url.substr(0,8) === "https://" ? require("https") : require("http");
|
||||
lib.get(url).on("response",function(response) {
|
||||
var type = (response.headers["content-type"] || "").split(";")[0],
|
||||
body = "";
|
||||
self.commander.write("Reading " + url + ": ");
|
||||
response.on("data",function(chunk) {
|
||||
body += chunk;
|
||||
self.commander.write(".");
|
||||
});
|
||||
response.on("end",function() {
|
||||
self.commander.write("\n");
|
||||
if(response.statusCode === 200) {
|
||||
self.processBody(body,type,options);
|
||||
callback(null);
|
||||
} else {
|
||||
callback("Error " + response.statusCode + " retrieving " + url)
|
||||
}
|
||||
});
|
||||
response.on("error",function(e) {
|
||||
console.log("Error on GET request: " + e);
|
||||
callback(e);
|
||||
});
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
Command.prototype.processBody = function(body,type,options) {
|
||||
// Deserialise the HTML file and put the tiddlers in their own wiki
|
||||
var self = this,
|
||||
incomingWiki = new $tw.Wiki(),
|
||||
tiddlers = this.commander.wiki.deserializeTiddlers(type || "text/html",body,{});
|
||||
$tw.utils.each(tiddlers,function(tiddler) {
|
||||
incomingWiki.addTiddler(new $tw.Tiddler(tiddler));
|
||||
});
|
||||
// Filter the tiddlers to select the ones we want
|
||||
var filteredTitles = incomingWiki.filterTiddlers(options.importFilter);
|
||||
// Import the selected tiddlers
|
||||
var count = 0;
|
||||
incomingWiki.each(function(tiddler,title) {
|
||||
if(filteredTitles.indexOf(title) !== -1) {
|
||||
var newTiddler;
|
||||
if(options.transformFilter) {
|
||||
var transformedTitle = (incomingWiki.filterTiddlers(options.transformFilter,null,self.commander.wiki.makeTiddlerIterator([title])) || [""])[0];
|
||||
if(transformedTitle) {
|
||||
self.commander.log("Importing " + title + " as " + transformedTitle)
|
||||
newTiddler = new $tw.Tiddler(tiddler,{title: transformedTitle});
|
||||
}
|
||||
} else {
|
||||
self.commander.log("Importing " + title)
|
||||
newTiddler = tiddler;
|
||||
}
|
||||
self.commander.wiki.importTiddler(newTiddler);
|
||||
count++;
|
||||
}
|
||||
});
|
||||
self.commander.log("Imported " + count + " tiddlers")
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
@@ -30,24 +30,21 @@ Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing filename";
|
||||
}
|
||||
var ext = path.extname(self.params[0]);
|
||||
fs.readFile(this.params[0],$tw.utils.getTypeEncoding(ext),function(err,data) {
|
||||
if (err) {
|
||||
self.callback(err);
|
||||
} else {
|
||||
var fields = {title: self.params[0]},
|
||||
type = path.extname(self.params[0]);
|
||||
var tiddlers = self.commander.wiki.deserializeTiddlers(type,data,fields);
|
||||
if(!tiddlers) {
|
||||
self.callback("No tiddlers found in file \"" + self.params[0] + "\"");
|
||||
} else {
|
||||
for(var t=0; t<tiddlers.length; t++) {
|
||||
self.commander.wiki.importTiddler(new $tw.Tiddler(tiddlers[t]));
|
||||
}
|
||||
self.callback(null);
|
||||
}
|
||||
}
|
||||
var ext = path.extname(self.params[0]),
|
||||
stat = fs.statSync(self.params[0]),
|
||||
tiddlers = $tw.loadTiddlersFromPath(self.params[0]),
|
||||
count = 0;
|
||||
$tw.utils.each(tiddlers,function(tiddlerInfo) {
|
||||
$tw.utils.each(tiddlerInfo.tiddlers,function(tiddler) {
|
||||
self.commander.wiki.importTiddler(new $tw.Tiddler(tiddler));
|
||||
count++;
|
||||
});
|
||||
});
|
||||
if(!count) {
|
||||
self.callback("No tiddlers found in file \"" + self.params[0] + "\"");
|
||||
} else {
|
||||
self.callback(null);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
@@ -34,12 +34,17 @@ Command.prototype.execute = function() {
|
||||
filename = path.resolve(this.commander.outputPath,this.params[1]),
|
||||
type = this.params[2] || "text/html",
|
||||
template = this.params[3],
|
||||
name = this.params[4],
|
||||
value = this.params[5],
|
||||
variables = {};
|
||||
$tw.utils.createFileDirectories(filename);
|
||||
if(template) {
|
||||
variables.currentTiddler = title;
|
||||
title = template;
|
||||
}
|
||||
if(name && value) {
|
||||
variables[name] = value;
|
||||
}
|
||||
fs.writeFile(filename,this.commander.wiki.renderTiddler(type,title,{variables: variables}),"utf8",function(err) {
|
||||
self.callback(err);
|
||||
});
|
||||
|
||||
@@ -91,57 +91,59 @@ SimpleServer.prototype.checkCredentials = function(request,incomingUsername,inco
|
||||
}
|
||||
};
|
||||
|
||||
SimpleServer.prototype.listen = function(port,host) {
|
||||
SimpleServer.prototype.requestHandler = function(request,response) {
|
||||
// Compose the state object
|
||||
var self = this;
|
||||
http.createServer(function(request,response) {
|
||||
// Compose the state object
|
||||
var state = {};
|
||||
state.wiki = self.wiki;
|
||||
state.server = self;
|
||||
state.urlInfo = url.parse(request.url);
|
||||
// Find the route that matches this path
|
||||
var route = self.findMatchingRoute(request,state);
|
||||
// Check for the username and password if we've got one
|
||||
var username = self.get("username"),
|
||||
password = self.get("password");
|
||||
if(username && password) {
|
||||
// Check they match
|
||||
if(self.checkCredentials(request,username,password) !== "ALLOWED") {
|
||||
var servername = state.wiki.getTiddlerText("$:/SiteTitle") || "TiddlyWiki5";
|
||||
response.writeHead(401,"Authentication required",{
|
||||
"WWW-Authenticate": 'Basic realm="Please provide your username and password to login to ' + servername + '"'
|
||||
});
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Return a 404 if we didn't find a route
|
||||
if(!route) {
|
||||
response.writeHead(404);
|
||||
var state = {};
|
||||
state.wiki = self.wiki;
|
||||
state.server = self;
|
||||
state.urlInfo = url.parse(request.url);
|
||||
// Find the route that matches this path
|
||||
var route = self.findMatchingRoute(request,state);
|
||||
// Check for the username and password if we've got one
|
||||
var username = self.get("username"),
|
||||
password = self.get("password");
|
||||
if(username && password) {
|
||||
// Check they match
|
||||
if(self.checkCredentials(request,username,password) !== "ALLOWED") {
|
||||
var servername = state.wiki.getTiddlerText("$:/SiteTitle") || "TiddlyWiki5";
|
||||
response.writeHead(401,"Authentication required",{
|
||||
"WWW-Authenticate": 'Basic realm="Please provide your username and password to login to ' + servername + '"'
|
||||
});
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
// Set the encoding for the incoming request
|
||||
// TODO: Presumably this would need tweaking if we supported PUTting binary tiddlers
|
||||
request.setEncoding("utf8");
|
||||
// Dispatch the appropriate method
|
||||
switch(request.method) {
|
||||
case "GET": // Intentional fall-through
|
||||
case "DELETE":
|
||||
}
|
||||
// Return a 404 if we didn't find a route
|
||||
if(!route) {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
// Set the encoding for the incoming request
|
||||
// TODO: Presumably this would need tweaking if we supported PUTting binary tiddlers
|
||||
request.setEncoding("utf8");
|
||||
// Dispatch the appropriate method
|
||||
switch(request.method) {
|
||||
case "GET": // Intentional fall-through
|
||||
case "DELETE":
|
||||
route.handler(request,response,state);
|
||||
break;
|
||||
case "PUT":
|
||||
var data = "";
|
||||
request.on("data",function(chunk) {
|
||||
data += chunk.toString();
|
||||
});
|
||||
request.on("end",function() {
|
||||
state.data = data;
|
||||
route.handler(request,response,state);
|
||||
break;
|
||||
case "PUT":
|
||||
var data = "";
|
||||
request.on("data",function(chunk) {
|
||||
data += chunk.toString();
|
||||
});
|
||||
request.on("end",function() {
|
||||
state.data = data;
|
||||
route.handler(request,response,state);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}).listen(port,host);
|
||||
});
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
SimpleServer.prototype.listen = function(port,host) {
|
||||
http.createServer(this.requestHandler.bind(this)).listen(port,host);
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
|
||||
@@ -72,19 +72,28 @@ exports["application/x-tiddler-html-div"] = function(text,fields) {
|
||||
};
|
||||
|
||||
exports["application/json"] = function(text,fields) {
|
||||
var incoming = JSON.parse(text),
|
||||
var incoming,
|
||||
results = [];
|
||||
if($tw.utils.isArray(incoming)) {
|
||||
for(var t=0; t<incoming.length; t++) {
|
||||
var incomingFields = incoming[t],
|
||||
fields = {};
|
||||
for(var f in incomingFields) {
|
||||
if(typeof incomingFields[f] === "string") {
|
||||
fields[f] = incomingFields[f];
|
||||
}
|
||||
try {
|
||||
incoming = JSON.parse(text);
|
||||
} catch(e) {
|
||||
incoming = [{
|
||||
title: "JSON error: " + e,
|
||||
text: ""
|
||||
}]
|
||||
}
|
||||
if(!$tw.utils.isArray(incoming)) {
|
||||
incoming = [incoming];
|
||||
}
|
||||
for(var t=0; t<incoming.length; t++) {
|
||||
var incomingFields = incoming[t],
|
||||
fields = {};
|
||||
for(var f in incomingFields) {
|
||||
if(typeof incomingFields[f] === "string") {
|
||||
fields[f] = incomingFields[f];
|
||||
}
|
||||
results.push(fields);
|
||||
}
|
||||
results.push(fields);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -64,7 +64,7 @@ Set the text of the engine if it doesn't currently have focus
|
||||
*/
|
||||
SimpleEngine.prototype.setText = function(text,type) {
|
||||
if(!this.domNode.isTiddlyWikiFakeDom) {
|
||||
if(this.domNode.ownerDocument.activeElement !== this.domNode) {
|
||||
if(this.domNode.ownerDocument.activeElement !== this.domNode || text === "") {
|
||||
this.domNode.value = text;
|
||||
}
|
||||
// Fix the height if needed
|
||||
|
||||
@@ -20,7 +20,7 @@ Parses an operation (i.e. a run) within a filter string
|
||||
Returns the new start position, after the parsed operation
|
||||
*/
|
||||
function parseFilterOperation(operators,filterString,p) {
|
||||
var operator, operand, bracketPos, curlyBracketPos;
|
||||
var nextBracketPos, operator;
|
||||
// Skip the starting square bracket
|
||||
if(filterString.charAt(p++) !== "[") {
|
||||
throw "Missing [ in filter expression";
|
||||
@@ -33,14 +33,14 @@ function parseFilterOperation(operators,filterString,p) {
|
||||
operator.prefix = filterString.charAt(p++);
|
||||
}
|
||||
// Get the operator name
|
||||
var nextBracketPos = filterString.substring(p).search(/[\[\{<\/]/);
|
||||
nextBracketPos = filterString.substring(p).search(/[\[\{<\/]/);
|
||||
if(nextBracketPos === -1) {
|
||||
throw "Missing [ in filter expression";
|
||||
}
|
||||
nextBracketPos += p;
|
||||
var bracket = filterString.charAt(nextBracketPos);
|
||||
operator.operator = filterString.substring(p,nextBracketPos);
|
||||
|
||||
|
||||
// Any suffix?
|
||||
var colon = operator.operator.indexOf(':');
|
||||
if(colon > -1) {
|
||||
@@ -79,7 +79,7 @@ console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if(nextBracketPos === -1) {
|
||||
throw "Missing closing bracket in filter expression";
|
||||
}
|
||||
@@ -87,7 +87,7 @@ console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand
|
||||
operator.operand = filterString.substring(p,nextBracketPos);
|
||||
}
|
||||
p = nextBracketPos + 1;
|
||||
|
||||
|
||||
// Push this operator
|
||||
operators.push(operator);
|
||||
} while(filterString.charAt(p) !== "]");
|
||||
|
||||
22
core/modules/filters/all/tags.js
Normal file
22
core/modules/filters/all/tags.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/all/tags.js
|
||||
type: application/javascript
|
||||
module-type: allfilteroperator
|
||||
|
||||
Filter function for [all[tags]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.tags = function(source,prefix,options) {
|
||||
return Object.keys(options.wiki.getTagMap());
|
||||
};
|
||||
|
||||
})();
|
||||
26
core/modules/filters/count.js
Normal file
26
core/modules/filters/count.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/count.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator returning the number of entries in the current list.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.count = function(source,operator,options) {
|
||||
var count = 0;
|
||||
source(function(tiddler,title) {
|
||||
count++;
|
||||
});
|
||||
return [count + ""];
|
||||
};
|
||||
|
||||
})();
|
||||
83
core/modules/filters/encodings.js
Normal file
83
core/modules/filters/encodings.js
Normal file
@@ -0,0 +1,83 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/decodeuricomponent.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for applying decodeURIComponent() to each item.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter functions
|
||||
*/
|
||||
|
||||
exports.decodeuricomponent = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(decodeURIComponent(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.encodeuricomponent = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(encodeURIComponent(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.decodeuri = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(decodeURI(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.encodeuri = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(encodeURI(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.decodehtml = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push($tw.utils.htmlDecode(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.encodehtml = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push($tw.utils.htmlEncode(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.stringify = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push($tw.utils.stringify(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.escaperegexp = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push($tw.utils.escapeRegExp(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
33
core/modules/filters/enlist.js
Normal file
33
core/modules/filters/enlist.js
Normal file
@@ -0,0 +1,33 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/enlist.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator returning its operand parsed as a list
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.enlist = function(source,operator,options) {
|
||||
var list = $tw.utils.parseStringArray(operator.operand);
|
||||
if(operator.prefix === "!") {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
if(list.indexOf(title) === -1) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
} else {
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -16,19 +16,37 @@ Filter operator for checking if a tiddler has the specified field
|
||||
Export our filter function
|
||||
*/
|
||||
exports.has = function(source,operator,options) {
|
||||
var results = [];
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(!tiddler || (tiddler && (!$tw.utils.hop(tiddler.fields,operator.operand) || tiddler.fields[operator.operand] === ""))) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
var results = [],
|
||||
invert = operator.prefix === "!";
|
||||
|
||||
if(operator.suffix === "field") {
|
||||
if(invert) {
|
||||
source(function(tiddler,title) {
|
||||
if(!tiddler || (tiddler && (!$tw.utils.hop(tiddler.fields,operator.operand)))) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && $tw.utils.hop(tiddler.fields,operator.operand)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && $tw.utils.hop(tiddler.fields,operator.operand) && !(tiddler.fields[operator.operand] === "" || tiddler.fields[operator.operand].length === 0)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
if(invert) {
|
||||
source(function(tiddler,title) {
|
||||
if(!tiddler || !$tw.utils.hop(tiddler.fields,operator.operand) || (tiddler.fields[operator.operand] === "")) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && $tw.utils.hop(tiddler.fields,operator.operand) && !(tiddler.fields[operator.operand] === "" || tiddler.fields[operator.operand].length === 0)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
41
core/modules/filters/insertbefore.js
Normal file
41
core/modules/filters/insertbefore.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/insertbefore.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Insert an item before another item in a list
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Order a list
|
||||
*/
|
||||
exports.insertbefore = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
var target = options.widget && options.widget.getVariable(operator.suffix || "currentTiddler");
|
||||
if(target !== operator.operand) {
|
||||
// Remove the entry from the list if it is present
|
||||
var pos = results.indexOf(operator.operand);
|
||||
if(pos !== -1) {
|
||||
results.splice(pos,1);
|
||||
}
|
||||
// Insert the entry before the target marker
|
||||
pos = results.indexOf(target);
|
||||
if(pos !== -1) {
|
||||
results.splice(pos,0,operator.operand);
|
||||
} else {
|
||||
results.push(operator.operand);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -28,11 +28,20 @@ Export our filter function
|
||||
exports.is = function(source,operator,options) {
|
||||
// Dispatch to the correct isfilteroperator
|
||||
var isFilterOperators = getIsFilterOperators();
|
||||
var isFilterOperator = isFilterOperators[operator.operand];
|
||||
if(isFilterOperator) {
|
||||
return isFilterOperator(source,operator.prefix,options);
|
||||
if(operator.operand) {
|
||||
var isFilterOperator = isFilterOperators[operator.operand];
|
||||
if(isFilterOperator) {
|
||||
return isFilterOperator(source,operator.prefix,options);
|
||||
} else {
|
||||
return [$tw.language.getString("Error/IsFilterOperator")];
|
||||
}
|
||||
} else {
|
||||
return [$tw.language.getString("Error/IsFilterOperator")];
|
||||
// Return all tiddlers if the operand is missing
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,23 @@ Filter operators for manipulating the current selection list
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Order a list
|
||||
*/
|
||||
exports.order = function(source,operator,options) {
|
||||
var results = [];
|
||||
if(operator.operand.toLowerCase() === "reverse") {
|
||||
source(function(tiddler,title) {
|
||||
results.unshift(title);
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
Reverse list
|
||||
*/
|
||||
|
||||
29
core/modules/filters/minlength.js
Normal file
29
core/modules/filters/minlength.js
Normal file
@@ -0,0 +1,29 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/minlength.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for filtering out titles that don't meet the minimum length in the operand
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.minlength = function(source,operator,options) {
|
||||
var results = [],
|
||||
minLength = parseInt(operator.operand || "",10) || 0;
|
||||
source(function(tiddler,title) {
|
||||
if(title.length >= minLength) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -20,12 +20,9 @@ exports.sameday = function(source,operator,options) {
|
||||
fieldName = operator.suffix || "modified",
|
||||
targetDate = (new Date($tw.utils.parseDate(operator.operand))).setHours(0,0,0,0);
|
||||
// Function to convert a date/time to a date integer
|
||||
var isSameDay = function(dateField) {
|
||||
return (new Date(dateField)).setHours(0,0,0,0) === targetDate;
|
||||
};
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && tiddler.fields[fieldName]) {
|
||||
if(isSameDay($tw.utils.parseDate(tiddler.fields[fieldName]))) {
|
||||
if(tiddler) {
|
||||
if(tiddler.getFieldDay(fieldName) === targetDate) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,19 +17,30 @@ Export our filter function
|
||||
*/
|
||||
exports.tag = function(source,operator,options) {
|
||||
var results = [];
|
||||
if(operator.prefix === "!") {
|
||||
if((operator.suffix || "").toLowerCase() === "strict" && !operator.operand) {
|
||||
// New semantics:
|
||||
// Always return copy of input if operator.operand is missing
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && !tiddler.hasTag(operator.operand)) {
|
||||
results.push(title);
|
||||
}
|
||||
results.push(title);
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && tiddler.hasTag(operator.operand)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
results = options.wiki.sortByList(results,operator.operand);
|
||||
// Old semantics:
|
||||
if(operator.prefix === "!") {
|
||||
// Returns a copy of the input if operator.operand is missing
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && !tiddler.hasTag(operator.operand)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Returns empty results if operator.operand is missing
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && tiddler.hasTag(operator.operand)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
results = options.wiki.sortByList(results,operator.operand);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -16,10 +16,11 @@ Filter operator for returning the names of the wiki parser rules in this wiki
|
||||
Export our filter function
|
||||
*/
|
||||
exports.wikiparserrules = function(source,operator,options) {
|
||||
var results = [];
|
||||
var results = [],
|
||||
operand = operator.operand;
|
||||
$tw.utils.each($tw.modules.types.wikirule,function(mod) {
|
||||
var exp = mod.exports;
|
||||
if(exp.types[operator.operand]) {
|
||||
if(!operand || exp.types[operand]) {
|
||||
results.push(exp.name);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -84,8 +84,9 @@ Extended filter operators to manipulate the current list.
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = parseInt(operator.suffix) || 1,
|
||||
marker = results.splice(index, 1);
|
||||
return results.slice(0, index + count).concat(marker).concat(results.slice(index + count));
|
||||
marker = results.splice(index, 1),
|
||||
offset = (index + count) > 0 ? index + count : 0;
|
||||
return results.slice(0, offset).concat(marker).concat(results.slice(offset));
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -18,6 +18,21 @@ exports.getInfoTiddlerFields = function() {
|
||||
// Basics
|
||||
infoTiddlerFields.push({title: "$:/info/browser", text: mapBoolean(!!$tw.browser)});
|
||||
infoTiddlerFields.push({title: "$:/info/node", text: mapBoolean(!!$tw.node)});
|
||||
// Document location
|
||||
if($tw.browser) {
|
||||
var setLocationProperty = function(name,value) {
|
||||
infoTiddlerFields.push({title: "$:/info/url/" + name, text: value});
|
||||
},
|
||||
location = document.location;
|
||||
setLocationProperty("full", (location.toString()).split("#")[0]);
|
||||
setLocationProperty("host", location.host);
|
||||
setLocationProperty("hostname", location.hostname);
|
||||
setLocationProperty("protocol", location.protocol);
|
||||
setLocationProperty("port", location.port);
|
||||
setLocationProperty("pathname", location.pathname);
|
||||
setLocationProperty("search", location.search);
|
||||
setLocationProperty("origin", location.origin);
|
||||
}
|
||||
return infoTiddlerFields;
|
||||
};
|
||||
|
||||
|
||||
40
core/modules/macros/jsontiddler.js
Normal file
40
core/modules/macros/jsontiddler.js
Normal file
@@ -0,0 +1,40 @@
|
||||
/*\
|
||||
title: $:/core/modules/macros/jsontiddler.js
|
||||
type: application/javascript
|
||||
module-type: macro
|
||||
|
||||
Macro to output a single tiddler to JSON
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Information about this macro
|
||||
*/
|
||||
|
||||
exports.name = "jsontiddler";
|
||||
|
||||
exports.params = [
|
||||
{name: "title"}
|
||||
];
|
||||
|
||||
/*
|
||||
Run the macro
|
||||
*/
|
||||
exports.run = function(title) {
|
||||
title = title || this.getVariable("currentTiddler");
|
||||
var tiddler = !!title && this.wiki.getTiddler(title),
|
||||
fields = new Object();
|
||||
if(tiddler) {
|
||||
for(var field in tiddler.fields) {
|
||||
fields[field] = tiddler.getFieldString(field);
|
||||
}
|
||||
}
|
||||
return JSON.stringify(fields,null,$tw.config.preferences.jsonSpaces);
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -21,14 +21,8 @@ var ImageParser = function(type,text,options) {
|
||||
src;
|
||||
if(options._canonical_uri) {
|
||||
element.attributes.src = {type: "string", value: options._canonical_uri};
|
||||
if(type === "application/pdf" || type === ".pdf") {
|
||||
element.tag = "embed";
|
||||
}
|
||||
} else if(text) {
|
||||
if(type === "application/pdf" || type === ".pdf") {
|
||||
element.attributes.src = {type: "string", value: "data:application/pdf;base64," + text};
|
||||
element.tag = "embed";
|
||||
} else if(type === "image/svg+xml" || type === ".svg") {
|
||||
if(type === "image/svg+xml" || type === ".svg") {
|
||||
element.attributes.src = {type: "string", value: "data:image/svg+xml," + encodeURIComponent(text)};
|
||||
} else {
|
||||
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
|
||||
@@ -42,7 +36,6 @@ exports["image/jpg"] = ImageParser;
|
||||
exports["image/jpeg"] = ImageParser;
|
||||
exports["image/png"] = ImageParser;
|
||||
exports["image/gif"] = ImageParser;
|
||||
exports["application/pdf"] = ImageParser;
|
||||
exports["image/x-icon"] = ImageParser;
|
||||
|
||||
})();
|
||||
|
||||
@@ -218,6 +218,7 @@ exports.parseAttribute = function(source,pos) {
|
||||
// Define our regexps
|
||||
var reAttributeName = /([^\/\s>"'=]+)/g,
|
||||
reUnquotedAttribute = /([^\/\s<>"'=]+)/g,
|
||||
reFilteredValue = /\{\{\{(.+?)\}\}\}/g,
|
||||
reIndirectValue = /\{\{([^\}]+)\}\}/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
@@ -243,29 +244,37 @@ exports.parseAttribute = function(source,pos) {
|
||||
node.type = "string";
|
||||
node.value = stringLiteral.value;
|
||||
} else {
|
||||
// Look for an indirect value
|
||||
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
|
||||
if(indirectValue) {
|
||||
pos = indirectValue.end;
|
||||
node.type = "indirect";
|
||||
node.textReference = indirectValue.match[1];
|
||||
// Look for a filtered value
|
||||
var filteredValue = $tw.utils.parseTokenRegExp(source,pos,reFilteredValue);
|
||||
if(filteredValue) {
|
||||
pos = filteredValue.end;
|
||||
node.type = "filtered";
|
||||
node.filter = filteredValue.match[1];
|
||||
} else {
|
||||
// Look for a unquoted value
|
||||
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
|
||||
if(unquotedValue) {
|
||||
pos = unquotedValue.end;
|
||||
node.type = "string";
|
||||
node.value = unquotedValue.match[1];
|
||||
// Look for an indirect value
|
||||
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
|
||||
if(indirectValue) {
|
||||
pos = indirectValue.end;
|
||||
node.type = "indirect";
|
||||
node.textReference = indirectValue.match[1];
|
||||
} else {
|
||||
// Look for a macro invocation value
|
||||
var macroInvocation = $tw.utils.parseMacroInvocation(source,pos);
|
||||
if(macroInvocation) {
|
||||
pos = macroInvocation.end;
|
||||
node.type = "macro";
|
||||
node.value = macroInvocation;
|
||||
} else {
|
||||
// Look for a unquoted value
|
||||
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
|
||||
if(unquotedValue) {
|
||||
pos = unquotedValue.end;
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
node.value = unquotedValue.match[1];
|
||||
} else {
|
||||
// Look for a macro invocation value
|
||||
var macroInvocation = $tw.utils.parseMacroInvocation(source,pos);
|
||||
if(macroInvocation) {
|
||||
pos = macroInvocation.end;
|
||||
node.type = "macro";
|
||||
node.value = macroInvocation;
|
||||
} else {
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
33
core/modules/parsers/pdfparser.js
Normal file
33
core/modules/parsers/pdfparser.js
Normal file
@@ -0,0 +1,33 @@
|
||||
/*\
|
||||
title: $:/core/modules/parsers/pdfparser.js
|
||||
type: application/javascript
|
||||
module-type: parser
|
||||
|
||||
The PDF parser embeds a PDF viewer
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var ImageParser = function(type,text,options) {
|
||||
var element = {
|
||||
type: "element",
|
||||
tag: "embed",
|
||||
attributes: {}
|
||||
},
|
||||
src;
|
||||
if(options._canonical_uri) {
|
||||
element.attributes.src = {type: "string", value: options._canonical_uri};
|
||||
} else if(text) {
|
||||
element.attributes.src = {type: "string", value: "data:application/pdf;base64," + text};
|
||||
}
|
||||
this.tree = [element];
|
||||
};
|
||||
|
||||
exports["application/pdf"] = ImageParser;
|
||||
|
||||
})();
|
||||
|
||||
@@ -12,7 +12,7 @@ The video parser parses a video tiddler into an embeddable HTML element
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var AudioParser = function(type,text,options) {
|
||||
var VideoParser = function(type,text,options) {
|
||||
var element = {
|
||||
type: "element",
|
||||
tag: "video",
|
||||
@@ -29,7 +29,8 @@ var AudioParser = function(type,text,options) {
|
||||
this.tree = [element];
|
||||
};
|
||||
|
||||
exports["video/mp4"] = AudioParser;
|
||||
exports["video/mp4"] = VideoParser;
|
||||
exports["video/quicktime"] = VideoParser;
|
||||
|
||||
})();
|
||||
|
||||
|
||||
@@ -101,6 +101,10 @@ exports.parseTag = function(source,pos,options) {
|
||||
node.type = node.tag.substr(1);
|
||||
}
|
||||
pos = token.end;
|
||||
// Check that the tag is terminated by a space, / or >
|
||||
if(!$tw.utils.parseWhiteSpace(source,pos) && !(source.charAt(pos) === "/") && !(source.charAt(pos) === ">") ) {
|
||||
return null;
|
||||
}
|
||||
// Process attributes
|
||||
var attribute = $tw.utils.parseAttribute(source,pos);
|
||||
while(attribute) {
|
||||
|
||||
@@ -61,7 +61,7 @@ exports.parse = function() {
|
||||
reEnd = /(\r?\n\\end[^\S\n\r]*(?:$|\r?\n))/mg;
|
||||
} else {
|
||||
// Otherwise, the end of the definition is marked by the end of the line
|
||||
reEnd = /(\r?\n)/mg;
|
||||
reEnd = /($|\r?\n)/mg;
|
||||
// Move past any whitespace
|
||||
this.parser.pos = $tw.utils.skipWhiteSpace(this.parser.source,this.parser.pos);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,12 @@ exports.types = {inline: true};
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
// Regexp to match
|
||||
this.matchRegExp = /~?\$:\/[a-zA-Z0-9/.\-_]+/mg;
|
||||
this.matchRegExp = new RegExp(
|
||||
"~?\\$:\\/[" +
|
||||
$tw.config.textPrimitives.anyLetter.substr(1,$tw.config.textPrimitives.anyLetter.length - 2) +
|
||||
"\/._-]+",
|
||||
"mg"
|
||||
);
|
||||
};
|
||||
|
||||
exports.parse = function() {
|
||||
|
||||
@@ -18,12 +18,14 @@ wiki: wiki store to be used
|
||||
pluginType: type of plugin to be switched
|
||||
controllerTitle: title of tiddler used to control switching of this resource
|
||||
defaultPlugins: array of default plugins to be used if nominated plugin isn't found
|
||||
onSwitch: callback when plugin is switched (single parameter is array of plugin titles)
|
||||
*/
|
||||
function PluginSwitcher(options) {
|
||||
this.wiki = options.wiki;
|
||||
this.pluginType = options.pluginType;
|
||||
this.controllerTitle = options.controllerTitle;
|
||||
this.defaultPlugins = options.defaultPlugins || [];
|
||||
this.onSwitch = options.onSwitch;
|
||||
// Switch to the current plugin
|
||||
this.switchPlugins();
|
||||
// Listen for changes to the selected plugin
|
||||
@@ -64,6 +66,10 @@ PluginSwitcher.prototype.switchPlugins = function() {
|
||||
var registeredTiddlers = $tw.wiki.registerPluginTiddlers(this.pluginType,plugins);
|
||||
// Unpack the current theme tiddlers
|
||||
$tw.wiki.unpackPluginTiddlers();
|
||||
// Call the switch handler
|
||||
if(this.onSwitch) {
|
||||
this.onSwitch(plugins);
|
||||
}
|
||||
};
|
||||
|
||||
exports.PluginSwitcher = PluginSwitcher;
|
||||
|
||||
@@ -37,10 +37,10 @@ function SaverHandler(options) {
|
||||
// Listen out for changes to tiddlers
|
||||
this.wiki.addEventListener("change",function(changes) {
|
||||
// Filter the changes so that we only count changes to tiddlers that we care about
|
||||
var filteredChanges = self.filterFn.call(self.wiki,function(callback) {
|
||||
var filteredChanges = self.filterFn.call(self.wiki,function(iterator) {
|
||||
$tw.utils.each(changes,function(change,title) {
|
||||
var tiddler = self.wiki.getTiddler(title);
|
||||
callback(tiddler,title);
|
||||
iterator(tiddler,title);
|
||||
});
|
||||
});
|
||||
// Adjust the number of changes
|
||||
|
||||
62
core/modules/savers/beaker.js
Normal file
62
core/modules/savers/beaker.js
Normal file
@@ -0,0 +1,62 @@
|
||||
/*\
|
||||
title: $:/core/modules/savers/beaker.js
|
||||
type: application/javascript
|
||||
module-type: saver
|
||||
|
||||
Saves files using the Beaker browser's (https://beakerbrowser.com) Dat protocol (https://datproject.org/)
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Set up the saver
|
||||
*/
|
||||
var BeakerSaver = function(wiki) {
|
||||
this.wiki = wiki;
|
||||
};
|
||||
|
||||
BeakerSaver.prototype.save = function(text,method,callback) {
|
||||
var url = (location.toString()).split("#")[0];
|
||||
dat.stat(url).then(function(value) {
|
||||
if(value.type === "directory") {
|
||||
url = url + "/index.html";
|
||||
}
|
||||
dat.writeFile(url,text,"utf8").then(function(value) {
|
||||
callback(null);
|
||||
},function(reason) {
|
||||
callback("Beaker Saver Write Error: " + reason);
|
||||
});
|
||||
},function(reason) {
|
||||
callback("Beaker Saver Stat Error: " + reason);
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
Information about this saver
|
||||
*/
|
||||
BeakerSaver.prototype.info = {
|
||||
name: "beaker",
|
||||
priority: 3000,
|
||||
capabilities: ["save", "autosave"]
|
||||
};
|
||||
|
||||
/*
|
||||
Static method that returns true if this saver is capable of working
|
||||
*/
|
||||
exports.canSave = function(wiki) {
|
||||
return !!window.dat;
|
||||
};
|
||||
|
||||
/*
|
||||
Create an instance of this saver
|
||||
*/
|
||||
exports.create = function(wiki) {
|
||||
return new BeakerSaver(wiki);
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -33,8 +33,6 @@ DownloadSaver.prototype.save = function(text,method,callback,options) {
|
||||
}
|
||||
// Set up the link
|
||||
var link = document.createElement("a");
|
||||
link.setAttribute("target","_blank");
|
||||
link.setAttribute("rel","noopener noreferrer");
|
||||
if(Blob !== undefined) {
|
||||
var blob = new Blob([text], {type: "text/html"});
|
||||
link.setAttribute("href", URL.createObjectURL(blob));
|
||||
@@ -55,10 +53,19 @@ Information about this saver
|
||||
*/
|
||||
DownloadSaver.prototype.info = {
|
||||
name: "download",
|
||||
priority: 100,
|
||||
capabilities: ["save", "download"]
|
||||
priority: 100
|
||||
};
|
||||
|
||||
Object.defineProperty(DownloadSaver.prototype.info, "capabilities", {
|
||||
get: function() {
|
||||
var capabilities = ["save", "download"];
|
||||
if(($tw.wiki.getTextReference("$:/config/DownloadSaver/AutoSave") || "").toLowerCase() === "yes") {
|
||||
capabilities.push("autosave");
|
||||
}
|
||||
return capabilities;
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
Static method that returns true if this saver is capable of working
|
||||
*/
|
||||
|
||||
@@ -21,36 +21,66 @@ Select the appropriate saver module and set it up
|
||||
var PutSaver = function(wiki) {
|
||||
this.wiki = wiki;
|
||||
var self = this;
|
||||
var uri = this.uri();
|
||||
// Async server probe. Until probe finishes, save will fail fast
|
||||
// See also https://github.com/Jermolene/TiddlyWiki5/issues/2276
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("OPTIONS",encodeURI(document.location.protocol + "//" + document.location.hostname + ":" + document.location.port + document.location.pathname));
|
||||
req.onload = function() {
|
||||
// Check DAV header http://www.webdav.org/specs/rfc2518.html#rfc.section.9.1
|
||||
self.serverAcceptsPuts = (this.status === 200 && !!this.getResponseHeader('dav'));
|
||||
};
|
||||
req.send();
|
||||
$tw.utils.httpRequest({
|
||||
url: uri,
|
||||
type: "OPTIONS",
|
||||
callback: function(err, data, xhr) {
|
||||
// Check DAV header http://www.webdav.org/specs/rfc2518.html#rfc.section.9.1
|
||||
if(!err) {
|
||||
self.serverAcceptsPuts = xhr.status === 200 && !!xhr.getResponseHeader("dav");
|
||||
}
|
||||
}
|
||||
});
|
||||
// Retrieve ETag if available
|
||||
$tw.utils.httpRequest({
|
||||
url: uri,
|
||||
type: "HEAD",
|
||||
callback: function(err, data, xhr) {
|
||||
if(!err) {
|
||||
self.etag = xhr.getResponseHeader("ETag");
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
PutSaver.prototype.save = function(text,method,callback) {
|
||||
if (!this.serverAcceptsPuts) {
|
||||
PutSaver.prototype.uri = function() {
|
||||
return encodeURI(document.location.toString().split("#")[0]);
|
||||
};
|
||||
|
||||
// TODO: in case of edit conflict
|
||||
// Prompt: Do you want to save over this? Y/N
|
||||
// Merging would be ideal, and may be possible using future generic merge flow
|
||||
PutSaver.prototype.save = function(text, method, callback) {
|
||||
if(!this.serverAcceptsPuts) {
|
||||
return false;
|
||||
}
|
||||
var req = new XMLHttpRequest();
|
||||
// TODO: store/check ETags if supported by server, to protect against overwrites
|
||||
// Prompt: Do you want to save over this? Y/N
|
||||
// Merging would be ideal, and may be possible using future generic merge flow
|
||||
req.onload = function() {
|
||||
if (this.status === 200 || this.status === 201) {
|
||||
callback(null); // success
|
||||
var self = this;
|
||||
var headers = { "Content-Type": "text/html;charset=UTF-8" };
|
||||
if(this.etag) {
|
||||
headers["If-Match"] = this.etag;
|
||||
}
|
||||
$tw.utils.httpRequest({
|
||||
url: this.uri(),
|
||||
type: "PUT",
|
||||
headers: headers,
|
||||
data: text,
|
||||
callback: function(err, data, xhr) {
|
||||
if(err) {
|
||||
callback(err);
|
||||
} if(xhr.status === 200 || xhr.status === 201) {
|
||||
self.etag = xhr.getResponseHeader("ETag");
|
||||
callback(null); // success
|
||||
} else if(xhr.status === 412) { // edit conflict
|
||||
var message = $tw.language.getString("Error/EditConflict");
|
||||
callback(message);
|
||||
} else {
|
||||
callback(xhr.responseText); // fail
|
||||
}
|
||||
}
|
||||
else {
|
||||
callback(this.responseText); // fail
|
||||
}
|
||||
};
|
||||
req.open("PUT", encodeURI(window.location.href));
|
||||
req.setRequestHeader("Content-Type", "text/html;charset=UTF-8");
|
||||
req.send(text);
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ TiddlyFoxSaver.prototype.info = {
|
||||
Static method that returns true if this saver is capable of working
|
||||
*/
|
||||
exports.canSave = function(wiki) {
|
||||
return (window.location.protocol === "file:");
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -29,16 +29,17 @@ function loadIFrame(url,callback) {
|
||||
callback(null,iframeInfo);
|
||||
} else {
|
||||
// Create the iframe and save it in the list
|
||||
var iframe = document.createElement("iframe"),
|
||||
iframeInfo = {
|
||||
url: url,
|
||||
status: "loading",
|
||||
domNode: iframe
|
||||
};
|
||||
var iframe = document.createElement("iframe");
|
||||
iframeInfo = {
|
||||
url: url,
|
||||
status: "loading",
|
||||
domNode: iframe
|
||||
};
|
||||
$tw.browserMessaging.iframeInfoMap[url] = iframeInfo;
|
||||
saveIFrameInfoTiddler(iframeInfo);
|
||||
// Add the iframe to the DOM and hide it
|
||||
iframe.style.display = "none";
|
||||
iframe.setAttribute("library","true");
|
||||
document.body.appendChild(iframe);
|
||||
// Set up onload
|
||||
iframe.onload = function() {
|
||||
@@ -57,6 +58,18 @@ function loadIFrame(url,callback) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Unload library iframe for given url
|
||||
*/
|
||||
function unloadIFrame(url){
|
||||
$tw.utils.each(document.getElementsByTagName('iframe'), function(iframe) {
|
||||
if(iframe.getAttribute("library") === "true" &&
|
||||
iframe.getAttribute("src") === url) {
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function saveIFrameInfoTiddler(iframeInfo) {
|
||||
$tw.wiki.addTiddler(new $tw.Tiddler($tw.wiki.getCreationFields(),{
|
||||
title: "$:/temp/ServerConnection/" + iframeInfo.url,
|
||||
@@ -93,6 +106,21 @@ exports.startup = function() {
|
||||
});
|
||||
}
|
||||
});
|
||||
// Listen for widget messages to control unloading the plugin library
|
||||
$tw.rootWidget.addEventListener("tm-unload-plugin-library",function(event) {
|
||||
var paramObject = event.paramObject || {},
|
||||
url = paramObject.url;
|
||||
$tw.browserMessaging.iframeInfoMap[url] = undefined;
|
||||
if(url) {
|
||||
unloadIFrame(url);
|
||||
$tw.utils.each(
|
||||
$tw.wiki.filterTiddlers("[[$:/temp/ServerConnection/" + url + "]] [prefix[$:/temp/RemoteAssetInfo/" + url + "/]]"),
|
||||
function(title) {
|
||||
$tw.wiki.deleteTiddler(title);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tm-load-plugin-from-library",function(event) {
|
||||
var paramObject = event.paramObject || {},
|
||||
url = paramObject.url,
|
||||
|
||||
@@ -63,7 +63,17 @@ exports.startup = function() {
|
||||
controllerTitle: "$:/language",
|
||||
defaultPlugins: [
|
||||
"$:/languages/en-US"
|
||||
]
|
||||
],
|
||||
onSwitch: function(plugins) {
|
||||
if($tw.browser) {
|
||||
var pluginTiddler = $tw.wiki.getTiddler(plugins[0]);
|
||||
if(pluginTiddler) {
|
||||
document.documentElement.setAttribute("dir",pluginTiddler.getFieldString("text-direction") || "auto");
|
||||
} else {
|
||||
document.documentElement.removeAttribute("dir");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// Kick off the theme manager
|
||||
$tw.themeManager = new $tw.PluginSwitcher({
|
||||
|
||||
@@ -53,6 +53,10 @@ exports.startup = function() {
|
||||
$tw.rootWidget.addEventListener("tm-browser-refresh",function(event) {
|
||||
window.location.reload(true);
|
||||
});
|
||||
// Listen for the tm-print message
|
||||
$tw.rootWidget.addEventListener("tm-print",function(event) {
|
||||
(event.event.view || window).print();
|
||||
});
|
||||
// Listen for the tm-home message
|
||||
$tw.rootWidget.addEventListener("tm-home",function(event) {
|
||||
window.location.hash = "";
|
||||
|
||||
@@ -49,7 +49,10 @@ exports.startup = function() {
|
||||
$tw.wiki.removeEventListener("change",refreshHandler);
|
||||
},false);
|
||||
// Set up the styles
|
||||
var styleWidgetNode = $tw.wiki.makeTranscludeWidget("$:/core/ui/PageStylesheet",{document: $tw.fakeDocument, variables: variables}),
|
||||
var styleWidgetNode = $tw.wiki.makeTranscludeWidget("$:/core/ui/PageStylesheet",{
|
||||
document: $tw.fakeDocument,
|
||||
variables: variables,
|
||||
importPageMacros: true}),
|
||||
styleContainer = $tw.fakeDocument.createElement("style");
|
||||
styleWidgetNode.render(styleContainer,null);
|
||||
var styleElement = srcDocument.createElement("style");
|
||||
|
||||
@@ -12,6 +12,18 @@ The syncer tracks changes to the store. If a syncadaptor is used then individual
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Defaults
|
||||
*/
|
||||
Syncer.prototype.titleIsLoggedIn = "$:/status/IsLoggedIn";
|
||||
Syncer.prototype.titleUserName = "$:/status/UserName";
|
||||
Syncer.prototype.titleSyncFilter = "$:/config/SyncFilter";
|
||||
Syncer.prototype.titleSavedNotification = "$:/language/Notifications/Save/Done";
|
||||
Syncer.prototype.taskTimerInterval = 1 * 1000; // Interval for sync timer
|
||||
Syncer.prototype.throttleInterval = 1 * 1000; // Defer saving tiddlers if they've changed in the last 1s...
|
||||
Syncer.prototype.fallbackInterval = 10 * 1000; // Unless the task is older than 10s
|
||||
Syncer.prototype.pollTimerInterval = 60 * 1000; // Interval for polling for changes from the adaptor
|
||||
|
||||
/*
|
||||
Instantiate the syncer with the following options:
|
||||
syncadaptor: reference to syncadaptor to be used
|
||||
@@ -21,8 +33,16 @@ function Syncer(options) {
|
||||
var self = this;
|
||||
this.wiki = options.wiki;
|
||||
this.syncadaptor = options.syncadaptor;
|
||||
this.titleIsLoggedIn = options.titleIsLoggedIn || this.titleIsLoggedIn;
|
||||
this.titleUserName = options.titleUserName || this.titleUserName;
|
||||
this.titleSyncFilter = options.titleSyncFilter || this.titleSyncFilter;
|
||||
this.titleSavedNotification = options.titleSavedNotification || this.titleSavedNotification;
|
||||
this.taskTimerInterval = options.taskTimerInterval || this.taskTimerInterval;
|
||||
this.throttleInterval = options.throttleInterval || this.throttleInterval;
|
||||
this.fallbackInterval = options.fallbackInterval || this.fallbackInterval;
|
||||
this.pollTimerInterval = options.pollTimerInterval || this.pollTimerInterval;
|
||||
// Make a logger
|
||||
this.logger = new $tw.utils.Logger("syncer" + ($tw.browser ? "-browser" : "") + ($tw.node ? "-server" : ""));
|
||||
this.logger = new $tw.utils.Logger("syncer" + ($tw.browser ? "-browser" : "") + ($tw.node ? "-server" : "") + (this.syncadaptor.name ? ("-" + this.syncadaptor.name) : ""));
|
||||
// Compile the dirty tiddler filter
|
||||
this.filterFn = this.wiki.compileFilter(this.wiki.getTiddlerText(this.titleSyncFilter));
|
||||
// Record information for known tiddlers
|
||||
@@ -69,19 +89,6 @@ function Syncer(options) {
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
Constants
|
||||
*/
|
||||
Syncer.prototype.titleIsLoggedIn = "$:/status/IsLoggedIn";
|
||||
Syncer.prototype.titleUserName = "$:/status/UserName";
|
||||
Syncer.prototype.titleSyncFilter = "$:/config/SyncFilter";
|
||||
Syncer.prototype.titleSavedNotification = "$:/language/Notifications/Save/Done";
|
||||
Syncer.prototype.taskTimerInterval = 1 * 1000; // Interval for sync timer
|
||||
Syncer.prototype.throttleInterval = 1 * 1000; // Defer saving tiddlers if they've changed in the last 1s...
|
||||
Syncer.prototype.fallbackInterval = 10 * 1000; // Unless the task is older than 10s
|
||||
Syncer.prototype.pollTimerInterval = 60 * 1000; // Interval for polling for changes from the adaptor
|
||||
|
||||
|
||||
/*
|
||||
Read (or re-read) the latest tiddler info from the store
|
||||
*/
|
||||
@@ -135,7 +142,7 @@ Syncer.prototype.updateDirtyStatus = function() {
|
||||
/*
|
||||
Save an incoming tiddler in the store, and updates the associated tiddlerInfo
|
||||
*/
|
||||
Syncer.prototype.storeTiddler = function(tiddlerFields) {
|
||||
Syncer.prototype.storeTiddler = function(tiddlerFields,hasBeenLazyLoaded) {
|
||||
// Save the tiddler
|
||||
var tiddler = new $tw.Tiddler(this.wiki.getTiddler(tiddlerFields.title),tiddlerFields);
|
||||
this.wiki.addTiddler(tiddler);
|
||||
@@ -144,7 +151,7 @@ Syncer.prototype.storeTiddler = function(tiddlerFields) {
|
||||
revision: tiddlerFields.revision,
|
||||
adaptorInfo: this.syncadaptor.getTiddlerInfo(tiddler),
|
||||
changeCount: this.wiki.getChangeCount(tiddlerFields.title),
|
||||
hasBeenLazyLoaded: true
|
||||
hasBeenLazyLoaded: hasBeenLazyLoaded !== undefined ? hasBeenLazyLoaded : true
|
||||
};
|
||||
};
|
||||
|
||||
@@ -218,7 +225,7 @@ Syncer.prototype.syncFromServer = function() {
|
||||
});
|
||||
} else {
|
||||
// Load the skinny version of the tiddler
|
||||
self.storeTiddler(tiddlerFields);
|
||||
self.storeTiddler(tiddlerFields,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -404,7 +411,7 @@ Process the task queue, performing the next task if appropriate
|
||||
Syncer.prototype.processTaskQueue = function() {
|
||||
var self = this;
|
||||
// Only process a task if the sync adaptor is fully initialised and we're not already performing a task. If we are already performing a task then we'll dispatch the next one when it completes
|
||||
if(this.syncadaptor.isReady() && this.numTasksInProgress() === 0) {
|
||||
if((!this.syncadaptor.isReady || this.syncadaptor.isReady()) && this.numTasksInProgress() === 0) {
|
||||
// Choose the next task to perform
|
||||
var task = this.chooseNextTask();
|
||||
// Perform the task if we had one
|
||||
@@ -499,7 +506,7 @@ Syncer.prototype.dispatchTask = function(task,callback) {
|
||||
}
|
||||
// Store the tiddler
|
||||
if(tiddlerFields) {
|
||||
self.storeTiddler(tiddlerFields);
|
||||
self.storeTiddler(tiddlerFields,true);
|
||||
}
|
||||
// Invoke the callback
|
||||
callback(null);
|
||||
|
||||
@@ -39,6 +39,24 @@ exports.getFieldString = function(field) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Get all the fields as a hashmap of strings. Options:
|
||||
exclude: an array of field names to exclude
|
||||
*/
|
||||
exports.getFieldStrings = function(options) {
|
||||
options = options || {};
|
||||
var exclude = options.exclude || [];
|
||||
var fields = {};
|
||||
for(var field in this.fields) {
|
||||
if($tw.utils.hop(this.fields,field)) {
|
||||
if(exclude.indexOf(field) === -1) {
|
||||
fields[field] = this.getFieldString(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
};
|
||||
|
||||
/*
|
||||
Get all the fields as a name:value block. Options:
|
||||
exclude: an array of field names to exclude
|
||||
@@ -108,4 +126,17 @@ exports.isEqual = function(tiddler,excludeFields) {
|
||||
return differences.length === 0;
|
||||
};
|
||||
|
||||
exports.getFieldDay = function(field) {
|
||||
if(this.cache && this.cache.day && $tw.utils.hop(this.cache.day,field) ) {
|
||||
return this.cache.day[field];
|
||||
}
|
||||
var day = "";
|
||||
if(this.fields[field]) {
|
||||
day = (new Date($tw.utils.parseDate(this.fields[field]))).setHours(0,0,0,0);
|
||||
}
|
||||
this.cache.day = this.cache.day || {};
|
||||
this.cache.day[field] = day;
|
||||
return day;
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
181
core/modules/utils/dom/dragndrop.js
Normal file
181
core/modules/utils/dom/dragndrop.js
Normal file
@@ -0,0 +1,181 @@
|
||||
/*\
|
||||
title: $:/core/modules/utils/dom/dragndrop.js
|
||||
type: application/javascript
|
||||
module-type: utils
|
||||
|
||||
Browser data transfer utilities, used with the clipboard and drag and drop
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Options:
|
||||
|
||||
domNode: dom node to make draggable
|
||||
dragImageType: "pill" or "dom"
|
||||
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
|
||||
*/
|
||||
exports.makeDraggable = function(options) {
|
||||
var dragImageType = options.dragImageType || "dom",
|
||||
dragImage,
|
||||
domNode = options.domNode;
|
||||
// Make the dom node draggable (not necessary for anchor tags)
|
||||
if((domNode.tagName || "").toLowerCase() !== "a") {
|
||||
domNode.setAttribute("draggable","true");
|
||||
}
|
||||
// Add event handlers
|
||||
$tw.utils.addEventListeners(domNode,[
|
||||
{name: "dragstart", handlerFunction: function(event) {
|
||||
// Collect the tiddlers being dragged
|
||||
var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(),
|
||||
dragFilter = options.dragFilterFn && options.dragFilterFn(),
|
||||
titles = dragTiddler ? [dragTiddler] : [];
|
||||
if(dragFilter) {
|
||||
titles.push.apply(titles,options.widget.wiki.filterTiddlers(dragFilter,options.widget));
|
||||
}
|
||||
var titleString = $tw.utils.stringifyList(titles);
|
||||
// Check that we've something to drag
|
||||
if(titles.length > 0 && event.target === domNode) {
|
||||
// Mark the drag in progress
|
||||
$tw.dragInProgress = domNode;
|
||||
// Set the dragging class on the element being dragged
|
||||
$tw.utils.addClass(event.target,"tc-dragging");
|
||||
// Create the drag image elements
|
||||
dragImage = options.widget.document.createElement("div");
|
||||
dragImage.className = "tc-tiddler-dragger";
|
||||
var inner = options.widget.document.createElement("div");
|
||||
inner.className = "tc-tiddler-dragger-inner";
|
||||
inner.appendChild(options.widget.document.createTextNode(
|
||||
titles.length === 1 ?
|
||||
titles[0] :
|
||||
titles.length + " tiddlers"
|
||||
));
|
||||
dragImage.appendChild(inner);
|
||||
options.widget.document.body.appendChild(dragImage);
|
||||
// Set the data transfer properties
|
||||
var dataTransfer = event.dataTransfer;
|
||||
// Set up the image
|
||||
dataTransfer.effectAllowed = "all";
|
||||
if(dataTransfer.setDragImage) {
|
||||
if(dragImageType === "pill") {
|
||||
dataTransfer.setDragImage(dragImage.firstChild,-16,-16);
|
||||
} else {
|
||||
var r = domNode.getBoundingClientRect();
|
||||
dataTransfer.setDragImage(domNode,event.clientX-r.left,event.clientY-r.top);
|
||||
}
|
||||
}
|
||||
// Set up the data transfer
|
||||
if(dataTransfer.clearData) {
|
||||
dataTransfer.clearData();
|
||||
}
|
||||
var jsonData = [];
|
||||
if(titles.length > 1) {
|
||||
titles.forEach(function(title) {
|
||||
jsonData.push(options.widget.wiki.getTiddlerAsJson(title));
|
||||
});
|
||||
jsonData = "[" + jsonData.join(",") + "]";
|
||||
} else {
|
||||
jsonData = options.widget.wiki.getTiddlerAsJson(titles[0]);
|
||||
}
|
||||
// IE doesn't like these content types
|
||||
if(!$tw.browser.isIE) {
|
||||
dataTransfer.setData("text/vnd.tiddler",jsonData);
|
||||
dataTransfer.setData("text/plain",titleString);
|
||||
dataTransfer.setData("text/x-moz-url","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
||||
}
|
||||
dataTransfer.setData("URL","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
||||
dataTransfer.setData("Text",titleString);
|
||||
event.stopPropagation();
|
||||
}
|
||||
return false;
|
||||
}},
|
||||
{name: "dragend", handlerFunction: function(event) {
|
||||
if(event.target === domNode) {
|
||||
$tw.dragInProgress = null;
|
||||
// Remove the dragging class on the element being dragged
|
||||
$tw.utils.removeClass(event.target,"tc-dragging");
|
||||
// Delete the drag image element
|
||||
if(dragImage) {
|
||||
dragImage.parentNode.removeChild(dragImage);
|
||||
dragImage = null;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}}
|
||||
]);
|
||||
};
|
||||
|
||||
exports.importDataTransfer = function(dataTransfer,fallbackTitle,callback) {
|
||||
// Try each provided data type in turn
|
||||
for(var t=0; t<importDataTypes.length; t++) {
|
||||
if(!$tw.browser.isIE || importDataTypes[t].IECompatible) {
|
||||
// Get the data
|
||||
var dataType = importDataTypes[t];
|
||||
var data = dataTransfer.getData(dataType.type);
|
||||
// Import the tiddlers in the data
|
||||
if(data !== "" && data !== null) {
|
||||
if($tw.log.IMPORT) {
|
||||
console.log("Importing data type '" + dataType.type + "', data: '" + data + "'")
|
||||
}
|
||||
var tiddlerFields = dataType.toTiddlerFieldsArray(data,fallbackTitle);
|
||||
callback(tiddlerFields);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var importDataTypes = [
|
||||
{type: "text/vnd.tiddler", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
||||
return parseJSONTiddlers(data,fallbackTitle);
|
||||
}},
|
||||
{type: "URL", IECompatible: true, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
||||
// Check for tiddler data URI
|
||||
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
if(match) {
|
||||
return parseJSONTiddlers(match[1],fallbackTitle);
|
||||
} else {
|
||||
return [{title: fallbackTitle, text: data}]; // As URL string
|
||||
}
|
||||
}},
|
||||
{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);
|
||||
if(match) {
|
||||
return parseJSONTiddlers(match[1],fallbackTitle);
|
||||
} else {
|
||||
return [{title: fallbackTitle, text: data}]; // As URL string
|
||||
}
|
||||
}},
|
||||
{type: "text/html", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
||||
return [{title: fallbackTitle, text: data}];
|
||||
}},
|
||||
{type: "text/plain", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
||||
return [{title: fallbackTitle, text: data}];
|
||||
}},
|
||||
{type: "Text", IECompatible: true, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
||||
return [{title: fallbackTitle, text: data}];
|
||||
}},
|
||||
{type: "text/uri-list", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
||||
return [{title: fallbackTitle, text: data}];
|
||||
}}
|
||||
];
|
||||
|
||||
function parseJSONTiddlers(json,fallbackTitle) {
|
||||
var data = JSON.parse(json);
|
||||
if(!$tw.utils.isArray(data)) {
|
||||
data = [data];
|
||||
}
|
||||
data.forEach(function(fields) {
|
||||
fields.title = fields.title || fallbackTitle;
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -17,10 +17,12 @@ A quick and dirty HTTP function; to be refactored later. Options are:
|
||||
url: URL to retrieve
|
||||
type: GET, PUT, POST etc
|
||||
callback: function invoked with (err,data)
|
||||
returnProp: string name of the property to return as first argument of callback
|
||||
*/
|
||||
exports.httpRequest = function(options) {
|
||||
var type = options.type || "GET",
|
||||
headers = options.headers || {accept: "application/json"},
|
||||
returnProp = options.returnProp || "responseText",
|
||||
request = new XMLHttpRequest(),
|
||||
data = "",
|
||||
f,results;
|
||||
@@ -41,7 +43,7 @@ exports.httpRequest = function(options) {
|
||||
if(this.readyState === 4) {
|
||||
if(this.status === 200 || this.status === 201 || this.status === 204) {
|
||||
// Success!
|
||||
options.callback(null,this.responseText,this);
|
||||
options.callback(null,this[returnProp],this);
|
||||
return;
|
||||
}
|
||||
// Something went wrong
|
||||
|
||||
@@ -81,14 +81,16 @@ Modal.prototype.display = function(title,options) {
|
||||
}}}],
|
||||
parentWidget: $tw.rootWidget,
|
||||
document: document,
|
||||
variables: variables
|
||||
variables: variables,
|
||||
importPageMacros: true
|
||||
});
|
||||
headerWidgetNode.render(headerTitle,null);
|
||||
// Render the body of the message
|
||||
var bodyWidgetNode = this.wiki.makeTranscludeWidget(title,{
|
||||
parentWidget: $tw.rootWidget,
|
||||
document: document,
|
||||
variables: variables
|
||||
variables: variables,
|
||||
importPageMacros: true
|
||||
});
|
||||
bodyWidgetNode.render(modalBody,null);
|
||||
// Setup the link if present
|
||||
@@ -128,7 +130,8 @@ Modal.prototype.display = function(title,options) {
|
||||
]}],
|
||||
parentWidget: $tw.rootWidget,
|
||||
document: document,
|
||||
variables: variables
|
||||
variables: variables,
|
||||
importPageMacros: true
|
||||
});
|
||||
footerWidgetNode.render(modalFooterButtons,null);
|
||||
// Set up the refresh handler
|
||||
|
||||
@@ -41,7 +41,11 @@ Notifier.prototype.display = function(title,options) {
|
||||
// Create the variables
|
||||
var variables = $tw.utils.extend({currentTiddler: title},options.variables);
|
||||
// Render the body of the notification
|
||||
var widgetNode = this.wiki.makeTranscludeWidget(title,{parentWidget: $tw.rootWidget, document: document, variables: variables});
|
||||
var widgetNode = this.wiki.makeTranscludeWidget(title,{
|
||||
parentWidget: $tw.rootWidget,
|
||||
document: document,
|
||||
variables: variables,
|
||||
importPageMacros: true});
|
||||
widgetNode.render(notification,null);
|
||||
refreshHandler = function(changes) {
|
||||
widgetNode.refresh(changes,notification,null);
|
||||
|
||||
@@ -23,7 +23,7 @@ var bumpSequenceNumber = function(object) {
|
||||
|
||||
var TW_TextNode = function(text) {
|
||||
bumpSequenceNumber(this);
|
||||
this.textContent = text;
|
||||
this.textContent = text + "";
|
||||
};
|
||||
|
||||
Object.defineProperty(TW_TextNode.prototype, "nodeType", {
|
||||
@@ -66,7 +66,7 @@ TW_Element.prototype.setAttribute = function(name,value) {
|
||||
if(this.isRaw) {
|
||||
throw "Cannot setAttribute on a raw TW_Element";
|
||||
}
|
||||
this.attributes[name] = value;
|
||||
this.attributes[name] = value + "";
|
||||
};
|
||||
|
||||
TW_Element.prototype.setAttributeNS = function(namespace,name,value) {
|
||||
@@ -139,7 +139,7 @@ Object.defineProperty(TW_Element.prototype, "className", {
|
||||
return this.attributes["class"] || "";
|
||||
},
|
||||
set: function(value) {
|
||||
this.attributes["class"] = value;
|
||||
this.attributes["class"] = value + "";
|
||||
}
|
||||
});
|
||||
|
||||
@@ -148,7 +148,7 @@ Object.defineProperty(TW_Element.prototype, "value", {
|
||||
return this.attributes.value || "";
|
||||
},
|
||||
set: function(value) {
|
||||
this.attributes.value = value;
|
||||
this.attributes.value = value + "";
|
||||
}
|
||||
});
|
||||
|
||||
@@ -206,13 +206,29 @@ Object.defineProperty(TW_Element.prototype, "innerHTML", {
|
||||
set: function(value) {
|
||||
this.isRaw = true;
|
||||
this.rawHTML = value;
|
||||
this.rawTextContent = null;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(TW_Element.prototype, "textInnerHTML", {
|
||||
set: function(value) {
|
||||
if(this.isRaw) {
|
||||
this.rawTextContent = value;
|
||||
} else {
|
||||
throw "Cannot set textInnerHTML of a non-raw TW_Element";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(TW_Element.prototype, "textContent", {
|
||||
get: function() {
|
||||
if(this.isRaw) {
|
||||
throw "Cannot get textContent on a raw TW_Element";
|
||||
if(this.rawTextContent === null) {
|
||||
console.log(booboo)
|
||||
throw "Cannot get textContent on a raw TW_Element";
|
||||
} else {
|
||||
return this.rawTextContent;
|
||||
}
|
||||
} else {
|
||||
var b = [];
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
|
||||
@@ -19,6 +19,15 @@ exports.warning = function(text) {
|
||||
console.log($tw.node ? "\x1b[1;33m" + text + "\x1b[0m" : text);
|
||||
};
|
||||
|
||||
/*
|
||||
Repeatedly replaces a substring within a string. Like String.prototype.replace, but without any of the default special handling of $ sequences in the replace string
|
||||
*/
|
||||
exports.replaceString = function(text,search,replace) {
|
||||
return text.replace(search,function() {
|
||||
return replace;
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Repeats a string
|
||||
*/
|
||||
@@ -215,11 +224,13 @@ exports.extendDeepCopy = function(object,extendedProperties) {
|
||||
|
||||
exports.deepFreeze = function deepFreeze(object) {
|
||||
var property, key;
|
||||
Object.freeze(object);
|
||||
for(key in object) {
|
||||
property = object[key];
|
||||
if($tw.utils.hop(object,key) && (typeof property === "object") && !Object.isFrozen(property)) {
|
||||
deepFreeze(property);
|
||||
if(object) {
|
||||
Object.freeze(object);
|
||||
for(key in object) {
|
||||
property = object[key];
|
||||
if($tw.utils.hop(object,key) && (typeof property === "object") && !Object.isFrozen(property)) {
|
||||
deepFreeze(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -349,7 +360,8 @@ exports.getWeek = function(date) {
|
||||
d = 7; // JavaScript Sun=0, ISO Sun=7
|
||||
}
|
||||
dt.setTime(dt.getTime() + (4 - d) * 86400000);// shift day to Thurs of same week to calculate weekNo
|
||||
var n = Math.floor((dt.getTime()-new Date(dt.getFullYear(),0,1) + 3600000) / 86400000);
|
||||
var x = new Date(dt.getFullYear(),0,1);
|
||||
var n = Math.floor((dt.getTime() - x.getTime()) / 86400000);
|
||||
return Math.floor(n / 7) + 1;
|
||||
};
|
||||
|
||||
@@ -687,7 +699,6 @@ exports.tagToCssSelector = function(tagName) {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
IE does not have sign function
|
||||
*/
|
||||
@@ -709,10 +720,88 @@ exports.strEndsWith = function(str,ending,position) {
|
||||
if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > str.length) {
|
||||
position = str.length;
|
||||
}
|
||||
position -= str.length;
|
||||
position -= ending.length;
|
||||
var lastIndex = str.indexOf(ending, position);
|
||||
return lastIndex !== -1 && lastIndex === position;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Transliterate string from eg. Cyrillic Russian to Latin
|
||||
*/
|
||||
var transliterationPairs = {
|
||||
"Ё":"YO",
|
||||
"Й":"I",
|
||||
"Ц":"TS",
|
||||
"У":"U",
|
||||
"К":"K",
|
||||
"Е":"E",
|
||||
"Н":"N",
|
||||
"Г":"G",
|
||||
"Ш":"SH",
|
||||
"Щ":"SCH",
|
||||
"З":"Z",
|
||||
"Х":"H",
|
||||
"Ъ":"'",
|
||||
"ё":"yo",
|
||||
"й":"i",
|
||||
"ц":"ts",
|
||||
"у":"u",
|
||||
"к":"k",
|
||||
"е":"e",
|
||||
"н":"n",
|
||||
"г":"g",
|
||||
"ш":"sh",
|
||||
"щ":"sch",
|
||||
"з":"z",
|
||||
"х":"h",
|
||||
"ъ":"'",
|
||||
"Ф":"F",
|
||||
"Ы":"I",
|
||||
"В":"V",
|
||||
"А":"a",
|
||||
"П":"P",
|
||||
"Р":"R",
|
||||
"О":"O",
|
||||
"Л":"L",
|
||||
"Д":"D",
|
||||
"Ж":"ZH",
|
||||
"Э":"E",
|
||||
"ф":"f",
|
||||
"ы":"i",
|
||||
"в":"v",
|
||||
"а":"a",
|
||||
"п":"p",
|
||||
"р":"r",
|
||||
"о":"o",
|
||||
"л":"l",
|
||||
"д":"d",
|
||||
"ж":"zh",
|
||||
"э":"e",
|
||||
"Я":"Ya",
|
||||
"Ч":"CH",
|
||||
"С":"S",
|
||||
"М":"M",
|
||||
"И":"I",
|
||||
"Т":"T",
|
||||
"Ь":"'",
|
||||
"Б":"B",
|
||||
"Ю":"YU",
|
||||
"я":"ya",
|
||||
"ч":"ch",
|
||||
"с":"s",
|
||||
"м":"m",
|
||||
"и":"i",
|
||||
"т":"t",
|
||||
"ь":"'",
|
||||
"б":"b",
|
||||
"ю":"yu"
|
||||
};
|
||||
|
||||
exports.transliterate = function(str) {
|
||||
return str.split("").map(function(char) {
|
||||
return transliterationPairs[char] || char;
|
||||
}).join("");
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
81
core/modules/widgets/action-createtiddler.js
Normal file
81
core/modules/widgets/action-createtiddler.js
Normal file
@@ -0,0 +1,81 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/action-createtiddler.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Action widget to create a new tiddler with a unique name and specified fields.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var CreateTiddlerWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
CreateTiddlerWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
CreateTiddlerWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
CreateTiddlerWidget.prototype.execute = function() {
|
||||
this.actionBaseTitle = this.getAttribute("$basetitle");
|
||||
this.actionSaveTitle = this.getAttribute("$savetitle");
|
||||
this.actionTimestamp = this.getAttribute("$timestamp","yes") === "yes";
|
||||
};
|
||||
|
||||
/*
|
||||
Refresh the widget by ensuring our attributes are up to date
|
||||
*/
|
||||
CreateTiddlerWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if($tw.utils.count(changedAttributes) > 0) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
/*
|
||||
Invoke the action associated with this widget
|
||||
*/
|
||||
CreateTiddlerWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
var title = this.wiki.generateNewTitle(this.actionBaseTitle),
|
||||
fields = {},
|
||||
creationFields,
|
||||
modificationFields;
|
||||
$tw.utils.each(this.attributes,function(attribute,name) {
|
||||
if(name.charAt(0) !== "$") {
|
||||
fields[name] = attribute;
|
||||
}
|
||||
});
|
||||
if(this.actionTimestamp) {
|
||||
creationFields = this.wiki.getCreationFields();
|
||||
modificationFields = this.wiki.getModificationFields();
|
||||
}
|
||||
var tiddler = this.wiki.addTiddler(new $tw.Tiddler(creationFields,fields,modificationFields,{title: title}));
|
||||
if(this.actionSaveTitle) {
|
||||
this.wiki.setTextReference(this.actionSaveTitle,title,this.getVariable("currentTiddler"));
|
||||
}
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
exports["action-createtiddler"] = CreateTiddlerWidget;
|
||||
|
||||
})();
|
||||
@@ -57,17 +57,24 @@ Invoke the action associated with this widget
|
||||
DeleteFieldWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
var self = this,
|
||||
tiddler = this.wiki.getTiddler(self.actionTiddler),
|
||||
removeFields = {};
|
||||
removeFields = {},
|
||||
hasChanged = false;
|
||||
if(this.actionField) {
|
||||
removeFields[this.actionField] = undefined;
|
||||
if(this.actionField in tiddler.fields) {
|
||||
hasChanged = true;
|
||||
}
|
||||
}
|
||||
if(tiddler) {
|
||||
$tw.utils.each(this.attributes,function(attribute,name) {
|
||||
if(name.charAt(0) !== "$" && name !== "title") {
|
||||
removeFields[name] = undefined;
|
||||
hasChanged = true;
|
||||
}
|
||||
});
|
||||
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getModificationFields(),tiddler,removeFields,this.wiki.getCreationFields()));
|
||||
if(hasChanged) {
|
||||
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getCreationFields(),tiddler,removeFields,this.wiki.getModificationFields()));
|
||||
}
|
||||
}
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
@@ -80,9 +80,13 @@ ActionListopsWidget.prototype.invokeAction = function(triggeringWidget,
|
||||
.filterTiddlers(subfilter, this)));
|
||||
}
|
||||
if(this.filtertags) {
|
||||
var tagfilter = "[list[" + this.target + "!!tags]] " + this.filtertags;
|
||||
this.wiki.setText(this.target, "tags", undefined, $tw.utils.stringifyList(
|
||||
this.wiki.filterTiddlers(tagfilter, this)));
|
||||
var tiddler = this.wiki.getTiddler(this.target),
|
||||
oldtags = tiddler ? (tiddler.fields.tags || []).slice(0) : [],
|
||||
tagfilter = "[list[" + this.target + "!!tags]] " + this.filtertags,
|
||||
newtags = this.wiki.filterTiddlers(tagfilter,this);
|
||||
if($tw.utils.stringifyList(oldtags.sort()) !== $tw.utils.stringifyList(newtags.sort())) {
|
||||
this.wiki.setText(this.target,"tags",undefined,$tw.utils.stringifyList(newtags));
|
||||
}
|
||||
}
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
@@ -78,7 +78,8 @@ SendMessageWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
param: param,
|
||||
paramObject: paramObject,
|
||||
tiddlerTitle: this.getVariable("currentTiddler"),
|
||||
navigateFromTitle: this.getVariable("storyTiddler")
|
||||
navigateFromTitle: this.getVariable("storyTiddler"),
|
||||
event: event
|
||||
});
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
@@ -95,6 +95,15 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
|
||||
}
|
||||
return handled;
|
||||
},false);
|
||||
// Make it draggable if required
|
||||
if(this.dragTiddler || this.dragFilter) {
|
||||
$tw.utils.makeDraggable({
|
||||
domNode: domNode,
|
||||
dragTiddlerFn: function() {return self.dragTiddler;},
|
||||
dragFilterFn: function() {return self.dragFilter;},
|
||||
widget: this
|
||||
});
|
||||
}
|
||||
// Insert element
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.renderChildren(domNode,null);
|
||||
@@ -131,12 +140,13 @@ ButtonWidget.prototype.navigateTo = function(event) {
|
||||
navigateFromNode: this,
|
||||
navigateFromClientRect: { top: bounds.top, left: bounds.left, width: bounds.width, right: bounds.right, bottom: bounds.bottom, height: bounds.height
|
||||
},
|
||||
navigateSuppressNavigation: event.metaKey || event.ctrlKey || (event.button === 1)
|
||||
navigateSuppressNavigation: event.metaKey || event.ctrlKey || (event.button === 1),
|
||||
event: event
|
||||
});
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.dispatchMessage = function(event) {
|
||||
this.dispatchEvent({type: this.message, param: this.param, tiddlerTitle: this.getVariable("currentTiddler")});
|
||||
this.dispatchEvent({type: this.message, param: this.param, tiddlerTitle: this.getVariable("currentTiddler"), event: event});
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.triggerPopup = function(event) {
|
||||
@@ -171,6 +181,8 @@ ButtonWidget.prototype.execute = function() {
|
||||
this.selectedClass = this.getAttribute("selectedClass");
|
||||
this.defaultSetValue = this.getAttribute("default","");
|
||||
this.buttonTag = this.getAttribute("tag");
|
||||
this.dragTiddler = this.getAttribute("dragTiddler");
|
||||
this.dragFilter = this.getAttribute("dragFilter");
|
||||
// Make child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
@@ -180,7 +192,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
ButtonWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes["class"] || changedAttributes.selectedClass || changedAttributes.style || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup])) {
|
||||
if(changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes["class"] || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup])) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,21 @@ CheckboxWidget.prototype.getValue = function() {
|
||||
}
|
||||
}
|
||||
if(this.checkboxField) {
|
||||
var value = tiddler.fields[this.checkboxField] || this.checkboxDefault || "";
|
||||
var value;
|
||||
if($tw.utils.hop(tiddler.fields,this.checkboxField)) {
|
||||
value = tiddler.fields[this.checkboxField] || "";
|
||||
} else {
|
||||
value = this.checkboxDefault || "";
|
||||
}
|
||||
if(value === this.checkboxChecked) {
|
||||
return true;
|
||||
}
|
||||
if(value === this.checkboxUnchecked) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(this.checkboxIndex) {
|
||||
var value = this.wiki.extractTiddlerDataItem(tiddler,this.checkboxIndex,this.checkboxDefault || "");
|
||||
if(value === this.checkboxChecked) {
|
||||
return true;
|
||||
}
|
||||
@@ -96,7 +110,8 @@ CheckboxWidget.prototype.handleChangeEvent = function(event) {
|
||||
newFields = {title: this.checkboxTitle},
|
||||
hasChanged = false,
|
||||
tagCheck = false,
|
||||
hasTag = tiddler && tiddler.hasTag(this.checkboxTag);
|
||||
hasTag = tiddler && tiddler.hasTag(this.checkboxTag),
|
||||
value = checked ? this.checkboxChecked : this.checkboxUnchecked;
|
||||
if(this.checkboxTag && this.checkboxInvertTag === "yes") {
|
||||
tagCheck = hasTag === checked;
|
||||
} else {
|
||||
@@ -118,14 +133,28 @@ CheckboxWidget.prototype.handleChangeEvent = function(event) {
|
||||
}
|
||||
// Set the field if specified
|
||||
if(this.checkboxField) {
|
||||
var value = checked ? this.checkboxChecked : this.checkboxUnchecked;
|
||||
if(!tiddler || tiddler.fields[this.checkboxField] !== value) {
|
||||
newFields[this.checkboxField] = value;
|
||||
hasChanged = true;
|
||||
}
|
||||
}
|
||||
// Set the index if specified
|
||||
if(this.checkboxIndex) {
|
||||
var indexValue = this.wiki.extractTiddlerDataItem(this.checkboxTitle,this.checkboxIndex);
|
||||
if(!tiddler || indexValue !== value) {
|
||||
hasChanged = true;
|
||||
}
|
||||
}
|
||||
if(hasChanged) {
|
||||
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getCreationFields(),fallbackFields,tiddler,newFields,this.wiki.getModificationFields()));
|
||||
if(this.checkboxIndex) {
|
||||
this.wiki.setText(this.checkboxTitle,"",this.checkboxIndex,value);
|
||||
} else {
|
||||
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getCreationFields(),fallbackFields,tiddler,newFields,this.wiki.getModificationFields()));
|
||||
}
|
||||
}
|
||||
// Trigger actions
|
||||
if(this.checkboxActions) {
|
||||
this.invokeActionString(this.checkboxActions,this,event);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -134,9 +163,11 @@ Compute the internal state of the widget
|
||||
*/
|
||||
CheckboxWidget.prototype.execute = function() {
|
||||
// Get the parameters from the attributes
|
||||
this.checkboxActions = this.getAttribute("actions");
|
||||
this.checkboxTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
|
||||
this.checkboxTag = this.getAttribute("tag");
|
||||
this.checkboxField = this.getAttribute("field");
|
||||
this.checkboxIndex = this.getAttribute("index");
|
||||
this.checkboxChecked = this.getAttribute("checked");
|
||||
this.checkboxUnchecked = this.getAttribute("unchecked");
|
||||
this.checkboxDefault = this.getAttribute("default");
|
||||
@@ -151,7 +182,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
CheckboxWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.tiddler || changedAttributes.tag || changedAttributes.invertTag || changedAttributes.field || changedAttributes.checked || changedAttributes.unchecked || changedAttributes["default"] || changedAttributes["class"]) {
|
||||
if(changedAttributes.tiddler || changedAttributes.tag || changedAttributes.invertTag || changedAttributes.field || changedAttributes.index || changedAttributes.checked || changedAttributes.unchecked || changedAttributes["default"] || changedAttributes["class"]) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
|
||||
88
core/modules/widgets/draggable.js
Normal file
88
core/modules/widgets/draggable.js
Normal file
@@ -0,0 +1,88 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/draggable.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Draggable widget
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var DraggableWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
DraggableWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
DraggableWidget.prototype.render = function(parent,nextSibling) {
|
||||
var self = this;
|
||||
// Save the parent dom node
|
||||
this.parentDomNode = parent;
|
||||
// Compute our attributes
|
||||
this.computeAttributes();
|
||||
// Execute our logic
|
||||
this.execute();
|
||||
// Sanitise the specified tag
|
||||
var tag = this.draggableTag;
|
||||
if($tw.config.htmlUnsafeElements.indexOf(tag) !== -1) {
|
||||
tag = "div";
|
||||
}
|
||||
// Create our element
|
||||
var domNode = this.document.createElement(tag);
|
||||
// Assign classes
|
||||
var classes = ["tc-draggable"];
|
||||
if(this.draggableClasses) {
|
||||
classes.push(this.draggableClasses);
|
||||
}
|
||||
domNode.setAttribute("class",classes.join(" "));
|
||||
// Add event handlers
|
||||
$tw.utils.makeDraggable({
|
||||
domNode: domNode,
|
||||
dragTiddlerFn: function() {return self.getAttribute("tiddler");},
|
||||
dragFilterFn: function() {return self.getAttribute("filter");},
|
||||
widget: this
|
||||
});
|
||||
// Insert the link into the DOM and render any children
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.renderChildren(domNode,null);
|
||||
this.domNodes.push(domNode);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
DraggableWidget.prototype.execute = function() {
|
||||
// Pick up our attributes
|
||||
this.draggableTag = this.getAttribute("tag","div");
|
||||
this.draggableClasses = this.getAttribute("class");
|
||||
// Make the child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
DraggableWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedTiddlers.tag || changedTiddlers["class"]) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
exports.draggable = DraggableWidget;
|
||||
|
||||
})();
|
||||
161
core/modules/widgets/droppable.js
Normal file
161
core/modules/widgets/droppable.js
Normal file
@@ -0,0 +1,161 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/droppable.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Droppable widget
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var DroppableWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
DroppableWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
DroppableWidget.prototype.render = function(parent,nextSibling) {
|
||||
var self = this;
|
||||
// Remember parent
|
||||
this.parentDomNode = parent;
|
||||
// Compute attributes and execute state
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
var tag = this.parseTreeNode.isBlock ? "div" : "span";
|
||||
if(this.droppableTag && $tw.config.htmlUnsafeElements.indexOf(this.droppableTag) === -1) {
|
||||
tag = this.droppableTag;
|
||||
}
|
||||
// Create element and assign classes
|
||||
var domNode = this.document.createElement(tag),
|
||||
classes = (this["class"] || "").split(" ");
|
||||
classes.push("tc-droppable");
|
||||
domNode.className = classes.join(" ");
|
||||
// Add event handlers
|
||||
$tw.utils.addEventListeners(domNode,[
|
||||
{name: "dragenter", handlerObject: this, handlerMethod: "handleDragEnterEvent"},
|
||||
{name: "dragover", handlerObject: this, handlerMethod: "handleDragOverEvent"},
|
||||
{name: "dragleave", handlerObject: this, handlerMethod: "handleDragLeaveEvent"},
|
||||
{name: "drop", handlerObject: this, handlerMethod: "handleDropEvent"}
|
||||
]);
|
||||
// Insert element
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.renderChildren(domNode,null);
|
||||
this.domNodes.push(domNode);
|
||||
// Stack of outstanding enter/leave events
|
||||
this.currentlyEntered = [];
|
||||
};
|
||||
|
||||
DroppableWidget.prototype.enterDrag = function(event) {
|
||||
if(this.currentlyEntered.indexOf(event.target) === -1) {
|
||||
this.currentlyEntered.push(event.target);
|
||||
}
|
||||
// If we're entering for the first time we need to apply highlighting
|
||||
$tw.utils.addClass(this.domNodes[0],"tc-dragover");
|
||||
};
|
||||
|
||||
DroppableWidget.prototype.leaveDrag = function(event) {
|
||||
var pos = this.currentlyEntered.indexOf(event.target);
|
||||
if(pos !== -1) {
|
||||
this.currentlyEntered.splice(pos,1);
|
||||
}
|
||||
// Remove highlighting if we're leaving externally. The hacky second condition is to resolve a problem with Firefox whereby there is an erroneous dragenter event if the node being dragged is within the dropzone
|
||||
if(this.currentlyEntered.length === 0 || (this.currentlyEntered.length === 1 && this.currentlyEntered[0] === $tw.dragInProgress)) {
|
||||
this.currentlyEntered = [];
|
||||
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
|
||||
}
|
||||
};
|
||||
|
||||
DroppableWidget.prototype.handleDragEnterEvent = function(event) {
|
||||
this.enterDrag(event);
|
||||
// Tell the browser that we're ready to handle the drop
|
||||
event.preventDefault();
|
||||
// Tell the browser not to ripple the drag up to any parent drop handlers
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
DroppableWidget.prototype.handleDragOverEvent = function(event) {
|
||||
// Check for being over a TEXTAREA or INPUT
|
||||
if(["TEXTAREA","INPUT"].indexOf(event.target.tagName) !== -1) {
|
||||
return false;
|
||||
}
|
||||
// Tell the browser that we're still interested in the drop
|
||||
event.preventDefault();
|
||||
// Set the drop effect
|
||||
event.dataTransfer.dropEffect = this.droppableEffect;
|
||||
return false;
|
||||
};
|
||||
|
||||
DroppableWidget.prototype.handleDragLeaveEvent = function(event) {
|
||||
this.leaveDrag(event);
|
||||
return false;
|
||||
};
|
||||
|
||||
DroppableWidget.prototype.handleDropEvent = function(event) {
|
||||
var self = this;
|
||||
this.leaveDrag(event);
|
||||
// Check for being over a TEXTAREA or INPUT
|
||||
if(["TEXTAREA","INPUT"].indexOf(event.target.tagName) !== -1) {
|
||||
return false;
|
||||
}
|
||||
var dataTransfer = event.dataTransfer;
|
||||
// Remove highlighting
|
||||
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
|
||||
// Try to import the various data types we understand
|
||||
$tw.utils.importDataTransfer(dataTransfer,null,function(fieldsArray) {
|
||||
fieldsArray.forEach(function(fields) {
|
||||
self.performActions(fields.title || fields.text,event);
|
||||
});
|
||||
});
|
||||
// Tell the browser that we handled the drop
|
||||
event.preventDefault();
|
||||
// Stop the drop ripple up to any parent handlers
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
DroppableWidget.prototype.performActions = function(title,event) {
|
||||
if(this.droppableActions) {
|
||||
this.invokeActionString(this.droppableActions,this,event,{actionTiddler: title});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
DroppableWidget.prototype.execute = function() {
|
||||
this.droppableActions = this.getAttribute("actions");
|
||||
this.droppableEffect = this.getAttribute("effect","copy");
|
||||
this.droppableTag = this.getAttribute("tag");
|
||||
this.droppableClass = this.getAttribute("class");
|
||||
// Make child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
DroppableWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes["class"] || changedAttributes.tag) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
exports.droppable = DroppableWidget;
|
||||
|
||||
})();
|
||||
@@ -50,32 +50,35 @@ DropZoneWidget.prototype.render = function(parent,nextSibling) {
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.renderChildren(domNode,null);
|
||||
this.domNodes.push(domNode);
|
||||
// Stack of outstanding enter/leave events
|
||||
this.currentlyEntered = [];
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.enterDrag = function() {
|
||||
// Check for this window being the source of the drag
|
||||
if($tw.dragInProgress) {
|
||||
return false;
|
||||
DropZoneWidget.prototype.enterDrag = function(event) {
|
||||
if(this.currentlyEntered.indexOf(event.target) === -1) {
|
||||
this.currentlyEntered.push(event.target);
|
||||
}
|
||||
// We count enter/leave events
|
||||
this.dragEnterCount = (this.dragEnterCount || 0) + 1;
|
||||
// If we're entering for the first time we need to apply highlighting
|
||||
if(this.dragEnterCount === 1) {
|
||||
$tw.utils.addClass(this.domNodes[0],"tc-dragover");
|
||||
}
|
||||
$tw.utils.addClass(this.domNodes[0],"tc-dragover");
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.leaveDrag = function() {
|
||||
// Reduce the enter count
|
||||
this.dragEnterCount = (this.dragEnterCount || 0) - 1;
|
||||
DropZoneWidget.prototype.leaveDrag = function(event) {
|
||||
var pos = this.currentlyEntered.indexOf(event.target);
|
||||
if(pos !== -1) {
|
||||
this.currentlyEntered.splice(pos,1);
|
||||
}
|
||||
// Remove highlighting if we're leaving externally
|
||||
if(this.dragEnterCount <= 0) {
|
||||
if(this.currentlyEntered.length === 0) {
|
||||
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
|
||||
}
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.handleDragEnterEvent = function(event) {
|
||||
this.enterDrag();
|
||||
// Check for this window being the source of the drag
|
||||
if($tw.dragInProgress) {
|
||||
return false;
|
||||
}
|
||||
this.enterDrag(event);
|
||||
// Tell the browser that we're ready to handle the drop
|
||||
event.preventDefault();
|
||||
// Tell the browser not to ripple the drag up to any parent drop handlers
|
||||
@@ -97,11 +100,12 @@ DropZoneWidget.prototype.handleDragOverEvent = function(event) {
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.handleDragLeaveEvent = function(event) {
|
||||
this.leaveDrag();
|
||||
this.leaveDrag(event);
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.handleDropEvent = function(event) {
|
||||
this.leaveDrag();
|
||||
var self = this;
|
||||
this.leaveDrag(event);
|
||||
// Check for being over a TEXTAREA or INPUT
|
||||
if(["TEXTAREA","INPUT"].indexOf(event.target.tagName) !== -1) {
|
||||
return false;
|
||||
@@ -112,17 +116,20 @@ DropZoneWidget.prototype.handleDropEvent = function(event) {
|
||||
}
|
||||
var self = this,
|
||||
dataTransfer = event.dataTransfer;
|
||||
// Reset the enter count
|
||||
this.dragEnterCount = 0;
|
||||
// Remove highlighting
|
||||
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
|
||||
// Import any files in the drop
|
||||
var numFiles = this.wiki.readFiles(dataTransfer.files,function(tiddlerFieldsArray) {
|
||||
self.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify(tiddlerFieldsArray)});
|
||||
});
|
||||
var numFiles = 0;
|
||||
if(dataTransfer.files) {
|
||||
numFiles = this.wiki.readFiles(dataTransfer.files,function(tiddlerFieldsArray) {
|
||||
self.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify(tiddlerFieldsArray)});
|
||||
});
|
||||
}
|
||||
// Try to import the various data types we understand
|
||||
if(numFiles === 0) {
|
||||
this.importData(dataTransfer);
|
||||
$tw.utils.importDataTransfer(dataTransfer,this.wiki.generateNewTitle("Untitled"),function(fieldsArray) {
|
||||
self.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify(fieldsArray)});
|
||||
});
|
||||
}
|
||||
// Tell the browser that we handled the drop
|
||||
event.preventDefault();
|
||||
@@ -130,77 +137,6 @@ DropZoneWidget.prototype.handleDropEvent = function(event) {
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.importData = function(dataTransfer) {
|
||||
// Try each provided data type in turn
|
||||
for(var t=0; t<this.importDataTypes.length; t++) {
|
||||
if(!$tw.browser.isIE || this.importDataTypes[t].IECompatible) {
|
||||
// Get the data
|
||||
var dataType = this.importDataTypes[t];
|
||||
var data = dataTransfer.getData(dataType.type);
|
||||
// Import the tiddlers in the data
|
||||
if(data !== "" && data !== null) {
|
||||
if($tw.log.IMPORT) {
|
||||
console.log("Importing data type '" + dataType.type + "', data: '" + data + "'")
|
||||
}
|
||||
var tiddlerFields = dataType.convertToFields(data);
|
||||
if(!tiddlerFields.title) {
|
||||
tiddlerFields.title = this.wiki.generateNewTitle("Untitled");
|
||||
}
|
||||
this.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify([tiddlerFields])});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.importDataTypes = [
|
||||
{type: "text/vnd.tiddler", IECompatible: false, convertToFields: function(data) {
|
||||
return JSON.parse(data);
|
||||
}},
|
||||
{type: "URL", IECompatible: true, convertToFields: function(data) {
|
||||
// Check for tiddler data URI
|
||||
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
if(match) {
|
||||
return JSON.parse(match[1]);
|
||||
} else {
|
||||
return { // As URL string
|
||||
text: data
|
||||
};
|
||||
}
|
||||
}},
|
||||
{type: "text/x-moz-url", IECompatible: false, convertToFields: function(data) {
|
||||
// Check for tiddler data URI
|
||||
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
if(match) {
|
||||
return JSON.parse(match[1]);
|
||||
} else {
|
||||
return { // As URL string
|
||||
text: data
|
||||
};
|
||||
}
|
||||
}},
|
||||
{type: "text/html", IECompatible: false, convertToFields: function(data) {
|
||||
return {
|
||||
text: data
|
||||
};
|
||||
}},
|
||||
{type: "text/plain", IECompatible: false, convertToFields: function(data) {
|
||||
return {
|
||||
text: data
|
||||
};
|
||||
}},
|
||||
{type: "Text", IECompatible: true, convertToFields: function(data) {
|
||||
return {
|
||||
text: data
|
||||
};
|
||||
}},
|
||||
{type: "text/uri-list", IECompatible: false, convertToFields: function(data) {
|
||||
return {
|
||||
text: data
|
||||
};
|
||||
}}
|
||||
];
|
||||
|
||||
DropZoneWidget.prototype.handlePasteEvent = function(event) {
|
||||
// Let the browser handle it if we're in a textarea or input box
|
||||
if(["TEXTAREA","INPUT"].indexOf(event.target.tagName) == -1) {
|
||||
|
||||
@@ -75,9 +75,9 @@ FieldsWidget.prototype.execute = function() {
|
||||
value = reMatch[1];
|
||||
}
|
||||
}
|
||||
row = row.replace("$name$",fieldName);
|
||||
row = row.replace("$value$",value);
|
||||
row = row.replace("$encoded_value$",$tw.utils.htmlEncode(value));
|
||||
row = $tw.utils.replaceString(row,"$name$",fieldName);
|
||||
row = $tw.utils.replaceString(row,"$value$",value);
|
||||
row = $tw.utils.replaceString(row,"$encoded_value$",$tw.utils.htmlEncode(value));
|
||||
text.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,12 @@ KeyboardWidget.prototype.render = function(parent,nextSibling) {
|
||||
// Compute attributes and execute state
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
var tag = this.parseTreeNode.isBlock ? "div" : "span";
|
||||
if(this.tag && $tw.config.htmlUnsafeElements.indexOf(this.tag) === -1) {
|
||||
tag = this.tag;
|
||||
}
|
||||
// Create element
|
||||
var domNode = this.document.createElement("div");
|
||||
var domNode = this.document.createElement(tag);
|
||||
// Assign classes
|
||||
var classes = (this["class"] || "").split(" ");
|
||||
classes.push("tc-keyboard");
|
||||
@@ -72,6 +76,7 @@ KeyboardWidget.prototype.execute = function() {
|
||||
this.message = this.getAttribute("message");
|
||||
this.param = this.getAttribute("param");
|
||||
this.key = this.getAttribute("key");
|
||||
this.tag = this.getAttribute("tag");
|
||||
this.keyInfoArray = $tw.keyboardManager.parseKeyDescriptors(this.key);
|
||||
this["class"] = this.getAttribute("class");
|
||||
// Make child widgets
|
||||
@@ -83,7 +88,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
KeyboardWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.message || changedAttributes.param || changedAttributes.key || changedAttributes["class"]) {
|
||||
if(changedAttributes.message || changedAttributes.param || changedAttributes.key || changedAttributes["class"] || changedAttributes.tag) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
|
||||
// Set an href
|
||||
var wikiLinkTemplateMacro = this.getVariable("tv-wikilink-template"),
|
||||
wikiLinkTemplate = wikiLinkTemplateMacro ? wikiLinkTemplateMacro.trim() : "#$uri_encoded$",
|
||||
wikiLinkText = wikiLinkTemplate.replace("$uri_encoded$",encodeURIComponent(this.to));
|
||||
wikiLinkText = wikiLinkText.replace("$uri_doubleencoded$",encodeURIComponent(encodeURIComponent(this.to)));
|
||||
wikiLinkText = $tw.utils.replaceString(wikiLinkTemplate,"$uri_encoded$",encodeURIComponent(this.to));
|
||||
wikiLinkText = $tw.utils.replaceString(wikiLinkText,"$uri_doubleencoded$",encodeURIComponent(encodeURIComponent(this.to)));
|
||||
wikiLinkText = this.getVariable("tv-get-export-link",{params: [{name: "to",value: this.to}],defaultValue: wikiLinkText});
|
||||
if(tag === "a") {
|
||||
domNode.setAttribute("href",wikiLinkText);
|
||||
@@ -111,11 +111,13 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
|
||||
$tw.utils.addEventListeners(domNode,[
|
||||
{name: "click", handlerObject: this, handlerMethod: "handleClickEvent"},
|
||||
]);
|
||||
// Make the link draggable if required
|
||||
if(this.draggable === "yes") {
|
||||
$tw.utils.addEventListeners(domNode,[
|
||||
{name: "dragstart", handlerObject: this, handlerMethod: "handleDragStartEvent"},
|
||||
{name: "dragend", handlerObject: this, handlerMethod: "handleDragEndEvent"}
|
||||
]);
|
||||
$tw.utils.makeDraggable({
|
||||
domNode: domNode,
|
||||
dragTiddlerFn: function() {return self.to;},
|
||||
widget: this
|
||||
});
|
||||
}
|
||||
// Insert the link into the DOM and render any children
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
@@ -142,67 +144,6 @@ LinkWidget.prototype.handleClickEvent = function(event) {
|
||||
return false;
|
||||
};
|
||||
|
||||
LinkWidget.prototype.handleDragStartEvent = function(event) {
|
||||
if(event.target === this.domNodes[0]) {
|
||||
if(this.to) {
|
||||
$tw.dragInProgress = true;
|
||||
// Set the dragging class on the element being dragged
|
||||
$tw.utils.addClass(event.target,"tc-tiddlylink-dragging");
|
||||
// Create the drag image elements
|
||||
this.dragImage = this.document.createElement("div");
|
||||
this.dragImage.className = "tc-tiddler-dragger";
|
||||
var inner = this.document.createElement("div");
|
||||
inner.className = "tc-tiddler-dragger-inner";
|
||||
inner.appendChild(this.document.createTextNode(this.to));
|
||||
this.dragImage.appendChild(inner);
|
||||
this.document.body.appendChild(this.dragImage);
|
||||
// Astoundingly, we need to cover the dragger up: http://www.kryogenix.org/code/browser/custom-drag-image.html
|
||||
var cover = this.document.createElement("div");
|
||||
cover.className = "tc-tiddler-dragger-cover";
|
||||
cover.style.left = (inner.offsetLeft - 16) + "px";
|
||||
cover.style.top = (inner.offsetTop - 16) + "px";
|
||||
cover.style.width = (inner.offsetWidth + 32) + "px";
|
||||
cover.style.height = (inner.offsetHeight + 32) + "px";
|
||||
this.dragImage.appendChild(cover);
|
||||
// Set the data transfer properties
|
||||
var dataTransfer = event.dataTransfer;
|
||||
// First the image
|
||||
dataTransfer.effectAllowed = "copy";
|
||||
if(dataTransfer.setDragImage) {
|
||||
dataTransfer.setDragImage(this.dragImage.firstChild,-16,-16);
|
||||
}
|
||||
// Then the data
|
||||
dataTransfer.clearData();
|
||||
var jsonData = this.wiki.getTiddlerAsJson(this.to),
|
||||
textData = this.wiki.getTiddlerText(this.to,""),
|
||||
title = (new RegExp("^" + $tw.config.textPrimitives.wikiLink + "$","mg")).exec(this.to) ? this.to : "[[" + this.to + "]]";
|
||||
// IE doesn't like these content types
|
||||
if(!$tw.browser.isIE) {
|
||||
dataTransfer.setData("text/vnd.tiddler",jsonData);
|
||||
dataTransfer.setData("text/plain",title);
|
||||
dataTransfer.setData("text/x-moz-url","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
||||
}
|
||||
dataTransfer.setData("URL","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
||||
dataTransfer.setData("Text",title);
|
||||
event.stopPropagation();
|
||||
} else {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
LinkWidget.prototype.handleDragEndEvent = function(event) {
|
||||
if(event.target === this.domNodes[0]) {
|
||||
$tw.dragInProgress = false;
|
||||
// Remove the dragging class on the element being dragged
|
||||
$tw.utils.removeClass(event.target,"tc-tiddlylink-dragging");
|
||||
// Delete the drag image element
|
||||
if(this.dragImage) {
|
||||
this.dragImage.parentNode.removeChild(this.dragImage);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
|
||||
@@ -43,6 +43,9 @@ ListWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.renderChildren(parent,nextSibling);
|
||||
// Construct the storyview
|
||||
var StoryView = this.storyViews[this.storyViewName];
|
||||
if(this.storyViewName && !StoryView) {
|
||||
StoryView = this.storyViews["classic"];
|
||||
}
|
||||
if(StoryView && !this.document.isTiddlyWikiFakeDom) {
|
||||
this.storyview = new StoryView(this);
|
||||
} else {
|
||||
|
||||
@@ -73,7 +73,7 @@ NavigatorWidget.prototype.refresh = function(changedTiddlers) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -174,6 +174,7 @@ NavigatorWidget.prototype.addToHistory = function(title,fromPageRect) {
|
||||
Handle a tm-navigate event
|
||||
*/
|
||||
NavigatorWidget.prototype.handleNavigateEvent = function(event) {
|
||||
event = $tw.hooks.invokeHook("th-navigating",event);
|
||||
if(event.navigateTo) {
|
||||
this.addToStory(event.navigateTo,event.navigateFromTitle);
|
||||
if(!event.navigateSuppressNavigation) {
|
||||
@@ -245,6 +246,7 @@ NavigatorWidget.prototype.handleDeleteTiddlerEvent = function(event) {
|
||||
tiddler = this.wiki.getTiddler(title),
|
||||
storyList = this.getStoryList(),
|
||||
originalTitle = tiddler ? tiddler.fields["draft.of"] : "",
|
||||
originalTiddler = originalTitle ? this.wiki.getTiddler(originalTitle) : undefined,
|
||||
confirmationTitle;
|
||||
if(!tiddler) {
|
||||
return false;
|
||||
@@ -268,10 +270,14 @@ NavigatorWidget.prototype.handleDeleteTiddlerEvent = function(event) {
|
||||
}
|
||||
// Delete the original tiddler
|
||||
if(originalTitle) {
|
||||
if(originalTiddler) {
|
||||
$tw.hooks.invokeHook("th-deleting-tiddler",originalTiddler);
|
||||
}
|
||||
this.wiki.deleteTiddler(originalTitle);
|
||||
this.removeTitleFromStory(storyList,originalTitle);
|
||||
}
|
||||
// Delete this tiddler
|
||||
// Invoke the hook function and delete this tiddler
|
||||
$tw.hooks.invokeHook("th-deleting-tiddler",tiddler);
|
||||
this.wiki.deleteTiddler(title);
|
||||
// Remove the closed tiddler from the story
|
||||
this.removeTitleFromStory(storyList,title);
|
||||
@@ -349,12 +355,21 @@ NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) {
|
||||
},this.wiki.getModificationFields());
|
||||
newTiddler = $tw.hooks.invokeHook("th-saving-tiddler",newTiddler);
|
||||
this.wiki.addTiddler(newTiddler);
|
||||
// If enabled, relink references to renamed tiddler
|
||||
var shouldRelink = this.getAttribute("relinkOnRename","no").toLowerCase().trim() === "yes";
|
||||
if(isRename && shouldRelink && this.wiki.tiddlerExists(draftOf)) {
|
||||
console.log("Relinking '" + draftOf + "' to '" + draftTitle + "'");
|
||||
this.wiki.relinkTiddler(draftOf,draftTitle);
|
||||
}
|
||||
// Remove the draft tiddler
|
||||
this.wiki.deleteTiddler(title);
|
||||
// Remove the original tiddler if we're renaming it
|
||||
if(isRename) {
|
||||
this.wiki.deleteTiddler(draftOf);
|
||||
}
|
||||
// #2381 always remove new title & old
|
||||
this.removeTitleFromStory(storyList,draftTitle);
|
||||
this.removeTitleFromStory(storyList,draftOf);
|
||||
if(!event.paramObject || event.paramObject.suppressNavigation !== "yes") {
|
||||
// Replace the draft in the story with the original
|
||||
this.replaceFirstTitleInStory(storyList,title,draftTitle);
|
||||
@@ -451,7 +466,7 @@ NavigatorWidget.prototype.handleNewTiddlerEvent = function(event) {
|
||||
// Merge the tags
|
||||
var mergedTags = [];
|
||||
if(existingTiddler && existingTiddler.fields.tags) {
|
||||
$tw.utils.pushTop(mergedTags,existingTiddler.fields.tags)
|
||||
$tw.utils.pushTop(mergedTags,existingTiddler.fields.tags);
|
||||
}
|
||||
if(additionalFields && additionalFields.tags) {
|
||||
// Merge tags
|
||||
@@ -492,7 +507,6 @@ NavigatorWidget.prototype.handleNewTiddlerEvent = function(event) {
|
||||
|
||||
// Import JSON tiddlers into a pending import tiddler
|
||||
NavigatorWidget.prototype.handleImportTiddlersEvent = function(event) {
|
||||
var self = this;
|
||||
// Get the tiddlers
|
||||
var tiddlers = [];
|
||||
try {
|
||||
@@ -544,7 +558,7 @@ NavigatorWidget.prototype.handleImportTiddlersEvent = function(event) {
|
||||
history.push(IMPORT_TITLE);
|
||||
// Save the updated story and history
|
||||
this.saveStoryList(storyList);
|
||||
this.addToHistory(history);
|
||||
this.addToHistory(history);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
@@ -560,7 +574,9 @@ NavigatorWidget.prototype.handlePerformImportEvent = function(event) {
|
||||
$tw.utils.each(importData.tiddlers,function(tiddlerFields) {
|
||||
var title = tiddlerFields.title;
|
||||
if(title && importTiddler && importTiddler.fields["selection-" + title] !== "unchecked") {
|
||||
self.wiki.addTiddler(new $tw.Tiddler(tiddlerFields));
|
||||
var tiddler = new $tw.Tiddler(tiddlerFields);
|
||||
tiddler = $tw.hooks.invokeHook("th-importing-tiddler",tiddler);
|
||||
self.wiki.addTiddler(tiddler);
|
||||
importReport.push("# [[" + tiddlerFields.title + "]]");
|
||||
}
|
||||
});
|
||||
@@ -577,8 +593,7 @@ NavigatorWidget.prototype.handlePerformImportEvent = function(event) {
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.handleFoldTiddlerEvent = function(event) {
|
||||
var self = this,
|
||||
paramObject = event.paramObject || {};
|
||||
var paramObject = event.paramObject || {};
|
||||
if(paramObject.foldedState) {
|
||||
var foldedState = this.wiki.getTiddlerText(paramObject.foldedState,"show") === "show" ? "hide" : "show";
|
||||
this.wiki.setText(paramObject.foldedState,"text",null,foldedState);
|
||||
@@ -613,8 +628,7 @@ NavigatorWidget.prototype.handleUnfoldAllTiddlersEvent = function(event) {
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.handleRenameTiddlerEvent = function(event) {
|
||||
var self = this,
|
||||
paramObject = event.paramObject || {},
|
||||
var paramObject = event.paramObject || {},
|
||||
from = paramObject.from || event.tiddlerTitle,
|
||||
to = paramObject.to;
|
||||
$tw.wiki.renameTiddler(from,to);
|
||||
|
||||
@@ -3,22 +3,7 @@ title: $:/core/modules/widgets/radio.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Radio widget
|
||||
|
||||
Will set a field to the selected value:
|
||||
|
||||
```
|
||||
<$radio field="myfield" value="check 1">one</$radio>
|
||||
<$radio field="myfield" value="check 2">two</$radio>
|
||||
<$radio field="myfield" value="check 3">three</$radio>
|
||||
```
|
||||
|
||||
|Parameter |Description |h
|
||||
|tiddler |Name of the tiddler in which the field should be set. Defaults to current tiddler |
|
||||
|field |The name of the field to be set |
|
||||
|value |The value to set |
|
||||
|class |Optional class name(s) |
|
||||
|
||||
Set a field or index at a given tiddler via radio buttons
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
@@ -70,12 +55,20 @@ RadioWidget.prototype.render = function(parent,nextSibling) {
|
||||
};
|
||||
|
||||
RadioWidget.prototype.getValue = function() {
|
||||
var tiddler = this.wiki.getTiddler(this.radioTitle);
|
||||
return tiddler && tiddler.getFieldString(this.radioField);
|
||||
var value,
|
||||
tiddler = this.wiki.getTiddler(this.radioTitle);
|
||||
if (this.radioIndex) {
|
||||
value = this.wiki.extractTiddlerDataItem(this.radioTitle,this.radioIndex);
|
||||
} else {
|
||||
value = tiddler && tiddler.getFieldString(this.radioField);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
RadioWidget.prototype.setValue = function() {
|
||||
if(this.radioField) {
|
||||
if(this.radioIndex) {
|
||||
this.wiki.setText(this.radioTitle,"",this.radioIndex,this.radioValue);
|
||||
} else {
|
||||
var tiddler = this.wiki.getTiddler(this.radioTitle),
|
||||
addition = {};
|
||||
addition[this.radioField] = this.radioValue;
|
||||
@@ -96,6 +89,7 @@ RadioWidget.prototype.execute = function() {
|
||||
// Get the parameters from the attributes
|
||||
this.radioTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
|
||||
this.radioField = this.getAttribute("field","text");
|
||||
this.radioIndex = this.getAttribute("index");
|
||||
this.radioValue = this.getAttribute("value");
|
||||
this.radioClass = this.getAttribute("class","");
|
||||
if(this.radioClass !== "") {
|
||||
@@ -111,7 +105,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
RadioWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.value || changedAttributes["class"]) {
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.value || changedAttributes["class"]) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -40,6 +40,7 @@ SetWidget.prototype.execute = function() {
|
||||
// Get our parameters
|
||||
this.setName = this.getAttribute("name","currentTiddler");
|
||||
this.setFilter = this.getAttribute("filter");
|
||||
this.setSelect = this.getAttribute("select");
|
||||
this.setValue = this.getAttribute("value");
|
||||
this.setEmptyValue = this.getAttribute("emptyValue");
|
||||
// Set context variable
|
||||
@@ -56,7 +57,15 @@ SetWidget.prototype.getValue = function() {
|
||||
if(this.setFilter) {
|
||||
var results = this.wiki.filterTiddlers(this.setFilter,this);
|
||||
if(!this.setValue) {
|
||||
value = $tw.utils.stringifyList(results);
|
||||
var select;
|
||||
if(this.setSelect) {
|
||||
select = parseInt(this.setSelect,10);
|
||||
}
|
||||
if(select !== undefined) {
|
||||
value = results[select] || "";
|
||||
} else {
|
||||
value = $tw.utils.stringifyList(results);
|
||||
}
|
||||
}
|
||||
if(results.length === 0 && this.setEmptyValue !== undefined) {
|
||||
value = this.setEmptyValue;
|
||||
@@ -72,7 +81,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
SetWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.name || changedAttributes.filter || changedAttributes.value || changedAttributes.emptyValue ||
|
||||
if(changedAttributes.name || changedAttributes.filter || changedAttributes.select ||changedAttributes.value || changedAttributes.emptyValue ||
|
||||
(this.setFilter && this.getValue() != this.variables[this.setName].value)) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
|
||||
@@ -125,7 +125,7 @@ Widget.prototype.substituteVariableParameters = function(text,formalParams,actua
|
||||
// If we've still not got a value, use the default, if any
|
||||
paramValue = paramValue || paramInfo["default"] || "";
|
||||
// Replace any instances of this parameter
|
||||
text = text.replace(new RegExp("\\$" + $tw.utils.escapeRegExp(paramInfo.name) + "\\$","mg"),paramValue);
|
||||
text = $tw.utils.replaceString(text,new RegExp("\\$" + $tw.utils.escapeRegExp(paramInfo.name) + "\\$","mg"),paramValue);
|
||||
}
|
||||
}
|
||||
return text;
|
||||
@@ -222,7 +222,9 @@ Widget.prototype.computeAttributes = function() {
|
||||
self = this,
|
||||
value;
|
||||
$tw.utils.each(this.parseTreeNode.attributes,function(attribute,name) {
|
||||
if(attribute.type === "indirect") {
|
||||
if(attribute.type === "filtered") {
|
||||
value = self.wiki.filterTiddlers(attribute.filter,self)[0] || "";
|
||||
} else if(attribute.type === "indirect") {
|
||||
value = self.wiki.getTextReference(attribute.textReference,"",self.getVariable("currentTiddler"));
|
||||
} else if(attribute.type === "macro") {
|
||||
value = self.getVariable(attribute.value.name,{params: attribute.value.params});
|
||||
@@ -493,8 +495,11 @@ Widget.prototype.invokeActions = function(triggeringWidget,event) {
|
||||
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 && child.invokeAction(triggeringWidget,event)) {
|
||||
handled = true;
|
||||
if(child.invokeAction) {
|
||||
child.refreshSelf();
|
||||
if(child.invokeAction(triggeringWidget,event)) {
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
// Propagate through through the child if it permits it
|
||||
if(child.allowActionPropagation() && child.invokeActions(triggeringWidget,event)) {
|
||||
@@ -507,7 +512,7 @@ Widget.prototype.invokeActions = function(triggeringWidget,event) {
|
||||
/*
|
||||
Invoke the action widgets defined in a string
|
||||
*/
|
||||
Widget.prototype.invokeActionString = function(actions,triggeringWidget,event) {
|
||||
Widget.prototype.invokeActionString = function(actions,triggeringWidget,event,variables) {
|
||||
actions = actions || "";
|
||||
var parser = this.wiki.parseText("text/vnd.tiddlywiki",actions,{
|
||||
parentWidget: this,
|
||||
@@ -515,7 +520,8 @@ Widget.prototype.invokeActionString = function(actions,triggeringWidget,event) {
|
||||
}),
|
||||
widgetNode = this.wiki.makeWidget(parser,{
|
||||
parentWidget: this,
|
||||
document: this.document
|
||||
document: this.document,
|
||||
variables: variables
|
||||
});
|
||||
var container = this.document.createElement("div");
|
||||
widgetNode.render(container,null);
|
||||
|
||||
@@ -71,6 +71,9 @@ WikifyWidget.prototype.getResult = function() {
|
||||
case "text":
|
||||
result = this.wikifyContainer.textContent;
|
||||
break;
|
||||
case "formattedtext":
|
||||
result = this.wikifyContainer.formattedTextContent;
|
||||
break;
|
||||
case "html":
|
||||
result = this.wikifyContainer.innerHTML;
|
||||
break;
|
||||
|
||||
@@ -15,39 +15,69 @@ Bulk tiddler operations such as rename.
|
||||
/*
|
||||
Rename a tiddler, and relink any tags or lists that reference it.
|
||||
*/
|
||||
exports.renameTiddler = function(fromTitle,toTitle) {
|
||||
var self = this;
|
||||
function renameTiddler(fromTitle,toTitle,options) {
|
||||
fromTitle = (fromTitle || "").trim();
|
||||
toTitle = (toTitle || "").trim();
|
||||
options = options || {};
|
||||
if(fromTitle && toTitle && fromTitle !== toTitle) {
|
||||
// Rename the tiddler itself
|
||||
var tiddler = this.getTiddler(fromTitle);
|
||||
this.addTiddler(new $tw.Tiddler(tiddler,{title: toTitle},this.getModificationFields()));
|
||||
var oldTiddler = this.getTiddler(fromTitle),
|
||||
newTiddler = new $tw.Tiddler(oldTiddler,{title: toTitle},this.getModificationFields());
|
||||
newTiddler = $tw.hooks.invokeHook("th-renaming-tiddler",newTiddler,oldTiddler);
|
||||
this.addTiddler(newTiddler);
|
||||
this.deleteTiddler(fromTitle);
|
||||
// Rename any tags or lists that reference it
|
||||
this.each(function(tiddler,title) {
|
||||
var tags = (tiddler.fields.tags || []).slice(0),
|
||||
list = (tiddler.fields.list || []).slice(0),
|
||||
isModified = false;
|
||||
// Rename tags
|
||||
$tw.utils.each(tags,function (title,index) {
|
||||
if(title === fromTitle) {
|
||||
tags[index] = toTitle;
|
||||
isModified = true;
|
||||
}
|
||||
});
|
||||
// Rename lists
|
||||
$tw.utils.each(list,function (title,index) {
|
||||
if(title === fromTitle) {
|
||||
list[index] = toTitle;
|
||||
isModified = true;
|
||||
}
|
||||
});
|
||||
if(isModified) {
|
||||
self.addTiddler(new $tw.Tiddler(tiddler,{tags: tags, list: list},self.getModificationFields()));
|
||||
}
|
||||
});
|
||||
this.relinkTiddler(fromTitle,toTitle,options)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Relink any tags or lists that reference a given tiddler
|
||||
*/
|
||||
function relinkTiddler(fromTitle,toTitle,options) {
|
||||
var self = this;
|
||||
fromTitle = (fromTitle || "").trim();
|
||||
toTitle = (toTitle || "").trim();
|
||||
options = options || {};
|
||||
if(fromTitle && toTitle && fromTitle !== toTitle) {
|
||||
this.each(function(tiddler,title) {
|
||||
var type = tiddler.fields.type || "";
|
||||
// Don't touch plugins or JavaScript modules
|
||||
if(!tiddler.fields["plugin-type"] && type !== "application/javascript") {
|
||||
var tags = (tiddler.fields.tags || []).slice(0),
|
||||
list = (tiddler.fields.list || []).slice(0),
|
||||
isModified = false;
|
||||
if(!options.dontRenameInTags) {
|
||||
// Rename tags
|
||||
$tw.utils.each(tags,function (title,index) {
|
||||
if(title === fromTitle) {
|
||||
console.log("Renaming tag '" + tags[index] + "' to '" + toTitle + "' of tiddler '" + tiddler.fields.title + "'");
|
||||
tags[index] = toTitle;
|
||||
isModified = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
if(!options.dontRenameInLists) {
|
||||
// Rename lists
|
||||
$tw.utils.each(list,function (title,index) {
|
||||
if(title === fromTitle) {
|
||||
console.log("Renaming list item '" + list[index] + "' to '" + toTitle + "' of tiddler '" + tiddler.fields.title + "'");
|
||||
list[index] = toTitle;
|
||||
isModified = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
if(isModified) {
|
||||
var newTiddler = new $tw.Tiddler(tiddler,{tags: tags, list: list},self.getModificationFields())
|
||||
newTiddler = $tw.hooks.invokeHook("th-relinking-tiddler",newTiddler,tiddler);
|
||||
self.addTiddler(newTiddler);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.renameTiddler = renameTiddler;
|
||||
exports.relinkTiddler = relinkTiddler;
|
||||
|
||||
})();
|
||||
|
||||
@@ -24,7 +24,8 @@ Adds the following properties to the wiki object:
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
var USER_NAME_TITLE = "$:/status/UserName";
|
||||
var USER_NAME_TITLE = "$:/status/UserName",
|
||||
TIMESTAMP_DISABLE_TITLE = "$:/config/TimestampDisable";
|
||||
|
||||
/*
|
||||
Get the value of a text reference. Text references can have any of these forms:
|
||||
@@ -231,27 +232,35 @@ exports.importTiddler = function(tiddler) {
|
||||
Return a hashmap of the fields that should be set when a tiddler is created
|
||||
*/
|
||||
exports.getCreationFields = function() {
|
||||
var fields = {
|
||||
created: new Date()
|
||||
},
|
||||
creator = this.getTiddlerText(USER_NAME_TITLE);
|
||||
if(creator) {
|
||||
fields.creator = creator;
|
||||
if(this.getTiddlerText(TIMESTAMP_DISABLE_TITLE,"").toLowerCase() !== "yes") {
|
||||
var fields = {
|
||||
created: new Date()
|
||||
},
|
||||
creator = this.getTiddlerText(USER_NAME_TITLE);
|
||||
if(creator) {
|
||||
fields.creator = creator;
|
||||
}
|
||||
return fields;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
return fields;
|
||||
};
|
||||
|
||||
/*
|
||||
Return a hashmap of the fields that should be set when a tiddler is modified
|
||||
*/
|
||||
exports.getModificationFields = function() {
|
||||
var fields = Object.create(null),
|
||||
modifier = this.getTiddlerText(USER_NAME_TITLE);
|
||||
fields.modified = new Date();
|
||||
if(modifier) {
|
||||
fields.modifier = modifier;
|
||||
if(this.getTiddlerText(TIMESTAMP_DISABLE_TITLE,"").toLowerCase() !== "yes") {
|
||||
var fields = Object.create(null),
|
||||
modifier = this.getTiddlerText(USER_NAME_TITLE);
|
||||
fields.modified = new Date();
|
||||
if(modifier) {
|
||||
fields.modifier = modifier;
|
||||
}
|
||||
return fields;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
return fields;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -328,7 +337,7 @@ exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,is
|
||||
var result =
|
||||
isNaN(x) && !isNaN(y) ? (isDescending ? -1 : 1) :
|
||||
!isNaN(x) && isNaN(y) ? (isDescending ? 1 : -1) :
|
||||
(isDescending ? y - x : x - y);
|
||||
(isDescending ? y - x : x - y);
|
||||
return result;
|
||||
};
|
||||
if(sortField !== "title") {
|
||||
@@ -632,10 +641,10 @@ exports.getTiddlerDataCached = function(titleOrTiddler,defaultData) {
|
||||
if(tiddler) {
|
||||
return this.getCacheForTiddler(tiddler.fields.title,"data",function() {
|
||||
// Return the frozen value
|
||||
var value = self.getTiddlerData(tiddler.fields.title,defaultData);
|
||||
var value = self.getTiddlerData(tiddler.fields.title,undefined);
|
||||
$tw.utils.deepFreeze(value);
|
||||
return value;
|
||||
});
|
||||
}) || defaultData;
|
||||
} else {
|
||||
return defaultData;
|
||||
}
|
||||
@@ -671,7 +680,7 @@ exports.getTiddlerData = function(titleOrTiddler,defaultData) {
|
||||
Extract an indexed field from within a data tiddler
|
||||
*/
|
||||
exports.extractTiddlerDataItem = function(titleOrTiddler,index,defaultText) {
|
||||
var data = this.getTiddlerData(titleOrTiddler,Object.create(null)),
|
||||
var data = this.getTiddlerDataCached(titleOrTiddler,Object.create(null)),
|
||||
text;
|
||||
if(data && $tw.utils.hop(data,index)) {
|
||||
text = data[index];
|
||||
@@ -904,31 +913,54 @@ options: as for wiki.makeWidget() plus:
|
||||
options.field: optional field to transclude (defaults to "text")
|
||||
options.mode: transclusion mode "inline" or "block"
|
||||
options.children: optional array of children for the transclude widget
|
||||
options.importVariables: optional importvariables filter string for macros to be included
|
||||
options.importPageMacros: optional boolean; if true, equivalent to passing "[[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]" to options.importVariables
|
||||
*/
|
||||
exports.makeTranscludeWidget = function(title,options) {
|
||||
options = options || {};
|
||||
var parseTree = {tree: [{
|
||||
var parseTreeDiv = {tree: [{
|
||||
type: "element",
|
||||
tag: "div",
|
||||
children: [{
|
||||
type: "transclude",
|
||||
attributes: {
|
||||
tiddler: {
|
||||
name: "tiddler",
|
||||
type: "string",
|
||||
value: title}},
|
||||
isBlock: !options.parseAsInline}]}
|
||||
]};
|
||||
children: []}]},
|
||||
parseTreeImportVariables = {
|
||||
type: "importvariables",
|
||||
attributes: {
|
||||
filter: {
|
||||
name: "filter",
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
isBlock: false,
|
||||
children: []},
|
||||
parseTreeTransclude = {
|
||||
type: "transclude",
|
||||
attributes: {
|
||||
tiddler: {
|
||||
name: "tiddler",
|
||||
type: "string",
|
||||
value: title}},
|
||||
isBlock: !options.parseAsInline};
|
||||
if(options.importVariables || options.importPageMacros) {
|
||||
if(options.importVariables) {
|
||||
parseTreeImportVariables.attributes.filter.value = options.importVariables;
|
||||
} else if(options.importPageMacros) {
|
||||
parseTreeImportVariables.attributes.filter.value = "[[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]";
|
||||
}
|
||||
parseTreeDiv.tree[0].children.push(parseTreeImportVariables);
|
||||
parseTreeImportVariables.children.push(parseTreeTransclude);
|
||||
} else {
|
||||
parseTreeDiv.tree[0].children.push(parseTreeTransclude);
|
||||
}
|
||||
if(options.field) {
|
||||
parseTree.tree[0].children[0].attributes.field = {type: "string", value: options.field};
|
||||
parseTreeTransclude.attributes.field = {type: "string", value: options.field};
|
||||
}
|
||||
if(options.mode) {
|
||||
parseTree.tree[0].children[0].attributes.mode = {type: "string", value: options.mode};
|
||||
parseTreeTransclude.attributes.mode = {type: "string", value: options.mode};
|
||||
}
|
||||
if(options.children) {
|
||||
parseTree.tree[0].children[0].children = options.children;
|
||||
parseTreeTransclude.children = options.children;
|
||||
}
|
||||
return $tw.wiki.makeWidget(parseTree,options);
|
||||
return $tw.wiki.makeWidget(parseTreeDiv,options);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1074,6 +1106,22 @@ exports.getTiddlerText = function(title,defaultText) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Check whether the text of a tiddler matches a given value. By default, the comparison is case insensitive, and any spaces at either end of the tiddler text is trimmed
|
||||
*/
|
||||
exports.checkTiddlerText = function(title,targetText,options) {
|
||||
options = options || {};
|
||||
var text = this.getTiddlerText(title,"");
|
||||
if(!options.noTrim) {
|
||||
text = text.trim();
|
||||
}
|
||||
if(!options.caseSensitive) {
|
||||
text = text.toLowerCase();
|
||||
targetText = targetText.toLowerCase();
|
||||
}
|
||||
return text === targetText;
|
||||
}
|
||||
|
||||
/*
|
||||
Read an array of browser File objects, invoking callback(tiddlerFieldsArray) once they're all read
|
||||
*/
|
||||
@@ -1118,29 +1166,24 @@ exports.readFile = function(file,callback) {
|
||||
var reader = new FileReader();
|
||||
// Onload
|
||||
reader.onload = function(event) {
|
||||
// Deserialise the file contents
|
||||
var text = event.target.result,
|
||||
tiddlerFields = {title: file.name || "Untitled", type: type};
|
||||
// Are we binary?
|
||||
if(isBinary) {
|
||||
// The base64 section starts after the first comma in the data URI
|
||||
var commaPos = text.indexOf(",");
|
||||
if(commaPos !== -1) {
|
||||
tiddlerFields.text = text.substr(commaPos+1);
|
||||
callback([tiddlerFields]);
|
||||
text = text.substr(commaPos + 1);
|
||||
}
|
||||
}
|
||||
// Check whether this is an encrypted TiddlyWiki file
|
||||
var encryptedJson = $tw.utils.extractEncryptedStoreArea(text);
|
||||
if(encryptedJson) {
|
||||
// If so, attempt to decrypt it with the current password
|
||||
$tw.utils.decryptStoreAreaInteractive(encryptedJson,function(tiddlers) {
|
||||
callback(tiddlers);
|
||||
});
|
||||
} else {
|
||||
// Check whether this is an encrypted TiddlyWiki file
|
||||
var encryptedJson = $tw.utils.extractEncryptedStoreArea(text);
|
||||
if(encryptedJson) {
|
||||
// If so, attempt to decrypt it with the current password
|
||||
$tw.utils.decryptStoreAreaInteractive(encryptedJson,function(tiddlers) {
|
||||
callback(tiddlers);
|
||||
});
|
||||
} else {
|
||||
// Otherwise, just try to deserialise any tiddlers in the file
|
||||
callback(self.deserializeTiddlers(type,text,tiddlerFields));
|
||||
}
|
||||
// Otherwise, just try to deserialise any tiddlers in the file
|
||||
callback(self.deserializeTiddlers(type,text,tiddlerFields));
|
||||
}
|
||||
};
|
||||
// Kick off the read
|
||||
@@ -1219,3 +1262,4 @@ exports.invokeUpgraders = function(titles,tiddlers) {
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user