mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-22 19:04:38 +00:00
Compare commits
415 Commits
word-games
...
fix-3692
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2bd54c9d9 | ||
|
|
4a3223b562 | ||
|
|
ab3109d84b | ||
|
|
a4ab42da8a | ||
|
|
af87727ffc | ||
|
|
6b4e5c74ad | ||
|
|
8af99878cc | ||
|
|
d6d2bc455c | ||
|
|
d5ff723d4c | ||
|
|
1d0af90ba2 | ||
|
|
59572cd75d | ||
|
|
1d16206188 | ||
|
|
37a6ff8521 | ||
|
|
d3ea98fcef | ||
|
|
5022516c61 | ||
|
|
965d8ee014 | ||
|
|
8e50ad1243 | ||
|
|
33f40c47c6 | ||
|
|
1b3c2557b8 | ||
|
|
1a4766c5a1 | ||
|
|
e49dda3b48 | ||
|
|
bd447f0716 | ||
|
|
13faeaa0bd | ||
|
|
7f0fb2b610 | ||
|
|
7d2994388b | ||
|
|
edb5dc3fdc | ||
|
|
df1b1316c8 | ||
|
|
1a0c831216 | ||
|
|
f4365e4bb4 | ||
|
|
75d10a2dc3 | ||
|
|
da7cf7a4f3 | ||
|
|
2469d0f0bf | ||
|
|
6452eb56a9 | ||
|
|
9fce8153df | ||
|
|
4cdfa4e3f9 | ||
|
|
d6384df6fc | ||
|
|
f0bd06b38d | ||
|
|
d823856082 | ||
|
|
b02a82ba0f | ||
|
|
c43b013539 | ||
|
|
5548186c93 | ||
|
|
def9b553a8 | ||
|
|
35f7a8ea06 | ||
|
|
54bfb28063 | ||
|
|
80c63b96cf | ||
|
|
2ef9ecbc44 | ||
|
|
88812092fd | ||
|
|
4e01fc1838 | ||
|
|
5cab75f4a7 | ||
|
|
1345384d39 | ||
|
|
927013a57a | ||
|
|
0d11fccba2 | ||
|
|
d78ad756db | ||
|
|
5613bcc884 | ||
|
|
0729d730f8 | ||
|
|
f2422efeb8 | ||
|
|
cbb002ec4b | ||
|
|
c7e8c87f85 | ||
|
|
66ae1d6930 | ||
|
|
8e3885277f | ||
|
|
9293dfa477 | ||
|
|
8a80d89582 | ||
|
|
10ebd93df3 | ||
|
|
d414eef773 | ||
|
|
7d1f0ea8f4 | ||
|
|
f477e90192 | ||
|
|
b4dec78a72 | ||
|
|
60187dc59e | ||
|
|
4453aefad8 | ||
|
|
54cfda76ee | ||
|
|
1e8c2821d6 | ||
|
|
cbc030fbe2 | ||
|
|
b454116163 | ||
|
|
0186c6490f | ||
|
|
853a899c77 | ||
|
|
95a3d7fde2 | ||
|
|
d33e0a05e2 | ||
|
|
cb833b3f65 | ||
|
|
b73c50adeb | ||
|
|
fdfa45329a | ||
|
|
7b1880404c | ||
|
|
2739b1bafe | ||
|
|
cc782ff518 | ||
|
|
492bfbebe9 | ||
|
|
c9fbff265a | ||
|
|
b0f72d0690 | ||
|
|
6070a2c921 | ||
|
|
cb43b91ab6 | ||
|
|
804bc9e9c0 | ||
|
|
4514a67a1f | ||
|
|
edcba4ee16 | ||
|
|
9e28356047 | ||
|
|
44ad8c770f | ||
|
|
2dd4fa41a5 | ||
|
|
f5389b3859 | ||
|
|
65c8d74218 | ||
|
|
f88e3939e1 | ||
|
|
769778b05b | ||
|
|
f84ff0d778 | ||
|
|
ca1aabe21f | ||
|
|
dd801d1571 | ||
|
|
485730483b | ||
|
|
8b6733d792 | ||
|
|
75aabcce64 | ||
|
|
5dfa6b2bb4 | ||
|
|
3798a3c7d0 | ||
|
|
1c4b2243a6 | ||
|
|
c11493ec37 | ||
|
|
b6c8cdae64 | ||
|
|
b80d079d71 | ||
|
|
6512b038c5 | ||
|
|
6d1d497a63 | ||
|
|
6ea7140e8f | ||
|
|
7b311b0e4a | ||
|
|
be3018fe3b | ||
|
|
68095eb392 | ||
|
|
4bb34e4801 | ||
|
|
1348607c8f | ||
|
|
2f86779a27 | ||
|
|
2af632a46d | ||
|
|
05606f72ad | ||
|
|
6d0701e0fa | ||
|
|
76cdc17f3b | ||
|
|
7b076eadfa | ||
|
|
c5ce2a0a94 | ||
|
|
7fcc84156e | ||
|
|
75bf12db7a | ||
|
|
07de96459e | ||
|
|
be036aa9c8 | ||
|
|
0664895670 | ||
|
|
dde1e4bc0f | ||
|
|
122de63b71 | ||
|
|
e3ba880e18 | ||
|
|
e3be15531f | ||
|
|
5a3ff4e3dc | ||
|
|
f7f32f00a3 | ||
|
|
d7d694b14f | ||
|
|
a6feb6dd66 | ||
|
|
ecf10e41c3 | ||
|
|
481edc1cfe | ||
|
|
ff5817ab50 | ||
|
|
80235bf049 | ||
|
|
ecddd5a7be | ||
|
|
f22fc788e5 | ||
|
|
f828a582c3 | ||
|
|
a94f94f352 | ||
|
|
9f34a01577 | ||
|
|
9cd49ed485 | ||
|
|
4ea1a05af6 | ||
|
|
b6eb6d477b | ||
|
|
cce18d8e2e | ||
|
|
45d469ca5c | ||
|
|
fbee714ffe | ||
|
|
2429dcc2e2 | ||
|
|
4d84422f22 | ||
|
|
d98bfbde58 | ||
|
|
983787a8f2 | ||
|
|
7b83c22e78 | ||
|
|
c8c43b2811 | ||
|
|
7e32e2efcf | ||
|
|
6f8e842105 | ||
|
|
ce99c0aa0f | ||
|
|
3ff165402c | ||
|
|
a350a76a00 | ||
|
|
05b9dd1822 | ||
|
|
5207b1c127 | ||
|
|
267c351735 | ||
|
|
f545418e55 | ||
|
|
97dd832d2e | ||
|
|
d7e7d87581 | ||
|
|
bd2efeaaa3 | ||
|
|
a206bf56b9 | ||
|
|
a33e94c4ee | ||
|
|
e9313b1c9d | ||
|
|
8096935d87 | ||
|
|
dcb083abb0 | ||
|
|
6cc76fe6ab | ||
|
|
4f8de1881c | ||
|
|
9caba544eb | ||
|
|
746a8ca17f | ||
|
|
2475e1b501 | ||
|
|
193628d63f | ||
|
|
b6ce353a7d | ||
|
|
7a50603d9d | ||
|
|
d21fabca4b | ||
|
|
daa9a8ae45 | ||
|
|
d9eb5499a3 | ||
|
|
870c7897ad | ||
|
|
95da1c2907 | ||
|
|
2bfe522b72 | ||
|
|
c099bf9893 | ||
|
|
ab0dda1177 | ||
|
|
4f65953da9 | ||
|
|
d77de61a06 | ||
|
|
3287cf56bb | ||
|
|
b5c81d2721 | ||
|
|
d3522854b6 | ||
|
|
2f3f9de7be | ||
|
|
6890952357 | ||
|
|
d695fca301 | ||
|
|
a0d2392f01 | ||
|
|
23b4e03cd5 | ||
|
|
d5f72cb282 | ||
|
|
5f57bf81cd | ||
|
|
e32c9e4658 | ||
|
|
2a73505508 | ||
|
|
4d87ef4231 | ||
|
|
71be167592 | ||
|
|
c543036a0f | ||
|
|
989947b99a | ||
|
|
3d86d62a6e | ||
|
|
0cfe6597d4 | ||
|
|
8ae4428332 | ||
|
|
81b4e99ccc | ||
|
|
2f133a08aa | ||
|
|
6b17e688da | ||
|
|
8654066f03 | ||
|
|
56dae90425 | ||
|
|
1f6ef07860 | ||
|
|
f30a455ee3 | ||
|
|
03bd99cd11 | ||
|
|
cc389ec82b | ||
|
|
f85678b6dc | ||
|
|
8d7c869072 | ||
|
|
8f592d3f0a | ||
|
|
1f2e0ed189 | ||
|
|
4d6c428ba9 | ||
|
|
d095aa0182 | ||
|
|
15bf850280 | ||
|
|
62b273266e | ||
|
|
1d058177be | ||
|
|
14676b345a | ||
|
|
a50e6eed38 | ||
|
|
073a064ae8 | ||
|
|
e00a3d3cb4 | ||
|
|
68d9200a6b | ||
|
|
2551bb3e3f | ||
|
|
80b18e6315 | ||
|
|
e0561397f1 | ||
|
|
b9c3c38edc | ||
|
|
077ced0d1a | ||
|
|
e5ff84035c | ||
|
|
e18a983209 | ||
|
|
6f61fa07fb | ||
|
|
d5d73e02e9 | ||
|
|
4ba7454d8d | ||
|
|
5192a39830 | ||
|
|
aa5413b942 | ||
|
|
ef284e9bde | ||
|
|
9c41fe1d18 | ||
|
|
e577cf7302 | ||
|
|
ebf563ac70 | ||
|
|
909340c6fe | ||
|
|
df6d38df65 | ||
|
|
59a53e695b | ||
|
|
6d17505f7b | ||
|
|
36dd8ea1d2 | ||
|
|
b965ae926b | ||
|
|
f6eadbd1c9 | ||
|
|
bdbb884be0 | ||
|
|
0be39cfbc2 | ||
|
|
ef2aeac7de | ||
|
|
157afda2fc | ||
|
|
fb4d77ef46 | ||
|
|
575c233597 | ||
|
|
2e59d770f7 | ||
|
|
baf0ee9cde | ||
|
|
af89bb591d | ||
|
|
d0dec741ad | ||
|
|
33a82e395e | ||
|
|
f223896c26 | ||
|
|
de33b365ae | ||
|
|
e9d8547a81 | ||
|
|
dcff318a98 | ||
|
|
f725123690 | ||
|
|
e9e5d37ff0 | ||
|
|
f70cee6907 | ||
|
|
1491339f50 | ||
|
|
8a5ed59ff4 | ||
|
|
a2ca5e4d1e | ||
|
|
fba993502d | ||
|
|
9fae3a932b | ||
|
|
62610f0666 | ||
|
|
7282ec5286 | ||
|
|
9830e0104f | ||
|
|
e6fd0caf6b | ||
|
|
137df37bc7 | ||
|
|
d895706199 | ||
|
|
6ed7d418b5 | ||
|
|
62b8a83741 | ||
|
|
e795b501ac | ||
|
|
03228d8d20 | ||
|
|
c9c5d4cf79 | ||
|
|
f5cc5bc6a1 | ||
|
|
447494ad4d | ||
|
|
c9f178ec87 | ||
|
|
33be326ef6 | ||
|
|
c13f04d838 | ||
|
|
737685149c | ||
|
|
33eef0202d | ||
|
|
a67b1b8bb5 | ||
|
|
124b49456a | ||
|
|
24956087cc | ||
|
|
199ca57f1c | ||
|
|
64d53ac533 | ||
|
|
b3accbf9e0 | ||
|
|
99249a3160 | ||
|
|
f7cd8bad3a | ||
|
|
e9613d7f12 | ||
|
|
97dff042f7 | ||
|
|
32b36fb2af | ||
|
|
41535150dd | ||
|
|
8e69284e8c | ||
|
|
61cfac4eeb | ||
|
|
2720072b23 | ||
|
|
0413c3a38e | ||
|
|
f2b30c1fe0 | ||
|
|
3c86cf7d2e | ||
|
|
451074f7ed | ||
|
|
1e5601ca31 | ||
|
|
75c99cd235 | ||
|
|
bb2c2be9b6 | ||
|
|
53c247b9a1 | ||
|
|
82667d9d16 | ||
|
|
97ed2757f0 | ||
|
|
19fd5ca5f2 | ||
|
|
6ae78a770f | ||
|
|
04962b4cd6 | ||
|
|
f97850dd05 | ||
|
|
2cb3ed3ab9 | ||
|
|
a4421f50c6 | ||
|
|
cb726f40fa | ||
|
|
be026aa308 | ||
|
|
0924ca6365 | ||
|
|
39fec2decf | ||
|
|
dbfd45814d | ||
|
|
d455072f13 | ||
|
|
155525708b | ||
|
|
fdca11dec3 | ||
|
|
f83875331d | ||
|
|
be6deb054e | ||
|
|
b0604a9bf5 | ||
|
|
30925ee7bf | ||
|
|
7204f442cd | ||
|
|
23fec9e390 | ||
|
|
8d9dc0cd29 | ||
|
|
a1d9464011 | ||
|
|
0b71f25f74 | ||
|
|
315464372f | ||
|
|
56068d8215 | ||
|
|
b95f6ca084 | ||
|
|
4a7f078abd | ||
|
|
1b55eb9eee | ||
|
|
3094e06236 | ||
|
|
f87b3bfcdb | ||
|
|
a0a0df9655 | ||
|
|
31c1584b9a | ||
|
|
f1f951e849 | ||
|
|
041c3e817c | ||
|
|
70e60cd93f | ||
|
|
54d8b8a373 | ||
|
|
dd6bd58140 | ||
|
|
a6990128f1 | ||
|
|
338b7c92a2 | ||
|
|
a409536ad0 | ||
|
|
c9af04d0e5 | ||
|
|
076a04fbfb | ||
|
|
83ee363cb4 | ||
|
|
63fa0c4fa4 | ||
|
|
644062fc21 | ||
|
|
021e9b8c4d | ||
|
|
afa653a7aa | ||
|
|
0b56d5fd37 | ||
|
|
2da7ae0b73 | ||
|
|
4c56bd771a | ||
|
|
9c0d6a46cc | ||
|
|
06318b7617 | ||
|
|
8f9e8c1dee | ||
|
|
3cd80de5bb | ||
|
|
f2e26927c1 | ||
|
|
960160b3a2 | ||
|
|
4f33d2f35c | ||
|
|
b5db488438 | ||
|
|
6dd1887f0b | ||
|
|
a70b26cd55 | ||
|
|
219beb13cc | ||
|
|
c18b7527a7 | ||
|
|
2f1806ab6a | ||
|
|
afa4ea3d03 | ||
|
|
2b911ac11f | ||
|
|
c4a7ae3164 | ||
|
|
056e6541a1 | ||
|
|
753bf8fe62 | ||
|
|
4f9dd50382 | ||
|
|
2e695801b1 | ||
|
|
55c522ab8f | ||
|
|
9faaa31299 | ||
|
|
582b156d5f | ||
|
|
8b8f654c9c | ||
|
|
9b247f6d63 | ||
|
|
f342fdc41d | ||
|
|
ca96f7f62b | ||
|
|
2f31eab8f4 | ||
|
|
c8528fd1f7 | ||
|
|
07ac85d9fa | ||
|
|
e84f214280 | ||
|
|
9cd65efad9 | ||
|
|
41200ab6d7 | ||
|
|
62fdaa633a | ||
|
|
79f5e6b498 | ||
|
|
23bd7e7817 | ||
|
|
792171c8fc | ||
|
|
051a468c63 | ||
|
|
1b226c7556 | ||
|
|
2bd9cc45fa |
@@ -1,15 +1,8 @@
|
||||
# Known minified files
|
||||
# Ignore "third party" code whose style we will not change.
|
||||
/boot/sjcl.js
|
||||
/core/modules/utils/base64-utf8/base64-utf8.module.js
|
||||
/core/modules/utils/base64-utf8/base64-utf8.module.min.js
|
||||
/core/modules/utils/diff-match-patch/diff_match_patch.js
|
||||
/plugins/tiddlywiki/async/files/async.min.v1.5.0.js
|
||||
/plugins/tiddlywiki/codemirror-autocomplete/files/addon/hint/anyword-hint.js
|
||||
/plugins/tiddlywiki/codemirror-autocomplete/files/addon/hint/css-hint.js
|
||||
/plugins/tiddlywiki/codemirror-autocomplete/files/addon/hint/html-hint.js
|
||||
/plugins/tiddlywiki/codemirror-autocomplete/files/addon/hint/javascript-hint.js
|
||||
/plugins/tiddlywiki/codemirror-autocomplete/files/addon/hint/show-hint.js
|
||||
/plugins/tiddlywiki/codemirror-autocomplete/files/addon/hint/xml-hint.js
|
||||
/plugins/tiddlywiki/codemirror-closebrackets/files/addon/edit/closebrackets.js
|
||||
/plugins/tiddlywiki/codemirror-closebrackets/files/addon/edit/matchbrackets.js
|
||||
/plugins/tiddlywiki/codemirror-closetag/files/addon/edit/closetag.js
|
||||
/plugins/tiddlywiki/codemirror-closetag/files/addon/fold/xml-fold.js
|
||||
/core/modules/utils/diff-match-patch/diff_match_patch_uncompressed.js
|
||||
/core/modules/utils/dom/csscolorparser.js
|
||||
/plugins/tiddlywiki/*/files/
|
||||
|
||||
@@ -64,7 +64,23 @@ rules:
|
||||
init-declarations: 'off'
|
||||
jsx-quotes: error
|
||||
key-spacing: 'off'
|
||||
keyword-spacing: 'off'
|
||||
keyword-spacing:
|
||||
- error
|
||||
- before: true
|
||||
after: false
|
||||
overrides:
|
||||
'case':
|
||||
after: true
|
||||
'do':
|
||||
'after': true
|
||||
'else':
|
||||
after: true
|
||||
'return':
|
||||
after: true
|
||||
'throw':
|
||||
after: true
|
||||
'try':
|
||||
after: true
|
||||
line-comment-position: 'off'
|
||||
linebreak-style: 'off'
|
||||
lines-around-comment: 'off'
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Default to the current version number for building the plugin library
|
||||
|
||||
if [ -z "$TW5_BUILD_VERSION" ]; then
|
||||
TW5_BUILD_VERSION=v5.1.24
|
||||
TW5_BUILD_VERSION=v5.2.2
|
||||
fi
|
||||
|
||||
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
||||
|
||||
104
boot/boot.js
104
boot/boot.js
@@ -256,6 +256,28 @@ $tw.utils.deepDefaults = function(object /*, sourceObjectList */) {
|
||||
return object;
|
||||
};
|
||||
|
||||
/*
|
||||
Convert a URIComponent encoded string to a string safely
|
||||
*/
|
||||
$tw.utils.decodeURIComponentSafe = function(s) {
|
||||
var v = s;
|
||||
try {
|
||||
v = decodeURIComponent(s);
|
||||
} catch(e) {}
|
||||
return v;
|
||||
};
|
||||
|
||||
/*
|
||||
Convert a URI encoded string to a string safely
|
||||
*/
|
||||
$tw.utils.decodeURISafe = function(s) {
|
||||
var v = s;
|
||||
try {
|
||||
v = decodeURI(s);
|
||||
} catch(e) {}
|
||||
return v;
|
||||
};
|
||||
|
||||
/*
|
||||
Convert "&" to &, " " to nbsp, "<" to <, ">" to > and """ to "
|
||||
*/
|
||||
@@ -1212,8 +1234,12 @@ $tw.Wiki = function(options) {
|
||||
index,titlesLength,title;
|
||||
for(index = 0, titlesLength = titles.length; index < titlesLength; index++) {
|
||||
title = titles[index];
|
||||
var shadowInfo = shadowTiddlers[title];
|
||||
callback(shadowInfo.tiddler,title);
|
||||
if(tiddlers[title]) {
|
||||
callback(tiddlers[title],title);
|
||||
} else {
|
||||
var shadowInfo = shadowTiddlers[title];
|
||||
callback(shadowInfo.tiddler,title);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1602,8 +1628,8 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
|
||||
}
|
||||
for(var f in data) {
|
||||
if($tw.utils.hop(data,f)) {
|
||||
// Check field name doesn't contain whitespace or control characters
|
||||
if(typeof(data[f]) !== "string" || /[\x00-\x1F\s]/.test(f)) {
|
||||
// Check field name doesn't contain control characters
|
||||
if(typeof(data[f]) !== "string" || /[\x00-\x1F]/.test(f)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1618,7 +1644,12 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
|
||||
}
|
||||
return true;
|
||||
},
|
||||
data = JSON.parse(text);
|
||||
data = {};
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
} catch(e) {
|
||||
// Ignore JSON parse errors
|
||||
}
|
||||
if($tw.utils.isArray(data) && isTiddlerArrayValid(data)) {
|
||||
return data;
|
||||
} else if(isTiddlerValid(data)) {
|
||||
@@ -1724,13 +1755,20 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/dom","tiddlerdeserializer",{
|
||||
},
|
||||
t,result = [];
|
||||
if(node) {
|
||||
for(t = 0; t < node.childNodes.length; t++) {
|
||||
var type = (node.getAttribute && node.getAttribute("type")) || null;
|
||||
if(type) {
|
||||
// A new-style container with an explicit deserialization type
|
||||
result = $tw.wiki.deserializeTiddlers(type,node.textContent);
|
||||
} else {
|
||||
// An old-style container of classic DIV-based tiddlers
|
||||
for(t = 0; t < node.childNodes.length; t++) {
|
||||
var childNode = node.childNodes[t],
|
||||
tiddlers = extractTextTiddlers(childNode);
|
||||
tiddlers = tiddlers || extractModuleTiddlers(childNode);
|
||||
if(tiddlers) {
|
||||
result.push.apply(result,tiddlers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -1739,17 +1777,23 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/dom","tiddlerdeserializer",{
|
||||
|
||||
$tw.loadTiddlersBrowser = function() {
|
||||
// In the browser, we load tiddlers from certain elements
|
||||
var containerIds = [
|
||||
"libraryModules",
|
||||
"modules",
|
||||
"bootKernelPrefix",
|
||||
"bootKernel",
|
||||
"styleArea",
|
||||
"storeArea",
|
||||
"systemArea"
|
||||
var containerSelectors = [
|
||||
// IDs for old-style v5.1.x tiddler stores
|
||||
"#libraryModules",
|
||||
"#modules",
|
||||
"#bootKernelPrefix",
|
||||
"#bootKernel",
|
||||
"#styleArea",
|
||||
"#storeArea",
|
||||
"#systemArea",
|
||||
// Classes for new-style v5.2.x JSON tiddler stores
|
||||
"script.tiddlywiki-tiddler-store"
|
||||
];
|
||||
for(var t=0; t<containerIds.length; t++) {
|
||||
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById(containerIds[t])));
|
||||
for(var t=0; t<containerSelectors.length; t++) {
|
||||
var nodes = document.querySelectorAll(containerSelectors[t]);
|
||||
for(var n=0; n<nodes.length; n++) {
|
||||
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",nodes[n]));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1872,13 +1916,13 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
value = path.basename(filename);
|
||||
break;
|
||||
case "filename-uri-decoded":
|
||||
value = decodeURIComponent(path.basename(filename));
|
||||
value = $tw.utils.decodeURIComponentSafe(path.basename(filename));
|
||||
break;
|
||||
case "basename":
|
||||
value = path.basename(filename,path.extname(filename));
|
||||
break;
|
||||
case "basename-uri-decoded":
|
||||
value = decodeURIComponent(path.basename(filename,path.extname(filename)));
|
||||
value = $tw.utils.decodeURIComponentSafe(path.basename(filename,path.extname(filename)));
|
||||
break;
|
||||
case "extname":
|
||||
value = path.extname(filename);
|
||||
@@ -1906,6 +1950,20 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
tiddlers.push({tiddlers: fileTiddlers});
|
||||
}
|
||||
};
|
||||
// Helper to recursively search subdirectories
|
||||
var getAllFiles = function(dirPath, recurse, arrayOfFiles) {
|
||||
recurse = recurse || false;
|
||||
arrayOfFiles = arrayOfFiles || [];
|
||||
var files = fs.readdirSync(dirPath);
|
||||
files.forEach(function(file) {
|
||||
if (recurse && fs.statSync(dirPath + path.sep + file).isDirectory()) {
|
||||
arrayOfFiles = getAllFiles(dirPath + path.sep + file, recurse, arrayOfFiles);
|
||||
} else if(fs.statSync(dirPath + path.sep + file).isFile()){
|
||||
arrayOfFiles.push(path.join(dirPath, path.sep, file));
|
||||
}
|
||||
});
|
||||
return arrayOfFiles;
|
||||
}
|
||||
// Process the listed tiddlers
|
||||
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
|
||||
if(tidInfo.prefix && tidInfo.suffix) {
|
||||
@@ -1929,13 +1987,14 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
// Process directory specifier
|
||||
var dirPath = path.resolve(filepath,dirSpec.path);
|
||||
if(fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
|
||||
var files = fs.readdirSync(dirPath),
|
||||
var files = getAllFiles(dirPath, dirSpec.searchSubdirectories),
|
||||
fileRegExp = new RegExp(dirSpec.filesRegExp || "^.*$"),
|
||||
metaRegExp = /^.*\.meta$/;
|
||||
for(var t=0; t<files.length; t++) {
|
||||
var filename = files[t];
|
||||
var thisPath = path.relative(filepath, files[t]),
|
||||
filename = path.basename(thisPath);
|
||||
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
||||
processFile(dirPath + path.sep + filename,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile);
|
||||
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1985,7 +2044,7 @@ $tw.loadPluginFolder = function(filepath,excludeRegExp) {
|
||||
pluginInfo.dependents = pluginInfo.dependents || [];
|
||||
pluginInfo.type = "application/json";
|
||||
// Set plugin text
|
||||
pluginInfo.text = JSON.stringify({tiddlers: pluginInfo.tiddlers},null,4);
|
||||
pluginInfo.text = JSON.stringify({tiddlers: pluginInfo.tiddlers});
|
||||
delete pluginInfo.tiddlers;
|
||||
// Deserialise array fields (currently required for the dependents field)
|
||||
for(var field in pluginInfo) {
|
||||
@@ -2590,3 +2649,4 @@ if(typeof(exports) !== "undefined") {
|
||||
} else {
|
||||
_boot(window.$tw);
|
||||
}
|
||||
//# sourceURL=$:/boot/boot.js
|
||||
|
||||
@@ -117,3 +117,4 @@ if(typeof(exports) === "undefined") {
|
||||
// Export functionality as a module
|
||||
exports.bootprefix = _bootprefix;
|
||||
}
|
||||
//# sourceURL=$:/boot/bootprefix.js
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@ type: text/plain
|
||||
TiddlyWiki created by Jeremy Ruston, (jeremy [at] jermolene [dot] com)
|
||||
|
||||
Copyright (c) 2004-2007, Jeremy Ruston
|
||||
Copyright (c) 2007-2021, UnaMesa Association
|
||||
Copyright (c) 2007-2022, UnaMesa Association
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -27,10 +27,15 @@ Basics/Tiddlers/Prompt: Number of tiddlers
|
||||
Basics/Title/Prompt: Title of this ~TiddlyWiki
|
||||
Basics/Username/Prompt: Username for signing edits
|
||||
Basics/Version/Prompt: ~TiddlyWiki version
|
||||
Cascades/Caption: Cascades
|
||||
Cascades/Hint: These global rules are used to dynamically choose certain templates. The result of the cascade is the result of the first filter in the sequence that returns a result
|
||||
Cascades/TagPrompt: Filters tagged <$macrocall $name="tag" tag=<<currentTiddler>>/>
|
||||
EditorTypes/Caption: Editor Types
|
||||
EditorTypes/Editor/Caption: Editor
|
||||
EditorTypes/Hint: These tiddlers determine which editor is used to edit specific tiddler types.
|
||||
EditorTypes/Type/Caption: Type
|
||||
EditTemplateBody/Caption: Edit Template Body
|
||||
EditTemplateBody/Hint: This rule cascade is used by the default edit template to dynamically choose the template for editing the body of a tiddler.
|
||||
Info/Caption: Info
|
||||
Info/Hint: Information about this TiddlyWiki
|
||||
KeyboardShortcuts/Add/Prompt: Type shortcut here
|
||||
@@ -191,6 +196,8 @@ Settings/TitleLinks/Yes/Description: Display tiddler titles as links
|
||||
Settings/MissingLinks/Caption: Wiki Links
|
||||
Settings/MissingLinks/Hint: Choose whether to link to tiddlers that do not exist yet
|
||||
Settings/MissingLinks/Description: Enable links to missing tiddlers
|
||||
StoryTiddler/Caption: Story Tiddler
|
||||
StoryTiddler/Hint: This rule cascade is used to dynamically choose the template for displaying a tiddler in the story river.
|
||||
StoryView/Caption: Story View
|
||||
StoryView/Prompt: Current view:
|
||||
Stylesheets/Caption: Stylesheets
|
||||
@@ -201,6 +208,10 @@ Theme/Caption: Theme
|
||||
Theme/Prompt: Current theme:
|
||||
TiddlerFields/Caption: Tiddler Fields
|
||||
TiddlerFields/Hint: This is the full set of TiddlerFields in use in this wiki (including system tiddlers but excluding shadow tiddlers).
|
||||
TiddlerColour/Caption: Tiddler Colour
|
||||
TiddlerColour/Hint: This rules cascade is used to dynamically choose the colour for a tiddler (used for the icon and the associated tag pill).
|
||||
TiddlerIcon/Caption: Tiddler Icon
|
||||
TiddlerIcon/Hint: This rules cascade is used to dynamically choose the icon for a tiddler.
|
||||
Toolbars/Caption: Toolbars
|
||||
Toolbars/EditToolbar/Caption: Edit Toolbar
|
||||
Toolbars/EditToolbar/Hint: Choose which buttons are displayed for tiddlers in edit mode. Drag and drop to change the ordering
|
||||
@@ -212,3 +223,7 @@ Toolbars/EditorToolbar/Hint: Choose which buttons are displayed in the editor to
|
||||
Toolbars/ViewToolbar/Caption: View Toolbar
|
||||
Toolbars/ViewToolbar/Hint: Choose which buttons are displayed for tiddlers in view mode. Drag and drop to change the ordering
|
||||
Tools/Download/Full/Caption: Download full wiki
|
||||
ViewTemplateBody/Caption: View Template Body
|
||||
ViewTemplateBody/Hint: This rule cascade is used by the default view template to dynamically choose the template for displaying the body of a tiddler.
|
||||
ViewTemplateTitle/Caption: View Template Title
|
||||
ViewTemplateTitle/Hint: This rule cascade is used by the default view template to dynamically choose the template for displaying the title of a tiddler.
|
||||
@@ -3,6 +3,7 @@ title: $:/language/Docs/Fields/
|
||||
_canonical_uri: The full URI of an external image tiddler
|
||||
bag: The name of the bag from which a tiddler came
|
||||
caption: The text to be displayed on a tab or button
|
||||
code-body: The view template will display the tiddler as code if set to ''yes''
|
||||
color: The CSS color value associated with a tiddler
|
||||
component: The name of the component responsible for an [[alert tiddler|AlertMechanism]]
|
||||
current-tiddler: Used to cache the top tiddler in a [[history list|HistoryMechanism]]
|
||||
@@ -13,9 +14,9 @@ description: The descriptive text for a plugin, or a modal dialogue
|
||||
draft.of: For draft tiddlers, contains the title of the tiddler of which this is a draft
|
||||
draft.title: For draft tiddlers, contains the proposed new title of the tiddler
|
||||
footer: The footer text for a wizard
|
||||
hide-body: The view template will hide bodies of tiddlers if set to: ''yes''
|
||||
hide-body: The view template will hide bodies of tiddlers if set to ''yes''
|
||||
icon: The title of the tiddler containing the icon associated with a tiddler
|
||||
library: Indicates that a tiddler should be saved as a JavaScript library if set to: ''yes''
|
||||
library: Indicates that a tiddler should be saved as a JavaScript library if set to ''yes''
|
||||
list: An ordered list of tiddler titles associated with a tiddler
|
||||
list-before: If set, the title of a tiddler before which this tiddler should be added to the ordered list of tiddler titles, or at the start of the list if this field is present but empty
|
||||
list-after: If set, the title of the tiddler after which this tiddler should be added to the ordered list of tiddler titles, or at the end of the list if this field is present but empty
|
||||
@@ -32,7 +33,7 @@ tags: A list of tags associated with a tiddler
|
||||
text: The body text of a tiddler
|
||||
throttle.refresh: If present, throttles refreshes of this tiddler
|
||||
title: The unique name of a tiddler
|
||||
toc-link: Suppresses the tiddler's link in a Table of Contents tree if set to: ''no''
|
||||
toc-link: Suppresses the tiddler's link in a Table of Contents tree if set to ''no''
|
||||
type: The content type of a tiddler
|
||||
version: Version information for a plugin
|
||||
_is_skinny: If present, indicates that the tiddler text field must be loaded from the server
|
||||
|
||||
@@ -22,7 +22,6 @@ All parameters are optional with safe defaults, and can be specified in any orde
|
||||
* ''readers'' - comma-separated list of principals allowed to read from this wiki
|
||||
* ''writers'' - comma-separated list of principals allowed to write to this wiki
|
||||
* ''csrf-disable'' - set to "yes" to disable CSRF checks (defaults to "no")
|
||||
* ''sse-enabled'' - set to "yes" to enable Server-sent events (defaults to "no")
|
||||
* ''root-tiddler'' - the tiddler to serve at the root (defaults to "$:/core/save/all")
|
||||
* ''root-render-type'' - the content type to which the root tiddler should be rendered (defaults to "text/plain")
|
||||
* ''root-serve-type'' - the content type with which the root tiddler should be served (defaults to "text/html")
|
||||
|
||||
@@ -3,6 +3,7 @@ title: $:/language/Import/
|
||||
Editor/Import/Heading: Import images and insert them into the editor.
|
||||
Imported/Hint: The following tiddlers were imported:
|
||||
Listing/Cancel/Caption: Cancel
|
||||
Listing/Cancel/Warning: Do you wish to cancel the import?
|
||||
Listing/Hint: These tiddlers are ready to import:
|
||||
Listing/Import/Caption: Import
|
||||
Listing/Select/Caption: Select
|
||||
@@ -29,5 +30,5 @@ Upgrader/System/Warning: Core module tiddler.
|
||||
Upgrader/System/Alert: You are about to import a tiddler that will overwrite a core module tiddler. This is not recommended as it may make the system unstable.
|
||||
Upgrader/ThemeTweaks/Created: Migrated theme tweak from <$text text=<<from>>/>.
|
||||
Upgrader/Tiddler/Disabled: Disabled tiddler.
|
||||
Upgrader/Tiddler/Selected: User selected.
|
||||
Upgrader/Tiddler/Selected: Selected tiddler.
|
||||
Upgrader/Tiddler/Unselected: Unselected tiddler.
|
||||
|
||||
@@ -14,7 +14,7 @@ ConfirmAction: Do you wish to proceed?
|
||||
Count: count
|
||||
DefaultNewTiddlerTitle: New Tiddler
|
||||
Diffs/CountMessage: <<diff-count>> differences
|
||||
DropMessage: Drop here (or use the 'Escape' key to cancel)
|
||||
DropMessage: Drop now (or use the 'Escape' key to cancel)
|
||||
Encryption/Cancel: Cancel
|
||||
Encryption/ConfirmClearPassword: Do you wish to clear the password? This will remove the encryption applied when saving this wiki
|
||||
Encryption/PromptSetPassword: Set a new password for this TiddlyWiki
|
||||
@@ -41,7 +41,6 @@ Error/WhileSaving: Error while saving
|
||||
Error/XMLHttpRequest: XMLHttpRequest error code
|
||||
InternalJavaScriptError/Title: Internal JavaScript Error
|
||||
InternalJavaScriptError/Hint: Well, this is embarrassing. It is recommended that you restart TiddlyWiki by refreshing your browser
|
||||
InvalidFieldName: Illegal characters in field name "<$text text=<<fieldName>>/>". Fields can only contain lowercase letters, digits and the characters underscore (`_`), hyphen (`-`) and period (`.`)
|
||||
LayoutSwitcher/Description: Open the layout switcher
|
||||
LazyLoadingWarning: <p>Trying to load external content from ''<$text text={{!!_canonical_uri}}/>''</p><p>If this message doesn't disappear, either the tiddler content type doesn't match the type of the external content, or you may be using a browser that doesn't support external content for wikis loaded as standalone files. See https://tiddlywiki.com/#ExternalText</p>
|
||||
LoginToTiddlySpace: Login to TiddlySpace
|
||||
|
||||
@@ -8,58 +8,59 @@ Render individual tiddlers and save the results to the specified files
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
exports.info = {
|
||||
name: "render",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing tiddler filter";
|
||||
}
|
||||
var self = this,
|
||||
fs = require("fs"),
|
||||
path = require("path"),
|
||||
wiki = this.commander.wiki,
|
||||
tiddlerFilter = this.params[0],
|
||||
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
|
||||
type = this.params[2] || "text/html",
|
||||
template = this.params[3],
|
||||
variableList = this.params.slice(4),
|
||||
tiddlers = wiki.filterTiddlers(tiddlerFilter),
|
||||
variables = Object.create(null);
|
||||
while(variableList.length >= 2) {
|
||||
variables[variableList[0]] = variableList[1];
|
||||
variableList = variableList.slice(2);
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
exports.info = {
|
||||
name: "render",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing tiddler filter";
|
||||
}
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
var parser = wiki.parseTiddler(template || title);
|
||||
var widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title})}),
|
||||
container = $tw.fakeDocument.createElement("div");
|
||||
widgetNode.render(container,null);
|
||||
var text = type === "text/html" ? container.innerHTML : container.textContent,
|
||||
filepath = path.resolve(self.commander.outputPath,wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]))[0]);
|
||||
if(self.commander.verbose) {
|
||||
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
|
||||
}
|
||||
$tw.utils.createFileDirectories(filepath);
|
||||
fs.writeFileSync(filepath,text,"utf8");
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
var self = this,
|
||||
fs = require("fs"),
|
||||
path = require("path"),
|
||||
wiki = this.commander.wiki,
|
||||
tiddlerFilter = this.params[0],
|
||||
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
|
||||
type = this.params[2] || "text/html",
|
||||
template = this.params[3],
|
||||
variableList = this.params.slice(4),
|
||||
tiddlers = wiki.filterTiddlers(tiddlerFilter),
|
||||
variables = Object.create(null);
|
||||
while(variableList.length >= 2) {
|
||||
variables[variableList[0]] = variableList[1];
|
||||
variableList = variableList.slice(2);
|
||||
}
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
var filepath = path.resolve(self.commander.outputPath,wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]))[0]);
|
||||
if(self.commander.verbose) {
|
||||
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
|
||||
}
|
||||
var parser = wiki.parseTiddler(template || title),
|
||||
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title})}),
|
||||
container = $tw.fakeDocument.createElement("div");
|
||||
widgetNode.render(container,null);
|
||||
var text = type === "text/html" ? container.innerHTML : container.textContent;
|
||||
$tw.utils.createFileDirectories(filepath);
|
||||
fs.writeFileSync(filepath,text,"utf8");
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
|
||||
@@ -12,63 +12,8 @@ Functions to deserialise tiddlers from a block of text
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Utility function to parse an old-style tiddler DIV in a *.tid file. It looks like this:
|
||||
|
||||
<div title="Title" creator="JoeBloggs" modifier="JoeBloggs" created="201102111106" modified="201102111310" tags="myTag [[my long tag]]">
|
||||
<pre>The text of the tiddler (without the expected HTML encoding).
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
Note that the field attributes are HTML encoded, but that the body of the <PRE> tag is not encoded.
|
||||
|
||||
When these tiddler DIVs are encountered within a TiddlyWiki HTML file then the body is encoded in the usual way.
|
||||
*/
|
||||
var parseTiddlerDiv = function(text /* [,fields] */) {
|
||||
// Slot together the default results
|
||||
var result = {};
|
||||
if(arguments.length > 1) {
|
||||
for(var f=1; f<arguments.length; f++) {
|
||||
var fields = arguments[f];
|
||||
for(var t in fields) {
|
||||
result[t] = fields[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Parse the DIV body
|
||||
var startRegExp = /^\s*<div\s+([^>]*)>(\s*<pre>)?/gi,
|
||||
endRegExp,
|
||||
match = startRegExp.exec(text);
|
||||
if(match) {
|
||||
// Old-style DIVs don't have the <pre> tag
|
||||
if(match[2]) {
|
||||
endRegExp = /<\/pre>\s*<\/div>\s*$/gi;
|
||||
} else {
|
||||
endRegExp = /<\/div>\s*$/gi;
|
||||
}
|
||||
var endMatch = endRegExp.exec(text);
|
||||
if(endMatch) {
|
||||
// Extract the text
|
||||
result.text = text.substring(match.index + match[0].length,endMatch.index);
|
||||
// Process the attributes
|
||||
var attrRegExp = /\s*([^=\s]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/gi,
|
||||
attrMatch;
|
||||
do {
|
||||
attrMatch = attrRegExp.exec(match[1]);
|
||||
if(attrMatch) {
|
||||
var name = attrMatch[1];
|
||||
var value = attrMatch[2] !== undefined ? attrMatch[2] : attrMatch[3];
|
||||
result[name] = value;
|
||||
}
|
||||
} while(attrMatch);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
exports["application/x-tiddler-html-div"] = function(text,fields) {
|
||||
return [parseTiddlerDiv(text,fields)];
|
||||
return [deserializeTiddlerDiv(text,fields)];
|
||||
};
|
||||
|
||||
exports["application/json"] = function(text,fields) {
|
||||
@@ -105,30 +50,34 @@ Parse an HTML file into tiddlers. There are three possibilities:
|
||||
# An ordinary HTML file
|
||||
*/
|
||||
exports["text/html"] = function(text,fields) {
|
||||
// Check if we've got a store area
|
||||
var results = [];
|
||||
// Check if we've got an old-style store area
|
||||
var storeAreaMarkerRegExp = /<div id=["']?storeArea['"]?( style=["']?display:none;["']?)?>/gi,
|
||||
match = storeAreaMarkerRegExp.exec(text);
|
||||
if(match) {
|
||||
// If so, it's either a classic TiddlyWiki file or an unencrypted TW5 file
|
||||
// First read the normal tiddlers
|
||||
var results = deserializeTiddlyWikiFile(text,storeAreaMarkerRegExp.lastIndex,!!match[1],fields);
|
||||
// Then any system tiddlers
|
||||
var systemAreaMarkerRegExp = /<div id=["']?systemArea['"]?( style=["']?display:none;["']?)?>/gi,
|
||||
sysMatch = systemAreaMarkerRegExp.exec(text);
|
||||
if(sysMatch) {
|
||||
results.push.apply(results,deserializeTiddlyWikiFile(text,systemAreaMarkerRegExp.lastIndex,!!sysMatch[1],fields));
|
||||
}
|
||||
storeAreaMatch = storeAreaMarkerRegExp.exec(text);
|
||||
if(storeAreaMatch) {
|
||||
// If so, we've got tiddlers in classic TiddlyWiki format or unencrypted old-style TW5 format
|
||||
results.push.apply(results,deserializeStoreArea(text,storeAreaMarkerRegExp.lastIndex,!!storeAreaMatch[1],fields));
|
||||
}
|
||||
// Check for new-style store areas
|
||||
var newStoreAreaMarkerRegExp = /<script class="tiddlywiki-tiddler-store" type="([^"]*)">/gi,
|
||||
newStoreAreaMatch = newStoreAreaMarkerRegExp.exec(text),
|
||||
haveHadNewStoreArea = !!newStoreAreaMatch;
|
||||
while(newStoreAreaMatch) {
|
||||
results.push.apply(results,deserializeNewStoreArea(text,newStoreAreaMarkerRegExp.lastIndex,newStoreAreaMatch[1],fields));
|
||||
newStoreAreaMatch = newStoreAreaMarkerRegExp.exec(text);
|
||||
}
|
||||
// Return if we had either an old-style or a new-style store area
|
||||
if(storeAreaMatch || haveHadNewStoreArea) {
|
||||
return results;
|
||||
}
|
||||
// Otherwise, check whether we've got an encrypted file
|
||||
var encryptedStoreArea = $tw.utils.extractEncryptedStoreArea(text);
|
||||
if(encryptedStoreArea) {
|
||||
// If so, attempt to decrypt it using the current password
|
||||
return $tw.utils.decryptStoreArea(encryptedStoreArea);
|
||||
} else {
|
||||
// Check whether we've got an encrypted file
|
||||
var encryptedStoreArea = $tw.utils.extractEncryptedStoreArea(text);
|
||||
if(encryptedStoreArea) {
|
||||
// If so, attempt to decrypt it using the current password
|
||||
return $tw.utils.decryptStoreArea(encryptedStoreArea);
|
||||
} else {
|
||||
// It's not a TiddlyWiki so we'll return the entire HTML file as a tiddler
|
||||
return deserializeHtmlFile(text,fields);
|
||||
}
|
||||
// It's not a TiddlyWiki so we'll return the entire HTML file as a tiddler
|
||||
return deserializeHtmlFile(text,fields);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -142,7 +91,19 @@ function deserializeHtmlFile(text,fields) {
|
||||
return [result];
|
||||
}
|
||||
|
||||
function deserializeTiddlyWikiFile(text,storeAreaEnd,isTiddlyWiki5,fields) {
|
||||
function deserializeNewStoreArea(text,storeAreaEnd,type,fields) {
|
||||
var endOfScriptRegExp = /<\/script>/gi;
|
||||
endOfScriptRegExp.lastIndex = storeAreaEnd;
|
||||
var match = endOfScriptRegExp.exec(text);
|
||||
if(match) {
|
||||
var scriptContent = text.substring(storeAreaEnd,match.index);
|
||||
return $tw.wiki.deserializeTiddlers(type,scriptContent);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function deserializeStoreArea(text,storeAreaEnd,isTiddlyWiki5,fields) {
|
||||
var results = [],
|
||||
endOfDivRegExp = /(<\/div>\s*)/gi,
|
||||
startPos = storeAreaEnd,
|
||||
@@ -151,7 +112,7 @@ function deserializeTiddlyWikiFile(text,storeAreaEnd,isTiddlyWiki5,fields) {
|
||||
var match = endOfDivRegExp.exec(text);
|
||||
while(match) {
|
||||
var endPos = endOfDivRegExp.lastIndex,
|
||||
tiddlerFields = parseTiddlerDiv(text.substring(startPos,endPos),fields,{type: defaultType});
|
||||
tiddlerFields = deserializeTiddlerDiv(text.substring(startPos,endPos),fields,{type: defaultType});
|
||||
if(!tiddlerFields) {
|
||||
break;
|
||||
}
|
||||
@@ -169,4 +130,59 @@ function deserializeTiddlyWikiFile(text,storeAreaEnd,isTiddlyWiki5,fields) {
|
||||
return results;
|
||||
}
|
||||
|
||||
/*
|
||||
Utility function to parse an old-style tiddler DIV in a *.tid file. It looks like this:
|
||||
|
||||
<div title="Title" creator="JoeBloggs" modifier="JoeBloggs" created="201102111106" modified="201102111310" tags="myTag [[my long tag]]">
|
||||
<pre>The text of the tiddler (without the expected HTML encoding).
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
Note that the field attributes are HTML encoded, but that the body of the <PRE> tag is not encoded.
|
||||
|
||||
When these tiddler DIVs are encountered within a TiddlyWiki HTML file then the body is encoded in the usual way.
|
||||
*/
|
||||
var deserializeTiddlerDiv = function(text /* [,fields] */) {
|
||||
// Slot together the default results
|
||||
var result = {};
|
||||
if(arguments.length > 1) {
|
||||
for(var f=1; f<arguments.length; f++) {
|
||||
var fields = arguments[f];
|
||||
for(var t in fields) {
|
||||
result[t] = fields[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Parse the DIV body
|
||||
var startRegExp = /^\s*<div\s+([^>]*)>(\s*<pre>)?/gi,
|
||||
endRegExp,
|
||||
match = startRegExp.exec(text);
|
||||
if(match) {
|
||||
// Old-style DIVs don't have the <pre> tag
|
||||
if(match[2]) {
|
||||
endRegExp = /<\/pre>\s*<\/div>\s*$/gi;
|
||||
} else {
|
||||
endRegExp = /<\/div>\s*$/gi;
|
||||
}
|
||||
var endMatch = endRegExp.exec(text);
|
||||
if(endMatch) {
|
||||
// Extract the text
|
||||
result.text = text.substring(match.index + match[0].length,endMatch.index);
|
||||
// Process the attributes
|
||||
var attrRegExp = /\s*([^=\s]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/gi,
|
||||
attrMatch;
|
||||
do {
|
||||
attrMatch = attrRegExp.exec(match[1]);
|
||||
if(attrMatch) {
|
||||
var name = attrMatch[1];
|
||||
var value = attrMatch[2] !== undefined ? attrMatch[2] : attrMatch[3];
|
||||
result[name] = value;
|
||||
}
|
||||
} while(attrMatch);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -135,7 +135,11 @@ FramedEngine.prototype.setText = function(text,type) {
|
||||
Update the DomNode with the new text
|
||||
*/
|
||||
FramedEngine.prototype.updateDomNodeText = function(text) {
|
||||
this.domNode.value = text;
|
||||
try {
|
||||
this.domNode.value = text;
|
||||
} catch(e) {
|
||||
// Ignore
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -201,7 +205,7 @@ FramedEngine.prototype.handleInputEvent = function(event) {
|
||||
this.widget.saveChanges(this.getText());
|
||||
this.fixHeight();
|
||||
if(this.widget.editInputActions) {
|
||||
this.widget.invokeActionString(this.widget.editInputActions);
|
||||
this.widget.invokeActionString(this.widget.editInputActions,this,event,{actionValue: this.getText()});
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -85,7 +85,11 @@ SimpleEngine.prototype.setText = function(text,type) {
|
||||
Update the DomNode with the new text
|
||||
*/
|
||||
SimpleEngine.prototype.updateDomNodeText = function(text) {
|
||||
this.domNode.value = text;
|
||||
try {
|
||||
this.domNode.value = text;
|
||||
} catch(e) {
|
||||
// Ignore
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -129,7 +133,7 @@ SimpleEngine.prototype.handleInputEvent = function(event) {
|
||||
this.widget.saveChanges(this.getText());
|
||||
this.fixHeight();
|
||||
if(this.widget.editInputActions) {
|
||||
this.widget.invokeActionString(this.widget.editInputActions);
|
||||
this.widget.invokeActionString(this.widget.editInputActions,this,event,{actionValue: this.getText()});
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -324,7 +324,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
If there are no Files, let the browser handle it.
|
||||
*/
|
||||
EditTextWidget.prototype.handleDropEvent = function(event) {
|
||||
if(event.dataTransfer.files.length) {
|
||||
if($tw.utils.dragEventContainsFiles(event)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.dispatchDOMEvent(this.cloneEvent(event,["dataTransfer"]));
|
||||
@@ -332,7 +332,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
};
|
||||
|
||||
EditTextWidget.prototype.handlePasteEvent = function(event) {
|
||||
if(event.clipboardData.files.length) {
|
||||
if(event.clipboardData && event.clipboardData.files && event.clipboardData.files.length) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.dispatchDOMEvent(this.cloneEvent(event,["clipboardData"]));
|
||||
|
||||
17
core/modules/editor/operations/text/focus-editor.js
Normal file
17
core/modules/editor/operations/text/focus-editor.js
Normal file
@@ -0,0 +1,17 @@
|
||||
/*\
|
||||
title: $:/core/modules/editor/operations/text/focus-editor.js
|
||||
type: application/javascript
|
||||
module-type: texteditoroperation
|
||||
Simply focus the Text editor
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports["focus-editor"] = function(event,operation) {
|
||||
operation = null;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -13,15 +13,17 @@ Text editor operation to wrap the selected lines with a prefix and suffix
|
||||
"use strict";
|
||||
|
||||
exports["wrap-lines"] = function(event,operation) {
|
||||
var prefix = event.paramObject.prefix || "",
|
||||
suffix = event.paramObject.suffix || "";
|
||||
// Cut just past the preceding line break, or the start of the text
|
||||
operation.cutStart = $tw.utils.findPrecedingLineBreak(operation.text,operation.selStart);
|
||||
// Cut to just past the following line break, or to the end of the text
|
||||
operation.cutEnd = $tw.utils.findFollowingLineBreak(operation.text,operation.selEnd);
|
||||
// Add the prefix and suffix
|
||||
operation.replacement = event.paramObject.prefix + "\n" +
|
||||
operation.replacement = prefix + "\n" +
|
||||
operation.text.substring(operation.cutStart,operation.cutEnd) + "\n" +
|
||||
event.paramObject.suffix + "\n";
|
||||
operation.newSelStart = operation.cutStart + event.paramObject.prefix.length + 1;
|
||||
suffix + "\n";
|
||||
operation.newSelStart = operation.cutStart + prefix.length + 1;
|
||||
operation.newSelEnd = operation.newSelStart + (operation.cutEnd - operation.cutStart);
|
||||
};
|
||||
|
||||
|
||||
53
core/modules/filterrunprefixes/cascade.js
Normal file
53
core/modules/filterrunprefixes/cascade.js
Normal file
@@ -0,0 +1,53 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/cascade.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.cascade = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length !== 0) {
|
||||
var filterList = operationSubFunction(source,widget),
|
||||
filterFnList = [];
|
||||
var inputResults = results.toArray();
|
||||
results.clear();
|
||||
$tw.utils.each(inputResults,function(title) {
|
||||
var result = ""; // If no filter matches, we return an empty string
|
||||
$tw.utils.each(filterList,function(filter,index) {
|
||||
if(!filterFnList[index]) {
|
||||
filterFnList[index] = options.wiki.compileFilter(filter);
|
||||
}
|
||||
var output = filterFnList[index](options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler")
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
if(output.length !== 0) {
|
||||
result = output[0];
|
||||
return false;
|
||||
}
|
||||
});
|
||||
results.push(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -16,23 +16,30 @@ Export our filter function
|
||||
exports.filter = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
var resultsToRemove = [];
|
||||
var resultsToRemove = [],
|
||||
index = 0;
|
||||
results.each(function(title) {
|
||||
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name) {
|
||||
switch(name) {
|
||||
case "currentTiddler":
|
||||
return "" + title;
|
||||
case "..currentTiddler":
|
||||
return widget.getVariable("currentTiddler");
|
||||
default:
|
||||
return widget.getVariable(name);
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler"),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (results.length - 1 - index),
|
||||
"length": "" + results.length
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
if(filtered.length === 0) {
|
||||
resultsToRemove.push(title);
|
||||
}
|
||||
++index;
|
||||
});
|
||||
results.remove(resultsToRemove);
|
||||
}
|
||||
|
||||
46
core/modules/filterrunprefixes/map.js
Normal file
46
core/modules/filterrunprefixes/map.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/map.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.map = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
var inputTitles = results.toArray(),
|
||||
index = 0;
|
||||
results.clear();
|
||||
$tw.utils.each(inputTitles,function(title) {
|
||||
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler"),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (inputTitles.length - 1 - index),
|
||||
"length": "" + inputTitles.length
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
results.push(filtered[0] || "");
|
||||
++index;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -15,26 +15,24 @@ Export our filter prefix function
|
||||
exports.reduce = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
var accumulator = "";
|
||||
var index = 0;
|
||||
var accumulator = "",
|
||||
index = 0;
|
||||
results.each(function(title) {
|
||||
var list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name) {
|
||||
switch(name) {
|
||||
case "currentTiddler":
|
||||
return "" + title;
|
||||
case "..currentTiddler":
|
||||
return widget.getVariable("currentTiddler");
|
||||
case "accumulator":
|
||||
return "" + accumulator;
|
||||
case "index":
|
||||
return "" + index;
|
||||
case "revIndex":
|
||||
return "" + (results.length - 1 - index);
|
||||
case "length":
|
||||
return "" + results.length;
|
||||
default:
|
||||
return widget.getVariable(name);
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler"),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (results.length - 1 - index),
|
||||
"length": "" + results.length,
|
||||
"accumulator": "" + accumulator
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -26,14 +26,16 @@ exports.sort = function(operationSubFunction,options) {
|
||||
compareFn;
|
||||
results.each(function(title) {
|
||||
var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name) {
|
||||
switch(name) {
|
||||
case "currentTiddler":
|
||||
return "" + title;
|
||||
case "..currentTiddler":
|
||||
return widget.getVariable("currentTiddler");
|
||||
default:
|
||||
return widget.getVariable(name);
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler")
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -95,10 +95,12 @@ function parseFilterOperation(operators,filterString,p) {
|
||||
if(nextBracketPos === -1) {
|
||||
throw "Missing closing bracket in filter expression";
|
||||
}
|
||||
if(!operator.regexp) {
|
||||
if(operator.regexp) {
|
||||
operand.text = "";
|
||||
} else {
|
||||
operand.text = filterString.substring(p,nextBracketPos);
|
||||
operator.operands.push(operand);
|
||||
}
|
||||
operator.operands.push(operand);
|
||||
p = nextBracketPos + 1;
|
||||
}
|
||||
|
||||
@@ -253,7 +255,8 @@ exports.compileFilter = function(filterString) {
|
||||
if(operand.indirect) {
|
||||
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
||||
} else if(operand.variable) {
|
||||
operand.value = widget.getVariable(operand.text,{defaultValue: ""});
|
||||
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
||||
operand.value = widget.getVariable(varTree.name,{params:varTree.params,defaultValue: ""});
|
||||
} else {
|
||||
operand.value = operand.text;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ exports.all = function(source,operator,options) {
|
||||
results.pushTop(subop(source,operator.prefix,options));
|
||||
}
|
||||
}
|
||||
return results.toArray();
|
||||
return results.makeTiddlerIterator(options.wiki);
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -16,11 +16,11 @@ Filter operator for returning all the backlinks from a tiddler
|
||||
Export our filter function
|
||||
*/
|
||||
exports.backlinks = function(source,operator,options) {
|
||||
var results = [];
|
||||
var results = new $tw.utils.LinkedList();
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.pushTop(results,options.wiki.getTiddlerBacklinks(title));
|
||||
results.pushTop(options.wiki.getTiddlerBacklinks(title));
|
||||
});
|
||||
return results;
|
||||
return results.makeTiddlerIterator(options.wiki);
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -17,7 +17,7 @@ Export our filter function
|
||||
*/
|
||||
exports.contains = function(source,operator,options) {
|
||||
var results = [],
|
||||
fieldname = (operator.suffix || "list").toLowerCase();
|
||||
fieldname = operator.suffix || "list";
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler) {
|
||||
|
||||
27
core/modules/filters/crypto.js
Normal file
27
core/modules/filters/crypto.js
Normal file
@@ -0,0 +1,27 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/crypto.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operators for cryptography, using the Stanford JavaScript library
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.sha256 = function(source,operator,options) {
|
||||
var results = [],
|
||||
length = parseInt(operator.operand,10) || 20,
|
||||
sha256 = function(text) {
|
||||
return sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(text)).substr(0,length);
|
||||
};
|
||||
source(function(tiddler,title) {
|
||||
results.push(sha256(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -19,12 +19,7 @@ Export our filter functions
|
||||
exports.decodeuricomponent = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var value = title;
|
||||
try {
|
||||
value = decodeURIComponent(title);
|
||||
} catch(e) {
|
||||
}
|
||||
results.push(value);
|
||||
results.push($tw.utils.decodeURIComponentSafe(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
@@ -40,12 +35,7 @@ exports.encodeuricomponent = function(source,operator,options) {
|
||||
exports.decodeuri = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var value = title;
|
||||
try {
|
||||
value = decodeURI(title);
|
||||
} catch(e) {
|
||||
}
|
||||
results.push(value);
|
||||
results.push($tw.utils.decodeURISafe(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ Export our filter function
|
||||
*/
|
||||
exports.field = function(source,operator,options) {
|
||||
var results = [],indexedResults,
|
||||
fieldname = (operator.suffix || operator.operator || "title").toLowerCase();
|
||||
fieldname = operator.suffix || operator.operator || "title";
|
||||
if(operator.prefix === "!") {
|
||||
if(operator.regexp) {
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -20,7 +20,7 @@ exports.links = function(source,operator,options) {
|
||||
source(function(tiddler,title) {
|
||||
results.pushTop(options.wiki.getTiddlerLinks(title));
|
||||
});
|
||||
return results.toArray();
|
||||
return results.makeTiddlerIterator(options.wiki);
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -103,4 +103,16 @@ exports.nth = function(source,operator,options) {
|
||||
return results.slice(count - 1,count);
|
||||
};
|
||||
|
||||
/*
|
||||
The zero based nth member of the list
|
||||
*/
|
||||
exports.zth = function(source,operator,options) {
|
||||
var count = $tw.utils.getInt(operator.operand,0),
|
||||
results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results.slice(count,count + 1);
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -5,9 +5,11 @@ module-type: filteroperator
|
||||
|
||||
Filter operator that looks up values via a title prefix
|
||||
|
||||
[lookup:<field>[<prefix>]]
|
||||
[lookup:<defaultvalue>:<field OR index>[<prefix>],[<field-name OR index-name>]]
|
||||
|
||||
Prepends the prefix to the selected items and returns the specified field value
|
||||
Prepends the prefix to the selected items and returns the specified
|
||||
field or index value. If the 2nd suffix does not exist, it defaults to field.
|
||||
If the second operand is missing it defaults to "text" for fields, and "0" for indexes
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
@@ -20,10 +22,31 @@ Prepends the prefix to the selected items and returns the specified field value
|
||||
Export our filter function
|
||||
*/
|
||||
exports.lookup = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(options.wiki.getTiddlerText(operator.operand + title) || operator.suffix || '');
|
||||
});
|
||||
var results = [],
|
||||
suffixes = operator.suffixes || [],
|
||||
defaultSuffix = suffixes[0] ? (suffixes[0][0] || "") : "",
|
||||
indexSuffix = (suffixes[1] && suffixes[1][0] === "index") ? true : false,
|
||||
target;
|
||||
if(operator.operands.length == 2) {
|
||||
target = operator.operands[1]
|
||||
} else {
|
||||
target = indexSuffix ? "0": "text";
|
||||
}
|
||||
if(indexSuffix) {
|
||||
source(function(tiddler,title) {
|
||||
var data = options.wiki.extractTiddlerDataItem(operator.operands[0]+title,target,defaultSuffix);
|
||||
results.push(data);
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
var value = defaultSuffix;
|
||||
var targetTiddler = options.wiki.getTiddler(operator.operands[0]+title);
|
||||
if(targetTiddler && targetTiddler.getFieldString(target)) {
|
||||
value = targetTiddler.getFieldString(target);
|
||||
}
|
||||
results.push(value);
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -165,6 +165,35 @@ exports["standard-deviation"] = makeNumericReducingOperator(
|
||||
}
|
||||
);
|
||||
|
||||
//trigonometry
|
||||
exports.cos = makeNumericBinaryOperator(
|
||||
function(a) {return Math.cos(a)}
|
||||
);
|
||||
|
||||
exports.sin = makeNumericBinaryOperator(
|
||||
function(a) {return Math.sin(a)}
|
||||
);
|
||||
|
||||
exports.tan = makeNumericBinaryOperator(
|
||||
function(a) {return Math.tan(a)}
|
||||
);
|
||||
|
||||
exports.acos = makeNumericBinaryOperator(
|
||||
function(a) {return Math.acos(a)}
|
||||
);
|
||||
|
||||
exports.asin = makeNumericBinaryOperator(
|
||||
function(a) {return Math.asin(a)}
|
||||
);
|
||||
|
||||
exports.atan = makeNumericBinaryOperator(
|
||||
function(a) {return Math.atan(a)}
|
||||
);
|
||||
|
||||
exports.atan2 = makeNumericBinaryOperator(
|
||||
function(a,b) {return Math.atan2(a,b)}
|
||||
);
|
||||
|
||||
//Calculate the variance of a population of numbers in an array given its mean
|
||||
function getVarianceFromArray(values,mean) {
|
||||
var deviationTotal = values.reduce(function(accumulator,value) {
|
||||
|
||||
30
core/modules/filters/moduleproperty.js
Normal file
30
core/modules/filters/moduleproperty.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/moduleproperty.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter [[module-name]moduleproperty[name]] retrieve a module property
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.moduleproperty = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var value = require(title)[operator.operand || ""];
|
||||
if(value !== undefined) {
|
||||
results.push(value);
|
||||
}
|
||||
});
|
||||
results.sort();
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -17,11 +17,23 @@ Export our filter function
|
||||
*/
|
||||
exports.modules = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
|
||||
results.push(moduleName);
|
||||
if(operator.operands.length >= 2) {
|
||||
// Return the modules that have the module property specified in the first operand with the value in the second operand
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
|
||||
if(require(moduleName)[operator.operands[0]] === operator.operands[1]) {
|
||||
results.push(moduleName);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Return all the module names without filtering
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
|
||||
results.push(moduleName);
|
||||
});
|
||||
});
|
||||
}
|
||||
results.sort();
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -17,9 +17,13 @@ Export our filter function
|
||||
*/
|
||||
exports.range = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Split the operand into numbers delimited by these symbols
|
||||
var parts = operator.operand.split(/[,:;]/g),
|
||||
beg, end, inc, i, fixed = 0;
|
||||
// For backwards compatibility, if there is only one operand, try to split it using one of the delimiters
|
||||
var parts = operator.operands || [];
|
||||
if(parts.length === 1) {
|
||||
parts = operator.operand.split(/[,:;]/g);
|
||||
}
|
||||
// Process the parts
|
||||
var beg, end, inc, i, fixed = 0;
|
||||
for (i=0; i<parts.length; i++) {
|
||||
// Validate real number
|
||||
if(!/^\s*[+-]?((\d+(\.\d*)?)|(\.\d+))\s*$/.test(parts[i])) {
|
||||
|
||||
@@ -17,7 +17,7 @@ Export our filter function
|
||||
*/
|
||||
exports.regexp = function(source,operator,options) {
|
||||
var results = [],
|
||||
fieldname = (operator.suffix || "title").toLowerCase(),
|
||||
fieldname = operator.suffix || "title",
|
||||
regexpString, regexp, flags = "", match,
|
||||
getFieldString = function(tiddler,title) {
|
||||
if(tiddler) {
|
||||
|
||||
@@ -40,6 +40,7 @@ exports.search = function(source,operator,options) {
|
||||
invert: invert,
|
||||
field: fields,
|
||||
excludeField: excludeFields,
|
||||
some: hasFlag("some"),
|
||||
caseSensitive: hasFlag("casesensitive"),
|
||||
literal: hasFlag("literal"),
|
||||
whitespace: hasFlag("whitespace"),
|
||||
|
||||
@@ -119,23 +119,25 @@ exports["search-replace"] = function(source,operator,options) {
|
||||
var results = [],
|
||||
suffixes = operator.suffixes || [],
|
||||
flagSuffix = (suffixes[0] ? (suffixes[0][0] || "") : ""),
|
||||
flags = (flagSuffix.indexOf("g") !== -1 ? "g" : "") + (flagSuffix.indexOf("i") !== -1 ? "i" : ""),
|
||||
flags = (flagSuffix.indexOf("g") !== -1 ? "g" : "") + (flagSuffix.indexOf("i") !== -1 ? "i" : "") + (flagSuffix.indexOf("m") !== -1 ? "m" : ""),
|
||||
isRegExp = (suffixes[1] && suffixes[1][0] === "regexp") ? true : false,
|
||||
searchTerm,
|
||||
//Escape regexp characters if the operand is not a regular expression
|
||||
searchTerm = isRegExp ? operator.operand : $tw.utils.escapeRegExp(operator.operand),
|
||||
//Escape $ character in replacement string if not in regular expression mode
|
||||
replacement = isRegExp ? operator.operands[1] : (operator.operands[1]||"").replace(/\$/g,"$$$$"),
|
||||
regExp;
|
||||
try {
|
||||
regExp = new RegExp(searchTerm,flags);
|
||||
} catch(ex) {
|
||||
return ["RegExp error: " + ex];
|
||||
}
|
||||
|
||||
source(function(tiddler,title) {
|
||||
if(title && (operator.operands.length > 1)) {
|
||||
//Escape regexp characters if the operand is not a regular expression
|
||||
searchTerm = isRegExp ? operator.operand : $tw.utils.escapeRegExp(operator.operand);
|
||||
try {
|
||||
regExp = new RegExp(searchTerm,flags);
|
||||
} catch(ex) {
|
||||
return ["RegExp error: " + ex];
|
||||
}
|
||||
results.push(
|
||||
title.replace(regExp,operator.operands[1])
|
||||
title.replace(regExp,replacement)
|
||||
);
|
||||
regExp.lastIndex = 0;
|
||||
} else {
|
||||
results.push(title);
|
||||
}
|
||||
@@ -172,4 +174,14 @@ exports.pad = function(source,operator,options) {
|
||||
return results;
|
||||
}
|
||||
|
||||
exports.charcode = function(source,operator,options) {
|
||||
var chars = [];
|
||||
$tw.utils.each(operator.operands,function(operand) {
|
||||
if(operand !== "") {
|
||||
chars.push(String.fromCharCode($tw.utils.parseInt(operand)));
|
||||
}
|
||||
});
|
||||
return [chars.join("")];
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -16,20 +16,13 @@ Filter operator returning all the selected tiddlers that are untagged
|
||||
Export our filter function
|
||||
*/
|
||||
exports.untagged = function(source,operator,options) {
|
||||
var results = [];
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && $tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length > 0) {
|
||||
$tw.utils.pushTop(results,title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(!tiddler || !tiddler.hasField("tags") || ($tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length === 0)) {
|
||||
$tw.utils.pushTop(results,title);
|
||||
}
|
||||
});
|
||||
}
|
||||
var results = [],
|
||||
expected = (operator.prefix === "!");
|
||||
source(function(tiddler,title) {
|
||||
if((tiddler && $tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length > 0) === expected) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ Key descriptors have the following format:
|
||||
ctrl+enter
|
||||
ctrl+shift+alt+A
|
||||
*/
|
||||
KeyboardManager.prototype.parseKeyDescriptor = function(keyDescriptor) {
|
||||
KeyboardManager.prototype.parseKeyDescriptor = function(keyDescriptor,options) {
|
||||
var components = keyDescriptor.split(/\+|\-/),
|
||||
info = {
|
||||
keyCode: 0,
|
||||
@@ -206,6 +206,9 @@ KeyboardManager.prototype.parseKeyDescriptor = function(keyDescriptor) {
|
||||
info.keyCode = this.namedKeys[s];
|
||||
}
|
||||
}
|
||||
if(options.keyDescriptor) {
|
||||
info.keyDescriptor = options.keyDescriptor;
|
||||
}
|
||||
if(info.keyCode) {
|
||||
return info;
|
||||
} else {
|
||||
@@ -237,6 +240,7 @@ KeyboardManager.prototype.parseKeyDescriptors = function(keyDescriptors,options)
|
||||
lookupName = function(configName) {
|
||||
var keyDescriptors = wiki.getTiddlerText("$:/config/" + configName + "/" + name);
|
||||
if(keyDescriptors) {
|
||||
options.keyDescriptor = keyDescriptor;
|
||||
result.push.apply(result,self.parseKeyDescriptors(keyDescriptors,options));
|
||||
}
|
||||
};
|
||||
@@ -245,7 +249,7 @@ KeyboardManager.prototype.parseKeyDescriptors = function(keyDescriptors,options)
|
||||
});
|
||||
}
|
||||
} else {
|
||||
result.push(self.parseKeyDescriptor(keyDescriptor));
|
||||
result.push(self.parseKeyDescriptor(keyDescriptor,options));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
@@ -276,12 +280,16 @@ KeyboardManager.prototype.checkKeyDescriptor = function(event,keyInfo) {
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.checkKeyDescriptors = function(event,keyInfoArray) {
|
||||
return (this.getMatchingKeyDescriptor(event,keyInfoArray) !== null);
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.getMatchingKeyDescriptor = function(event,keyInfoArray) {
|
||||
for(var t=0; t<keyInfoArray.length; t++) {
|
||||
if(this.checkKeyDescriptor(event,keyInfoArray[t])) {
|
||||
return true;
|
||||
return keyInfoArray[t];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.getEventModifierKeyDescriptor = function(event) {
|
||||
@@ -324,7 +332,7 @@ KeyboardManager.prototype.handleKeydownEvent = function(event) {
|
||||
if(key !== undefined) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
$tw.rootWidget.invokeActionString(action,$tw.rootWidget);
|
||||
$tw.rootWidget.invokeActionString(action,$tw.rootWidget,event);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -123,6 +123,19 @@ exports.parseStringLiteral = function(source,pos) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.parseMacroParameters = function(node,source,pos) {
|
||||
// Process parameters
|
||||
var parameter = $tw.utils.parseMacroParameter(source,pos);
|
||||
while(parameter) {
|
||||
node.params.push(parameter);
|
||||
pos = parameter.end;
|
||||
// Get the next parameter
|
||||
parameter = $tw.utils.parseMacroParameter(source,pos);
|
||||
}
|
||||
node.end = pos;
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
Look for a macro invocation parameter. Returns null if not found, or {type: "macro-parameter", name:, value:, start:, end:}
|
||||
*/
|
||||
@@ -187,14 +200,8 @@ exports.parseMacroInvocation = function(source,pos) {
|
||||
}
|
||||
node.name = name.match[1];
|
||||
pos = name.end;
|
||||
// Process parameters
|
||||
var parameter = $tw.utils.parseMacroParameter(source,pos);
|
||||
while(parameter) {
|
||||
node.params.push(parameter);
|
||||
pos = parameter.end;
|
||||
// Get the next parameter
|
||||
parameter = $tw.utils.parseMacroParameter(source,pos);
|
||||
}
|
||||
node = $tw.utils.parseMacroParameters(node,source,pos);
|
||||
pos = node.end;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a double greater than sign
|
||||
@@ -208,8 +215,31 @@ exports.parseMacroInvocation = function(source,pos) {
|
||||
return node;
|
||||
};
|
||||
|
||||
exports.parseFilterVariable = function(source) {
|
||||
var node = {
|
||||
name: "",
|
||||
params: [],
|
||||
},
|
||||
pos = 0,
|
||||
reName = /([^\s"']+)/g;
|
||||
// If there is no whitespace or it is an empty string then there are no macro parameters
|
||||
if(/^\S*$/.test(source)) {
|
||||
node.name = source;
|
||||
return node;
|
||||
}
|
||||
// Get the variable name
|
||||
var nameMatch = $tw.utils.parseTokenRegExp(source,pos,reName);
|
||||
if(nameMatch) {
|
||||
node.name = nameMatch.match[1];
|
||||
pos = nameMatch.end;
|
||||
node = $tw.utils.parseMacroParameters(node,source,pos);
|
||||
delete node.end;
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for an HTML attribute definition. Returns null if not found, otherwise returns {type: "attribute", name:, valueType: "string|indirect|macro", value:, start:, end:,}
|
||||
Look for an HTML attribute definition. Returns null if not found, otherwise returns {type: "attribute", name:, type: "filtered|string|indirect|macro", value|filter|textReference:, start:, end:,}
|
||||
*/
|
||||
exports.parseAttribute = function(source,pos) {
|
||||
var node = {
|
||||
@@ -218,7 +248,7 @@ exports.parseAttribute = function(source,pos) {
|
||||
// Define our regexps
|
||||
var reAttributeName = /([^\/\s>"'=]+)/g,
|
||||
reUnquotedAttribute = /([^\/\s<>"'=]+)/g,
|
||||
reFilteredValue = /\{\{\{(.+?)\}\}\}/g,
|
||||
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/g,
|
||||
reIndirectValue = /\{\{([^\}]+)\}\}/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
|
||||
@@ -7,6 +7,12 @@ Wiki text block rule for HTML comments. For example:
|
||||
|
||||
```
|
||||
<!-- This is a comment -->
|
||||
\define macroX()
|
||||
<!-- This is a comment -->
|
||||
xxxx
|
||||
\end
|
||||
<!-- This is a comment -->
|
||||
|
||||
```
|
||||
|
||||
Note that the syntax for comments is simplified to an opening "<!--" sequence and a closing "-->" sequence -- HTML itself implements a more complex format (see http://ostermiller.org/findhtmlcomment.html)
|
||||
@@ -19,7 +25,7 @@ Note that the syntax for comments is simplified to an opening "<!--" sequence an
|
||||
"use strict";
|
||||
|
||||
exports.name = "commentblock";
|
||||
exports.types = {block: true};
|
||||
exports.types = {block:true, pragma:true};
|
||||
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
|
||||
@@ -66,7 +66,7 @@ exports.parse = function() {
|
||||
};
|
||||
|
||||
/*
|
||||
Look for an HTML tag. Returns null if not found, otherwise returns {type: "element", name:, attributes: [], isSelfClosing:, start:, end:,}
|
||||
Look for an HTML tag. Returns null if not found, otherwise returns {type: "element", name:, attributes: {}, orderedAttributes: [], isSelfClosing:, start:, end:,}
|
||||
*/
|
||||
exports.parseTag = function(source,pos,options) {
|
||||
options = options || {};
|
||||
@@ -74,7 +74,8 @@ exports.parseTag = function(source,pos,options) {
|
||||
node = {
|
||||
type: "element",
|
||||
start: pos,
|
||||
attributes: {}
|
||||
attributes: {},
|
||||
orderedAttributes: []
|
||||
};
|
||||
// Define our regexps
|
||||
var reTagName = /([a-zA-Z0-9\-\$]+)/g;
|
||||
@@ -106,6 +107,7 @@ exports.parseTag = function(source,pos,options) {
|
||||
// Process attributes
|
||||
var attribute = $tw.utils.parseAttribute(source,pos);
|
||||
while(attribute) {
|
||||
node.orderedAttributes.push(attribute);
|
||||
node.attributes[attribute.name] = attribute;
|
||||
pos = attribute.end;
|
||||
// Get the next attribute
|
||||
|
||||
@@ -231,7 +231,10 @@ WikiParser.prototype.parseBlock = function(terminatorRegExpString) {
|
||||
return nextMatch.rule.parse();
|
||||
}
|
||||
// Treat it as a paragraph if we didn't find a block rule
|
||||
return [{type: "element", tag: "p", children: this.parseInlineRun(terminatorRegExp)}];
|
||||
var start = this.pos;
|
||||
var children = this.parseInlineRun(terminatorRegExp);
|
||||
var end = this.pos;
|
||||
return [{type: "element", tag: "p", children: children, start: start, end: end }];
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -307,7 +310,7 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) {
|
||||
while(this.pos < this.sourceLength && nextMatch) {
|
||||
// Process the text preceding the run rule
|
||||
if(nextMatch.matchIndex > this.pos) {
|
||||
this.pushTextWidget(tree,this.source.substring(this.pos,nextMatch.matchIndex));
|
||||
this.pushTextWidget(tree,this.source.substring(this.pos,nextMatch.matchIndex),this.pos,nextMatch.matchIndex);
|
||||
this.pos = nextMatch.matchIndex;
|
||||
}
|
||||
// Process the run rule
|
||||
@@ -317,7 +320,7 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) {
|
||||
}
|
||||
// Process the remaining text
|
||||
if(this.pos < this.sourceLength) {
|
||||
this.pushTextWidget(tree,this.source.substr(this.pos));
|
||||
this.pushTextWidget(tree,this.source.substr(this.pos),this.pos,this.sourceLength);
|
||||
}
|
||||
this.pos = this.sourceLength;
|
||||
return tree;
|
||||
@@ -337,7 +340,7 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
||||
if(terminatorMatch) {
|
||||
if(!inlineRuleMatch || inlineRuleMatch.matchIndex >= terminatorMatch.index) {
|
||||
if(terminatorMatch.index > this.pos) {
|
||||
this.pushTextWidget(tree,this.source.substring(this.pos,terminatorMatch.index));
|
||||
this.pushTextWidget(tree,this.source.substring(this.pos,terminatorMatch.index),this.pos,terminatorMatch.index);
|
||||
}
|
||||
this.pos = terminatorMatch.index;
|
||||
if(options.eatTerminator) {
|
||||
@@ -350,7 +353,7 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
||||
if(inlineRuleMatch) {
|
||||
// Preceding text
|
||||
if(inlineRuleMatch.matchIndex > this.pos) {
|
||||
this.pushTextWidget(tree,this.source.substring(this.pos,inlineRuleMatch.matchIndex));
|
||||
this.pushTextWidget(tree,this.source.substring(this.pos,inlineRuleMatch.matchIndex),this.pos,inlineRuleMatch.matchIndex);
|
||||
this.pos = inlineRuleMatch.matchIndex;
|
||||
}
|
||||
// Process the inline rule
|
||||
@@ -364,7 +367,7 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
||||
}
|
||||
// Process the remaining text
|
||||
if(this.pos < this.sourceLength) {
|
||||
this.pushTextWidget(tree,this.source.substr(this.pos));
|
||||
this.pushTextWidget(tree,this.source.substr(this.pos),this.pos,this.sourceLength);
|
||||
}
|
||||
this.pos = this.sourceLength;
|
||||
return tree;
|
||||
@@ -373,12 +376,12 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
||||
/*
|
||||
Push a text widget onto an array, respecting the configTrimWhiteSpace setting
|
||||
*/
|
||||
WikiParser.prototype.pushTextWidget = function(array,text) {
|
||||
WikiParser.prototype.pushTextWidget = function(array,text,start,end) {
|
||||
if(this.configTrimWhiteSpace) {
|
||||
text = $tw.utils.trim(text);
|
||||
}
|
||||
if(text) {
|
||||
array.push({type: "text", text: text});
|
||||
array.push({type: "text", text: text, start: start, end: end});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -157,7 +157,8 @@ SaverHandler.prototype.saveWiki = function(options) {
|
||||
return false;
|
||||
}
|
||||
var variables = options.variables || {},
|
||||
template = options.template || "$:/core/save/all",
|
||||
template = (options.template ||
|
||||
this.wiki.getTiddlerText("$:/config/SaveWikiButton/Template","$:/core/save/all")).trim(),
|
||||
downloadType = options.downloadType || "text/plain",
|
||||
text = this.wiki.renderTiddler(downloadType,template,options),
|
||||
callback = function(err) {
|
||||
|
||||
@@ -42,7 +42,7 @@ AndTidWiki.prototype.save = function(text,method,callback,options) {
|
||||
window.twi.saveWiki(text);
|
||||
} else {
|
||||
// Get the pathname of this document
|
||||
var pathname = decodeURIComponent(document.location.toString().split("#")[0]);
|
||||
var pathname = $tw.utils.decodeURIComponentSafe(document.location.toString().split("#")[0]);
|
||||
// Strip the file://
|
||||
if(pathname.indexOf("file://") === 0) {
|
||||
pathname = pathname.substr(7);
|
||||
|
||||
@@ -26,7 +26,7 @@ DownloadSaver.prototype.save = function(text,method,callback,options) {
|
||||
var p = document.location.pathname.lastIndexOf("/");
|
||||
if(p !== -1) {
|
||||
// We decode the pathname because document.location is URL encoded by the browser
|
||||
filename = decodeURIComponent(document.location.pathname.substr(p+1));
|
||||
filename = $tw.utils.decodeURIComponentSafe(document.location.pathname.substr(p+1));
|
||||
}
|
||||
}
|
||||
if(!filename) {
|
||||
|
||||
@@ -72,7 +72,7 @@ GiteaSaver.prototype.save = function(text,method,callback) {
|
||||
}
|
||||
}
|
||||
var data = {
|
||||
message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
content: $tw.utils.base64Encode(text),
|
||||
sha: sha
|
||||
};
|
||||
|
||||
@@ -69,7 +69,7 @@ GitHubSaver.prototype.save = function(text,method,callback) {
|
||||
});
|
||||
}
|
||||
var data = {
|
||||
message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
content: $tw.utils.base64Encode(text),
|
||||
branch: branch,
|
||||
sha: sha
|
||||
|
||||
@@ -67,7 +67,7 @@ GitLabSaver.prototype.save = function(text,method,callback) {
|
||||
});
|
||||
}
|
||||
var data = {
|
||||
commit_message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
commit_message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
content: text,
|
||||
branch: branch,
|
||||
sha: sha
|
||||
|
||||
@@ -43,7 +43,7 @@ TiddlyFoxSaver.prototype.save = function(text,method,callback) {
|
||||
}
|
||||
// Create the message element and put it in the message box
|
||||
var message = document.createElement("div");
|
||||
message.setAttribute("data-tiddlyfox-path",decodeURIComponent(pathname));
|
||||
message.setAttribute("data-tiddlyfox-path",$tw.utils.decodeURIComponentSafe(pathname));
|
||||
message.setAttribute("data-tiddlyfox-content",text);
|
||||
messageBox.appendChild(message);
|
||||
// Add an event handler for when the file has been saved
|
||||
|
||||
@@ -21,7 +21,7 @@ TWEditSaver.prototype.save = function(text,method,callback) {
|
||||
return false;
|
||||
}
|
||||
// Get the pathname of this document
|
||||
var pathname = decodeURIComponent(document.location.pathname);
|
||||
var pathname = $tw.utils.decodeURIComponentSafe(document.location.pathname);
|
||||
// Strip any query or location part
|
||||
var p = pathname.indexOf("?");
|
||||
if(p !== -1) {
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.method = "DELETE";
|
||||
exports.path = /^\/bags\/default\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = decodeURIComponent(state.params[0]);
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
||||
state.wiki.deleteTiddler(title);
|
||||
response.writeHead(204, "OK", {
|
||||
"Content-Type": "text/plain"
|
||||
|
||||
@@ -20,22 +20,29 @@ exports.handler = function(request,response,state) {
|
||||
var path = require("path"),
|
||||
fs = require("fs"),
|
||||
util = require("util"),
|
||||
suppliedFilename = decodeURIComponent(state.params[0]),
|
||||
filename = path.resolve(state.boot.wikiPath,"files",suppliedFilename),
|
||||
suppliedFilename = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
baseFilename = path.resolve(state.boot.wikiPath,"files"),
|
||||
filename = path.resolve(baseFilename,suppliedFilename),
|
||||
extension = path.extname(filename);
|
||||
fs.readFile(filename,function(err,content) {
|
||||
var status,content,type = "text/plain";
|
||||
if(err) {
|
||||
console.log("Error accessing file " + filename + ": " + err.toString());
|
||||
status = 404;
|
||||
content = "File '" + suppliedFilename + "' not found";
|
||||
} else {
|
||||
status = 200;
|
||||
content = content;
|
||||
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
|
||||
}
|
||||
state.sendResponse(status,{"Content-Type": type},content);
|
||||
});
|
||||
// Check that the filename is inside the wiki files folder
|
||||
if(path.relative(baseFilename,filename).indexOf("..") !== 0) {
|
||||
// Send the file
|
||||
fs.readFile(filename,function(err,content) {
|
||||
var status,content,type = "text/plain";
|
||||
if(err) {
|
||||
console.log("Error accessing file " + filename + ": " + err.toString());
|
||||
status = 404;
|
||||
content = "File '" + suppliedFilename + "' not found";
|
||||
} else {
|
||||
status = 200;
|
||||
content = content;
|
||||
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
|
||||
}
|
||||
state.sendResponse(status,{"Content-Type": type},content);
|
||||
});
|
||||
} else {
|
||||
state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
|
||||
}
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
@@ -21,7 +21,6 @@ exports.handler = function(request,response,state) {
|
||||
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
||||
anonymous: !state.authenticatedUsername,
|
||||
read_only: !state.server.isAuthorized("writers",state.authenticatedUsername),
|
||||
sse_enabled: state.server.get("sse-enabled") === "yes",
|
||||
space: {
|
||||
recipe: "default"
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.method = "GET";
|
||||
exports.path = /^\/([^\/]+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = decodeURIComponent(state.params[0]),
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
tiddler = state.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
var renderType = tiddler.getFieldString("_render_type"),
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.method = "GET";
|
||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = decodeURIComponent(state.params[0]),
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
tiddler = state.wiki.getTiddler(title),
|
||||
tiddlerFields = {},
|
||||
knownFields = [
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.method = "PUT";
|
||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = decodeURIComponent(state.params[0]),
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
fields = JSON.parse(state.data);
|
||||
// Pull up any subfields in the `fields` object
|
||||
if(fields.fields) {
|
||||
@@ -30,7 +30,7 @@ exports.handler = function(request,response,state) {
|
||||
if(fields.revision) {
|
||||
delete fields.revision;
|
||||
}
|
||||
state.wiki.addTiddler(new $tw.Tiddler(state.wiki.getCreationFields(),fields,{title: title},state.wiki.getModificationFields()));
|
||||
state.wiki.addTiddler(new $tw.Tiddler(fields,{title: title}));
|
||||
var changeCount = state.wiki.getChangeCount(title).toString();
|
||||
response.writeHead(204, "OK",{
|
||||
Etag: "\"default/" + encodeURIComponent(title) + "/" + changeCount + ":\"",
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/server/server-sent-events.js
|
||||
type: application/javascript
|
||||
module-type: library
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
parameters:
|
||||
prefix - usually the plugin path, such as `plugins/tiddlywiki/tiddlyweb`. The
|
||||
route will match `/events/${prefix}` exactly.
|
||||
|
||||
handler - a function that will be called each time a request comes in with the
|
||||
request and state from the route and an emit function to call.
|
||||
*/
|
||||
|
||||
var ServerSentEvents = function ServerSentEvents(prefix, handler) {
|
||||
this.handler = handler;
|
||||
this.prefix = prefix;
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.getExports = function() {
|
||||
return {
|
||||
bodyFormat: "stream",
|
||||
method: "GET",
|
||||
path: new RegExp("^/events/" + this.prefix + "$"),
|
||||
handler: this.handleEventRequest.bind(this)
|
||||
};
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.handleEventRequest = function(request,response,state) {
|
||||
if(ServerSentEvents.prototype.isEventStreamRequest(request)) {
|
||||
response.writeHead(200, {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
"Connection": "keep-alive"
|
||||
});
|
||||
this.handler(request,state,this.emit.bind(this,response),this.end.bind(this,response));
|
||||
} else {
|
||||
response.writeHead(406,"Not Acceptable",{});
|
||||
response.end();
|
||||
}
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.isEventStreamRequest = function(request) {
|
||||
return request.headers.accept &&
|
||||
request.headers.accept.match(/^text\/event-stream/);
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.emit = function(response,event,data) {
|
||||
if(typeof event !== "string" || event.indexOf("\n") !== -1) {
|
||||
throw new Error("Type must be a single-line string");
|
||||
}
|
||||
if(typeof data !== "string" || data.indexOf("\n") !== -1) {
|
||||
throw new Error("Data must be a single-line string");
|
||||
}
|
||||
response.write("event: " + event + "\ndata: " + data + "\n\n", "utf8");
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.end = function(response) {
|
||||
response.end();
|
||||
};
|
||||
|
||||
exports.ServerSentEvents = ServerSentEvents;
|
||||
|
||||
})();
|
||||
@@ -34,7 +34,6 @@ function Server(options) {
|
||||
this.authenticators = options.authenticators || [];
|
||||
this.wiki = options.wiki;
|
||||
this.boot = options.boot || $tw.boot;
|
||||
this.servername = $tw.utils.transliterateToSafeASCII(this.wiki.getTiddlerText("$:/SiteTitle") || "TiddlyWiki5");
|
||||
// Initialise the variables
|
||||
this.variables = $tw.utils.extend({},this.defaultVariables);
|
||||
if(options.variables) {
|
||||
@@ -44,7 +43,8 @@ function Server(options) {
|
||||
}
|
||||
}
|
||||
}
|
||||
$tw.utils.extend({},this.defaultVariables,options.variables);
|
||||
// Setup the default required plugins
|
||||
this.requiredPlugins = this.get("required-plugins").split(',');
|
||||
// Initialise CSRF
|
||||
this.csrfDisable = this.get("csrf-disable") === "yes";
|
||||
// Initialize Gzip compression
|
||||
@@ -52,14 +52,24 @@ function Server(options) {
|
||||
// Initialize browser-caching
|
||||
this.enableBrowserCache = this.get("use-browser-cache") === "yes";
|
||||
// Initialise authorization
|
||||
var authorizedUserName = (this.get("username") && this.get("password")) ? this.get("username") : "(anon)";
|
||||
var authorizedUserName;
|
||||
if(this.get("username") && this.get("password")) {
|
||||
authorizedUserName = this.get("username");
|
||||
} else if(this.get("credentials")) {
|
||||
authorizedUserName = "(authenticated)";
|
||||
} else {
|
||||
authorizedUserName = "(anon)";
|
||||
}
|
||||
this.authorizationPrincipals = {
|
||||
readers: (this.get("readers") || authorizedUserName).split(",").map($tw.utils.trim),
|
||||
writers: (this.get("writers") || authorizedUserName).split(",").map($tw.utils.trim)
|
||||
}
|
||||
if(this.get("admin") || authorizedUserName !== "(anon)") {
|
||||
this.authorizationPrincipals["admin"] = (this.get("admin") || authorizedUserName).split(',').map($tw.utils.trim)
|
||||
}
|
||||
// Load and initialise authenticators
|
||||
$tw.modules.forEachModuleOfType("authenticator", function(title,authenticatorDefinition) {
|
||||
// console.log("Loading server route " + title);
|
||||
// console.log("Loading authenticator " + title);
|
||||
self.addAuthenticator(authenticatorDefinition.AuthenticatorClass);
|
||||
});
|
||||
// Load route handlers
|
||||
@@ -71,15 +81,21 @@ function Server(options) {
|
||||
this.listenOptions = null;
|
||||
this.protocol = "http";
|
||||
var tlsKeyFilepath = this.get("tls-key"),
|
||||
tlsCertFilepath = this.get("tls-cert");
|
||||
tlsCertFilepath = this.get("tls-cert"),
|
||||
tlsPassphrase = this.get("tls-passphrase");
|
||||
if(tlsCertFilepath && tlsKeyFilepath) {
|
||||
this.listenOptions = {
|
||||
key: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsKeyFilepath),"utf8"),
|
||||
cert: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsCertFilepath),"utf8")
|
||||
cert: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsCertFilepath),"utf8"),
|
||||
passphrase: tlsPassphrase || ''
|
||||
};
|
||||
this.protocol = "https";
|
||||
}
|
||||
this.transport = require(this.protocol);
|
||||
// Name the server and init the boot state
|
||||
this.servername = $tw.utils.transliterateToSafeASCII(this.get("server-name") || this.wiki.getTiddlerText("$:/SiteTitle") || "TiddlyWiki5");
|
||||
this.boot.origin = this.get("origin")? this.get("origin"): this.protocol+"://"+this.get("host")+":"+this.get("port");
|
||||
this.boot.pathPrefix = this.get("path-prefix") || "";
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -150,6 +166,7 @@ function sendResponse(request,response,statusCode,headers,data,encoding) {
|
||||
Server.prototype.defaultVariables = {
|
||||
port: "8080",
|
||||
host: "127.0.0.1",
|
||||
"required-plugins": "$:/plugins/tiddlywiki/filesystem,$:/plugins/tiddlywiki/tiddlyweb",
|
||||
"root-tiddler": "$:/core/save/all",
|
||||
"root-render-type": "text/plain",
|
||||
"root-serve-type": "text/html",
|
||||
@@ -239,15 +256,15 @@ Server.prototype.requestHandler = function(request,response,options) {
|
||||
state.pathPrefix = options.pathPrefix || this.get("path-prefix") || "";
|
||||
state.sendResponse = sendResponse.bind(self,request,response);
|
||||
// Get the principals authorized to access this resource
|
||||
var authorizationType = this.methodMappings[request.method] || "readers";
|
||||
state.authorizationType = options.authorizationType || this.methodMappings[request.method] || "readers";
|
||||
// Check for the CSRF header if this is a write
|
||||
if(!this.csrfDisable && authorizationType === "writers" && request.headers["x-requested-with"] !== "TiddlyWiki") {
|
||||
if(!this.csrfDisable && state.authorizationType === "writers" && request.headers["x-requested-with"] !== "TiddlyWiki") {
|
||||
response.writeHead(403,"'X-Requested-With' header required to login to '" + this.servername + "'");
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
// Check whether anonymous access is granted
|
||||
state.allowAnon = this.isAuthorized(authorizationType,null);
|
||||
state.allowAnon = this.isAuthorized(state.authorizationType,null);
|
||||
// Authenticate with the first active authenticator
|
||||
if(this.authenticators.length > 0) {
|
||||
if(!this.authenticators[0].authenticateRequest(request,response,state)) {
|
||||
@@ -256,7 +273,7 @@ Server.prototype.requestHandler = function(request,response,options) {
|
||||
}
|
||||
}
|
||||
// Authorize with the authenticated username
|
||||
if(!this.isAuthorized(authorizationType,state.authenticatedUsername)) {
|
||||
if(!this.isAuthorized(state.authorizationType,state.authenticatedUsername)) {
|
||||
response.writeHead(401,"'" + state.authenticatedUsername + "' is not authorized to access '" + this.servername + "'");
|
||||
response.end();
|
||||
return;
|
||||
@@ -322,8 +339,16 @@ Server.prototype.listen = function(port,host,prefix) {
|
||||
port = process.env[port] || 8080;
|
||||
}
|
||||
// Warn if required plugins are missing
|
||||
if(!this.wiki.getTiddler("$:/plugins/tiddlywiki/tiddlyweb") || !this.wiki.getTiddler("$:/plugins/tiddlywiki/filesystem")) {
|
||||
$tw.utils.warning("Warning: Plugins required for client-server operation (\"tiddlywiki/filesystem\" and \"tiddlywiki/tiddlyweb\") are missing from tiddlywiki.info file");
|
||||
var missing = [];
|
||||
for (var index=0; index<this.requiredPlugins.length; index++) {
|
||||
if (!this.wiki.getTiddler(this.requiredPlugins[index])) {
|
||||
missing.push(this.requiredPlugins[index]);
|
||||
}
|
||||
}
|
||||
if(missing.length > 0) {
|
||||
var error = "Warning: Plugin(s) required for client-server operation are missing.\n"+
|
||||
"\""+ missing.join("\", \"")+"\"";
|
||||
$tw.utils.warning(error);
|
||||
}
|
||||
// Create the server
|
||||
var server;
|
||||
|
||||
@@ -40,9 +40,10 @@ exports.startup = function() {
|
||||
// Install the tm-focus-selector message
|
||||
$tw.rootWidget.addEventListener("tm-focus-selector",function(event) {
|
||||
var selector = event.param || "",
|
||||
element;
|
||||
element,
|
||||
doc = event.event && event.event.target ? event.event.target.ownerDocument : document;
|
||||
try {
|
||||
element = document.querySelector(selector);
|
||||
element = doc.querySelector(selector);
|
||||
} catch(e) {
|
||||
console.log("Error in selector: ",selector)
|
||||
}
|
||||
@@ -50,6 +51,20 @@ exports.startup = function() {
|
||||
element.focus(event.paramObject);
|
||||
}
|
||||
});
|
||||
// Install the tm-rename-tiddler and tm-relink-tiddler messages
|
||||
var makeRenameHandler = function(method) {
|
||||
return function(event) {
|
||||
var options = {},
|
||||
paramObject = event.paramObject || {},
|
||||
from = paramObject.from || event.tiddlerTitle,
|
||||
to = paramObject.to;
|
||||
options.dontRenameInTags = (paramObject.renameInTags === "false" || paramObject.renameInTags === "no") ? true : false;
|
||||
options.dontRenameInLists = (paramObject.renameInLists === "false" || paramObject.renameInLists === "no") ? true : false;
|
||||
$tw.wiki[method](from,to,options);
|
||||
};
|
||||
};
|
||||
$tw.rootWidget.addEventListener("tm-rename-tiddler",makeRenameHandler("renameTiddler"));
|
||||
$tw.rootWidget.addEventListener("tm-relink-tiddler",makeRenameHandler("relinkTiddler"));
|
||||
// Install the scroller
|
||||
$tw.pageScroller = new $tw.utils.PageScroller();
|
||||
$tw.rootWidget.addEventListener("tm-scroll",function(event) {
|
||||
|
||||
@@ -120,10 +120,10 @@ function openStartupTiddlers(options) {
|
||||
var hash = $tw.locationHash.substr(1),
|
||||
split = hash.indexOf(":");
|
||||
if(split === -1) {
|
||||
target = decodeURIComponent(hash.trim());
|
||||
target = $tw.utils.decodeURIComponentSafe(hash.trim());
|
||||
} else {
|
||||
target = decodeURIComponent(hash.substr(0,split).trim());
|
||||
storyFilter = decodeURIComponent(hash.substr(split + 1).trim());
|
||||
target = $tw.utils.decodeURIComponentSafe(hash.substr(0,split).trim());
|
||||
storyFilter = $tw.utils.decodeURIComponentSafe(hash.substr(split + 1).trim());
|
||||
}
|
||||
}
|
||||
// If the story wasn't specified use the current tiddlers or a blank story
|
||||
|
||||
@@ -32,13 +32,15 @@ exports.startup = function() {
|
||||
template = paramObject.template || "$:/core/templates/single.tiddler.window",
|
||||
width = paramObject.width || "700",
|
||||
height = paramObject.height || "600",
|
||||
top = paramObject.top,
|
||||
left = paramObject.left,
|
||||
variables = $tw.utils.extend({},paramObject,{currentTiddler: title});
|
||||
// Open the window
|
||||
var srcWindow,
|
||||
srcDocument;
|
||||
// In case that popup blockers deny opening a new window
|
||||
try {
|
||||
srcWindow = window.open("","external-" + title,"scrollbars,width=" + width + ",height=" + height),
|
||||
srcWindow = window.open("","external-" + title,"scrollbars,width=" + width + ",height=" + height + (top ? ",top=" + top : "" ) + (left ? ",left=" + left : "" )),
|
||||
srcDocument = srcWindow.document;
|
||||
}
|
||||
catch(e) {
|
||||
|
||||
@@ -27,7 +27,7 @@ ClassicStoryView.prototype.navigateTo = function(historyInfo) {
|
||||
var listItemWidget = this.listWidget.children[listElementIndex],
|
||||
targetElement = listItemWidget.findFirstDomNode();
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
return;
|
||||
}
|
||||
if(duration) {
|
||||
@@ -43,7 +43,7 @@ ClassicStoryView.prototype.insert = function(widget) {
|
||||
if(duration) {
|
||||
var targetElement = widget.findFirstDomNode();
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
return;
|
||||
}
|
||||
// Get the current height of the tiddler
|
||||
@@ -83,7 +83,7 @@ ClassicStoryView.prototype.remove = function(widget) {
|
||||
widget.removeChildDomNodes();
|
||||
};
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
removeElement();
|
||||
return;
|
||||
}
|
||||
@@ -118,4 +118,4 @@ ClassicStoryView.prototype.remove = function(widget) {
|
||||
|
||||
exports.classic = ClassicStoryView;
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -24,7 +24,7 @@ PopStoryView.prototype.navigateTo = function(historyInfo) {
|
||||
var listItemWidget = this.listWidget.children[listElementIndex],
|
||||
targetElement = listItemWidget.findFirstDomNode();
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
return;
|
||||
}
|
||||
// Scroll the node into view
|
||||
@@ -35,7 +35,7 @@ PopStoryView.prototype.insert = function(widget) {
|
||||
var targetElement = widget.findFirstDomNode(),
|
||||
duration = $tw.utils.getAnimationDuration();
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
return;
|
||||
}
|
||||
// Reset once the transition is over
|
||||
@@ -77,7 +77,7 @@ PopStoryView.prototype.remove = function(widget) {
|
||||
}
|
||||
};
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
removeElement();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ ZoominListView.prototype.navigateTo = function(historyInfo) {
|
||||
var listItemWidget = this.listWidget.children[listElementIndex],
|
||||
targetElement = listItemWidget.findFirstDomNode();
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
return;
|
||||
}
|
||||
// Make the new tiddler be position absolute and visible so that we can measure it
|
||||
@@ -130,7 +130,7 @@ function findTitleDomNode(widget,targetClass) {
|
||||
ZoominListView.prototype.insert = function(widget) {
|
||||
var targetElement = widget.findFirstDomNode();
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
return;
|
||||
}
|
||||
// Make the newly inserted node position absolute and hidden
|
||||
@@ -147,7 +147,7 @@ ZoominListView.prototype.remove = function(widget) {
|
||||
widget.removeChildDomNodes();
|
||||
};
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
removeElement();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ Syncer.prototype.titleIsAnonymous = "$:/status/IsAnonymous";
|
||||
Syncer.prototype.titleIsReadOnly = "$:/status/IsReadOnly";
|
||||
Syncer.prototype.titleUserName = "$:/status/UserName";
|
||||
Syncer.prototype.titleSyncFilter = "$:/config/SyncFilter";
|
||||
Syncer.prototype.titleSyncDisablePolling = "$:/config/SyncDisablePolling";
|
||||
Syncer.prototype.titleSyncPollingInterval = "$:/config/SyncPollingInterval";
|
||||
Syncer.prototype.titleSyncDisableLazyLoading = "$:/config/SyncDisableLazyLoading";
|
||||
Syncer.prototype.titleSavedNotification = "$:/language/Notifications/Save/Done";
|
||||
@@ -90,7 +89,7 @@ function Syncer(options) {
|
||||
if(filteredChanges.length > 0) {
|
||||
self.processTaskQueue();
|
||||
} else {
|
||||
// Look for deletions of tiddlers we're already syncing
|
||||
// Look for deletions of tiddlers we're already syncing
|
||||
var outstandingDeletion = false
|
||||
$tw.utils.each(changes,function(change,title,object) {
|
||||
if(change.deleted && $tw.utils.hop(self.tiddlerInfo,title)) {
|
||||
@@ -122,7 +121,7 @@ function Syncer(options) {
|
||||
self.login(username,password,function() {});
|
||||
} else {
|
||||
// No username and password, so we display a prompt
|
||||
self.handleLoginEvent();
|
||||
self.handleLoginEvent();
|
||||
}
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tm-logout",function() {
|
||||
@@ -139,7 +138,7 @@ function Syncer(options) {
|
||||
if(!this.disableUI && this.wiki.getTiddlerText(this.titleSyncDisableLazyLoading) !== "yes") {
|
||||
this.wiki.addEventListener("lazyLoad",function(title) {
|
||||
self.handleLazyLoadEvent(title);
|
||||
});
|
||||
});
|
||||
}
|
||||
// Get the login status
|
||||
this.getStatus(function(err,isLoggedIn) {
|
||||
@@ -174,8 +173,8 @@ Syncer.prototype.getTiddlerRevision = function(title) {
|
||||
if(this.syncadaptor && this.syncadaptor.getTiddlerRevision) {
|
||||
return this.syncadaptor.getTiddlerRevision(title);
|
||||
} else {
|
||||
return this.wiki.getTiddler(title).fields.revision;
|
||||
}
|
||||
return this.wiki.getTiddler(title).fields.revision;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -268,9 +267,9 @@ Syncer.prototype.getStatus = function(callback) {
|
||||
// Mark us as not logged in
|
||||
this.wiki.addTiddler({title: this.titleIsLoggedIn,text: "no"});
|
||||
// Get login status
|
||||
this.syncadaptor.getStatus(function(err,isLoggedIn,username,isReadOnly,isAnonymous,isPollingDisabled) {
|
||||
this.syncadaptor.getStatus(function(err,isLoggedIn,username,isReadOnly,isAnonymous) {
|
||||
if(err) {
|
||||
self.logger.alert(err);
|
||||
self.displayError("Get Status Error",err);
|
||||
} else {
|
||||
// Set the various status tiddlers
|
||||
self.wiki.addTiddler({title: self.titleIsReadOnly,text: isReadOnly ? "yes" : "no"});
|
||||
@@ -279,9 +278,6 @@ Syncer.prototype.getStatus = function(callback) {
|
||||
if(isLoggedIn) {
|
||||
self.wiki.addTiddler({title: self.titleUserName,text: username || ""});
|
||||
}
|
||||
if(isPollingDisabled) {
|
||||
self.wiki.addTiddler({title: self.titleSyncDisablePolling, text: "yes"});
|
||||
}
|
||||
}
|
||||
// Invoke the callback
|
||||
if(callback) {
|
||||
@@ -305,15 +301,12 @@ Syncer.prototype.syncFromServer = function() {
|
||||
}
|
||||
},
|
||||
triggerNextSync = function() {
|
||||
if(pollingEnabled) {
|
||||
self.pollTimerId = setTimeout(function() {
|
||||
self.pollTimerId = null;
|
||||
self.syncFromServer.call(self);
|
||||
},self.pollTimerInterval);
|
||||
}
|
||||
self.pollTimerId = setTimeout(function() {
|
||||
self.pollTimerId = null;
|
||||
self.syncFromServer.call(self);
|
||||
},self.pollTimerInterval);
|
||||
},
|
||||
syncSystemFromServer = (self.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "yes"),
|
||||
pollingEnabled = (self.wiki.getTiddlerText(self.titleSyncDisablePolling) !== "yes");
|
||||
syncSystemFromServer = (self.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "yes" ? true : false);
|
||||
if(this.syncadaptor && this.syncadaptor.getUpdatedTiddlers) {
|
||||
this.logger.log("Retrieving updated tiddler list");
|
||||
cancelNextSync();
|
||||
@@ -336,7 +329,7 @@ Syncer.prototype.syncFromServer = function() {
|
||||
});
|
||||
if(updates.modifications.length > 0 || updates.deletions.length > 0) {
|
||||
self.processTaskQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if(this.syncadaptor && this.syncadaptor.getSkinnyTiddlers) {
|
||||
@@ -479,7 +472,7 @@ Syncer.prototype.handleLogoutEvent = function() {
|
||||
if(this.syncadaptor.logout) {
|
||||
this.syncadaptor.logout(function(err) {
|
||||
if(err) {
|
||||
self.logger.alert(err);
|
||||
self.displayError("Logout Error",err);
|
||||
} else {
|
||||
self.getStatus();
|
||||
}
|
||||
@@ -516,7 +509,7 @@ Syncer.prototype.processTaskQueue = function() {
|
||||
} else {
|
||||
self.updateDirtyStatus();
|
||||
// Process the next task
|
||||
self.processTaskQueue.call(self);
|
||||
self.processTaskQueue.call(self);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -524,11 +517,11 @@ Syncer.prototype.processTaskQueue = function() {
|
||||
this.updateDirtyStatus();
|
||||
// And trigger a timeout if there is a pending task
|
||||
if(task === true) {
|
||||
this.triggerTimeout();
|
||||
this.triggerTimeout();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.updateDirtyStatus();
|
||||
this.updateDirtyStatus();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -562,7 +555,7 @@ Syncer.prototype.chooseNextTask = function() {
|
||||
isReadyToSave = !tiddlerInfo || !tiddlerInfo.timestampLastSaved || tiddlerInfo.timestampLastSaved < thresholdLastSaved;
|
||||
if(hasChanged) {
|
||||
if(isReadyToSave) {
|
||||
return new SaveTiddlerTask(this,title);
|
||||
return new SaveTiddlerTask(this,title);
|
||||
} else {
|
||||
havePending = true;
|
||||
}
|
||||
@@ -601,10 +594,7 @@ SaveTiddlerTask.prototype.run = function(callback) {
|
||||
tiddler = this.syncer.wiki.tiddlerExists(this.title) && this.syncer.wiki.getTiddler(this.title);
|
||||
this.syncer.logger.log("Dispatching 'save' task:",this.title);
|
||||
if(tiddler) {
|
||||
this.syncer.syncadaptor.saveTiddler(tiddler,{
|
||||
changeCount: changeCount,
|
||||
tiddlerInfo: self.syncer.tiddlerInfo[self.title]
|
||||
},function(err,adaptorInfo,revision) {
|
||||
this.syncer.syncadaptor.saveTiddler(tiddler,function(err,adaptorInfo,revision) {
|
||||
// If there's an error, exit without changing any internal state
|
||||
if(err) {
|
||||
return callback(err);
|
||||
@@ -618,6 +608,8 @@ SaveTiddlerTask.prototype.run = function(callback) {
|
||||
};
|
||||
// Invoke the callback
|
||||
callback(null);
|
||||
},{
|
||||
tiddlerInfo: self.syncer.tiddlerInfo[self.title]
|
||||
});
|
||||
} else {
|
||||
this.syncer.logger.log(" Not Dispatching 'save' task:",this.title,"tiddler does not exist");
|
||||
@@ -634,9 +626,7 @@ function DeleteTiddlerTask(syncer,title) {
|
||||
DeleteTiddlerTask.prototype.run = function(callback) {
|
||||
var self = this;
|
||||
this.syncer.logger.log("Dispatching 'delete' task:",this.title);
|
||||
this.syncer.syncadaptor.deleteTiddler(this.title,{
|
||||
tiddlerInfo: self.syncer.tiddlerInfo[this.title]
|
||||
},function(err,adaptorInfo) {
|
||||
this.syncer.syncadaptor.deleteTiddler(this.title,function(err) {
|
||||
// If there's an error, exit without changing any internal state
|
||||
if(err) {
|
||||
return callback(err);
|
||||
@@ -645,6 +635,8 @@ DeleteTiddlerTask.prototype.run = function(callback) {
|
||||
delete self.syncer.tiddlerInfo[self.title];
|
||||
// Invoke the callback
|
||||
callback(null);
|
||||
},{
|
||||
tiddlerInfo: self.syncer.tiddlerInfo[this.title]
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -24,13 +24,13 @@ exports.isDraft = function() {
|
||||
return this.hasField("draft.of");
|
||||
};
|
||||
|
||||
exports.getFieldString = function(field) {
|
||||
exports.getFieldString = function(field,defaultValue) {
|
||||
var value = this.fields[field];
|
||||
// Check for a missing field
|
||||
if(value === undefined || value === null) {
|
||||
return "";
|
||||
return defaultValue || "";
|
||||
}
|
||||
// Parse the field with the associated module (if any)
|
||||
// Stringify the field with the associated tiddler field module (if any)
|
||||
var fieldModule = $tw.Tiddler.fieldModules[field];
|
||||
if(fieldModule && fieldModule.stringify) {
|
||||
return fieldModule.stringify.call(this,value);
|
||||
|
||||
@@ -21,7 +21,7 @@ exports.extractEncryptedStoreArea = function(text) {
|
||||
if(encryptedStoreAreaStart !== -1) {
|
||||
var encryptedStoreAreaEnd = text.indexOf("</pre>",encryptedStoreAreaStart);
|
||||
if(encryptedStoreAreaEnd !== -1) {
|
||||
return $tw.utils.htmlDecode(text.substring(encryptedStoreAreaStart + encryptedStoreAreaStartMarker.length,encryptedStoreAreaEnd-1));
|
||||
return $tw.utils.htmlDecode(text.substring(encryptedStoreAreaStart + encryptedStoreAreaStartMarker.length,encryptedStoreAreaEnd));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -16,7 +16,7 @@ Browser data transfer utilities, used with the clipboard and drag and drop
|
||||
Options:
|
||||
|
||||
domNode: dom node to make draggable
|
||||
dragImageType: "pill" or "dom"
|
||||
dragImageType: "pill", "blank" or "dom" (the default)
|
||||
dragTiddlerFn: optional function to retrieve the title of tiddler to drag
|
||||
dragFilterFn: optional function to retreive the filter defining a list of tiddlers to drag
|
||||
widget: widget to use as the contect for the filter
|
||||
@@ -73,6 +73,9 @@ exports.makeDraggable = function(options) {
|
||||
if(dataTransfer.setDragImage) {
|
||||
if(dragImageType === "pill") {
|
||||
dataTransfer.setDragImage(dragImage.firstChild,-16,-16);
|
||||
} else if (dragImageType === "blank") {
|
||||
dragImage.removeChild(dragImage.firstChild);
|
||||
dataTransfer.setDragImage(dragImage,0,0);
|
||||
} else {
|
||||
var r = domNode.getBoundingClientRect();
|
||||
dataTransfer.setDragImage(domNode,event.clientX-r.left,event.clientY-r.top);
|
||||
@@ -164,7 +167,7 @@ var importDataTypes = [
|
||||
}},
|
||||
{type: "URL", IECompatible: true, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
||||
// Check for tiddler data URI
|
||||
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
var match = $tw.utils.decodeURIComponentSafe(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
if(match) {
|
||||
return parseJSONTiddlers(match[1],fallbackTitle);
|
||||
} else {
|
||||
@@ -173,7 +176,7 @@ var importDataTypes = [
|
||||
}},
|
||||
{type: "text/x-moz-url", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
||||
// Check for tiddler data URI
|
||||
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
var match = $tw.utils.decodeURIComponentSafe(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
if(match) {
|
||||
return parseJSONTiddlers(match[1],fallbackTitle);
|
||||
} else {
|
||||
@@ -205,10 +208,10 @@ function parseJSONTiddlers(json,fallbackTitle) {
|
||||
return data;
|
||||
};
|
||||
|
||||
exports.dragEventContainsFiles = function(event) {
|
||||
function dragEventContainsType(event,targetType) {
|
||||
if(event.dataTransfer.types) {
|
||||
for(var i=0; i<event.dataTransfer.types.length; i++) {
|
||||
if(event.dataTransfer.types[i] === "Files") {
|
||||
if(event.dataTransfer.types[i] === targetType) {
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
@@ -217,4 +220,10 @@ exports.dragEventContainsFiles = function(event) {
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.dragEventContainsFiles = function(event) {
|
||||
return (dragEventContainsType(event,"Files") && !dragEventContainsType(event,"text/plain"));
|
||||
};
|
||||
|
||||
exports.dragEventContainsType = dragEventContainsType;
|
||||
|
||||
})();
|
||||
|
||||
@@ -34,6 +34,23 @@ exports.httpRequest = function(options) {
|
||||
});
|
||||
return result;
|
||||
},
|
||||
getHeader = function(targetHeader) {
|
||||
return headers[targetHeader] || headers[targetHeader.toLowerCase()];
|
||||
},
|
||||
isSimpleRequest = function(type,headers) {
|
||||
if(["GET","HEAD","POST"].indexOf(type) === -1) {
|
||||
return false;
|
||||
}
|
||||
for(var header in headers) {
|
||||
if(["accept","accept-language","content-language","content-type"].indexOf(header.toLowerCase()) === -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(hasHeader("Content-Type") && ["application/x-www-form-urlencoded","multipart/form-data","text/plain"].indexOf(getHeader["Content-Type"]) === -1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
returnProp = options.returnProp || "responseText",
|
||||
request = new XMLHttpRequest(),
|
||||
data = "",
|
||||
@@ -76,7 +93,7 @@ exports.httpRequest = function(options) {
|
||||
if(data && !hasHeader("Content-Type")) {
|
||||
request.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
|
||||
}
|
||||
if(!hasHeader("X-Requested-With")) {
|
||||
if(!hasHeader("X-Requested-With") && !isSimpleRequest(type,headers)) {
|
||||
request.setRequestHeader("X-Requested-With","TiddlyWiki");
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -243,6 +243,7 @@ Modal.prototype.adjustPageClass = function() {
|
||||
if(windowContainer) {
|
||||
$tw.utils.toggleClass(windowContainer,"tc-modal-displayed",this.modalCount > 0);
|
||||
}
|
||||
$tw.utils.toggleClass(this.srcDocument.body,"tc-modal-prevent-scroll",this.modalCount > 0);
|
||||
};
|
||||
|
||||
exports.Modal = Modal;
|
||||
|
||||
@@ -49,10 +49,14 @@ Handle an event
|
||||
*/
|
||||
PageScroller.prototype.handleEvent = function(event) {
|
||||
if(event.type === "tm-scroll") {
|
||||
var options = {};
|
||||
if($tw.utils.hop(event.paramObject,"animationDuration")) {
|
||||
options.animationDuration = event.paramObject.animationDuration;
|
||||
}
|
||||
if(event.paramObject && event.paramObject.selector) {
|
||||
this.scrollSelectorIntoView(null,event.paramObject.selector);
|
||||
this.scrollSelectorIntoView(null,event.paramObject.selector,null,options);
|
||||
} else {
|
||||
this.scrollIntoView(event.target);
|
||||
this.scrollIntoView(event.target,null,options);
|
||||
}
|
||||
return false; // Event was handled
|
||||
}
|
||||
@@ -62,10 +66,10 @@ PageScroller.prototype.handleEvent = function(event) {
|
||||
/*
|
||||
Handle a scroll event hitting the page document
|
||||
*/
|
||||
PageScroller.prototype.scrollIntoView = function(element,callback) {
|
||||
PageScroller.prototype.scrollIntoView = function(element,callback,options) {
|
||||
var self = this,
|
||||
duration = $tw.utils.getAnimationDuration(),
|
||||
srcWindow = element ? element.ownerDocument.defaultView : window;
|
||||
duration = $tw.utils.hop(options,"animationDuration") ? parseInt(options.animationDuration) : $tw.utils.getAnimationDuration(),
|
||||
srcWindow = element ? element.ownerDocument.defaultView : window;
|
||||
// Now get ready to scroll the body
|
||||
this.cancelScroll(srcWindow);
|
||||
this.startTime = Date.now();
|
||||
@@ -122,11 +126,11 @@ PageScroller.prototype.scrollIntoView = function(element,callback) {
|
||||
drawFrame();
|
||||
};
|
||||
|
||||
PageScroller.prototype.scrollSelectorIntoView = function(baseElement,selector,callback) {
|
||||
PageScroller.prototype.scrollSelectorIntoView = function(baseElement,selector,callback,options) {
|
||||
baseElement = baseElement || document.body;
|
||||
var element = baseElement.querySelector(selector);
|
||||
if(element) {
|
||||
this.scrollIntoView(element,callback);
|
||||
this.scrollIntoView(element,callback,options);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ Object.defineProperty(TW_Element.prototype, "innerHTML", {
|
||||
if(node instanceof TW_Element) {
|
||||
b.push(node.outerHTML);
|
||||
} else if(node instanceof TW_TextNode) {
|
||||
b.push($tw.utils.htmlEncode(node.textContent));
|
||||
b.push($tw.utils.htmlTextEncode(node.textContent));
|
||||
}
|
||||
});
|
||||
return b.join("");
|
||||
|
||||
@@ -228,6 +228,7 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
|
||||
hasUnsafeFields = hasUnsafeFields || /[\x00-\x1F]/mg.test(value);
|
||||
hasUnsafeFields = hasUnsafeFields || ($tw.utils.trim(value) !== value);
|
||||
}
|
||||
hasUnsafeFields = hasUnsafeFields || /:/mg.test(fieldName);
|
||||
});
|
||||
// Check for field values
|
||||
if(hasUnsafeFields) {
|
||||
|
||||
@@ -95,6 +95,15 @@ LinkedList.prototype.toArray = function() {
|
||||
return output;
|
||||
};
|
||||
|
||||
LinkedList.prototype.makeTiddlerIterator = function(wiki) {
|
||||
var self = this;
|
||||
return function(callback) {
|
||||
self.each(function(title) {
|
||||
callback(wiki.getTiddler(title),title);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
function _removeOne(list,value) {
|
||||
var prevEntry = list.prev[value],
|
||||
nextEntry = list.next[value],
|
||||
|
||||
@@ -199,6 +199,8 @@ exports.transliterationPairs = {
|
||||
"Nj":"N",
|
||||
"Ñ":"N",
|
||||
"NJ":"NJ",
|
||||
"ð":"d",
|
||||
"Ð":"D",
|
||||
"Ó":"O",
|
||||
"Ŏ":"O",
|
||||
"Ǒ":"O",
|
||||
@@ -265,6 +267,8 @@ exports.transliterationPairs = {
|
||||
"Ɽ":"R",
|
||||
"Ꜿ":"C",
|
||||
"Ǝ":"E",
|
||||
"ß":"ss",
|
||||
"ẞ":"SS",
|
||||
"Ś":"S",
|
||||
"Ṥ":"S",
|
||||
"Š":"S",
|
||||
@@ -275,6 +279,8 @@ exports.transliterationPairs = {
|
||||
"Ṡ":"S",
|
||||
"Ṣ":"S",
|
||||
"Ṩ":"S",
|
||||
"þ": "th",
|
||||
"Þ": "TH",
|
||||
"Ť":"T",
|
||||
"Ţ":"T",
|
||||
"Ṱ":"T",
|
||||
@@ -907,7 +913,8 @@ exports.transliterationPairs = {
|
||||
"т":"t",
|
||||
"ь":"'",
|
||||
"б":"b",
|
||||
"ю":"yu"
|
||||
"ю":"yu",
|
||||
"…":"..."
|
||||
};
|
||||
|
||||
exports.transliterate = function(str) {
|
||||
|
||||
@@ -223,6 +223,7 @@ exports.removeArrayEntries = function(array,value) {
|
||||
array.splice(p,1);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -382,6 +383,15 @@ exports.formatDateString = function(date,template) {
|
||||
[/^0WW/, function() {
|
||||
return $tw.utils.pad($tw.utils.getWeek(date));
|
||||
}],
|
||||
[/^0ddddd/, function() {
|
||||
return $tw.utils.pad(Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24),3);
|
||||
}],
|
||||
[/^ddddd/, function() {
|
||||
return Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24);
|
||||
}],
|
||||
[/^dddd/, function() {
|
||||
return [7,1,2,3,4,5,6][date.getDay()];
|
||||
}],
|
||||
[/^ddd/, function() {
|
||||
return $tw.language.getString("Date/Short/Day/" + date.getDay());
|
||||
}],
|
||||
@@ -740,9 +750,8 @@ exports.isValidFieldName = function(name) {
|
||||
if(!name || typeof name !== "string") {
|
||||
return false;
|
||||
}
|
||||
name = name.toLowerCase().trim();
|
||||
var fieldValidatorRegEx = /^[a-z0-9\-\._]+$/mg;
|
||||
return fieldValidatorRegEx.test(name);
|
||||
// Since v5.2.x, there are no restrictions on characters in field names
|
||||
return name;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -58,9 +58,10 @@ Invoke the action associated with this widget
|
||||
*/
|
||||
ConfirmWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
var invokeActions = true,
|
||||
handled = true;
|
||||
handled = true,
|
||||
win = event && event.event && event.event.view ? event.event.view : window;
|
||||
if(this.prompt) {
|
||||
invokeActions = confirm(this.message);
|
||||
invokeActions = win.confirm(this.message);
|
||||
}
|
||||
if(invokeActions) {
|
||||
handled = this.invokeActions(triggeringWidget,event);
|
||||
@@ -74,4 +75,4 @@ ConfirmWidget.prototype.allowActionPropagation = function() {
|
||||
|
||||
exports["action-confirm"] = ConfirmWidget;
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -27,8 +27,11 @@ CreateTiddlerWidget.prototype = new Widget();
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
CreateTiddlerWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
// Render children
|
||||
this.renderChildren(parent,nextSibling);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -44,7 +47,8 @@ CreateTiddlerWidget.prototype.execute = function() {
|
||||
this.actionTemplate = this.getAttribute("$template");
|
||||
this.useTemplate = !!this.actionTemplate;
|
||||
this.actionOverwrite = this.getAttribute("$overwrite","no");
|
||||
|
||||
// Construct the child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -86,18 +90,21 @@ CreateTiddlerWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
if (!this.hasBase && this.useTemplate) {
|
||||
title = this.wiki.generateNewTitle(this.actionTemplate);
|
||||
} else if (!this.hasBase && !this.useTemplate) {
|
||||
// If NO $basetitle AND NO $template use initial title
|
||||
// DON'T overwrite any stuff
|
||||
// If no $basetitle and no $template then use initial title
|
||||
title = this.wiki.generateNewTitle(title);
|
||||
}
|
||||
var templateTiddler = this.wiki.getTiddler(this.actionTemplate) || {};
|
||||
var tiddler = this.wiki.addTiddler(new $tw.Tiddler(templateTiddler.fields,creationFields,fields,modificationFields,{title: title}));
|
||||
this.wiki.addTiddler(new $tw.Tiddler(templateTiddler.fields,creationFields,fields,modificationFields,{title: title}));
|
||||
var draftTitle = this.wiki.generateDraftTitle(title);
|
||||
if(this.actionSaveTitle) {
|
||||
this.wiki.setTextReference(this.actionSaveTitle,title,this.getVariable("currentTiddler"));
|
||||
}
|
||||
if(this.actionSaveDraftTitle) {
|
||||
this.wiki.setTextReference(this.actionSaveDraftTitle,this.wiki.generateDraftTitle(title),this.getVariable("currentTiddler"));
|
||||
this.wiki.setTextReference(this.actionSaveDraftTitle,draftTitle,this.getVariable("currentTiddler"));
|
||||
}
|
||||
this.setVariable("createTiddler-title",title);
|
||||
this.setVariable("createTiddler-draftTitle",draftTitle);
|
||||
this.refreshChildren();
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
|
||||
@@ -70,7 +70,18 @@ NavigateWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
navigateFromNode: triggeringWidget,
|
||||
navigateFromClientRect: bounds && { top: bounds.top, left: bounds.left, width: bounds.width, right: bounds.right, bottom: bounds.bottom, height: bounds.height
|
||||
},
|
||||
navigateSuppressNavigation: suppressNavigation
|
||||
navigateFromClientTop: bounds && bounds.top,
|
||||
navigateFromClientLeft: bounds && bounds.left,
|
||||
navigateFromClientWidth: bounds && bounds.width,
|
||||
navigateFromClientRight: bounds && bounds.right,
|
||||
navigateFromClientBottom: bounds && bounds.bottom,
|
||||
navigateFromClientHeight: bounds && bounds.height,
|
||||
navigateSuppressNavigation: suppressNavigation,
|
||||
metaKey: event.metaKey,
|
||||
ctrlKey: event.ctrlKey,
|
||||
altKey: event.altKey,
|
||||
shiftKey: event.shiftKey,
|
||||
event: event
|
||||
});
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
@@ -39,6 +39,8 @@ SendMessageWidget.prototype.execute = function() {
|
||||
this.actionParam = this.getAttribute("$param");
|
||||
this.actionName = this.getAttribute("$name");
|
||||
this.actionValue = this.getAttribute("$value","");
|
||||
this.actionNames = this.getAttribute("$names");
|
||||
this.actionValues = this.getAttribute("$values");
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -59,13 +61,20 @@ Invoke the action associated with this widget
|
||||
SendMessageWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
// Get the string parameter
|
||||
var param = this.actionParam;
|
||||
// Assemble the attributes as a hashmap
|
||||
// Assemble the parameters as a hashmap
|
||||
var paramObject = Object.create(null);
|
||||
var count = 0;
|
||||
// Add names/values pairs if present
|
||||
if(this.actionNames && this.actionValues) {
|
||||
var names = this.wiki.filterTiddlers(this.actionNames,this),
|
||||
values = this.wiki.filterTiddlers(this.actionValues,this);
|
||||
$tw.utils.each(names,function(name,index) {
|
||||
paramObject[name] = values[index] || "";
|
||||
});
|
||||
}
|
||||
// Add raw parameters
|
||||
$tw.utils.each(this.attributes,function(attribute,name) {
|
||||
if(name.charAt(0) !== "$") {
|
||||
paramObject[name] = attribute;
|
||||
count++;
|
||||
}
|
||||
});
|
||||
// Add name/value pair if present
|
||||
@@ -73,14 +82,15 @@ SendMessageWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
paramObject[this.actionName] = this.actionValue;
|
||||
}
|
||||
// Dispatch the message
|
||||
this.dispatchEvent({
|
||||
var params = {
|
||||
type: this.actionMessage,
|
||||
param: param,
|
||||
paramObject: paramObject,
|
||||
event: event,
|
||||
tiddlerTitle: this.getVariable("currentTiddler"),
|
||||
navigateFromTitle: this.getVariable("storyTiddler"),
|
||||
event: event
|
||||
});
|
||||
navigateFromTitle: this.getVariable("storyTiddler")
|
||||
};
|
||||
this.dispatchEvent(params);
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
|
||||
86
core/modules/widgets/action-setmultiplefields.js
Normal file
86
core/modules/widgets/action-setmultiplefields.js
Normal file
@@ -0,0 +1,86 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/action-setmultiplefields.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Action widget to set multiple fields or indexes on a tiddler
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var SetMultipleFieldsWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
SetMultipleFieldsWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
SetMultipleFieldsWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
SetMultipleFieldsWidget.prototype.execute = function() {
|
||||
this.actionTiddler = this.getAttribute("$tiddler",this.getVariable("currentTiddler"));
|
||||
this.actionFields = this.getAttribute("$fields");
|
||||
this.actionIndexes = this.getAttribute("$indexes");
|
||||
this.actionValues = this.getAttribute("$values");
|
||||
this.actionTimestamp = this.getAttribute("$timestamp","yes") === "yes";
|
||||
};
|
||||
|
||||
/*
|
||||
Refresh the widget by ensuring our attributes are up to date
|
||||
*/
|
||||
SetMultipleFieldsWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes["$tiddler"] || changedAttributes["$fields"] || changedAttributes["$indexes"] || changedAttributes["$values"] || changedAttributes["$timestamp"]) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
/*
|
||||
Invoke the action associated with this widget
|
||||
*/
|
||||
SetMultipleFieldsWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
var tiddler = this.wiki.getTiddler(this.actionTiddler),
|
||||
names, values = this.wiki.filterTiddlers(this.actionValues,this);
|
||||
if(this.actionFields) {
|
||||
var additions = {};
|
||||
names = this.wiki.filterTiddlers(this.actionFields,this);
|
||||
$tw.utils.each(names,function(fieldname,index) {
|
||||
additions[fieldname] = values[index] || "";
|
||||
});
|
||||
var creationFields = this.actionTimestamp ? this.wiki.getCreationFields() : undefined,
|
||||
modificationFields = this.actionTimestamp ? this.wiki.getModificationFields() : undefined;
|
||||
this.wiki.addTiddler(new $tw.Tiddler(creationFields,tiddler,{title: this.actionTiddler},modificationFields,additions));
|
||||
} else if(this.actionIndexes) {
|
||||
var data = this.wiki.getTiddlerData(this.actionTiddler,Object.create(null));
|
||||
names = this.wiki.filterTiddlers(this.actionIndexes,this);
|
||||
$tw.utils.each(names,function(name,index) {
|
||||
data[name] = values[index] || "";
|
||||
});
|
||||
this.wiki.setTiddlerData(this.actionTiddler,data,{},{suppressTimestamp: !this.actionTimestamp});
|
||||
}
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
exports["action-setmultiplefields"] = SetMultipleFieldsWidget;
|
||||
|
||||
})();
|
||||
|
||||
@@ -52,7 +52,13 @@ CodeBlockWidget.prototype.execute = function() {
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
CodeBlockWidget.prototype.refresh = function(changedTiddlers) {
|
||||
return false;
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.code || changedAttributes.language) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
exports.codeblock = CodeBlockWidget;
|
||||
|
||||
@@ -54,6 +54,7 @@ DraggableWidget.prototype.render = function(parent,nextSibling) {
|
||||
dragFilterFn: function() {return self.getAttribute("filter");},
|
||||
startActions: self.startActions,
|
||||
endActions: self.endActions,
|
||||
dragImageType: self.dragImageType,
|
||||
widget: this
|
||||
});
|
||||
// Insert the link into the DOM and render any children
|
||||
@@ -71,6 +72,7 @@ DraggableWidget.prototype.execute = function() {
|
||||
this.draggableClasses = this.getAttribute("class");
|
||||
this.startActions = this.getAttribute("startactions");
|
||||
this.endActions = this.getAttribute("endactions");
|
||||
this.dragImageType = this.getAttribute("dragimagetype");
|
||||
// Make the child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
@@ -198,7 +198,8 @@ DropZoneWidget.prototype.handleDropEvent = function(event) {
|
||||
this.resetState();
|
||||
// Import any files in the drop
|
||||
var numFiles = 0;
|
||||
if(dataTransfer.files) {
|
||||
// If we have type text/vnd.tiddlywiki then skip trying to import files
|
||||
if(dataTransfer.files && !$tw.utils.dragEventContainsType(event,"text/vnd.tiddler")) {
|
||||
numFiles = this.wiki.readFiles(dataTransfer.files,{
|
||||
callback: readFileCallback,
|
||||
deserializer: this.dropzoneDeserializer
|
||||
|
||||
@@ -46,7 +46,7 @@ EventWidget.prototype.render = function(parent,nextSibling) {
|
||||
$tw.utils.each(this.types,function(type) {
|
||||
domNode.addEventListener(type,function(event) {
|
||||
var selector = self.getAttribute("selector"),
|
||||
actions = self.getAttribute("actions-"+type),
|
||||
actions = self.getAttribute("$"+type) || self.getAttribute("actions-"+type),
|
||||
stopPropagation = self.getAttribute("stopPropagation","onaction"),
|
||||
selectedNode = event.target,
|
||||
selectedNodeRect,
|
||||
@@ -76,16 +76,22 @@ EventWidget.prototype.render = function(parent,nextSibling) {
|
||||
variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString();
|
||||
variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString();
|
||||
variables["tv-selectednode-height"] = selectedNode.offsetHeight.toString();
|
||||
|
||||
if(event.clientX && event.clientY) {
|
||||
//Add variables for event X and Y position relative to selected node
|
||||
selectedNodeRect = selectedNode.getBoundingClientRect();
|
||||
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
|
||||
variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();
|
||||
|
||||
//Add variables for event X and Y position relative to selected node
|
||||
selectedNodeRect = selectedNode.getBoundingClientRect();
|
||||
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
|
||||
variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();
|
||||
//Add variables for event X and Y position relative to event catcher node
|
||||
catcherNodeRect = self.domNode.getBoundingClientRect();
|
||||
variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
|
||||
variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
|
||||
|
||||
//Add variables for event X and Y position relative to event catcher node
|
||||
catcherNodeRect = self.domNode.getBoundingClientRect();
|
||||
variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
|
||||
variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
|
||||
//Add variables for event X and Y position relative to the viewport
|
||||
variables["event-fromviewport-posx"] = event.clientX.toString();
|
||||
variables["event-fromviewport-posy"] = event.clientY.toString();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
@@ -135,7 +141,15 @@ Compute the internal state of the widget
|
||||
EventWidget.prototype.execute = function() {
|
||||
var self = this;
|
||||
// Get attributes that require a refresh on change
|
||||
this.types = this.getAttribute("events","").split(" ");
|
||||
this.types = [];
|
||||
$tw.utils.each(this.attributes,function(value,key) {
|
||||
if(key.charAt(0) === "$") {
|
||||
self.types.push(key.slice(1));
|
||||
}
|
||||
});
|
||||
if(!this.types.length) {
|
||||
this.types = this.getAttribute("events","").split(" ");
|
||||
}
|
||||
this.elementTag = this.getAttribute("tag");
|
||||
// Make child widgets
|
||||
this.makeChildWidgets();
|
||||
@@ -151,12 +165,13 @@ EventWidget.prototype.assignDomNodeClasses = function() {
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
EventWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes["events"] || changedAttributes["tag"]) {
|
||||
var changedAttributes = this.computeAttributes(),
|
||||
changedAttributesCount = $tw.utils.count(changedAttributes);
|
||||
if(changedAttributesCount === 1 && changedAttributes["class"]) {
|
||||
this.assignDomNodeClasses();
|
||||
} else if(changedAttributesCount > 0) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else if(changedAttributes["class"]) {
|
||||
this.assignDomNodeClasses();
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
@@ -73,26 +73,12 @@ FieldManglerWidget.prototype.handleRemoveFieldEvent = function(event) {
|
||||
FieldManglerWidget.prototype.handleAddFieldEvent = function(event) {
|
||||
var tiddler = this.wiki.getTiddler(this.mangleTitle),
|
||||
addition = this.wiki.getModificationFields(),
|
||||
hadInvalidFieldName = false,
|
||||
addField = function(name,value) {
|
||||
var trimmedName = name.toLowerCase().trim();
|
||||
if(!$tw.utils.isValidFieldName(trimmedName)) {
|
||||
if(!hadInvalidFieldName) {
|
||||
alert($tw.language.getString(
|
||||
"InvalidFieldName",
|
||||
{variables:
|
||||
{fieldName: trimmedName}
|
||||
}
|
||||
));
|
||||
hadInvalidFieldName = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if(!value && tiddler) {
|
||||
value = tiddler.fields[trimmedName];
|
||||
}
|
||||
addition[trimmedName] = value || "";
|
||||
var trimmedName = name.trim();
|
||||
if(!value && tiddler) {
|
||||
value = tiddler.fields[trimmedName];
|
||||
}
|
||||
addition[trimmedName] = value || "";
|
||||
return;
|
||||
};
|
||||
addition.title = this.mangleTitle;
|
||||
|
||||
@@ -111,6 +111,16 @@ ImageWidget.prototype.render = function(parent,nextSibling) {
|
||||
if(this.imageAlt) {
|
||||
domNode.setAttribute("alt",this.imageAlt);
|
||||
}
|
||||
// Add classes when the image loads or fails
|
||||
$tw.utils.addClass(domNode,"tc-image-loading");
|
||||
domNode.addEventListener("load",function() {
|
||||
$tw.utils.removeClass(domNode,"tc-image-loading");
|
||||
$tw.utils.addClass(domNode,"tc-image-loaded");
|
||||
},false);
|
||||
domNode.addEventListener("error",function() {
|
||||
$tw.utils.removeClass(domNode,"tc-image-loading");
|
||||
$tw.utils.addClass(domNode,"tc-image-error");
|
||||
},false);
|
||||
// Insert element
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.domNodes.push(domNode);
|
||||
|
||||
@@ -46,7 +46,7 @@ ImportVariablesWidget.prototype.execute = function(tiddlerList) {
|
||||
this.tiddlerList = tiddlerList || this.wiki.filterTiddlers(this.filter,this);
|
||||
// Accumulate the <$set> widgets from each tiddler
|
||||
$tw.utils.each(this.tiddlerList,function(title) {
|
||||
var parser = widgetPointer.wiki.parseTiddler(title);
|
||||
var parser = widgetPointer.wiki.parseTiddler(title,{parseAsInline:true});
|
||||
if(parser) {
|
||||
var parseTreeNode = parser.tree[0];
|
||||
while(parseTreeNode && parseTreeNode.type === "set") {
|
||||
|
||||
91
core/modules/widgets/jsontiddler.js
Normal file
91
core/modules/widgets/jsontiddler.js
Normal file
@@ -0,0 +1,91 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/jsontiddler.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Render a tiddler as JSON text
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var JSONTiddlerWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
JSONTiddlerWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
JSONTiddlerWidget.prototype.render = function(parent,nextSibling) {
|
||||
var self = this;
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
// Collect the fields from the optional base tiddler
|
||||
var fields = this.getTiddlerFields();
|
||||
// Add custom fields specified in attributes starting with $
|
||||
$tw.utils.each(this.attributes,function(attribute,name) {
|
||||
if(name.charAt(0) === "$") {
|
||||
fields[name.slice(1)] = attribute;
|
||||
}
|
||||
});
|
||||
// JSONify
|
||||
var json = JSON.stringify(fields);
|
||||
// Escape unsafe script characters
|
||||
if(this.attEscapeUnsafeScriptChars) {
|
||||
json = json.replace(/</g,"\\u003C");
|
||||
}
|
||||
// Update the DOM
|
||||
var textNode = this.document.createTextNode(json);
|
||||
parent.insertBefore(textNode,nextSibling);
|
||||
this.domNodes.push(textNode);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
JSONTiddlerWidget.prototype.execute = function() {
|
||||
this.attTiddler = this.getAttribute("tiddler");
|
||||
this.attExclude = this.getAttribute("exclude","");
|
||||
this.attEscapeUnsafeScriptChars = this.getAttribute("escapeUnsafeScriptChars","no") === "yes";
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
JSONTiddlerWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if($tw.utils.count(changedAttributes) > 0 || (this.attTiddler && changedTiddlers[this.attTiddler])) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
JSONTiddlerWidget.prototype.getTiddlerFields = function() {
|
||||
var fields = {};
|
||||
if(this.attTiddler) {
|
||||
var tiddler = this.wiki.getTiddler(this.attTiddler);
|
||||
if(tiddler) {
|
||||
fields = tiddler.getFieldStrings({exclude: this.attExclude.split(" ")});
|
||||
} else {
|
||||
fields = {title: this.attTiddler};
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
};
|
||||
|
||||
exports.jsontiddler = JSONTiddlerWidget;
|
||||
|
||||
})();
|
||||
@@ -40,9 +40,8 @@ KeyboardWidget.prototype.render = function(parent,nextSibling) {
|
||||
// Create element
|
||||
var domNode = this.document.createElement(tag);
|
||||
// Assign classes
|
||||
var classes = (this["class"] || "").split(" ");
|
||||
classes.push("tc-keyboard");
|
||||
domNode.className = classes.join(" ");
|
||||
this.domNode = domNode;
|
||||
this.assignDomNodeClasses();
|
||||
// Add a keyboard event handler
|
||||
$tw.utils.addEventListeners(domNode,[
|
||||
{name: "keydown", handlerObject: this, handlerMethod: "handleChangeEvent"}
|
||||
@@ -54,7 +53,8 @@ KeyboardWidget.prototype.render = function(parent,nextSibling) {
|
||||
};
|
||||
|
||||
KeyboardWidget.prototype.handleChangeEvent = function(event) {
|
||||
if($tw.keyboardManager.checkKeyDescriptors(event,this.keyInfoArray)) {
|
||||
var keyInfo = $tw.keyboardManager.getMatchingKeyDescriptor(event,this.keyInfoArray);
|
||||
if(keyInfo) {
|
||||
var handled = this.invokeActions(this,event);
|
||||
if(this.actions) {
|
||||
var variables = {
|
||||
@@ -62,6 +62,9 @@ KeyboardWidget.prototype.handleChangeEvent = function(event) {
|
||||
"event-code": event.code,
|
||||
"modifier": $tw.keyboardManager.getEventModifierKeyDescriptor(event)
|
||||
};
|
||||
if(keyInfo.keyDescriptor) {
|
||||
variables["event-key-descriptor"] = keyInfo.keyDescriptor;
|
||||
}
|
||||
this.invokeActionString(this.actions,this,event,variables);
|
||||
}
|
||||
this.dispatchMessage(event);
|
||||
@@ -90,7 +93,6 @@ KeyboardWidget.prototype.execute = function() {
|
||||
this.key = this.getAttribute("key","");
|
||||
this.tag = this.getAttribute("tag","");
|
||||
this.keyInfoArray = $tw.keyboardManager.parseKeyDescriptors(this.key);
|
||||
this["class"] = this.getAttribute("class","");
|
||||
if(this.key.substr(0,2) === "((" && this.key.substr(-2,2) === "))") {
|
||||
this.shortcutTiddlers = [];
|
||||
var name = this.key.substring(2,this.key.length -2);
|
||||
@@ -102,14 +104,22 @@ KeyboardWidget.prototype.execute = function() {
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
KeyboardWidget.prototype.assignDomNodeClasses = function() {
|
||||
var classes = this.getAttribute("class","").split(" ");
|
||||
classes.push("tc-keyboard");
|
||||
this.domNode.className = classes.join(" ");
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
KeyboardWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.message || changedAttributes.param || changedAttributes.key || changedAttributes["class"] || changedAttributes.tag) {
|
||||
if(changedAttributes.message || changedAttributes.param || changedAttributes.key || changedAttributes.tag) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else if(changedAttributes["class"]) {
|
||||
this.assignDomNodeClasses();
|
||||
}
|
||||
// Update the keyInfoArray if one of its shortcut-config-tiddlers has changed
|
||||
if(this.shortcutTiddlers && $tw.utils.hopArray(changedTiddlers,this.shortcutTiddlers)) {
|
||||
|
||||
96
core/modules/widgets/let.js
Normal file
96
core/modules/widgets/let.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/let.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
This widget allows defining multiple variables at once, while allowing
|
||||
the later variables to depend upon the earlier ones.
|
||||
|
||||
```
|
||||
\define helloworld() Hello world!
|
||||
<$let currentTiddler="target" value={{!!value}} currentTiddler="different">
|
||||
{{!!value}} will be different from <<value>>
|
||||
</$let>
|
||||
```
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var LetWidget = function(parseTreeNode,options) {
|
||||
// Initialise
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
LetWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
LetWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
this.renderChildren(parent,nextSibling);
|
||||
};
|
||||
|
||||
LetWidget.prototype.computeAttributes = function() {
|
||||
// Before computing attributes, we must make clear that none of the
|
||||
// existing attributes are staged for lookup, even on a refresh
|
||||
var changedAttributes = {},
|
||||
self = this;
|
||||
this.currentValueFor = Object.create(null);
|
||||
$tw.utils.each(this.parseTreeNode.orderedAttributes,function(attribute,index) {
|
||||
var value = self.computeAttribute(attribute),
|
||||
name = attribute.name;
|
||||
if(name.charAt(0) !== "$") {
|
||||
// Now that it's prepped, we're allowed to look this variable up
|
||||
// when defining later variables
|
||||
self.currentValueFor[name] = value;
|
||||
}
|
||||
});
|
||||
// Run through again, setting variables and looking for differences
|
||||
$tw.utils.each(this.currentValueFor,function(value,name) {
|
||||
if (self.attributes[name] !== value) {
|
||||
self.attributes[name] = value;
|
||||
self.setVariable(name,value);
|
||||
changedAttributes[name] = true;
|
||||
}
|
||||
});
|
||||
return changedAttributes;
|
||||
};
|
||||
|
||||
LetWidget.prototype.getVariableInfo = function(name,options) {
|
||||
// Special handling: If this variable exists in this very $let, we can
|
||||
// use it, but only if it's been staged.
|
||||
if ($tw.utils.hop(this.currentValueFor,name)) {
|
||||
return {
|
||||
text: this.currentValueFor[name]
|
||||
};
|
||||
}
|
||||
return Widget.prototype.getVariableInfo.call(this,name,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Refresh the widget by ensuring our attributes are up to date
|
||||
*/
|
||||
LetWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if($tw.utils.count(changedAttributes) > 0) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
exports["let"] = LetWidget;
|
||||
|
||||
})();
|
||||
@@ -154,6 +154,12 @@ LinkWidget.prototype.handleClickEvent = function(event) {
|
||||
navigateFromNode: this,
|
||||
navigateFromClientRect: { top: bounds.top, left: bounds.left, width: bounds.width, right: bounds.right, bottom: bounds.bottom, height: bounds.height
|
||||
},
|
||||
navigateFromClientTop: bounds.top,
|
||||
navigateFromClientLeft: bounds.left,
|
||||
navigateFromClientWidth: bounds.width,
|
||||
navigateFromClientRight: bounds.right,
|
||||
navigateFromClientBottom: bounds.bottom,
|
||||
navigateFromClientHeight: bounds.height,
|
||||
navigateSuppressNavigation: event.metaKey || event.ctrlKey || (event.button === 1),
|
||||
metaKey: event.metaKey,
|
||||
ctrlKey: event.ctrlKey,
|
||||
@@ -201,7 +207,8 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
LinkWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.to || changedTiddlers[this.to] || changedAttributes["aria-label"] || changedAttributes.tooltip) {
|
||||
if(changedAttributes.to || changedTiddlers[this.to] || changedAttributes["aria-label"] || changedAttributes.tooltip ||
|
||||
changedAttributes["class"] || changedAttributes.tabindex || changedAttributes.draggable || changedAttributes.tag) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,9 @@ ListWidget.prototype.render = function(parent,nextSibling) {
|
||||
} else {
|
||||
this.storyview = null;
|
||||
}
|
||||
if(this.storyview && this.storyview.renderEnd) {
|
||||
this.storyview.renderEnd();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -236,6 +239,11 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
|
||||
hasRefreshed = hasRefreshed || refreshed;
|
||||
}
|
||||
}
|
||||
// If there are items to remove and we have not refreshed then recreate the item that will now be at the last position
|
||||
if(!hasRefreshed && this.children.length > this.list.length) {
|
||||
this.removeListItem(this.list.length-1);
|
||||
this.insertListItem(this.list.length-1,this.list[this.list.length-1]);
|
||||
}
|
||||
} else {
|
||||
// Cycle through the list, inserting and removing list items as needed
|
||||
for(t=0; t<this.list.length; t++) {
|
||||
|
||||
@@ -33,12 +33,54 @@ MessageCatcherWidget.prototype.render = function(parent,nextSibling) {
|
||||
// Compute attributes and execute state
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
// Add our message handler
|
||||
if(this.messageType) {
|
||||
this.addEventListeners([
|
||||
{type: this.messageType, handler: "handleEvent"}
|
||||
]);
|
||||
// Helper to add an event handler
|
||||
var addEventHandler = function(type,actions) {
|
||||
if(type && actions) {
|
||||
var isActionStringExecuting = false;
|
||||
self.addEventListener(
|
||||
type,
|
||||
function(event) {
|
||||
// Don't trap the event if it came from one of our action handlers
|
||||
if(isActionStringExecuting) {
|
||||
return true;
|
||||
}
|
||||
// Collect all the event properties into variables
|
||||
var collectProps = function(obj,prefix) {
|
||||
prefix = prefix || "";
|
||||
var props = {},
|
||||
names = [];
|
||||
$tw.utils.each(obj,function(value,name) {
|
||||
if(["string","boolean","number"].indexOf(typeof value) !== -1) {
|
||||
names.push(name);
|
||||
props[prefix + "-" + name] = value.toString();
|
||||
}
|
||||
});
|
||||
props["list-" + prefix] = $tw.utils.stringifyList(names);
|
||||
return props;
|
||||
};
|
||||
var variables = $tw.utils.extend(
|
||||
{},
|
||||
collectProps(event.paramObject,"event-paramObject"),
|
||||
collectProps(event,"event"),
|
||||
{
|
||||
modifier: $tw.keyboardManager.getEventModifierKeyDescriptor(event)
|
||||
});
|
||||
isActionStringExecuting = true;
|
||||
self.invokeActionString(actions,self,event,variables);
|
||||
isActionStringExecuting = false;
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
// Add the main event handler
|
||||
addEventHandler(this.getAttribute("type"),this.getAttribute("actions"));
|
||||
// Add any other event handlers
|
||||
$tw.utils.each(this.attributes,function(value,key) {
|
||||
if(key.charAt(0) === "$") {
|
||||
addEventHandler(key.slice(1),value);
|
||||
}
|
||||
});
|
||||
// Render children
|
||||
this.renderChildren(parent,null);
|
||||
};
|
||||
@@ -47,48 +89,16 @@ MessageCatcherWidget.prototype.render = function(parent,nextSibling) {
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
MessageCatcherWidget.prototype.execute = function() {
|
||||
var self = this;
|
||||
// Get attributes that require a refresh on change
|
||||
this.messageType = this.getAttribute("type");
|
||||
this.messageActions = this.getAttribute("actions");
|
||||
// Make child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
/*
|
||||
Handle an event
|
||||
*/
|
||||
MessageCatcherWidget.prototype.handleEvent = function(event) {
|
||||
if(this.messageActions) {
|
||||
// Collect all the event properties into variables
|
||||
var collectProps = function(obj,prefix) {
|
||||
prefix = prefix || "";
|
||||
var props = {};
|
||||
$tw.utils.each(obj,function(value,name) {
|
||||
if(["string","boolean","number"].indexOf(typeof value) !== -1) {
|
||||
props[prefix + name] = value.toString();
|
||||
}
|
||||
});
|
||||
return props;
|
||||
};
|
||||
var variables = $tw.utils.extend(
|
||||
{},
|
||||
collectProps(event.paramObject,"event-paramObject-"),
|
||||
collectProps(event,"event-"),
|
||||
{
|
||||
modifier: $tw.keyboardManager.getEventModifierKeyDescriptor(event)
|
||||
});
|
||||
this.invokeActionString(this.messageActions,this,event,variables);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
MessageCatcherWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes["type"]) {
|
||||
if($tw.utils.count(changedAttributes) > 0) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -44,8 +44,7 @@ NavigatorWidget.prototype.render = function(parent,nextSibling) {
|
||||
{type: "tm-fold-tiddler", handler: "handleFoldTiddlerEvent"},
|
||||
{type: "tm-fold-other-tiddlers", handler: "handleFoldOtherTiddlersEvent"},
|
||||
{type: "tm-fold-all-tiddlers", handler: "handleFoldAllTiddlersEvent"},
|
||||
{type: "tm-unfold-all-tiddlers", handler: "handleUnfoldAllTiddlersEvent"},
|
||||
{type: "tm-rename-tiddler", handler: "handleRenameTiddlerEvent"}
|
||||
{type: "tm-unfold-all-tiddlers", handler: "handleUnfoldAllTiddlersEvent"}
|
||||
]);
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
@@ -160,6 +159,7 @@ NavigatorWidget.prototype.handleNavigateEvent = function(event) {
|
||||
|
||||
// Close a specified tiddler
|
||||
NavigatorWidget.prototype.handleCloseTiddlerEvent = function(event) {
|
||||
event = $tw.hooks.invokeHook("th-closing-tiddler",event);
|
||||
var title = event.param || event.tiddlerTitle,
|
||||
storyList = this.getStoryList();
|
||||
// Look for tiddlers with this title to close
|
||||
@@ -183,7 +183,8 @@ NavigatorWidget.prototype.handleCloseOtherTiddlersEvent = function(event) {
|
||||
|
||||
// Place a tiddler in edit mode
|
||||
NavigatorWidget.prototype.handleEditTiddlerEvent = function(event) {
|
||||
var editTiddler = $tw.hooks.invokeHook("th-editing-tiddler",event);
|
||||
var editTiddler = $tw.hooks.invokeHook("th-editing-tiddler",event),
|
||||
win = event.event && event.event.view ? event.event.view : window;
|
||||
if(!editTiddler) {
|
||||
return false;
|
||||
}
|
||||
@@ -192,7 +193,7 @@ NavigatorWidget.prototype.handleEditTiddlerEvent = function(event) {
|
||||
return self.wiki.isShadowTiddler(title) && !self.wiki.tiddlerExists(title);
|
||||
}
|
||||
function confirmEditShadow(title) {
|
||||
return confirm($tw.language.getString(
|
||||
return win.confirm($tw.language.getString(
|
||||
"ConfirmEditShadowTiddler",
|
||||
{variables:
|
||||
{title: title}
|
||||
@@ -225,7 +226,8 @@ NavigatorWidget.prototype.handleDeleteTiddlerEvent = function(event) {
|
||||
storyList = this.getStoryList(),
|
||||
originalTitle = tiddler ? tiddler.fields["draft.of"] : "",
|
||||
originalTiddler = originalTitle ? this.wiki.getTiddler(originalTitle) : undefined,
|
||||
confirmationTitle;
|
||||
confirmationTitle,
|
||||
win = event.event && event.event.view ? event.event.view : window;
|
||||
if(!tiddler) {
|
||||
return false;
|
||||
}
|
||||
@@ -238,7 +240,7 @@ NavigatorWidget.prototype.handleDeleteTiddlerEvent = function(event) {
|
||||
confirmationTitle = title;
|
||||
}
|
||||
// Seek confirmation
|
||||
if((this.wiki.getTiddler(originalTitle) || (tiddler.fields.text || "") !== "") && !confirm($tw.language.getString(
|
||||
if((this.wiki.getTiddler(originalTitle) || (tiddler.fields.text || "") !== "") && !win.confirm($tw.language.getString(
|
||||
"ConfirmDeleteTiddler",
|
||||
{variables:
|
||||
{title: confirmationTitle}
|
||||
@@ -304,7 +306,8 @@ NavigatorWidget.prototype.generateDraftTitle = function(title) {
|
||||
NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) {
|
||||
var title = event.param || event.tiddlerTitle,
|
||||
tiddler = this.wiki.getTiddler(title),
|
||||
storyList = this.getStoryList();
|
||||
storyList = this.getStoryList(),
|
||||
win = event.event && event.event.view ? event.event.view : window;
|
||||
// Replace the original tiddler with the draft
|
||||
if(tiddler) {
|
||||
var draftTitle = (tiddler.fields["draft.title"] || "").trim(),
|
||||
@@ -313,7 +316,7 @@ NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) {
|
||||
var isRename = draftOf !== draftTitle,
|
||||
isConfirmed = true;
|
||||
if(isRename && this.wiki.tiddlerExists(draftTitle)) {
|
||||
isConfirmed = confirm($tw.language.getString(
|
||||
isConfirmed = win.confirm($tw.language.getString(
|
||||
"ConfirmOverwriteTiddler",
|
||||
{variables:
|
||||
{title: draftTitle}
|
||||
@@ -362,6 +365,7 @@ NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) {
|
||||
// Take a tiddler out of edit mode without saving the changes
|
||||
NavigatorWidget.prototype.handleCancelTiddlerEvent = function(event) {
|
||||
event = $tw.hooks.invokeHook("th-cancelling-tiddler", event);
|
||||
var win = event.event && event.event.view ? event.event.view : window;
|
||||
// Flip the specified tiddler from draft back to the original
|
||||
var draftTitle = event.param || event.tiddlerTitle,
|
||||
draftTiddler = this.wiki.getTiddler(draftTitle),
|
||||
@@ -372,7 +376,7 @@ NavigatorWidget.prototype.handleCancelTiddlerEvent = function(event) {
|
||||
originalTiddler = this.wiki.getTiddler(originalTitle),
|
||||
storyList = this.getStoryList();
|
||||
if(this.wiki.isDraftModified(draftTitle)) {
|
||||
isConfirmed = confirm($tw.language.getString(
|
||||
isConfirmed = win.confirm($tw.language.getString(
|
||||
"ConfirmCancelTiddler",
|
||||
{variables:
|
||||
{title: draftTitle}
|
||||
@@ -631,16 +635,6 @@ NavigatorWidget.prototype.handleUnfoldAllTiddlersEvent = function(event) {
|
||||
});
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.handleRenameTiddlerEvent = function(event) {
|
||||
var options = {},
|
||||
paramObject = event.paramObject || {},
|
||||
from = paramObject.from || event.tiddlerTitle,
|
||||
to = paramObject.to;
|
||||
options.dontRenameInTags = (paramObject.renameInTags === "false" || paramObject.renameInTags === "no") ? true : false;
|
||||
options.dontRenameInLists = (paramObject.renameInLists === "false" || paramObject.renameInLists === "no") ? true : false;
|
||||
this.wiki.renameTiddler(from,to,options);
|
||||
};
|
||||
|
||||
exports.navigator = NavigatorWidget;
|
||||
|
||||
})();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user