mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-23 03:14:40 +00:00
Compare commits
614 Commits
single-tid
...
v5.1.23
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac8f521303 | ||
|
|
2ab5fd9abb | ||
|
|
f6339d437e | ||
|
|
8e61e37f2b | ||
|
|
2632ed0078 | ||
|
|
7cb6dc0e4f | ||
|
|
8620b77b45 | ||
|
|
03ad396db1 | ||
|
|
9e70e89a84 | ||
|
|
2f8a100bab | ||
|
|
a9a36b641a | ||
|
|
625c3de6f7 | ||
|
|
ddda9a34ae | ||
|
|
c0a56e790d | ||
|
|
dc83ee411d | ||
|
|
3c003364d2 | ||
|
|
1e9cc2b747 | ||
|
|
f968130696 | ||
|
|
e046d5ad76 | ||
|
|
3c3cd4673e | ||
|
|
d50f6b406e | ||
|
|
c1a1e272cc | ||
|
|
81947edd5c | ||
|
|
88e29b4558 | ||
|
|
8798ebadbd | ||
|
|
a17fa35c28 | ||
|
|
0911d99813 | ||
|
|
93309b0b7d | ||
|
|
c0dd13d446 | ||
|
|
ae61b08ae5 | ||
|
|
f60d0ef109 | ||
|
|
6ca89304a1 | ||
|
|
78c2beb640 | ||
|
|
e34a88e3e4 | ||
|
|
0d2b6cf837 | ||
|
|
1af1f6621a | ||
|
|
50d8325d4c | ||
|
|
3016b3d094 | ||
|
|
da5d12d6fb | ||
|
|
cd5d9bd5b9 | ||
|
|
1e1aeefd93 | ||
|
|
1d7091e637 | ||
|
|
4334de88a0 | ||
|
|
bb6d41f3dd | ||
|
|
a878d82c7a | ||
|
|
85ff47366c | ||
|
|
ce5d20b8fc | ||
|
|
2c76cfa67a | ||
|
|
90f05295a2 | ||
|
|
5df0225356 | ||
|
|
c3e34b469c | ||
|
|
e8815b79ff | ||
|
|
958f57f2c0 | ||
|
|
43a3228200 | ||
|
|
96d4f87e78 | ||
|
|
a8c1e6a3bd | ||
|
|
36fe519eff | ||
|
|
b2d270a7e8 | ||
|
|
005f7c55b6 | ||
|
|
122306fc24 | ||
|
|
0b1a05d10d | ||
|
|
b0f6d50b60 | ||
|
|
a3a7d6450d | ||
|
|
a857b4ab9a | ||
|
|
c4dcf510ef | ||
|
|
7fd24de372 | ||
|
|
396703c478 | ||
|
|
bfc4b447da | ||
|
|
d957b3e4e6 | ||
|
|
f798eab33f | ||
|
|
fbe5bb229a | ||
|
|
ae5d78b4dd | ||
|
|
9825b5b4a0 | ||
|
|
8799911162 | ||
|
|
813e28e1ea | ||
|
|
911e23ee6d | ||
|
|
046746ba20 | ||
|
|
8ffe138942 | ||
|
|
15be409c42 | ||
|
|
c92f9dd404 | ||
|
|
2bbcc94b4d | ||
|
|
1f5e1205ec | ||
|
|
6b03105bed | ||
|
|
9d5babc248 | ||
|
|
e620aaed80 | ||
|
|
552843369c | ||
|
|
f0eba7fdc6 | ||
|
|
9871c1a6a9 | ||
|
|
a1ef66ec6d | ||
|
|
fc797f3722 | ||
|
|
c6bb783308 | ||
|
|
c3055f92a9 | ||
|
|
4079f72310 | ||
|
|
cc1f32067f | ||
|
|
880930da8b | ||
|
|
68cb08749f | ||
|
|
13b69a9c10 | ||
|
|
b63049b4df | ||
|
|
6a91dbfe2f | ||
|
|
dde4182830 | ||
|
|
abe9af1369 | ||
|
|
6f09a5ee65 | ||
|
|
706fc3e06e | ||
|
|
6a319940d3 | ||
|
|
fe8606759e | ||
|
|
1de747b182 | ||
|
|
3406b98af6 | ||
|
|
80191903b6 | ||
|
|
367854c81b | ||
|
|
4f13848ca2 | ||
|
|
fd3e77d38f | ||
|
|
8fc6910c03 | ||
|
|
4623c45d29 | ||
|
|
5cbe4c5317 | ||
|
|
4d9e6831bb | ||
|
|
5887c6621e | ||
|
|
ce937595d7 | ||
|
|
cc850d7151 | ||
|
|
a21428a33a | ||
|
|
12bb938463 | ||
|
|
e54f3368e9 | ||
|
|
eb7f59a855 | ||
|
|
b3cbd7d733 | ||
|
|
28724138d1 | ||
|
|
62a2a0e579 | ||
|
|
98e60758a9 | ||
|
|
c655ec5469 | ||
|
|
7d2703bffb | ||
|
|
09d7a77f1b | ||
|
|
8005c91e79 | ||
|
|
86a9f922bf | ||
|
|
2175be27b0 | ||
|
|
9637a29e55 | ||
|
|
8320a55fef | ||
|
|
2267e31546 | ||
|
|
e3bf1f43cf | ||
|
|
64ac29adca | ||
|
|
94ffb50e04 | ||
|
|
3e3f185562 | ||
|
|
6c98bb706a | ||
|
|
4f88d79d8b | ||
|
|
0e247c991d | ||
|
|
ce27492b96 | ||
|
|
a9d583b85e | ||
|
|
5769cf9784 | ||
|
|
c854e518fa | ||
|
|
7327a3fb92 | ||
|
|
50a3c5526f | ||
|
|
77971ff720 | ||
|
|
e0f4d82214 | ||
|
|
af72fdf245 | ||
|
|
519962b4a9 | ||
|
|
c9a77c5877 | ||
|
|
3d93790573 | ||
|
|
cb62c8c96d | ||
|
|
aa6f152d35 | ||
|
|
72b32946aa | ||
|
|
60850ee69b | ||
|
|
8c4d67ba2b | ||
|
|
3c195b05cb | ||
|
|
530b4308e3 | ||
|
|
fa63ac5d1e | ||
|
|
51ca14861e | ||
|
|
d2f87d6200 | ||
|
|
a0f145197c | ||
|
|
c97003238b | ||
|
|
4f07539164 | ||
|
|
5945506169 | ||
|
|
483fd941f5 | ||
|
|
1339c23b3a | ||
|
|
89541edcff | ||
|
|
fd14e94610 | ||
|
|
f591a78f37 | ||
|
|
e2bea854b6 | ||
|
|
0d434583ec | ||
|
|
a81b7fc9f4 | ||
|
|
da66323dc5 | ||
|
|
0be778fc27 | ||
|
|
37f4421ed1 | ||
|
|
f61906501d | ||
|
|
1a8c6fdc4b | ||
|
|
6f8dca956b | ||
|
|
061b75741b | ||
|
|
d181b96518 | ||
|
|
527638d5e6 | ||
|
|
b95f9e6000 | ||
|
|
6d5ea90bfd | ||
|
|
eae3da0e9d | ||
|
|
684f13fbcb | ||
|
|
8cd13e2f89 | ||
|
|
3b75297168 | ||
|
|
2b60ab1fdc | ||
|
|
d6e055368d | ||
|
|
fc1721709a | ||
|
|
43061e64a6 | ||
|
|
d8d88c67e3 | ||
|
|
ffd6a8cce7 | ||
|
|
a637f7fb60 | ||
|
|
ca4cdc81dd | ||
|
|
13499557bf | ||
|
|
a2b2e117e3 | ||
|
|
d9b8a800c6 | ||
|
|
2aa6e761fd | ||
|
|
7078ca2c1e | ||
|
|
04bf6e0fd8 | ||
|
|
bb6fee4e1c | ||
|
|
f087a62c99 | ||
|
|
1b31c25ea7 | ||
|
|
02a956b1bb | ||
|
|
cc3462999b | ||
|
|
b63c90e401 | ||
|
|
497b334d60 | ||
|
|
fa373a1c6f | ||
|
|
1eac5c051f | ||
|
|
568990409a | ||
|
|
09f7ad84b2 | ||
|
|
445c15e719 | ||
|
|
27bed615ab | ||
|
|
1ec8b7877e | ||
|
|
59c6f4447e | ||
|
|
343207fc35 | ||
|
|
519ce3e89d | ||
|
|
71194d8767 | ||
|
|
480e4e2ce9 | ||
|
|
db48ce5f2c | ||
|
|
4d85d267a1 | ||
|
|
98f67373b1 | ||
|
|
e574cb4724 | ||
|
|
e72d90c227 | ||
|
|
c729115506 | ||
|
|
9854a4fc08 | ||
|
|
9fe4c4889a | ||
|
|
750f56a235 | ||
|
|
66636d1a86 | ||
|
|
2a7cdb22c0 | ||
|
|
b69b84b38e | ||
|
|
ee250bf6c9 | ||
|
|
de69ab0d0e | ||
|
|
cf58dcf116 | ||
|
|
53922d3558 | ||
|
|
c41e34793d | ||
|
|
5aa4e4cb68 | ||
|
|
2b31c7a509 | ||
|
|
0bd866e2f9 | ||
|
|
93e7380188 | ||
|
|
9003c81039 | ||
|
|
900a29fbb3 | ||
|
|
b3d0303139 | ||
|
|
feefc4cceb | ||
|
|
d51975b183 | ||
|
|
15e8772170 | ||
|
|
bc5143f190 | ||
|
|
458460354e | ||
|
|
78c72b85fb | ||
|
|
22e25c05eb | ||
|
|
4394b8e723 | ||
|
|
d5c4aa250a | ||
|
|
70561bd481 | ||
|
|
2f5f0db00f | ||
|
|
4a6aa865b3 | ||
|
|
f29d24a1f5 | ||
|
|
2818f52f95 | ||
|
|
9453c4d684 | ||
|
|
42b965c9f0 | ||
|
|
e9a635dc81 | ||
|
|
26ade60e93 | ||
|
|
e7245a709c | ||
|
|
a6efc14a7c | ||
|
|
9fbcdeb29e | ||
|
|
ef1b7d619a | ||
|
|
ec70e5c179 | ||
|
|
4de0dc301b | ||
|
|
769ffa19b7 | ||
|
|
c0b021f509 | ||
|
|
635ec65d3f | ||
|
|
da06b64845 | ||
|
|
ecb3c86e7b | ||
|
|
c6cd4d33e6 | ||
|
|
77fe6244a2 | ||
|
|
f6e485b897 | ||
|
|
4b5d287c90 | ||
|
|
c01e9cef12 | ||
|
|
655501140b | ||
|
|
cae32d39a5 | ||
|
|
bc5609820f | ||
|
|
4914208011 | ||
|
|
b8fa6f0f0a | ||
|
|
9605d94b6c | ||
|
|
49b11bc493 | ||
|
|
9a4eb1e835 | ||
|
|
e71bf27dae | ||
|
|
c985fd63f9 | ||
|
|
f5ad5010bc | ||
|
|
12be7ac7e9 | ||
|
|
651619076a | ||
|
|
57ba4c8cba | ||
|
|
6a01ab20a0 | ||
|
|
81e3ab0bc5 | ||
|
|
e43ffe860b | ||
|
|
d0081a7247 | ||
|
|
972456ca07 | ||
|
|
9eec6ff915 | ||
|
|
c9efa23f02 | ||
|
|
3843c61132 | ||
|
|
f6938d6abb | ||
|
|
aa7a00d080 | ||
|
|
4c6de22711 | ||
|
|
83f976ea54 | ||
|
|
3153c588ec | ||
|
|
0ce1843070 | ||
|
|
15338e60e8 | ||
|
|
f7f55e8eff | ||
|
|
5cc1600072 | ||
|
|
1a91f81976 | ||
|
|
b9234fe238 | ||
|
|
4cdbe6540b | ||
|
|
4877891980 | ||
|
|
a1b486436e | ||
|
|
c3a8cc7eb4 | ||
|
|
707e9d8926 | ||
|
|
adf0c1a12a | ||
|
|
fd4cfaeb02 | ||
|
|
ae8ee5b955 | ||
|
|
7686be7b14 | ||
|
|
84479bc403 | ||
|
|
794dfb96f2 | ||
|
|
d254612826 | ||
|
|
c8721b38fd | ||
|
|
f863acf8ac | ||
|
|
7e7ecbe7a5 | ||
|
|
4ecd885a0c | ||
|
|
dbda09b9fc | ||
|
|
41931082e6 | ||
|
|
5af76c5ea1 | ||
|
|
1446a1e44c | ||
|
|
69c12618d9 | ||
|
|
651fb777ab | ||
|
|
34a51d2e23 | ||
|
|
2fc62c1a52 | ||
|
|
5ebd98779a | ||
|
|
14a28b7779 | ||
|
|
0027b990e4 | ||
|
|
9716c32695 | ||
|
|
f7a626fef2 | ||
|
|
f8961abb8a | ||
|
|
59f233cd46 | ||
|
|
ae13a0fee1 | ||
|
|
543f9107b6 | ||
|
|
5bf810408a | ||
|
|
405c618b6b | ||
|
|
4cd6a24431 | ||
|
|
773dcce713 | ||
|
|
d5cf4112fa | ||
|
|
72c07a3f81 | ||
|
|
bdaf3a4502 | ||
|
|
f7fe47914e | ||
|
|
0338f0fee2 | ||
|
|
843319ebb0 | ||
|
|
2374fb5104 | ||
|
|
31c9c23a18 | ||
|
|
af82a95a29 | ||
|
|
87dc67d0cd | ||
|
|
68b455565b | ||
|
|
c60402b06d | ||
|
|
422eb43e50 | ||
|
|
a78570c99a | ||
|
|
5202441769 | ||
|
|
ef29d05ea4 | ||
|
|
e332bb1728 | ||
|
|
14573d2c2d | ||
|
|
cbf79b8b90 | ||
|
|
ae604cd660 | ||
|
|
a206dccf0a | ||
|
|
c187f4b238 | ||
|
|
4eda601a32 | ||
|
|
4f376fba35 | ||
|
|
8bfd8f3a26 | ||
|
|
ba9de17b87 | ||
|
|
8497e5b95d | ||
|
|
918e52b37b | ||
|
|
b86bbf3fc4 | ||
|
|
7de8e1fc97 | ||
|
|
b16f5592fc | ||
|
|
48c6146ab6 | ||
|
|
485022797f | ||
|
|
7bd719f3f3 | ||
|
|
6645afcd15 | ||
|
|
05de5b4c49 | ||
|
|
259b45065a | ||
|
|
aa08210e44 | ||
|
|
a0509a5170 | ||
|
|
21f1c163d8 | ||
|
|
a2796d89ab | ||
|
|
c23eedd069 | ||
|
|
ccda938248 | ||
|
|
acd2cbf56a | ||
|
|
f74c49f393 | ||
|
|
8cf458d3b3 | ||
|
|
fca9879321 | ||
|
|
7e964e9501 | ||
|
|
89c0c6157b | ||
|
|
981e3bed45 | ||
|
|
17e2b208e8 | ||
|
|
bbdd12cffd | ||
|
|
dd79c096be | ||
|
|
9898e5e2db | ||
|
|
84b6a85293 | ||
|
|
7acb9a255b | ||
|
|
5a6e35b4b0 | ||
|
|
222821804e | ||
|
|
b32eb49d50 | ||
|
|
97d2af7ebd | ||
|
|
a9d79a1a84 | ||
|
|
792d285970 | ||
|
|
4de95a64c1 | ||
|
|
95e30138f0 | ||
|
|
484c9e986f | ||
|
|
00ff0d6fa0 | ||
|
|
a0bd93c596 | ||
|
|
d66725fd31 | ||
|
|
5b2048fad1 | ||
|
|
0d2df34c58 | ||
|
|
d505eeb269 | ||
|
|
a0db3abe99 | ||
|
|
bd2cf5c464 | ||
|
|
8b5a4faa07 | ||
|
|
4c39db1f54 | ||
|
|
c0f0aadf09 | ||
|
|
55109177ee | ||
|
|
2e39b5add5 | ||
|
|
4127ce8e9f | ||
|
|
6f4f38506e | ||
|
|
33ee650fb7 | ||
|
|
7f08025175 | ||
|
|
35a842ade6 | ||
|
|
d46872c061 | ||
|
|
64034f4977 | ||
|
|
4d2d6cc818 | ||
|
|
c57bdc46f4 | ||
|
|
4a84ed0018 | ||
|
|
3de6c95fd6 | ||
|
|
7911007973 | ||
|
|
24ef51df01 | ||
|
|
a689f31978 | ||
|
|
f760a2fa79 | ||
|
|
9a479a95ad | ||
|
|
7e1f5b8471 | ||
|
|
6265be01cd | ||
|
|
fc1877dcce | ||
|
|
5cda5c82e1 | ||
|
|
b8225f6993 | ||
|
|
1e221ddbdb | ||
|
|
09a2db1cff | ||
|
|
881aed879b | ||
|
|
2f55a8808c | ||
|
|
38e329edad | ||
|
|
d832cb93ce | ||
|
|
bbf20f8955 | ||
|
|
17a36726fa | ||
|
|
482f7a92ae | ||
|
|
b191ee9210 | ||
|
|
25f8b3f903 | ||
|
|
e3ad276dd0 | ||
|
|
1f1fd49d0b | ||
|
|
e01b354f7d | ||
|
|
84cd761c8c | ||
|
|
a947a6b6bc | ||
|
|
b0485eef6a | ||
|
|
5b9dbf7b95 | ||
|
|
d31d4621a4 | ||
|
|
d42b7f173b | ||
|
|
ceb2411794 | ||
|
|
cbff2fb692 | ||
|
|
e59f606566 | ||
|
|
042c8d8a69 | ||
|
|
d32fb6f900 | ||
|
|
2c24f30cdd | ||
|
|
954c9944ad | ||
|
|
41a7d98e17 | ||
|
|
75589d78d8 | ||
|
|
b0e40e8641 | ||
|
|
99a07f80f1 | ||
|
|
79ec21346d | ||
|
|
5d91c27980 | ||
|
|
72ff1a26fc | ||
|
|
1812cbbb7c | ||
|
|
3440f0f308 | ||
|
|
6570561d4e | ||
|
|
9c22537b4e | ||
|
|
84a4784dee | ||
|
|
5c0d91c510 | ||
|
|
d1441d29fd | ||
|
|
bf6735420d | ||
|
|
34181230c7 | ||
|
|
2eb11d9a2d | ||
|
|
4966f6ab62 | ||
|
|
33d973fb91 | ||
|
|
81f07cdf85 | ||
|
|
48dfadd85b | ||
|
|
71a827eead | ||
|
|
86640474b5 | ||
|
|
31c4fd586b | ||
|
|
33e9f88c73 | ||
|
|
b9d02b61b1 | ||
|
|
c9692d7a50 | ||
|
|
7ee9003df7 | ||
|
|
75d65d2694 | ||
|
|
6a0ff7db18 | ||
|
|
85fd43a38c | ||
|
|
1f354a972e | ||
|
|
5eee11beed | ||
|
|
9cd5415dfe | ||
|
|
7f01445903 | ||
|
|
13b8281f6b | ||
|
|
ad575efdcc | ||
|
|
685157266d | ||
|
|
619c0752bd | ||
|
|
bed76b9a32 | ||
|
|
2385bd978f | ||
|
|
1cc5c5e7f0 | ||
|
|
2a8f7a9c50 | ||
|
|
5f98e7d7b3 | ||
|
|
a4fb57bf15 | ||
|
|
cae937f107 | ||
|
|
77a929faa3 | ||
|
|
c86a621d5d | ||
|
|
3a20fb1e3a | ||
|
|
d6ee700bca | ||
|
|
c87f4a1e94 | ||
|
|
075321932a | ||
|
|
39d532a4a0 | ||
|
|
86d7564661 | ||
|
|
d579ce942c | ||
|
|
4efcad46f3 | ||
|
|
1546a4a189 | ||
|
|
2649d2f7dc | ||
|
|
154e886873 | ||
|
|
d9387cf4f8 | ||
|
|
5688670da6 | ||
|
|
678e25f510 | ||
|
|
15d7255728 | ||
|
|
05e6c1bf62 | ||
|
|
4ea79cb0c3 | ||
|
|
e71a27ac2d | ||
|
|
d897989965 | ||
|
|
90469679a5 | ||
|
|
00686fc002 | ||
|
|
1a6be5ae09 | ||
|
|
efb121e016 | ||
|
|
8dd13bdb20 | ||
|
|
28fe82feff | ||
|
|
74eb7e8031 | ||
|
|
22802b4be8 | ||
|
|
7cbe766bde | ||
|
|
f21d013241 | ||
|
|
de5b0062b5 | ||
|
|
2b6c87fb4b | ||
|
|
01226fbe90 | ||
|
|
2f3a95a0b8 | ||
|
|
6507397343 | ||
|
|
69e6da9f5c | ||
|
|
161643c5da | ||
|
|
1f313e8555 | ||
|
|
bc3e5cda9e | ||
|
|
7900412fd0 | ||
|
|
65347ae858 | ||
|
|
43fdb553b7 | ||
|
|
4873e9447a | ||
|
|
a8c55781fa | ||
|
|
9313d9427d | ||
|
|
5c3a19f298 | ||
|
|
69c8058b72 | ||
|
|
dc82365956 | ||
|
|
27ab7d81b7 | ||
|
|
0836fb7184 | ||
|
|
4146a04a9e | ||
|
|
84eaee8210 | ||
|
|
4bbc58dd24 | ||
|
|
4529123777 | ||
|
|
0d0698ea6e | ||
|
|
63dee16611 | ||
|
|
bd0b9d5f81 | ||
|
|
8310af068c | ||
|
|
4cc98e361c | ||
|
|
dc98432fa0 | ||
|
|
fd9938f2cc | ||
|
|
86296b67aa | ||
|
|
245dab0c8c | ||
|
|
7b53f5724c | ||
|
|
3733f8b4ae | ||
|
|
308ac8c5b0 | ||
|
|
bc8859b550 | ||
|
|
bdc5ac592f | ||
|
|
c80f580833 | ||
|
|
1ed36adab6 | ||
|
|
5393187f66 | ||
|
|
72159c5118 | ||
|
|
d2f2d7a11b | ||
|
|
de5bb823fa | ||
|
|
322c37d693 | ||
|
|
338cffd8c7 | ||
|
|
e8506813fe | ||
|
|
fa86a90ef8 | ||
|
|
291b1e2d33 | ||
|
|
9d4c05b6ce | ||
|
|
c7d8492842 | ||
|
|
d1b8cce6bf | ||
|
|
c259aea3bc | ||
|
|
59fd557067 | ||
|
|
06639850ba | ||
|
|
21565f635e | ||
|
|
cf46b6b0ff | ||
|
|
bd449a177b | ||
|
|
bbdebb27ce |
15
.eslintignore
Normal file
15
.eslintignore
Normal file
@@ -0,0 +1,15 @@
|
||||
# Known minified files
|
||||
/boot/sjcl.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
|
||||
267
.eslintrc.yml
Normal file
267
.eslintrc.yml
Normal file
@@ -0,0 +1,267 @@
|
||||
env:
|
||||
browser: true
|
||||
commonjs: true
|
||||
es2021: true
|
||||
node: true
|
||||
extends: 'eslint:recommended'
|
||||
globals:
|
||||
"$tw": "writable" # temporary
|
||||
parserOptions:
|
||||
ecmaVersion: 5
|
||||
rules:
|
||||
array-bracket-newline: 'off'
|
||||
array-bracket-spacing: 'off'
|
||||
array-callback-return: 'off'
|
||||
array-element-newline: 'off'
|
||||
arrow-body-style: error
|
||||
arrow-parens:
|
||||
- error
|
||||
- as-needed
|
||||
arrow-spacing:
|
||||
- error
|
||||
- after: true
|
||||
before: true
|
||||
block-scoped-var: 'off'
|
||||
block-spacing: 'off'
|
||||
brace-style: 'off'
|
||||
callback-return: 'off'
|
||||
camelcase: 'off'
|
||||
capitalized-comments: 'off'
|
||||
class-methods-use-this: error
|
||||
comma-dangle: 'off'
|
||||
comma-spacing: 'off'
|
||||
comma-style: 'off'
|
||||
complexity: 'off'
|
||||
computed-property-spacing: 'off'
|
||||
consistent-return: 'off'
|
||||
consistent-this: 'off'
|
||||
curly: 'off'
|
||||
default-case: 'off'
|
||||
default-case-last: error
|
||||
default-param-last: error
|
||||
dot-location: 'off'
|
||||
dot-notation: 'off'
|
||||
eol-last: 'off'
|
||||
eqeqeq: 'off'
|
||||
func-call-spacing: 'off'
|
||||
func-name-matching: 'off'
|
||||
func-names: 'off'
|
||||
func-style: 'off'
|
||||
function-call-argument-newline: 'off'
|
||||
function-paren-newline: 'off'
|
||||
generator-star-spacing: error
|
||||
global-require: 'off'
|
||||
grouped-accessor-pairs: error
|
||||
guard-for-in: 'off'
|
||||
handle-callback-err: 'off'
|
||||
id-blacklist: error
|
||||
id-denylist: error
|
||||
id-length: 'off'
|
||||
id-match: error
|
||||
implicit-arrow-linebreak: error
|
||||
indent: 'off'
|
||||
indent-legacy: 'off'
|
||||
init-declarations: 'off'
|
||||
jsx-quotes: error
|
||||
key-spacing: 'off'
|
||||
keyword-spacing: 'off'
|
||||
line-comment-position: 'off'
|
||||
linebreak-style: 'off'
|
||||
lines-around-comment: 'off'
|
||||
lines-around-directive: 'off'
|
||||
lines-between-class-members: error
|
||||
max-classes-per-file: error
|
||||
max-depth: 'off'
|
||||
max-len: 'off'
|
||||
max-lines: 'off'
|
||||
max-lines-per-function: 'off'
|
||||
max-nested-callbacks: error
|
||||
max-params: 'off'
|
||||
max-statements: 'off'
|
||||
max-statements-per-line: 'off'
|
||||
multiline-comment-style: 'off'
|
||||
multiline-ternary: 'off'
|
||||
new-parens: 'off'
|
||||
newline-after-var: 'off'
|
||||
newline-before-return: 'off'
|
||||
newline-per-chained-call: 'off'
|
||||
no-alert: 'off'
|
||||
no-array-constructor: 'off'
|
||||
no-await-in-loop: error
|
||||
no-bitwise: 'off'
|
||||
no-buffer-constructor: 'off'
|
||||
no-caller: error
|
||||
no-catch-shadow: 'off'
|
||||
no-confusing-arrow: error
|
||||
no-console: 'off'
|
||||
no-constant-condition:
|
||||
- error
|
||||
- checkLoops: false
|
||||
no-constructor-return: error
|
||||
no-continue: 'off'
|
||||
no-div-regex: 'off'
|
||||
no-duplicate-imports: error
|
||||
no-else-return: 'off'
|
||||
no-empty-function: 'off'
|
||||
no-eq-null: 'off'
|
||||
no-eval: 'off'
|
||||
no-extend-native: 'off'
|
||||
no-extra-bind: 'off'
|
||||
no-extra-label: 'off'
|
||||
no-extra-parens: 'off'
|
||||
no-floating-decimal: 'off'
|
||||
no-implicit-coercion:
|
||||
- error
|
||||
- boolean: false
|
||||
number: false
|
||||
string: false
|
||||
no-implicit-globals: 'off'
|
||||
no-implied-eval: error
|
||||
no-inline-comments: 'off'
|
||||
no-invalid-this: 'off'
|
||||
no-iterator: error
|
||||
no-label-var: 'off'
|
||||
no-labels: 'off'
|
||||
no-lone-blocks: 'off'
|
||||
no-lonely-if: 'off'
|
||||
no-loop-func: 'off'
|
||||
no-loss-of-precision: error
|
||||
no-magic-numbers: 'off'
|
||||
no-mixed-operators: 'off'
|
||||
no-mixed-requires: 'off'
|
||||
no-multi-assign: 'off'
|
||||
no-multi-spaces: 'off'
|
||||
no-multi-str: error
|
||||
no-multiple-empty-lines: 'off'
|
||||
no-native-reassign: 'off'
|
||||
no-negated-condition: 'off'
|
||||
no-negated-in-lhs: error
|
||||
no-nested-ternary: 'off'
|
||||
no-new: 'off'
|
||||
no-new-func: 'off'
|
||||
no-new-object: 'off'
|
||||
no-new-require: error
|
||||
no-new-wrappers: error
|
||||
no-octal-escape: error
|
||||
no-param-reassign: 'off'
|
||||
no-path-concat: error
|
||||
no-plusplus: 'off'
|
||||
no-process-env: 'off'
|
||||
no-process-exit: 'off'
|
||||
no-promise-executor-return: error
|
||||
no-proto: 'off'
|
||||
no-restricted-exports: error
|
||||
no-restricted-globals: error
|
||||
no-restricted-imports: error
|
||||
no-restricted-modules: error
|
||||
no-restricted-properties: error
|
||||
no-restricted-syntax: error
|
||||
no-return-assign: 'off'
|
||||
no-return-await: error
|
||||
no-script-url: 'off'
|
||||
no-self-compare: 'off'
|
||||
no-sequences: 'off'
|
||||
no-shadow: 'off'
|
||||
no-spaced-func: 'off'
|
||||
no-sync: 'off'
|
||||
no-tabs: 'off'
|
||||
no-template-curly-in-string: error
|
||||
no-ternary: 'off'
|
||||
no-throw-literal: 'off'
|
||||
no-trailing-spaces: 'off'
|
||||
no-undef-init: 'off'
|
||||
no-undefined: 'off'
|
||||
no-underscore-dangle: 'off'
|
||||
no-unmodified-loop-condition: 'off'
|
||||
no-unneeded-ternary: 'off'
|
||||
no-unreachable-loop: error
|
||||
no-unused-expressions: 'off'
|
||||
no-use-before-define: 'off'
|
||||
no-useless-backreference: error
|
||||
no-useless-call: 'off'
|
||||
no-useless-computed-key: error
|
||||
no-useless-concat: 'off'
|
||||
no-useless-constructor: error
|
||||
no-useless-rename: error
|
||||
no-useless-return: 'off'
|
||||
no-var: 'off'
|
||||
no-void: 'off'
|
||||
no-warning-comments: 'off'
|
||||
no-whitespace-before-property: error
|
||||
nonblock-statement-body-position:
|
||||
- error
|
||||
- any
|
||||
object-curly-newline: 'off'
|
||||
object-curly-spacing: 'off'
|
||||
object-property-newline: 'off'
|
||||
object-shorthand: 'off'
|
||||
one-var: 'off'
|
||||
one-var-declaration-per-line: 'off'
|
||||
operator-assignment: 'off'
|
||||
operator-linebreak: 'off'
|
||||
padded-blocks: 'off'
|
||||
padding-line-between-statements: error
|
||||
prefer-arrow-callback: 'off'
|
||||
prefer-const: 'off'
|
||||
prefer-destructuring: 'off'
|
||||
prefer-exponentiation-operator: 'off'
|
||||
prefer-named-capture-group: 'off'
|
||||
prefer-numeric-literals: error
|
||||
prefer-object-spread: 'off'
|
||||
prefer-promise-reject-errors: error
|
||||
prefer-reflect: 'off'
|
||||
prefer-regex-literals: 'off'
|
||||
prefer-rest-params: 'off'
|
||||
prefer-spread: 'off'
|
||||
prefer-template: 'off'
|
||||
quote-props: 'off'
|
||||
quotes: 'off'
|
||||
radix: 'off'
|
||||
require-atomic-updates: error
|
||||
require-await: error
|
||||
require-jsdoc: 'off'
|
||||
require-unicode-regexp: 'off'
|
||||
rest-spread-spacing: error
|
||||
semi: 'off'
|
||||
semi-spacing: 'off'
|
||||
semi-style: 'off'
|
||||
sort-imports: error
|
||||
sort-keys: 'off'
|
||||
sort-vars: 'off'
|
||||
space-before-blocks: 'off'
|
||||
space-before-function-paren: 'off'
|
||||
space-in-parens: 'off'
|
||||
space-infix-ops: 'off'
|
||||
space-unary-ops: 'off'
|
||||
spaced-comment: 'off'
|
||||
strict: 'off'
|
||||
switch-colon-spacing: 'off'
|
||||
symbol-description: error
|
||||
template-curly-spacing: error
|
||||
template-tag-spacing: error
|
||||
unicode-bom:
|
||||
- error
|
||||
- never
|
||||
valid-jsdoc: 'off'
|
||||
valid-typeof:
|
||||
- error
|
||||
- requireStringLiterals: false
|
||||
vars-on-top: 'off'
|
||||
wrap-iife: 'off'
|
||||
wrap-regex: 'off'
|
||||
yield-star-spacing: error
|
||||
yoda: 'off'
|
||||
|
||||
# temporary rules
|
||||
no-useless-escape: 'off'
|
||||
no-unused-vars: 'off'
|
||||
no-empty: 'off'
|
||||
no-extra-semi: 'off'
|
||||
no-redeclare: 'off'
|
||||
no-control-regex: "off"
|
||||
no-mixed-spaces-and-tabs: "off"
|
||||
no-extra-boolean-cast: "off"
|
||||
no-prototype-builtins: "off"
|
||||
no-undef: "off"
|
||||
no-unreachable: "off"
|
||||
no-self-assign: "off"
|
||||
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve TiddlyWiki 5
|
||||
title: "[BUG]"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for TiddlyWiki 5
|
||||
title: "[IDEA]"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
22
.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
vendored
Normal file
22
.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: Pull Request
|
||||
about: Propose a change to TiddlyWiki 5
|
||||
title: ""
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your PR related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you are proposing**
|
||||
A clear and concise description of the changes you are proposing. Include images to show visual changes.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
|
||||
If you link to discussions elsewhere then please copy and paste the important text, and don't expect readers to scan the entire discussion to find the relevant part.
|
||||
74
.github/workflows/ci.yml
vendored
Normal file
74
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- tiddlywiki-com
|
||||
env:
|
||||
NODE_VERSION: "12"
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
- run: "./bin/test.sh"
|
||||
build-prerelease:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/master'
|
||||
needs: test
|
||||
env:
|
||||
TW5_BUILD_TIDDLYWIKI: "./tiddlywiki.js"
|
||||
TW5_BUILD_MAIN_EDITION: "./editions/prerelease"
|
||||
TW5_BUILD_OUTPUT: "./output/prerelease"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
- run: "./bin/ci-pre-build.sh"
|
||||
# There's another near-duplicate "Set dynamic environment variables" step in
|
||||
# the `build-tiddlywiki-com` job.
|
||||
# These _could_ be extracted as a script (or moved into `ci-pre-build.sh`) to do away with the
|
||||
# duplication, but, the visibility that comes from having these in the workflow file seems
|
||||
# valuable. Environment variables are global variables and setting them at the top-level
|
||||
# makes sense.
|
||||
# Time to reconsider this decision might be when this setup turns out to be mistake-prone.
|
||||
- name: "Set dynamic environment variables"
|
||||
run: |
|
||||
TW5_BUILD_BRANCH=$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')
|
||||
echo "TW5_BUILD_BRANCH=${TW5_BUILD_BRANCH}" >> $GITHUB_ENV
|
||||
echo "TW5_BUILD_VERSION=$(./bin/get-plugin-library-version-number)" >> $GITHUB_ENV
|
||||
echo "TW5_BUILD_DETAILS=Prerelease built from branch '$TW5_BUILD_BRANCH' at commit $(git rev-parse HEAD) of $(git remote get-url origin) at $(date +'%F %T %Z')" >> $GITHUB_ENV
|
||||
- run: "./bin/build-site.sh"
|
||||
- run: "./bin/ci-push.sh"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUBPUSHTOKEN }}
|
||||
build-tiddlywiki-com:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/tiddlywiki-com'
|
||||
needs: test
|
||||
env:
|
||||
TW5_BUILD_TIDDLYWIKI: "./node_modules/tiddlywiki/tiddlywiki.js"
|
||||
TW5_BUILD_MAIN_EDITION: "./editions/tw5.com"
|
||||
TW5_BUILD_OUTPUT: "./output"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
- run: "./bin/ci-pre-build.sh"
|
||||
# When making a change here, don't forget to see if it also applies to the step
|
||||
# with the same name in the `build-prerelease` job.
|
||||
- name: "Set dynamic environment variables"
|
||||
run: |
|
||||
TW5_BUILD_BRANCH=$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')
|
||||
echo "TW5_BUILD_BRANCH=${TW5_BUILD_BRANCH}" >> $GITHUB_ENV
|
||||
echo "TW5_BUILD_VERSION=$(./bin/get-plugin-library-version-number)" >> $GITHUB_ENV
|
||||
echo "TW5_BUILD_DETAILS=Built from branch '$TW5_BUILD_BRANCH' at commit $(git rev-parse HEAD) of $(git remote get-url origin) at $(date +'%F %T %Z')" >> $GITHUB_ENV
|
||||
- run: "./bin/build-site.sh"
|
||||
- run: "./bin/ci-push.sh"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUBPUSHTOKEN }}
|
||||
35
.travis.yml
35
.travis.yml
@@ -1,35 +0,0 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "12.4.0"
|
||||
|
||||
stages:
|
||||
- name: test
|
||||
- name: build-prerelease
|
||||
if: branch = "master"
|
||||
- name: build-tiddlywiki-com
|
||||
if: branch = "tiddlywiki-com"
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: test
|
||||
script: ./bin/test.sh
|
||||
- stage: build-prerelease
|
||||
script:
|
||||
- ./bin/travis-pre-build.sh
|
||||
- export TW5_BUILD_TIDDLYWIKI='./tiddlywiki.js'
|
||||
- export TW5_BUILD_VERSION=$(./bin/get-plugin-library-version-number)
|
||||
- export TW5_BUILD_DETAILS="Prerelease built from branch '$TRAVIS_BRANCH' at commit $(git rev-parse HEAD) of $(git remote get-url origin) at $(date +'%F %T %Z')"
|
||||
- export TW5_BUILD_MAIN_EDITION='./editions/prerelease'
|
||||
- export TW5_BUILD_OUTPUT='./output/prerelease'
|
||||
- ./bin/build-site.sh || travis_terminate 1
|
||||
- ./bin/travis-push.sh || travis_terminate 1
|
||||
- stage: build-tiddlywiki-com
|
||||
script:
|
||||
- ./bin/travis-pre-build.sh
|
||||
- export TW5_BUILD_TIDDLYWIKI='./node_modules/tiddlywiki/tiddlywiki.js'
|
||||
- export TW5_BUILD_VERSION=$(./bin/get-plugin-library-version-number)
|
||||
- export TW5_BUILD_DETAILS="Built from branch '$TRAVIS_BRANCH' at commit $(git rev-parse HEAD) of $(git remote get-url origin) at $(date +'%F %T %Z')"
|
||||
- export TW5_BUILD_MAIN_EDITION='./editions/tw5.com'
|
||||
- export TW5_BUILD_OUTPUT='./output'
|
||||
- ./bin/build-site.sh || travis_terminate 1
|
||||
- ./bin/travis-push.sh || travis_terminate 1
|
||||
@@ -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.21
|
||||
TW5_BUILD_VERSION=v5.1.23
|
||||
fi
|
||||
|
||||
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
||||
|
||||
15
bin/ci-push.sh
Executable file
15
bin/ci-push.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Push output back to GitHub
|
||||
|
||||
# Exit script immediately if any command fails
|
||||
set -e
|
||||
|
||||
cd output
|
||||
git config --global user.email "actions@github.com"
|
||||
git config --global user.name "GitHub Actions"
|
||||
git add -A .
|
||||
git commit --message "GitHub build: $GITHUB_RUN_NUMBER of $TW5_BUILD_BRANCH ($(date +'%F %T %Z'))"
|
||||
git remote add deploy "https://$GH_TOKEN@github.com/Jermolene/jermolene.github.io.git" &>/dev/null
|
||||
git push deploy master &>/dev/null
|
||||
cd ..
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Push output back to GitHub
|
||||
|
||||
|
||||
cd output || exit 1
|
||||
|
||||
git config --global user.email "travis@travis-ci.org" || exit 1
|
||||
|
||||
git config --global user.name "Travis CI" || exit 1
|
||||
|
||||
git add -A . || exit 1
|
||||
|
||||
git commit --message "Travis build: $TRAVIS_BUILD_NUMBER of $TRAVIS_BRANCH ($(date +'%F %T %Z'))" || exit 1
|
||||
|
||||
git remote add deploy "https://$GH_TOKEN@github.com/Jermolene/jermolene.github.io.git" &>/dev/null || exit 1
|
||||
|
||||
git push deploy master &>/dev/null || exit 1
|
||||
|
||||
cd .. || exit 1
|
||||
25
bin/update-translation-from-html-file.sh
Executable file
25
bin/update-translation-from-html-file.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Process translation updates made via the translators edition
|
||||
|
||||
# ./bin/update-translation-from-html-file.sh <language-code> <path-to-html-file>
|
||||
|
||||
# Assign and check parameters
|
||||
|
||||
LANGUAGE_CODE=$1
|
||||
HTML_FILE_PATH=$2
|
||||
|
||||
if [ -z "$LANGUAGE_CODE" ]; then
|
||||
echo "Missing parameter: language code"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$HTML_FILE_PATH" ]; then
|
||||
echo "Missing parameter: path to HTML file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
./tiddlywiki.js editions/translators/ --verbose --unpackplugin $:/languages/$LANGUAGE_CODE --load $HTML_FILE_PATH --build output-files || exit 1
|
||||
|
||||
cp -R ./editions/translators/output/language/. ./languages/$LANGUAGE_CODE/ || exit 1
|
||||
|
||||
160
boot/boot.js
160
boot/boot.js
@@ -267,8 +267,16 @@ $tw.utils.htmlDecode = function(s) {
|
||||
Get the browser location.hash. We don't use location.hash because of the way that Firefox auto-urldecodes it (see http://stackoverflow.com/questions/1703552/encoding-of-window-location-hash)
|
||||
*/
|
||||
$tw.utils.getLocationHash = function() {
|
||||
var parts = window.location.href.split('#');
|
||||
return "#" + (parts.length > 1 ? parts[1] : "");
|
||||
var href = window.location.href;
|
||||
var idx = href.indexOf('#');
|
||||
if(idx === -1) {
|
||||
return "#";
|
||||
} else if(idx < href.length-1 && href[idx+1] === '#') {
|
||||
// Special case: ignore location hash if it itself starts with a #
|
||||
return "#";
|
||||
} else {
|
||||
return href.substring(idx);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -297,13 +305,21 @@ $tw.utils.stringifyDate = function(value) {
|
||||
// Parse a date from a UTC YYYYMMDDHHMMSSmmm format string
|
||||
$tw.utils.parseDate = function(value) {
|
||||
if(typeof value === "string") {
|
||||
return new Date(Date.UTC(parseInt(value.substr(0,4),10),
|
||||
var negative = 1;
|
||||
if(value.charAt(0) === "-") {
|
||||
negative = -1;
|
||||
value = value.substr(1);
|
||||
}
|
||||
var year = parseInt(value.substr(0,4),10) * negative,
|
||||
d = new Date(Date.UTC(year,
|
||||
parseInt(value.substr(4,2),10)-1,
|
||||
parseInt(value.substr(6,2),10),
|
||||
parseInt(value.substr(8,2)||"00",10),
|
||||
parseInt(value.substr(10,2)||"00",10),
|
||||
parseInt(value.substr(12,2)||"00",10),
|
||||
parseInt(value.substr(14,3)||"000",10)));
|
||||
d.setUTCFullYear(year); // See https://stackoverflow.com/a/5870822
|
||||
return d;
|
||||
} else if($tw.utils.isDate(value)) {
|
||||
return value;
|
||||
} else {
|
||||
@@ -409,10 +425,10 @@ $tw.utils.resolvePath = function(sourcepath,rootpath) {
|
||||
};
|
||||
|
||||
/*
|
||||
Parse a semantic version string into its constituent parts
|
||||
Parse a semantic version string into its constituent parts -- see https://semver.org
|
||||
*/
|
||||
$tw.utils.parseVersion = function(version) {
|
||||
var match = /^((\d+)\.(\d+)\.(\d+))(?:-([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?(?:\+([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?$/.exec(version);
|
||||
var match = /^v?((\d+)\.(\d+)\.(\d+))(?:-([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?(?:\+([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?$/.exec(version);
|
||||
if(match) {
|
||||
return {
|
||||
version: match[1],
|
||||
@@ -427,25 +443,37 @@ $tw.utils.parseVersion = function(version) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Returns +1 if the version string A is greater than the version string B, 0 if they are the same, and +1 if B is greater than A.
|
||||
Missing or malformed version strings are parsed as 0.0.0
|
||||
*/
|
||||
$tw.utils.compareVersions = function(versionStringA,versionStringB) {
|
||||
var defaultVersion = {
|
||||
major: 0,
|
||||
minor: 0,
|
||||
patch: 0
|
||||
},
|
||||
versionA = $tw.utils.parseVersion(versionStringA) || defaultVersion,
|
||||
versionB = $tw.utils.parseVersion(versionStringB) || defaultVersion,
|
||||
diff = [
|
||||
versionA.major - versionB.major,
|
||||
versionA.minor - versionB.minor,
|
||||
versionA.patch - versionB.patch
|
||||
];
|
||||
if((diff[0] > 0) || (diff[0] === 0 && diff[1] > 0) || (diff[0] === 0 & diff[1] === 0 & diff[2] > 0)) {
|
||||
return +1;
|
||||
} else if((diff[0] < 0) || (diff[0] === 0 && diff[1] < 0) || (diff[0] === 0 & diff[1] === 0 & diff[2] < 0)) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Returns true if the version string A is greater than the version string B. Returns true if the versions are the same
|
||||
*/
|
||||
$tw.utils.checkVersions = function(versionStringA,versionStringB) {
|
||||
var defaultVersion = {
|
||||
major: 0,
|
||||
minor: 0,
|
||||
patch: 0
|
||||
},
|
||||
versionA = $tw.utils.parseVersion(versionStringA) || defaultVersion,
|
||||
versionB = $tw.utils.parseVersion(versionStringB) || defaultVersion,
|
||||
diff = [
|
||||
versionA.major - versionB.major,
|
||||
versionA.minor - versionB.minor,
|
||||
versionA.patch - versionB.patch
|
||||
];
|
||||
return (diff[0] > 0) ||
|
||||
(diff[0] === 0 && diff[1] > 0) ||
|
||||
(diff[0] === 0 && diff[1] === 0 && diff[2] >= 0);
|
||||
return $tw.utils.compareVersions(versionStringA,versionStringB) !== -1;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -640,11 +668,13 @@ $tw.utils.PasswordPrompt.prototype.createPrompt = function(options) {
|
||||
var promptInfo = {
|
||||
serviceName: options.serviceName,
|
||||
callback: options.callback,
|
||||
form: form
|
||||
form: form,
|
||||
owner: this
|
||||
};
|
||||
this.passwordPrompts.push(promptInfo);
|
||||
// Make sure the wrapper is displayed
|
||||
this.setWrapperDisplay();
|
||||
return promptInfo;
|
||||
};
|
||||
|
||||
$tw.utils.PasswordPrompt.prototype.removePrompt = function(promptInfo) {
|
||||
@@ -1258,7 +1288,7 @@ $tw.Wiki = function(options) {
|
||||
$tw.utils.each(titles || getTiddlerTitles(),function(title) {
|
||||
var tiddler = tiddlers[title];
|
||||
if(tiddler) {
|
||||
if(tiddler.fields.type === "application/json" && tiddler.hasField("plugin-type")) {
|
||||
if(tiddler.fields.type === "application/json" && tiddler.hasField("plugin-type") && tiddler.fields.text) {
|
||||
pluginInfo[tiddler.fields.title] = JSON.parse(tiddler.fields.text);
|
||||
results.modifiedPlugins.push(tiddler.fields.title);
|
||||
}
|
||||
@@ -1810,7 +1840,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
// Read the specification
|
||||
var filesInfo = JSON.parse(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"));
|
||||
// Helper to process a file
|
||||
var processFile = function(filename,isTiddlerFile,fields) {
|
||||
var processFile = function(filename,isTiddlerFile,fields,isEditableFile) {
|
||||
var extInfo = $tw.config.fileExtensionInfo[path.extname(filename)],
|
||||
type = (extInfo || {}).type || fields.type || "text/plain",
|
||||
typeInfo = $tw.config.contentTypeInfo[type] || {},
|
||||
@@ -1863,7 +1893,11 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
}
|
||||
});
|
||||
});
|
||||
tiddlers.push({tiddlers: fileTiddlers});
|
||||
if(isEditableFile) {
|
||||
tiddlers.push({filepath: pathname, hasMetaFile: !!metadata && !isTiddlerFile, isEditableFile: true, tiddlers: fileTiddlers});
|
||||
} else {
|
||||
tiddlers.push({tiddlers: fileTiddlers});
|
||||
}
|
||||
};
|
||||
// Process the listed tiddlers
|
||||
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
|
||||
@@ -1886,15 +1920,21 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
}
|
||||
} else {
|
||||
// Process directory specifier
|
||||
var dirPath = path.resolve(filepath,dirSpec.path),
|
||||
files = fs.readdirSync(dirPath),
|
||||
fileRegExp = new RegExp(dirSpec.filesRegExp || "^.*$"),
|
||||
metaRegExp = /^.*\.meta$/;
|
||||
for(var t=0; t<files.length; t++) {
|
||||
var filename = files[t];
|
||||
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
||||
processFile(dirPath + path.sep + filename,dirSpec.isTiddlerFile,dirSpec.fields);
|
||||
var dirPath = path.resolve(filepath,dirSpec.path);
|
||||
if(fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
|
||||
var files = fs.readdirSync(dirPath),
|
||||
fileRegExp = new RegExp(dirSpec.filesRegExp || "^.*$"),
|
||||
metaRegExp = /^.*\.meta$/;
|
||||
for(var t=0; t<files.length; t++) {
|
||||
var filename = files[t];
|
||||
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
||||
processFile(dirPath + path.sep + filename,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log("Warning: a directory in a tiddlywiki.files file does not exist.");
|
||||
console.log("dirPath: " + dirPath);
|
||||
console.log("tiddlywiki.files location: " + filepath);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -2034,6 +2074,11 @@ $tw.loadWikiTiddlers = function(wikiPath,options) {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
// Save the path to the tiddlers folder for the filesystemadaptor
|
||||
var config = wikiInfo.config || {};
|
||||
if($tw.boot.wikiPath == wikiPath) {
|
||||
$tw.boot.wikiTiddlersPath = path.resolve($tw.boot.wikiPath,config["default-tiddler-location"] || $tw.config.wikiTiddlersSubDir);
|
||||
}
|
||||
// Load any parent wikis
|
||||
if(wikiInfo.includeWikis) {
|
||||
parentPaths = parentPaths.slice(0);
|
||||
@@ -2067,27 +2112,30 @@ $tw.loadWikiTiddlers = function(wikiPath,options) {
|
||||
$tw.boot.files[tiddler.title] = {
|
||||
filepath: tiddlerFile.filepath,
|
||||
type: tiddlerFile.type,
|
||||
hasMetaFile: tiddlerFile.hasMetaFile
|
||||
hasMetaFile: tiddlerFile.hasMetaFile,
|
||||
isEditableFile: config["retain-original-tiddler-path"] || tiddlerFile.isEditableFile || tiddlerFile.filepath.indexOf($tw.boot.wikiTiddlersPath) !== 0
|
||||
};
|
||||
});
|
||||
}
|
||||
$tw.wiki.addTiddlers(tiddlerFile.tiddlers);
|
||||
});
|
||||
// Save the original tiddler file locations if requested
|
||||
var config = wikiInfo.config || {};
|
||||
if(config["retain-original-tiddler-path"]) {
|
||||
var output = {}, relativePath;
|
||||
if ($tw.boot.wikiPath == wikiPath) {
|
||||
// Save the original tiddler file locations if requested
|
||||
var output = {}, relativePath, fileInfo;
|
||||
for(var title in $tw.boot.files) {
|
||||
relativePath = path.relative(resolvedWikiPath,$tw.boot.files[title].filepath);
|
||||
output[title] =
|
||||
path.sep === "/" ?
|
||||
relativePath :
|
||||
relativePath.split(path.sep).join("/");
|
||||
fileInfo = $tw.boot.files[title];
|
||||
if(fileInfo.isEditableFile) {
|
||||
relativePath = path.relative($tw.boot.wikiTiddlersPath,fileInfo.filepath);
|
||||
output[title] =
|
||||
path.sep === "/" ?
|
||||
relativePath :
|
||||
relativePath.split(path.sep).join("/");
|
||||
}
|
||||
}
|
||||
if(Object.keys(output).length > 0){
|
||||
$tw.wiki.addTiddler({title: "$:/config/OriginalTiddlerPaths", type: "application/json", text: JSON.stringify(output)});
|
||||
}
|
||||
$tw.wiki.addTiddler({title: "$:/config/OriginalTiddlerPaths", type: "application/json", text: JSON.stringify(output)});
|
||||
}
|
||||
// Save the path to the tiddlers folder for the filesystemadaptor
|
||||
$tw.boot.wikiTiddlersPath = path.resolve($tw.boot.wikiPath,config["default-tiddler-location"] || $tw.config.wikiTiddlersSubDir);
|
||||
// Load any plugins within the wiki folder
|
||||
var wikiPluginsPath = path.resolve(wikiPath,$tw.config.wikiPluginsSubDir);
|
||||
if(fs.existsSync(wikiPluginsPath)) {
|
||||
@@ -2134,7 +2182,7 @@ $tw.loadTiddlersNode = function() {
|
||||
// Load any extra plugins
|
||||
$tw.utils.each($tw.boot.extraPlugins,function(name) {
|
||||
if(name.charAt(0) === "+") { // Relative path to plugin
|
||||
var pluginFields = $tw.loadPluginFolder(name.substring(1));;
|
||||
var pluginFields = $tw.loadPluginFolder(name.substring(1));
|
||||
if(pluginFields) {
|
||||
$tw.wiki.addTiddler(pluginFields);
|
||||
}
|
||||
@@ -2160,8 +2208,7 @@ $tw.loadTiddlersNode = function() {
|
||||
/*
|
||||
Startup TiddlyWiki
|
||||
*/
|
||||
$tw.boot.startup = function(options) {
|
||||
options = options || {};
|
||||
$tw.boot.initStartup = function(options) {
|
||||
// Get the URL hash and check for safe mode
|
||||
$tw.locationHash = "#";
|
||||
if($tw.browser && !$tw.node) {
|
||||
@@ -2247,6 +2294,7 @@ $tw.boot.startup = function(options) {
|
||||
$tw.utils.registerFileType("application/zip","base64",".zip");
|
||||
$tw.utils.registerFileType("application/x-zip-compressed","base64",".zip");
|
||||
$tw.utils.registerFileType("image/jpeg","base64",[".jpg",".jpeg"],{flags:["image"]});
|
||||
$tw.utils.registerFileType("image/jpg","base64",[".jpg",".jpeg"],{flags:["image"]});
|
||||
$tw.utils.registerFileType("image/png","base64",".png",{flags:["image"]});
|
||||
$tw.utils.registerFileType("image/gif","base64",".gif",{flags:["image"]});
|
||||
$tw.utils.registerFileType("image/webp","base64",".webp",{flags:["image"]});
|
||||
@@ -2256,6 +2304,7 @@ $tw.boot.startup = function(options) {
|
||||
$tw.utils.registerFileType("image/x-icon","base64",".ico",{flags:["image"]});
|
||||
$tw.utils.registerFileType("application/font-woff","base64",".woff");
|
||||
$tw.utils.registerFileType("application/x-font-ttf","base64",".woff");
|
||||
$tw.utils.registerFileType("application/font-woff2","base64",".woff2");
|
||||
$tw.utils.registerFileType("audio/ogg","base64",".ogg");
|
||||
$tw.utils.registerFileType("video/ogg","base64",[".ogm",".ogv",".ogg"]);
|
||||
$tw.utils.registerFileType("video/webm","base64",".webm");
|
||||
@@ -2293,6 +2342,9 @@ $tw.boot.startup = function(options) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
$tw.boot.loadStartup = function(options){
|
||||
|
||||
// Load tiddlers
|
||||
if($tw.boot.tasks.readBrowserTiddlers) {
|
||||
$tw.loadTiddlersBrowser();
|
||||
@@ -2305,6 +2357,8 @@ $tw.boot.startup = function(options) {
|
||||
}
|
||||
// Give hooks a chance to modify the store
|
||||
$tw.hooks.invokeHook("th-boot-tiddlers-loaded");
|
||||
}
|
||||
$tw.boot.execStartup = function(options){
|
||||
// Unpack plugin tiddlers
|
||||
$tw.wiki.readPluginInfo();
|
||||
$tw.wiki.registerPluginTiddlers("plugin",$tw.safeMode ? ["$:/core"] : undefined);
|
||||
@@ -2333,6 +2387,16 @@ $tw.boot.startup = function(options) {
|
||||
$tw.boot.disabledStartupModules = $tw.boot.disabledStartupModules || [];
|
||||
// Repeatedly execute the next eligible task
|
||||
$tw.boot.executeNextStartupTask(options.callback);
|
||||
}
|
||||
/*
|
||||
Startup TiddlyWiki
|
||||
*/
|
||||
$tw.boot.startup = function(options) {
|
||||
options = options || {};
|
||||
// Get the URL hash and check for safe mode
|
||||
$tw.boot.initStartup(options);
|
||||
$tw.boot.loadStartup(options);
|
||||
$tw.boot.execStartup(options);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
title: $:/core/images/storyview-solo
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg width="22pt" height="22pt" class="tc-image-storyview-single tc-image-button" viewBox="0 0 128 128"><path fill-rule="evenodd" d="M8.007 0A8.01 8.01 0 000 8.007v111.986A8.01 8.01 0 008.007 128h111.986a8.01 8.01 0 008.007-8.007V8.007A8.01 8.01 0 00119.993 0H8.007zm15.992 16A8 8 0 0016 24.009V71.99C16 76.414 19.588 80 24 80h80a8 8 0 008-8.009V24.01c0-4.423-3.588-8.009-8-8.009H24z"/></svg>
|
||||
@@ -17,6 +17,8 @@ Basics/NewJournal/Tags/Prompt: Tags for new journal tiddlers
|
||||
Basics/NewTiddler/Title/Prompt: Title of new tiddlers
|
||||
Basics/NewTiddler/Tags/Prompt: Tags for new tiddlers
|
||||
Basics/OverriddenShadowTiddlers/Prompt: Number of overridden shadow tiddlers
|
||||
Basics/RemoveTags: Update to current format
|
||||
Basics/RemoveTags/Hint: Update the tags configuration to the latest format
|
||||
Basics/ShadowTiddlers/Prompt: Number of shadow tiddlers
|
||||
Basics/Subtitle/Prompt: Subtitle
|
||||
Basics/SystemTiddlers/Prompt: Number of system tiddlers
|
||||
@@ -44,6 +46,7 @@ KeyboardShortcuts/Platform/Linux: Linux platform only
|
||||
KeyboardShortcuts/Platform/NonLinux: Non-Linux platforms only
|
||||
KeyboardShortcuts/Platform/Windows: Windows platform only
|
||||
KeyboardShortcuts/Platform/NonWindows: Non-Windows platforms only
|
||||
LayoutSwitcher/Caption: Layout
|
||||
LoadedModules/Caption: Loaded Modules
|
||||
LoadedModules/Hint: These are the currently loaded tiddler modules linked to their source tiddlers. Any italicised modules lack a source tiddler, typically because they were setup during the boot process.
|
||||
Palette/Caption: Palette
|
||||
@@ -70,6 +73,7 @@ Plugins/Caption: Plugins
|
||||
Plugins/Disable/Caption: disable
|
||||
Plugins/Disable/Hint: Disable this plugin when reloading page
|
||||
Plugins/Disabled/Status: (disabled)
|
||||
Plugins/Downgrade/Caption: downgrade
|
||||
Plugins/Empty/Hint: None
|
||||
Plugins/Enable/Caption: enable
|
||||
Plugins/Enable/Hint: Enable this plugin when reloading page
|
||||
@@ -87,6 +91,11 @@ Plugins/Plugins/Hint: Plugins
|
||||
Plugins/Reinstall/Caption: reinstall
|
||||
Plugins/Themes/Caption: Themes
|
||||
Plugins/Themes/Hint: Theme plugins
|
||||
Plugins/Update/Caption: update
|
||||
Plugins/Updates/Caption: Updates
|
||||
Plugins/Updates/Hint: Available updates to installed plugins
|
||||
Plugins/Updates/UpdateAll/Caption: Update <<update-count>> plugins
|
||||
Plugins/SubPluginPrompt: With <<count>> sub-plugins available
|
||||
Saving/Caption: Saving
|
||||
Saving/DownloadSaver/AutoSave/Description: Permit automatic saving for the download saver
|
||||
Saving/DownloadSaver/AutoSave/Hint: Enable Autosave for Download Saver
|
||||
@@ -111,6 +120,7 @@ Saving/GitService/Gitea/Caption: Gitea Saver
|
||||
Saving/GitService/Gitea/Password: Personal access token for API (via Gitea’s web interface: `Settings | Applications | Generate New Token`)
|
||||
Saving/TiddlySpot/Advanced/Heading: Advanced Settings
|
||||
Saving/TiddlySpot/BackupDir: Backup Directory
|
||||
Saving/TiddlySpot/ControlPanel: ~TiddlySpot Control Panel
|
||||
Saving/TiddlySpot/Backups: Backups
|
||||
Saving/TiddlySpot/Caption: ~TiddlySpot Saver
|
||||
Saving/TiddlySpot/Description: These settings are only used when saving to http://tiddlyspot.com or a compatible remote server
|
||||
@@ -118,6 +128,7 @@ Saving/TiddlySpot/Filename: Upload Filename
|
||||
Saving/TiddlySpot/Heading: ~TiddlySpot
|
||||
Saving/TiddlySpot/Hint: //The server URL defaults to `http://<wikiname>.tiddlyspot.com/store.cgi` and can be changed to use a custom server address, e.g. `http://example.com/store.php`.//
|
||||
Saving/TiddlySpot/Password: Password
|
||||
Saving/TiddlySpot/ReadOnly: The ~TiddlySpot service is currently only available in read-only form. Please see http://tiddlyspot.com/ for the latest details. The ~TiddlySpot saver can still be used to save to compatible servers.
|
||||
Saving/TiddlySpot/ServerURL: Server URL
|
||||
Saving/TiddlySpot/UploadDir: Upload Directory
|
||||
Saving/TiddlySpot/UserName: Wiki Name
|
||||
|
||||
@@ -19,6 +19,8 @@ Shadow/OverriddenWarning: This is a modified shadow tiddler. You can revert to t
|
||||
Tags/Add/Button: add
|
||||
Tags/Add/Button/Hint: add tag
|
||||
Tags/Add/Placeholder: tag name
|
||||
Tags/ClearInput/Caption: clear input
|
||||
Tags/ClearInput/Hint: Clear tag input
|
||||
Tags/Dropdown/Caption: tag list
|
||||
Tags/Dropdown/Hint: Show tag list
|
||||
Title/BadCharacterWarning: Warning: avoid using any of the characters <<bad-chars>> in tiddler titles
|
||||
|
||||
@@ -6,13 +6,13 @@ description: Render tiddlers matching a filter to a specified ContentType
|
||||
Render a set of tiddlers matching a filter to separate files of a specified ContentType (defaults to `text/html`) and extension (defaults to `.html`).
|
||||
|
||||
```
|
||||
--rendertiddlers <filter> <template> <pathname> [<type>] [<extension>] ["noclean"]
|
||||
--rendertiddlers '<filter>' <template> <pathname> [<type>] [<extension>] ["noclean"]
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
--rendertiddlers [!is[system]] $:/core/templates/static.tiddler.html ./static text/plain
|
||||
--rendertiddlers '[!is[system]]' $:/core/templates/static.tiddler.html ./static text/plain
|
||||
```
|
||||
|
||||
By default, the pathname is resolved relative to the `output` subdirectory of the edition directory. The `--output` command can be used to direct output to a different directory.
|
||||
|
||||
@@ -13,11 +13,16 @@ Listing/Preview/TextRaw: Text (Raw)
|
||||
Listing/Preview/Fields: Fields
|
||||
Listing/Preview/Diff: Diff
|
||||
Listing/Preview/DiffFields: Diff (Fields)
|
||||
Upgrader/Plugins/Suppressed/Incompatible: Blocked incompatible or obsolete plugin
|
||||
Upgrader/Plugins/Suppressed/Version: Blocked plugin (due to incoming <<incoming>> being older than existing <<existing>>)
|
||||
Upgrader/Plugins/Upgraded: Upgraded plugin from <<incoming>> to <<upgraded>>
|
||||
Upgrader/State/Suppressed: Blocked temporary state tiddler
|
||||
Upgrader/System/Suppressed: Blocked system tiddler
|
||||
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>>/>
|
||||
Listing/Rename/Tooltip: Rename tiddler before importing
|
||||
Listing/Rename/Prompt: Rename to:
|
||||
Listing/Rename/ConfirmRename: Rename tiddler
|
||||
Listing/Rename/CancelRename: Cancel
|
||||
Listing/Rename/OverwriteWarning: A tiddler with this title already exists.
|
||||
Upgrader/Plugins/Suppressed/Incompatible: Blocked incompatible or obsolete plugin.
|
||||
Upgrader/Plugins/Suppressed/Version: Blocked plugin (due to incoming <<incoming>> not being newer than existing <<existing>>).
|
||||
Upgrader/Plugins/Upgraded: Upgraded plugin from <<incoming>> to <<upgraded>>.
|
||||
Upgrader/State/Suppressed: Blocked temporary state tiddler.
|
||||
Upgrader/System/Suppressed: Blocked system tiddler.
|
||||
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>>/>.
|
||||
|
||||
@@ -10,6 +10,7 @@ ConfirmCancelTiddler: Do you wish to discard changes to the tiddler "<$text text
|
||||
ConfirmDeleteTiddler: Do you wish to delete the tiddler "<$text text=<<title>>/>"?
|
||||
ConfirmOverwriteTiddler: Do you wish to overwrite the tiddler "<$text text=<<title>>/>"?
|
||||
ConfirmEditShadowTiddler: You are about to edit a ShadowTiddler. Any changes will override the default system making future upgrades non-trivial. Are you sure you want to edit "<$text text=<<title>>/>"?
|
||||
ConfirmAction: Do you wish to proceed?
|
||||
Count: count
|
||||
DefaultNewTiddlerTitle: New Tiddler
|
||||
Diffs/CountMessage: <<diff-count>> differences
|
||||
@@ -26,7 +27,9 @@ Error/Caption: Error
|
||||
Error/EditConflict: File changed on server
|
||||
Error/Filter: Filter error
|
||||
Error/FilterSyntax: Syntax error in filter expression
|
||||
Error/FilterRunPrefix: Filter Error: Unknown prefix for filter run
|
||||
Error/IsFilterOperator: Filter Error: Unknown operand for the 'is' filter operator
|
||||
Error/FormatFilterOperator: Filter Error: Unknown suffix for the 'format' filter operator
|
||||
Error/LoadingPluginLibrary: Error loading plugin library
|
||||
Error/NetworkErrorAlert: `<h2>''Network Error''</h2>It looks like the connection to the server has been lost. This may indicate a problem with your network connection. Please attempt to restore network connectivity before continuing.<br><br>''Any unsaved changes will be automatically synchronised when connectivity is restored''.`
|
||||
Error/RecursiveTransclusion: Recursive transclusion error in transclude widget
|
||||
@@ -37,6 +40,7 @@ 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
|
||||
Manager/Controls/FilterByTag/None: (none)
|
||||
@@ -60,8 +64,23 @@ MissingTiddler/Hint: Missing tiddler "<$text text=<<currentTiddler>>/>" -- click
|
||||
No: No
|
||||
OfficialPluginLibrary: Official ~TiddlyWiki Plugin Library
|
||||
OfficialPluginLibrary/Hint: The official ~TiddlyWiki plugin library at tiddlywiki.com. Plugins, themes and language packs are maintained by the core team.
|
||||
PageTemplate/Description: the default ~TiddlyWiki layout
|
||||
PageTemplate/Name: Default ~PageTemplate
|
||||
PluginReloadWarning: Please save {{$:/core/ui/Buttons/save-wiki}} and reload {{$:/core/ui/Buttons/refresh}} to allow changes to ~JavaScript plugins to take effect
|
||||
RecentChanges/DateFormat: DDth MMM YYYY
|
||||
Shortcuts/Input/AdvancedSearch/Hint: Open the ~AdvancedSearch panel from within the sidebar search field
|
||||
Shortcuts/Input/Accept/Hint: Accept the selected item
|
||||
Shortcuts/Input/AcceptVariant/Hint: Accept the selected item (variant)
|
||||
Shortcuts/Input/Cancel/Hint: Clear the input field
|
||||
Shortcuts/Input/Down/Hint: Select the next item
|
||||
Shortcuts/Input/Tab-Left/Hint: Select the previous Tab
|
||||
Shortcuts/Input/Tab-Right/Hint: Select the next Tab
|
||||
Shortcuts/Input/Up/Hint: Select the previous item
|
||||
Shortcuts/SidebarLayout/Hint: Change the sidebar layout
|
||||
Switcher/Subtitle/theme: Switch Theme
|
||||
Switcher/Subtitle/layout: Switch Layout
|
||||
Switcher/Subtitle/language: Switch Language
|
||||
Switcher/Subtitle/palette: Switch Palette
|
||||
SystemTiddler/Tooltip: This is a system tiddler
|
||||
SystemTiddlers/Include/Prompt: Include system tiddlers
|
||||
TagManager/Colour/Heading: Colour
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
title: $:/config/NewJournal/Tags
|
||||
tags: Journal
|
||||
|
||||
Journal
|
||||
|
||||
@@ -4,7 +4,6 @@ All/Caption: All
|
||||
Contents/Caption: Contents
|
||||
Drafts/Caption: Drafts
|
||||
Explorer/Caption: Explorer
|
||||
History/Caption: History
|
||||
Missing/Caption: Missing
|
||||
More/Caption: More
|
||||
Open/Caption: Open
|
||||
|
||||
@@ -14,7 +14,7 @@ List/Caption: List
|
||||
List/Empty: This tiddler does not have a list
|
||||
Listed/Caption: Listed
|
||||
Listed/Empty: This tiddler is not listed by any others
|
||||
References/Caption: References
|
||||
References/Caption: Backlinks
|
||||
References/Empty: No tiddlers link to this one
|
||||
Tagging/Caption: Tagging
|
||||
Tagging/Empty: No tiddlers are tagged with this one
|
||||
|
||||
@@ -71,7 +71,7 @@ Command.prototype.fetchFiles = function(options) {
|
||||
if(options.url) {
|
||||
urls = [options.url]
|
||||
} else if(options.urlFilter) {
|
||||
urls = $tw.wiki.filterTiddlers(options.urlFilter);
|
||||
urls = this.commander.wiki.filterTiddlers(options.urlFilter);
|
||||
} else {
|
||||
return "Missing URL";
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ Command.prototype.execute = function() {
|
||||
tiddlers = {};
|
||||
// Collect up the library plugins
|
||||
var collectPlugins = function(folder) {
|
||||
var pluginFolders = fs.readdirSync(folder);
|
||||
var pluginFolders = $tw.utils.getSubdirectories(folder) || [];
|
||||
for(var p=0; p<pluginFolders.length; p++) {
|
||||
if(!$tw.boot.excludeRegExp.test(pluginFolders[p])) {
|
||||
pluginFields = $tw.loadPluginFolder(path.resolve(folder,"./" + pluginFolders[p]));
|
||||
@@ -44,16 +44,16 @@ Command.prototype.execute = function() {
|
||||
}
|
||||
},
|
||||
collectPublisherPlugins = function(folder) {
|
||||
var publisherFolders = fs.readdirSync(folder);
|
||||
var publisherFolders = $tw.utils.getSubdirectories(folder) || [];
|
||||
for(var t=0; t<publisherFolders.length; t++) {
|
||||
if(!$tw.boot.excludeRegExp.test(publisherFolders[t])) {
|
||||
collectPlugins(path.resolve(folder,"./" + publisherFolders[t]));
|
||||
}
|
||||
}
|
||||
};
|
||||
collectPublisherPlugins(path.resolve($tw.boot.corePath,$tw.config.pluginsPath));
|
||||
collectPublisherPlugins(path.resolve($tw.boot.corePath,$tw.config.themesPath));
|
||||
collectPlugins(path.resolve($tw.boot.corePath,$tw.config.languagesPath));
|
||||
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.pluginsPath,$tw.config.pluginsEnvVar),collectPublisherPlugins);
|
||||
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.themesPath,$tw.config.themesEnvVar),collectPublisherPlugins);
|
||||
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.languagesPath,$tw.config.languagesEnvVar),collectPlugins);
|
||||
// Save the upgrade library tiddler
|
||||
var pluginFields = {
|
||||
title: upgradeLibraryTitle,
|
||||
|
||||
@@ -5,10 +5,12 @@ module-type: command
|
||||
|
||||
Command to save the subtiddlers of a bundle tiddler as a series of JSON files
|
||||
|
||||
--savelibrarytiddlers <tiddler> <pathname> <skinnylisting>
|
||||
--savelibrarytiddlers <tiddler> <tiddler-filter> <pathname> <skinnylisting>
|
||||
|
||||
The tiddler identifies the bundle tiddler that contains the subtiddlers.
|
||||
|
||||
The tiddler filter specifies the plugins to be included.
|
||||
|
||||
The pathname specifies the pathname to the folder in which the JSON files should be saved. The filename is the URL encoded title of the subtiddler.
|
||||
|
||||
The skinnylisting specifies the title of the tiddler to which a JSON catalogue of the subtiddlers will be saved. The JSON file contains the same data as the bundle tiddler but with the `text` field removed.
|
||||
@@ -69,7 +71,7 @@ Command.prototype.execute = function() {
|
||||
// Collect the skinny list data
|
||||
var pluginTiddlers = JSON.parse(tiddler.text),
|
||||
readmeContent = (pluginTiddlers.tiddlers[title + "/readme"] || {}).text,
|
||||
doesRequireReload = !!$tw.wiki.doesPluginInfoRequireReload(pluginTiddlers),
|
||||
doesRequireReload = !!self.commander.wiki.doesPluginInfoRequireReload(pluginTiddlers),
|
||||
iconTiddler = pluginTiddlers.tiddlers[title + "/icon"] || {},
|
||||
iconType = iconTiddler.type,
|
||||
iconText = iconTiddler.text,
|
||||
|
||||
@@ -42,7 +42,6 @@ function FramedEngine(options) {
|
||||
this.iframeNode.style.border = "none";
|
||||
this.iframeNode.style.padding = "0";
|
||||
this.iframeNode.style.resize = "none";
|
||||
this.iframeNode.style["background-color"] = this.widget.wiki.extractTiddlerDataItem(this.widget.wiki.getTiddlerText("$:/palette"),"tiddler-editor-background");
|
||||
this.iframeDoc.body.style.margin = "0";
|
||||
this.iframeDoc.body.style.padding = "0";
|
||||
this.widget.domNodes.push(this.iframeNode);
|
||||
@@ -74,13 +73,20 @@ function FramedEngine(options) {
|
||||
if(this.widget.editTabIndex) {
|
||||
this.iframeNode.setAttribute("tabindex",this.widget.editTabIndex);
|
||||
}
|
||||
if(this.widget.editAutoComplete) {
|
||||
this.domNode.setAttribute("autocomplete",this.widget.editAutoComplete);
|
||||
}
|
||||
if(this.widget.isDisabled === "yes") {
|
||||
this.domNode.setAttribute("disabled",true);
|
||||
}
|
||||
// Copy the styles from the dummy textarea
|
||||
this.copyStyles();
|
||||
// Add event listeners
|
||||
$tw.utils.addEventListeners(this.domNode,[
|
||||
{name: "click",handlerObject: this,handlerMethod: "handleClickEvent"},
|
||||
{name: "input",handlerObject: this,handlerMethod: "handleInputEvent"},
|
||||
{name: "keydown",handlerObject: this.widget,handlerMethod: "handleKeydownEvent"}
|
||||
{name: "keydown",handlerObject: this.widget,handlerMethod: "handleKeydownEvent"},
|
||||
{name: "focus",handlerObject: this,handlerMethod: "handleFocusEvent"}
|
||||
]);
|
||||
// Insert the element into the DOM
|
||||
this.iframeDoc.body.appendChild(this.domNode);
|
||||
@@ -96,7 +102,6 @@ FramedEngine.prototype.copyStyles = function() {
|
||||
this.domNode.style.display = "block";
|
||||
this.domNode.style.width = "100%";
|
||||
this.domNode.style.margin = "0";
|
||||
this.domNode.style["background-color"] = this.widget.wiki.extractTiddlerDataItem(this.widget.wiki.getTiddlerText("$:/palette"),"tiddler-editor-background");
|
||||
// In Chrome setting -webkit-text-fill-color overrides the placeholder text colour
|
||||
this.domNode.style["-webkit-text-fill-color"] = "currentcolor";
|
||||
};
|
||||
@@ -107,13 +112,20 @@ Set the text of the engine if it doesn't currently have focus
|
||||
FramedEngine.prototype.setText = function(text,type) {
|
||||
if(!this.domNode.isTiddlyWikiFakeDom) {
|
||||
if(this.domNode.ownerDocument.activeElement !== this.domNode) {
|
||||
this.domNode.value = text;
|
||||
this.updateDomNodeText(text);
|
||||
}
|
||||
// Fix the height if needed
|
||||
this.fixHeight();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Update the DomNode with the new text
|
||||
*/
|
||||
FramedEngine.prototype.updateDomNodeText = function(text) {
|
||||
this.domNode.value = text;
|
||||
};
|
||||
|
||||
/*
|
||||
Get the text of the engine
|
||||
*/
|
||||
@@ -153,6 +165,15 @@ FramedEngine.prototype.focus = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a focus event
|
||||
*/
|
||||
FramedEngine.prototype.handleFocusEvent = function(event) {
|
||||
if(this.widget.editCancelPopups) {
|
||||
$tw.popup.cancel(0);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a click
|
||||
*/
|
||||
@@ -167,6 +188,9 @@ Handle a dom "input" event which occurs when the text has changed
|
||||
FramedEngine.prototype.handleInputEvent = function(event) {
|
||||
this.widget.saveChanges(this.getText());
|
||||
this.fixHeight();
|
||||
if(this.widget.editInputActions) {
|
||||
this.widget.invokeActionString(this.widget.editInputActions);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
@@ -52,6 +52,12 @@ function SimpleEngine(options) {
|
||||
if(this.widget.editTabIndex) {
|
||||
this.domNode.setAttribute("tabindex",this.widget.editTabIndex);
|
||||
}
|
||||
if(this.widget.editAutoComplete) {
|
||||
this.domNode.setAttribute("autocomplete",this.widget.editAutoComplete);
|
||||
}
|
||||
if(this.widget.isDisabled === "yes") {
|
||||
this.domNode.setAttribute("disabled",true);
|
||||
}
|
||||
// Add an input event handler
|
||||
$tw.utils.addEventListeners(this.domNode,[
|
||||
{name: "focus", handlerObject: this, handlerMethod: "handleFocusEvent"},
|
||||
@@ -68,13 +74,20 @@ Set the text of the engine if it doesn't currently have focus
|
||||
SimpleEngine.prototype.setText = function(text,type) {
|
||||
if(!this.domNode.isTiddlyWikiFakeDom) {
|
||||
if(this.domNode.ownerDocument.activeElement !== this.domNode || text === "") {
|
||||
this.domNode.value = text;
|
||||
this.updateDomNodeText(text);
|
||||
}
|
||||
// Fix the height if needed
|
||||
this.fixHeight();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Update the DomNode with the new text
|
||||
*/
|
||||
SimpleEngine.prototype.updateDomNodeText = function(text) {
|
||||
this.domNode.value = text;
|
||||
};
|
||||
|
||||
/*
|
||||
Get the text of the engine
|
||||
*/
|
||||
@@ -115,6 +128,9 @@ Handle a dom "input" event which occurs when the text has changed
|
||||
SimpleEngine.prototype.handleInputEvent = function(event) {
|
||||
this.widget.saveChanges(this.getText());
|
||||
this.fixHeight();
|
||||
if(this.widget.editInputActions) {
|
||||
this.widget.invokeActionString(this.widget.editInputActions);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -122,6 +138,9 @@ SimpleEngine.prototype.handleInputEvent = function(event) {
|
||||
Handle a dom "focus" event
|
||||
*/
|
||||
SimpleEngine.prototype.handleFocusEvent = function(event) {
|
||||
if(this.widget.editCancelPopups) {
|
||||
$tw.popup.cancel(0);
|
||||
}
|
||||
if(this.widget.editFocusPopup) {
|
||||
$tw.popup.triggerPopup({
|
||||
domNode: this.domNode,
|
||||
|
||||
@@ -177,6 +177,11 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
this.editFocusPopup = this.getAttribute("focusPopup");
|
||||
this.editFocus = this.getAttribute("focus");
|
||||
this.editTabIndex = this.getAttribute("tabindex");
|
||||
this.editCancelPopups = this.getAttribute("cancelPopups","") === "yes";
|
||||
this.editInputActions = this.getAttribute("inputActions");
|
||||
this.editRefreshTitle = this.getAttribute("refreshTitle");
|
||||
this.editAutoComplete = this.getAttribute("autocomplete");
|
||||
this.isDisabled = this.getAttribute("disabled","no");
|
||||
// Get the default editor element tag and type
|
||||
var tag,type;
|
||||
if(this.editField === "text") {
|
||||
@@ -208,9 +213,11 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
EditTextWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
// Completely rerender if any of our attributes have changed
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE]) {
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedAttributes.disabled) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else if (changedTiddlers[this.editRefreshTitle]) {
|
||||
this.engine.updateDomNodeText(this.getEditInfo().value);
|
||||
} else if(changedTiddlers[this.editTitle]) {
|
||||
var editInfo = this.getEditInfo();
|
||||
this.updateEditor(editInfo.value,editInfo.type);
|
||||
|
||||
25
core/modules/filterrunprefixes/all.js
Normal file
25
core/modules/filterrunprefixes/all.js
Normal file
@@ -0,0 +1,25 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/all.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
Union of sets without de-duplication.
|
||||
Equivalent to = filter run prefix.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.all = function(operationSubFunction) {
|
||||
return function(results,source,widget) {
|
||||
results.push.apply(results, operationSubFunction(source,widget));
|
||||
};
|
||||
};
|
||||
|
||||
})();
|
||||
28
core/modules/filterrunprefixes/and.js
Normal file
28
core/modules/filterrunprefixes/and.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/and.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
Intersection of sets.
|
||||
Equivalent to + filter run prefix.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.and = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
// This replaces all the elements of the array, but keeps the actual array so that references to it are preserved
|
||||
source = options.wiki.makeTiddlerIterator(results.toArray());
|
||||
results.clear();
|
||||
results.pushTop(operationSubFunction(source,widget));
|
||||
};
|
||||
};
|
||||
|
||||
})();
|
||||
27
core/modules/filterrunprefixes/else.js
Normal file
27
core/modules/filterrunprefixes/else.js
Normal file
@@ -0,0 +1,27 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/else.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
Equivalent to ~ filter run prefix.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.else = function(operationSubFunction) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length === 0) {
|
||||
// Main result so far is empty
|
||||
results.pushTop(operationSubFunction(source,widget));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
})();
|
||||
25
core/modules/filterrunprefixes/except.js
Normal file
25
core/modules/filterrunprefixes/except.js
Normal file
@@ -0,0 +1,25 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/except.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
Difference of sets.
|
||||
Equivalent to - filter run prefix.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.except = function(operationSubFunction) {
|
||||
return function(results,source,widget) {
|
||||
results.remove(operationSubFunction(source,widget));
|
||||
};
|
||||
};
|
||||
|
||||
})();
|
||||
31
core/modules/filterrunprefixes/filter.js
Normal file
31
core/modules/filterrunprefixes/filter.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/filter.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.filter = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
var resultsToRemove = [];
|
||||
results.each(function(result) {
|
||||
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([result]),widget);
|
||||
if(filtered.length === 0) {
|
||||
resultsToRemove.push(result);
|
||||
}
|
||||
});
|
||||
results.remove(resultsToRemove);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
31
core/modules/filterrunprefixes/intersection.js
Normal file
31
core/modules/filterrunprefixes/intersection.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/intersection.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.intersection = function(operationSubFunction) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length !== 0) {
|
||||
var secondRunResults = operationSubFunction(source,widget);
|
||||
var firstRunResults = results.toArray();
|
||||
results.clear();
|
||||
$tw.utils.each(firstRunResults,function(title) {
|
||||
if(secondRunResults.indexOf(title) !== -1) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
})();
|
||||
24
core/modules/filterrunprefixes/or.js
Normal file
24
core/modules/filterrunprefixes/or.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/or.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
Equivalent to a filter run with no prefix.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.or = function(operationSubFunction) {
|
||||
return function(results,source,widget) {
|
||||
results.pushTop(operationSubFunction(source,widget));
|
||||
};
|
||||
};
|
||||
|
||||
})();
|
||||
50
core/modules/filterrunprefixes/reduce.js
Normal file
50
core/modules/filterrunprefixes/reduce.js
Normal file
@@ -0,0 +1,50 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/reduce.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.reduce = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
var accumulator = "";
|
||||
var index = 0;
|
||||
results.each(function(title) {
|
||||
var list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name) {
|
||||
switch(name) {
|
||||
case "currentTiddler":
|
||||
return "" + title;
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
if(list.length > 0) {
|
||||
accumulator = "" + list[0];
|
||||
}
|
||||
++index;
|
||||
});
|
||||
results.clear();
|
||||
results.push(accumulator);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -62,43 +62,61 @@ function parseFilterOperation(operators,filterString,p) {
|
||||
else if(operator.operator === "") {
|
||||
operator.operator = "title";
|
||||
}
|
||||
operator.operands = [];
|
||||
function parseOperand(bracketType) {
|
||||
var operand = {};
|
||||
switch (bracketType) {
|
||||
case "{": // Curly brackets
|
||||
operand.indirect = true;
|
||||
nextBracketPos = filterString.indexOf("}",p);
|
||||
break;
|
||||
case "[": // Square brackets
|
||||
nextBracketPos = filterString.indexOf("]",p);
|
||||
break;
|
||||
case "<": // Angle brackets
|
||||
operand.variable = true;
|
||||
nextBracketPos = filterString.indexOf(">",p);
|
||||
break;
|
||||
case "/": // regexp brackets
|
||||
var rex = /^((?:[^\\\/]*|\\.)*)\/(?:\(([mygi]+)\))?/g,
|
||||
rexMatch = rex.exec(filterString.substring(p));
|
||||
if(rexMatch) {
|
||||
operator.regexp = new RegExp(rexMatch[1], rexMatch[2]);
|
||||
// DEPRECATION WARNING
|
||||
console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand",operator.regexp);
|
||||
nextBracketPos = p + rex.lastIndex - 1;
|
||||
}
|
||||
else {
|
||||
throw "Unterminated regular expression in filter expression";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(nextBracketPos === -1) {
|
||||
throw "Missing closing bracket in filter expression";
|
||||
}
|
||||
if(!operator.regexp) {
|
||||
operand.text = filterString.substring(p,nextBracketPos);
|
||||
operator.operands.push(operand);
|
||||
}
|
||||
p = nextBracketPos + 1;
|
||||
}
|
||||
|
||||
p = nextBracketPos + 1;
|
||||
switch (bracket) {
|
||||
case "{": // Curly brackets
|
||||
operator.indirect = true;
|
||||
nextBracketPos = filterString.indexOf("}",p);
|
||||
break;
|
||||
case "[": // Square brackets
|
||||
nextBracketPos = filterString.indexOf("]",p);
|
||||
break;
|
||||
case "<": // Angle brackets
|
||||
operator.variable = true;
|
||||
nextBracketPos = filterString.indexOf(">",p);
|
||||
break;
|
||||
case "/": // regexp brackets
|
||||
var rex = /^((?:[^\\\/]*|\\.)*)\/(?:\(([mygi]+)\))?/g,
|
||||
rexMatch = rex.exec(filterString.substring(p));
|
||||
if(rexMatch) {
|
||||
operator.regexp = new RegExp(rexMatch[1], rexMatch[2]);
|
||||
// DEPRECATION WARNING
|
||||
console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand",operator.regexp);
|
||||
nextBracketPos = p + rex.lastIndex - 1;
|
||||
}
|
||||
else {
|
||||
throw "Unterminated regular expression in filter expression";
|
||||
}
|
||||
break;
|
||||
parseOperand(bracket);
|
||||
|
||||
// Check for multiple operands
|
||||
while(filterString.charAt(p) === ",") {
|
||||
p++;
|
||||
if(/^[\[\{<\/]/.test(filterString.substring(p))) {
|
||||
nextBracketPos = p;
|
||||
p++;
|
||||
parseOperand(filterString.charAt(nextBracketPos));
|
||||
} else {
|
||||
throw "Missing [ in filter expression";
|
||||
}
|
||||
}
|
||||
|
||||
if(nextBracketPos === -1) {
|
||||
throw "Missing closing bracket in filter expression";
|
||||
}
|
||||
if(!operator.regexp) {
|
||||
operator.operand = filterString.substring(p,nextBracketPos);
|
||||
}
|
||||
p = nextBracketPos + 1;
|
||||
|
||||
|
||||
// Push this operator
|
||||
operators.push(operator);
|
||||
} while(filterString.charAt(p) !== "]");
|
||||
@@ -119,7 +137,7 @@ exports.parseFilter = function(filterString) {
|
||||
p = 0, // Current position in the filter string
|
||||
match;
|
||||
var whitespaceRegExp = /(\s+)/mg,
|
||||
operandRegExp = /((?:\+|\-|~|=)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||
operandRegExp = /((?:\+|\-|~|=|\:(\w+))?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||
while(p < filterString.length) {
|
||||
// Skip any whitespace
|
||||
whitespaceRegExp.lastIndex = p;
|
||||
@@ -140,16 +158,19 @@ exports.parseFilter = function(filterString) {
|
||||
};
|
||||
if(match[1]) {
|
||||
operation.prefix = match[1];
|
||||
p++;
|
||||
p = p + operation.prefix.length;
|
||||
if(match[2]) {
|
||||
operation.namedPrefix = match[2];
|
||||
}
|
||||
}
|
||||
if(match[2]) { // Opening square bracket
|
||||
if(match[3]) { // Opening square bracket
|
||||
p = parseFilterOperation(operation.operators,filterString,p);
|
||||
} else {
|
||||
p = match.index + match[0].length;
|
||||
}
|
||||
if(match[3] || match[4] || match[5]) { // Double quoted string, single quoted string or unquoted title
|
||||
if(match[4] || match[5] || match[6]) { // Double quoted string, single quoted string or unquoted title
|
||||
operation.operators.push(
|
||||
{operator: "title", operand: match[3] || match[4] || match[5]}
|
||||
{operator: "title", operands: [{text: match[4] || match[5] || match[6]}]}
|
||||
);
|
||||
}
|
||||
results.push(operation);
|
||||
@@ -166,6 +187,14 @@ exports.getFilterOperators = function() {
|
||||
return this.filterOperators;
|
||||
};
|
||||
|
||||
exports.getFilterRunPrefixes = function() {
|
||||
if(!this.filterRunPrefixes) {
|
||||
$tw.Wiki.prototype.filterRunPrefixes = {};
|
||||
$tw.modules.applyMethods("filterrunprefix",this.filterRunPrefixes);
|
||||
}
|
||||
return this.filterRunPrefixes;
|
||||
}
|
||||
|
||||
exports.filterTiddlers = function(filterString,widget,source) {
|
||||
var fn = this.compileFilter(filterString);
|
||||
return fn.call(this,source,widget);
|
||||
@@ -198,7 +227,7 @@ exports.compileFilter = function(filterString) {
|
||||
results = [],
|
||||
currTiddlerTitle = widget && widget.getVariable("currentTiddler");
|
||||
$tw.utils.each(operation.operators,function(operator) {
|
||||
var operand = operator.operand,
|
||||
var operands = [],
|
||||
operatorFunction;
|
||||
if(!operator.operator) {
|
||||
operatorFunction = filterOperators.title;
|
||||
@@ -207,16 +236,23 @@ exports.compileFilter = function(filterString) {
|
||||
} else {
|
||||
operatorFunction = filterOperators[operator.operator];
|
||||
}
|
||||
if(operator.indirect) {
|
||||
operand = self.getTextReference(operator.operand,"",currTiddlerTitle);
|
||||
}
|
||||
if(operator.variable) {
|
||||
operand = widget.getVariable(operator.operand,{defaultValue: ""});
|
||||
}
|
||||
|
||||
$tw.utils.each(operator.operands,function(operand) {
|
||||
if(operand.indirect) {
|
||||
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
||||
} else if(operand.variable) {
|
||||
operand.value = widget.getVariable(operand.text,{defaultValue: ""});
|
||||
} else {
|
||||
operand.value = operand.text;
|
||||
}
|
||||
operands.push(operand.value);
|
||||
});
|
||||
|
||||
// Invoke the appropriate filteroperator module
|
||||
results = operatorFunction(accumulator,{
|
||||
operator: operator.operator,
|
||||
operand: operand,
|
||||
operand: operands.length > 0 ? operands[0] : undefined,
|
||||
operands: operands,
|
||||
prefix: operator.prefix,
|
||||
suffix: operator.suffix,
|
||||
suffixes: operator.suffixes,
|
||||
@@ -241,35 +277,30 @@ exports.compileFilter = function(filterString) {
|
||||
return resultArray;
|
||||
}
|
||||
};
|
||||
var filterRunPrefixes = self.getFilterRunPrefixes();
|
||||
// Wrap the operator functions in a wrapper function that depends on the prefix
|
||||
operationFunctions.push((function() {
|
||||
var options = {wiki: self};
|
||||
switch(operation.prefix || "") {
|
||||
case "": // No prefix means that the operation is unioned into the result
|
||||
return function(results,source,widget) {
|
||||
$tw.utils.pushTop(results,operationSubFunction(source,widget));
|
||||
};
|
||||
return filterRunPrefixes["or"](operationSubFunction, options);
|
||||
case "=": // The results of the operation are pushed into the result without deduplication
|
||||
return function(results,source,widget) {
|
||||
Array.prototype.push.apply(results,operationSubFunction(source,widget));
|
||||
};
|
||||
return filterRunPrefixes["all"](operationSubFunction, options);
|
||||
case "-": // The results of this operation are removed from the main result
|
||||
return function(results,source,widget) {
|
||||
$tw.utils.removeArrayEntries(results,operationSubFunction(source,widget));
|
||||
};
|
||||
return filterRunPrefixes["except"](operationSubFunction, options);
|
||||
case "+": // This operation is applied to the main results so far
|
||||
return function(results,source,widget) {
|
||||
// This replaces all the elements of the array, but keeps the actual array so that references to it are preserved
|
||||
source = self.makeTiddlerIterator(results);
|
||||
results.splice(0,results.length);
|
||||
$tw.utils.pushTop(results,operationSubFunction(source,widget));
|
||||
};
|
||||
return filterRunPrefixes["and"](operationSubFunction, options);
|
||||
case "~": // This operation is unioned into the result only if the main result so far is empty
|
||||
return function(results,source,widget) {
|
||||
if(results.length === 0) {
|
||||
// Main result so far is empty
|
||||
$tw.utils.pushTop(results,operationSubFunction(source,widget));
|
||||
}
|
||||
};
|
||||
return filterRunPrefixes["else"](operationSubFunction, options);
|
||||
default:
|
||||
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
|
||||
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
|
||||
} else {
|
||||
return function(results,source,widget) {
|
||||
results.clear();
|
||||
results.push($tw.language.getString("Error/FilterRunPrefix"));
|
||||
};
|
||||
}
|
||||
}
|
||||
})());
|
||||
});
|
||||
@@ -280,11 +311,11 @@ exports.compileFilter = function(filterString) {
|
||||
} else if(typeof source === "object") { // Array or hashmap
|
||||
source = self.makeTiddlerIterator(source);
|
||||
}
|
||||
var results = [];
|
||||
var results = new $tw.utils.LinkedList();
|
||||
$tw.utils.each(operationFunctions,function(operationFunction) {
|
||||
operationFunction(results,source,widget);
|
||||
});
|
||||
return results;
|
||||
return results.toArray();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
40
core/modules/filters/compare.js
Normal file
40
core/modules/filters/compare.js
Normal file
@@ -0,0 +1,40 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/compare.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
General purpose comparison operator
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.compare = function(source,operator,options) {
|
||||
var suffixes = operator.suffixes || [],
|
||||
type = (suffixes[0] || [])[0],
|
||||
mode = (suffixes[1] || [])[0],
|
||||
typeFn = $tw.utils.makeCompareFunction(type,{defaultType: "number"}),
|
||||
modeFn = modes[mode] || modes.eq,
|
||||
invert = operator.prefix === "!",
|
||||
results = [];
|
||||
source(function(tiddler,title) {
|
||||
if(modeFn(typeFn(title,operator.operand)) !== invert) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
var modes = {
|
||||
"eq": function(value) {return value === 0;},
|
||||
"ne": function(value) {return value !== 0;},
|
||||
"gteq": function(value) {return value >= 0;},
|
||||
"gt": function(value) {return value > 0;},
|
||||
"lteq": function(value) {return value <= 0;},
|
||||
"lt": function(value) {return value < 0;}
|
||||
}
|
||||
|
||||
})();
|
||||
36
core/modules/filters/duplicateslugs.js
Normal file
36
core/modules/filters/duplicateslugs.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/duplicateslugs.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter function for [duplicateslugs[]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.duplicateslugs = function(source,operator,options) {
|
||||
var slugs = Object.create(null), // Hashmap by slug of title, replaced with "true" if the duplicate title has already been output
|
||||
results = [];
|
||||
source(function(tiddler,title) {
|
||||
var slug = options.wiki.slugify(title);
|
||||
if(slug in slugs) {
|
||||
if(slugs[slug] !== true) {
|
||||
results.push(slugs[slug]);
|
||||
slugs[slug] = true;
|
||||
}
|
||||
results.push(title);
|
||||
} else {
|
||||
slugs[slug] = title;
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -16,14 +16,16 @@ Filter operator for returning the descriptions of the specified edition names
|
||||
Export our filter function
|
||||
*/
|
||||
exports.editiondescription = function(source,operator,options) {
|
||||
var results = [],
|
||||
editionInfo = $tw.utils.getEditionInfo();
|
||||
if(editionInfo) {
|
||||
source(function(tiddler,title) {
|
||||
if($tw.utils.hop(editionInfo,title)) {
|
||||
results.push(editionInfo[title].description || "");
|
||||
}
|
||||
});
|
||||
var results = [];
|
||||
if($tw.node) {
|
||||
var editionInfo = $tw.utils.getEditionInfo();
|
||||
if(editionInfo) {
|
||||
source(function(tiddler,title) {
|
||||
if($tw.utils.hop(editionInfo,title)) {
|
||||
results.push(editionInfo[title].description || "");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -16,14 +16,16 @@ Filter operator for returning the names of the available editions in this wiki
|
||||
Export our filter function
|
||||
*/
|
||||
exports.editions = function(source,operator,options) {
|
||||
var results = [],
|
||||
editionInfo = $tw.utils.getEditionInfo();
|
||||
if(editionInfo) {
|
||||
$tw.utils.each(editionInfo,function(info,name) {
|
||||
results.push(name);
|
||||
});
|
||||
var results = [];
|
||||
if($tw.node) {
|
||||
var editionInfo = $tw.utils.getEditionInfo();
|
||||
if(editionInfo) {
|
||||
$tw.utils.each(editionInfo,function(info,name) {
|
||||
results.push(name);
|
||||
});
|
||||
}
|
||||
results.sort();
|
||||
}
|
||||
results.sort();
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ exports.encodehtml = function(source,operator,options) {
|
||||
exports.stringify = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push($tw.utils.stringify(title));
|
||||
results.push($tw.utils.stringify(title,(operator.suffix === "rawunicode")));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
@@ -85,7 +85,7 @@ exports.stringify = function(source,operator,options) {
|
||||
exports.jsonstringify = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push($tw.utils.jsonStringify(title));
|
||||
results.push($tw.utils.jsonStringify(title,(operator.suffix === "rawunicode")));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -16,13 +16,28 @@ Filter operator for returning the names of the fields on the selected tiddlers
|
||||
Export our filter function
|
||||
*/
|
||||
exports.fields = function(source,operator,options) {
|
||||
var results = [];
|
||||
var results = [],
|
||||
fieldName,
|
||||
suffixes = (operator.suffixes || [])[0] || [],
|
||||
operand = $tw.utils.parseStringArray(operator.operand);
|
||||
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler) {
|
||||
for(var fieldName in tiddler.fields) {
|
||||
$tw.utils.pushTop(results,fieldName);
|
||||
}
|
||||
}
|
||||
if(suffixes.indexOf("include") !== -1) {
|
||||
for(fieldName in tiddler.fields) {
|
||||
(operand.indexOf(fieldName) !== -1) ? $tw.utils.pushTop(results,fieldName) : "";
|
||||
}
|
||||
} else if (suffixes.indexOf("exclude") !== -1) {
|
||||
for(fieldName in tiddler.fields) {
|
||||
(operand.indexOf(fieldName) !== -1) ? "" : $tw.utils.pushTop(results,fieldName);
|
||||
}
|
||||
} // else if
|
||||
else {
|
||||
for(fieldName in tiddler.fields) {
|
||||
$tw.utils.pushTop(results,fieldName);
|
||||
}
|
||||
} // else
|
||||
} // if (tiddler)
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
31
core/modules/filters/filter.js
Normal file
31
core/modules/filters/filter.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/filter.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator returning those input titles that pass a subfilter
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.filter = function(source,operator,options) {
|
||||
var filterFn = options.wiki.compileFilter(operator.operand),
|
||||
results = [],
|
||||
target = operator.prefix !== "!";
|
||||
source(function(tiddler,title) {
|
||||
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]));
|
||||
if((list.length > 0) === target) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
46
core/modules/filters/format.js
Normal file
46
core/modules/filters/format.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/format.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
Filter operator for formatting strings
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var formatFilterOperators;
|
||||
|
||||
function getFormatFilterOperators() {
|
||||
if(!formatFilterOperators) {
|
||||
formatFilterOperators = {};
|
||||
$tw.modules.applyMethods("formatfilteroperator",formatFilterOperators);
|
||||
}
|
||||
return formatFilterOperators;
|
||||
}
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.format = function(source,operator,options) {
|
||||
// Dispatch to the correct formatfilteroperator
|
||||
var formatFilterOperators = getFormatFilterOperators();
|
||||
if(operator.suffix) {
|
||||
var formatFilterOperator = formatFilterOperators[operator.suffix];
|
||||
if(formatFilterOperator) {
|
||||
return formatFilterOperator(source,operator.operand,options);
|
||||
} else {
|
||||
return [$tw.language.getString("Error/FormatFilterOperator")];
|
||||
}
|
||||
} else {
|
||||
// Return all unchanged if the suffix is missing
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results;
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
26
core/modules/filters/format/date.js
Normal file
26
core/modules/filters/format/date.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/format/date.js
|
||||
type: application/javascript
|
||||
module-type: formatfilteroperator
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.date = function(source,operand,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var value = $tw.utils.parseDate(title);
|
||||
if(value && $tw.utils.isDate(value) && value.toString() !== "Invalid Date") {
|
||||
results.push($tw.utils.formatDateString(value,operand || "YYYY MM DD 0hh:0mm"));
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
26
core/modules/filters/format/relativedate.js
Normal file
26
core/modules/filters/format/relativedate.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/format/relativedate.js
|
||||
type: application/javascript
|
||||
module-type: formatfilteroperator
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.relativedate = function(source,operand,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var value = $tw.utils.parseDate(title);
|
||||
if(value && $tw.utils.isDate(value) && value.toString() !== "Invalid Date") {
|
||||
results.push($tw.utils.getRelativeDate((new Date()) - (new Date(value))).description);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -1,38 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/getstoryviewmode.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for retrieving modes from a storyview. Only "singletiddlermode" is implemented at present
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter functions
|
||||
*/
|
||||
|
||||
exports.getstoryviewmode = function(source,operator,options) {
|
||||
// Initialise the storyviews if they've not been done already
|
||||
var storyviews = {};
|
||||
$tw.modules.applyMethods("storyview",storyviews);
|
||||
if(operator.operand !== "singletiddlermode") {
|
||||
return [];
|
||||
}
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var storyview = storyviews[title];
|
||||
if(storyview && storyview.singleTiddlerMode) {
|
||||
results.push("yes");
|
||||
} else {
|
||||
results.push("no");
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -3,7 +3,7 @@ title: $:/core/modules/filters/has.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for checking if a tiddler has the specified field
|
||||
Filter operator for checking if a tiddler has the specified field or index
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
@@ -33,16 +33,32 @@ exports.has = function(source,operator,options) {
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else if(operator.suffix === "index") {
|
||||
if(invert) {
|
||||
source(function(tiddler,title) {
|
||||
if(!tiddler || !$tw.utils.hop(tiddler.fields,operator.operand) || (tiddler.fields[operator.operand] === "")) {
|
||||
if(!tiddler || (tiddler && (!$tw.utils.hop(options.wiki.getTiddlerDataCached(tiddler,Object.create(null)),operator.operand)))) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && $tw.utils.hop(tiddler.fields,operator.operand) && !(tiddler.fields[operator.operand] === "" || tiddler.fields[operator.operand].length === 0)) {
|
||||
if(tiddler && $tw.utils.hop(options.wiki.getTiddlerDataCached(tiddler,Object.create(null)),operator.operand)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(invert) {
|
||||
source(function(tiddler,title) {
|
||||
if(!tiddler || !$tw.utils.hop(tiddler.fields,operator.operand) || (tiddler.fields[operator.operand].length === 0)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && $tw.utils.hop(tiddler.fields,operator.operand) && (tiddler.fields[operator.operand].length !== 0)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
|
||||
36
core/modules/filters/is/draft.js
Normal file
36
core/modules/filters/is/draft.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/is/draft.js
|
||||
type: application/javascript
|
||||
module-type: isfilteroperator
|
||||
|
||||
Filter function for [is[draft]] analagous to [has[draft.of]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.draft = function(source,prefix,options) {
|
||||
var results = [];
|
||||
if(prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(!tiddler || !$tw.utils.hop(tiddler.fields,"draft.of")) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && $tw.utils.hop(tiddler.fields,"draft.of") && (tiddler.fields["draft.of"].length !== 0)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -22,7 +22,7 @@ Export our filter function
|
||||
exports.lookup = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(options.wiki.getTiddlerText(operator.operand + title) || options.wiki.getTiddlerText(operator.operand + operator.suffix));
|
||||
results.push(options.wiki.getTiddlerText(operator.operand + title) || operator.suffix);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -91,6 +91,20 @@ exports.exponential = makeNumericBinaryOperator(
|
||||
function(a,b) {return Number.prototype.toExponential.call(a,Math.min(Math.max(b,0),100));}
|
||||
);
|
||||
|
||||
exports.power = makeNumericBinaryOperator(
|
||||
function(a,b) {return Math.pow(a,b);}
|
||||
);
|
||||
|
||||
exports.log = makeNumericBinaryOperator(
|
||||
function(a,b) {
|
||||
if(b) {
|
||||
return Math.log(a)/Math.log(b);
|
||||
} else {
|
||||
return Math.log(a);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
exports.sum = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return accumulator + value},
|
||||
0 // Initial value
|
||||
@@ -114,9 +128,9 @@ exports.minall = makeNumericReducingOperator(
|
||||
function makeNumericBinaryOperator(fnCalc) {
|
||||
return function(source,operator,options) {
|
||||
var result = [],
|
||||
numOperand = parseNumber(operator.operand);
|
||||
numOperand = $tw.utils.parseNumber(operator.operand);
|
||||
source(function(tiddler,title) {
|
||||
result.push(stringifyNumber(fnCalc(parseNumber(title),numOperand)));
|
||||
result.push($tw.utils.stringifyNumber(fnCalc($tw.utils.parseNumber(title),numOperand)));
|
||||
});
|
||||
return result;
|
||||
};
|
||||
@@ -129,18 +143,10 @@ function makeNumericReducingOperator(fnCalc,initialValue) {
|
||||
source(function(tiddler,title) {
|
||||
result.push(title);
|
||||
});
|
||||
return [stringifyNumber(result.reduce(function(accumulator,currentValue) {
|
||||
return fnCalc(accumulator,parseNumber(currentValue));
|
||||
return [$tw.utils.stringifyNumber(result.reduce(function(accumulator,currentValue) {
|
||||
return fnCalc(accumulator,$tw.utils.parseNumber(currentValue));
|
||||
},initialValue))];
|
||||
};
|
||||
}
|
||||
|
||||
function parseNumber(str) {
|
||||
return parseFloat(str) || 0;
|
||||
}
|
||||
|
||||
function stringifyNumber(num) {
|
||||
return num + "";
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
58
core/modules/filters/reduce.js
Normal file
58
core/modules/filters/reduce.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/reduce.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator evaluates a subfilter for each item, making the running total available in the variable `accumulator`, and the current index available in the variable `index`
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.reduce = function(source,operator,options) {
|
||||
// Accumulate the list
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
// Run the filter over each item
|
||||
var filterFn = options.wiki.compileFilter(operator.operand),
|
||||
accumulator = operator.operands[1] || "";
|
||||
for(var index=0; index<results.length; index++) {
|
||||
var title = results[index],
|
||||
list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name) {
|
||||
switch(name) {
|
||||
case "currentTiddler":
|
||||
return "" + title;
|
||||
case "accumulator":
|
||||
return "" + accumulator;
|
||||
case "index":
|
||||
return "" + index;
|
||||
case "revIndex":
|
||||
return "" + (results.length - 1 - index);
|
||||
case "length":
|
||||
return "" + results.length;
|
||||
default:
|
||||
return options.widget.getVariable(name);
|
||||
}
|
||||
}
|
||||
});
|
||||
if(list.length > 0) {
|
||||
accumulator = "" + list[0];
|
||||
}
|
||||
}
|
||||
if(results.length > 0) {
|
||||
return [accumulator];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
23
core/modules/filters/slugify.js
Normal file
23
core/modules/filters/slugify.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/slugify.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for slugifying a tiddler title
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.slugify = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(options.wiki.slugify(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
57
core/modules/filters/sortsub.js
Normal file
57
core/modules/filters/sortsub.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/sortsub.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for sorting by a subfilter
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.sortsub = function(source,operator,options) {
|
||||
// Compile the subfilter
|
||||
var filterFn = options.wiki.compileFilter(operator.operand);
|
||||
// Collect the input titles and the corresponding sort keys
|
||||
var inputTitles = [],
|
||||
sortKeys = [];
|
||||
source(function(tiddler,title) {
|
||||
inputTitles.push(title);
|
||||
var r = filterFn.call(options.wiki,function(iterator) {
|
||||
iterator(options.wiki.getTiddler(title),title);
|
||||
},{
|
||||
getVariable: function(name) {
|
||||
if(name === "currentTiddler") {
|
||||
return title;
|
||||
} else {
|
||||
return options.widget.getVariable(name);
|
||||
}
|
||||
}
|
||||
});
|
||||
sortKeys.push(r[0] || "");
|
||||
});
|
||||
// Rather than sorting the titles array, we'll sort the indexes so that we can consult both arrays
|
||||
var indexes = new Array(inputTitles.length);
|
||||
for(var t=0; t<inputTitles.length; t++) {
|
||||
indexes[t] = t;
|
||||
}
|
||||
// Sort the indexes
|
||||
var compareFn = $tw.utils.makeCompareFunction(operator.suffix,{defaultType: "string",invert: operator.prefix === "!"});
|
||||
indexes = indexes.sort(function(a,b) {
|
||||
return compareFn(sortKeys[a],sortKeys[b]);
|
||||
});
|
||||
// Make the results array in order
|
||||
var results = [];
|
||||
$tw.utils.each(indexes,function(index) {
|
||||
results.push(inputTitles[index]);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -34,14 +34,36 @@ exports.titlecase = makeStringBinaryOperator(
|
||||
function(a) {return [$tw.utils.toTitleCase(a)];}
|
||||
);
|
||||
|
||||
exports.trim = makeStringBinaryOperator(
|
||||
function(a) {return [$tw.utils.trim(a)];}
|
||||
);
|
||||
exports.trim = function(source,operator,options) {
|
||||
var result = [],
|
||||
suffix = operator.suffix || "",
|
||||
operand = (operator.operand || ""),
|
||||
fnCalc;
|
||||
if(suffix === "prefix") {
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];}
|
||||
} else if(suffix === "suffix") {
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];}
|
||||
} else {
|
||||
if(operand === "") {
|
||||
fnCalc = function(a) {return [$tw.utils.trim(a)];}
|
||||
} else {
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];}
|
||||
}
|
||||
}
|
||||
source(function(tiddler,title) {
|
||||
Array.prototype.push.apply(result,fnCalc(title,operand));
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
exports.split = makeStringBinaryOperator(
|
||||
function(a,b) {return ("" + a).split(b);}
|
||||
);
|
||||
|
||||
exports["enlist-input"] = makeStringBinaryOperator(
|
||||
function(a,o,s) {return $tw.utils.parseStringArray("" + a,(s === "raw"));}
|
||||
);
|
||||
|
||||
exports.join = makeStringReducingOperator(
|
||||
function(accumulator,value,operand) {
|
||||
if(accumulator === null) {
|
||||
@@ -56,7 +78,7 @@ function makeStringBinaryOperator(fnCalc) {
|
||||
return function(source,operator,options) {
|
||||
var result = [];
|
||||
source(function(tiddler,title) {
|
||||
Array.prototype.push.apply(result,fnCalc(title,operator.operand || ""));
|
||||
Array.prototype.push.apply(result,fnCalc(title,operator.operand || "",operator.suffix || ""));
|
||||
});
|
||||
return result;
|
||||
};
|
||||
@@ -68,9 +90,12 @@ function makeStringReducingOperator(fnCalc,initialValue) {
|
||||
source(function(tiddler,title) {
|
||||
result.push(title);
|
||||
});
|
||||
if(result.length === 0) {
|
||||
return [];
|
||||
}
|
||||
return [result.reduce(function(accumulator,currentValue) {
|
||||
return fnCalc(accumulator,currentValue,operator.operand || "");
|
||||
},initialValue)];
|
||||
},initialValue) || ""];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -90,4 +115,61 @@ exports.splitregexp = function(source,operator,options) {
|
||||
return result;
|
||||
};
|
||||
|
||||
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" : ""),
|
||||
isRegExp = (suffixes[1] && suffixes[1][0] === "regexp") ? true : false,
|
||||
searchTerm,
|
||||
regExp;
|
||||
|
||||
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])
|
||||
);
|
||||
} else {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.pad = function(source,operator,options) {
|
||||
var results = [],
|
||||
targetLength = operator.operand ? parseInt(operator.operand) : 0,
|
||||
fill = operator.operands[1] || "0";
|
||||
|
||||
source(function(tiddler,title) {
|
||||
if(title && title.length) {
|
||||
if(title.length >= targetLength) {
|
||||
results.push(title);
|
||||
} else {
|
||||
var padString = "",
|
||||
padStringLength = targetLength - title.length;
|
||||
while (padStringLength > padString.length) {
|
||||
padString += fill;
|
||||
}
|
||||
//make sure we do not exceed the specified length
|
||||
padString = padString.slice(0,padStringLength);
|
||||
if(operator.suffix && (operator.suffix === "suffix")) {
|
||||
title = title + padString;
|
||||
} else {
|
||||
title = padString + title;
|
||||
}
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
});
|
||||
return results;
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
@@ -8,183 +8,228 @@ Extended filter operators to manipulate the current list.
|
||||
\*/
|
||||
(function () {
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Fetch titles from the current list
|
||||
*/
|
||||
var prepare_results = function (source) {
|
||||
var results = [];
|
||||
source(function (tiddler, title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
/*
|
||||
Fetch titles from the current list
|
||||
*/
|
||||
var prepare_results = function (source) {
|
||||
var results = [];
|
||||
source(function (tiddler, title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
Moves a number of items from the tail of the current list before the item named in the operand
|
||||
*/
|
||||
exports.putbefore = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return (index === -1) ?
|
||||
results.slice(0, -1) :
|
||||
results.slice(0, index).concat(results.slice(-count)).concat(results.slice(index, -count));
|
||||
};
|
||||
/*
|
||||
Moves a number of items from the tail of the current list before the item named in the operand
|
||||
*/
|
||||
exports.putbefore = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return (index === -1) ?
|
||||
results.slice(0, -1) :
|
||||
results.slice(0, index).concat(results.slice(-count)).concat(results.slice(index, -count));
|
||||
};
|
||||
|
||||
/*
|
||||
Moves a number of items from the tail of the current list after the item named in the operand
|
||||
*/
|
||||
exports.putafter = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return (index === -1) ?
|
||||
results.slice(0, -1) :
|
||||
results.slice(0, index + 1).concat(results.slice(-count)).concat(results.slice(index + 1, -count));
|
||||
};
|
||||
/*
|
||||
Moves a number of items from the tail of the current list after the item named in the operand
|
||||
*/
|
||||
exports.putafter = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return (index === -1) ?
|
||||
results.slice(0, -1) :
|
||||
results.slice(0, index + 1).concat(results.slice(-count)).concat(results.slice(index + 1, -count));
|
||||
};
|
||||
|
||||
/*
|
||||
Replaces the item named in the operand with a number of items from the tail of the current list
|
||||
*/
|
||||
exports.replace = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return (index === -1) ?
|
||||
results.slice(0, -count) :
|
||||
results.slice(0, index).concat(results.slice(-count)).concat(results.slice(index + 1, -count));
|
||||
};
|
||||
/*
|
||||
Replaces the item named in the operand with a number of items from the tail of the current list
|
||||
*/
|
||||
exports.replace = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return (index === -1) ?
|
||||
results.slice(0, -count) :
|
||||
results.slice(0, index).concat(results.slice(-count)).concat(results.slice(index + 1, -count));
|
||||
};
|
||||
|
||||
/*
|
||||
Moves a number of items from the tail of the current list to the head of the list
|
||||
*/
|
||||
exports.putfirst = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return results.slice(-count).concat(results.slice(0, -count));
|
||||
};
|
||||
/*
|
||||
Moves a number of items from the tail of the current list to the head of the list
|
||||
*/
|
||||
exports.putfirst = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return results.slice(-count).concat(results.slice(0, -count));
|
||||
};
|
||||
|
||||
/*
|
||||
Moves a number of items from the head of the current list to the tail of the list
|
||||
*/
|
||||
exports.putlast = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return results.slice(count).concat(results.slice(0, count));
|
||||
};
|
||||
/*
|
||||
Moves a number of items from the head of the current list to the tail of the list
|
||||
*/
|
||||
exports.putlast = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return results.slice(count).concat(results.slice(0, count));
|
||||
};
|
||||
|
||||
/*
|
||||
Moves the item named in the operand a number of places forward or backward in the list
|
||||
*/
|
||||
exports.move = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1),
|
||||
marker = results.splice(index, 1),
|
||||
offset = (index + count) > 0 ? index + count : 0;
|
||||
return results.slice(0, offset).concat(marker).concat(results.slice(offset));
|
||||
};
|
||||
/*
|
||||
Moves the item named in the operand a number of places forward or backward in the list
|
||||
*/
|
||||
exports.move = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1),
|
||||
marker = results.splice(index, 1),
|
||||
offset = (index + count) > 0 ? index + count : 0;
|
||||
return results.slice(0, offset).concat(marker).concat(results.slice(offset));
|
||||
};
|
||||
|
||||
/*
|
||||
Returns the items from the current list that are after the item named in the operand
|
||||
*/
|
||||
exports.allafter = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand);
|
||||
return (index === -1) ? [] :
|
||||
(operator.suffix) ? results.slice(index) :
|
||||
results.slice(index + 1);
|
||||
};
|
||||
/*
|
||||
Returns the items from the current list that are after the item named in the operand
|
||||
*/
|
||||
exports.allafter = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand);
|
||||
return (index === -1) ? [] :
|
||||
(operator.suffix) ? results.slice(index) :
|
||||
results.slice(index + 1);
|
||||
};
|
||||
|
||||
/*
|
||||
Returns the items from the current list that are before the item named in the operand
|
||||
*/
|
||||
exports.allbefore = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand);
|
||||
return (index === -1) ? [] :
|
||||
(operator.suffix) ? results.slice(0, index + 1) :
|
||||
results.slice(0, index);
|
||||
};
|
||||
/*
|
||||
Returns the items from the current list that are before the item named in the operand
|
||||
*/
|
||||
exports.allbefore = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand);
|
||||
return (index === -1) ? [] :
|
||||
(operator.suffix) ? results.slice(0, index + 1) :
|
||||
results.slice(0, index);
|
||||
};
|
||||
|
||||
/*
|
||||
Appends the items listed in the operand array to the tail of the current list
|
||||
*/
|
||||
exports.append = function (source, operator) {
|
||||
var append = $tw.utils.parseStringArray(operator.operand, "true"),
|
||||
results = prepare_results(source),
|
||||
count = parseInt(operator.suffix) || append.length;
|
||||
return (append.length === 0) ? results :
|
||||
(operator.prefix) ? results.concat(append.slice(-count)) :
|
||||
results.concat(append.slice(0, count));
|
||||
};
|
||||
/*
|
||||
Appends the items listed in the operand array to the tail of the current list
|
||||
*/
|
||||
exports.append = function (source, operator) {
|
||||
var append = $tw.utils.parseStringArray(operator.operand, "true"),
|
||||
results = prepare_results(source),
|
||||
count = parseInt(operator.suffix) || append.length;
|
||||
return (append.length === 0) ? results :
|
||||
(operator.prefix) ? results.concat(append.slice(-count)) :
|
||||
results.concat(append.slice(0, count));
|
||||
};
|
||||
|
||||
/*
|
||||
Prepends the items listed in the operand array to the head of the current list
|
||||
*/
|
||||
exports.prepend = function (source, operator) {
|
||||
var prepend = $tw.utils.parseStringArray(operator.operand, "true"),
|
||||
results = prepare_results(source),
|
||||
count = $tw.utils.getInt(operator.suffix,prepend.length);
|
||||
return (prepend.length === 0) ? results :
|
||||
(operator.prefix) ? prepend.slice(-count).concat(results) :
|
||||
prepend.slice(0, count).concat(results);
|
||||
};
|
||||
/*
|
||||
Prepends the items listed in the operand array to the head of the current list
|
||||
*/
|
||||
exports.prepend = function (source, operator) {
|
||||
var prepend = $tw.utils.parseStringArray(operator.operand, "true"),
|
||||
results = prepare_results(source),
|
||||
count = $tw.utils.getInt(operator.suffix,prepend.length);
|
||||
return (prepend.length === 0) ? results :
|
||||
(operator.prefix) ? prepend.slice(-count).concat(results) :
|
||||
prepend.slice(0, count).concat(results);
|
||||
};
|
||||
|
||||
/*
|
||||
Returns all items from the current list except the items listed in the operand array
|
||||
*/
|
||||
exports.remove = function (source, operator) {
|
||||
var array = $tw.utils.parseStringArray(operator.operand, "true"),
|
||||
results = prepare_results(source),
|
||||
count = parseInt(operator.suffix) || array.length,
|
||||
p,
|
||||
len,
|
||||
index;
|
||||
len = array.length - 1;
|
||||
for (p = 0; p < count; ++p) {
|
||||
if (operator.prefix) {
|
||||
index = results.indexOf(array[len - p]);
|
||||
} else {
|
||||
index = results.indexOf(array[p]);
|
||||
}
|
||||
if (index !== -1) {
|
||||
results.splice(index, 1);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
/*
|
||||
Returns all items from the current list except the items listed in the operand array
|
||||
*/
|
||||
exports.remove = function (source, operator) {
|
||||
var array = $tw.utils.parseStringArray(operator.operand, "true"),
|
||||
results = prepare_results(source),
|
||||
count = parseInt(operator.suffix) || array.length,
|
||||
p,
|
||||
len,
|
||||
index;
|
||||
len = array.length - 1;
|
||||
for (p = 0; p < count; ++p) {
|
||||
if (operator.prefix) {
|
||||
index = results.indexOf(array[len - p]);
|
||||
} else {
|
||||
index = results.indexOf(array[p]);
|
||||
}
|
||||
if (index !== -1) {
|
||||
results.splice(index, 1);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
Returns all items from the current list sorted in the order of the items in the operand array
|
||||
*/
|
||||
exports.sortby = function (source, operator) {
|
||||
var results = prepare_results(source);
|
||||
if (!results || results.length < 2) {
|
||||
return results;
|
||||
}
|
||||
var lookup = $tw.utils.parseStringArray(operator.operand, "true");
|
||||
results.sort(function (a, b) {
|
||||
return lookup.indexOf(a) - lookup.indexOf(b);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
/*
|
||||
Returns all items from the current list sorted in the order of the items in the operand array
|
||||
*/
|
||||
exports.sortby = function (source, operator) {
|
||||
var results = prepare_results(source);
|
||||
if (!results || results.length < 2) {
|
||||
return results;
|
||||
}
|
||||
var lookup = $tw.utils.parseStringArray(operator.operand, "true");
|
||||
results.sort(function (a, b) {
|
||||
return lookup.indexOf(a) - lookup.indexOf(b);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
Removes all duplicate items from the current list
|
||||
*/
|
||||
exports.unique = function (source, operator) {
|
||||
var results = prepare_results(source);
|
||||
var set = results.reduce(function (a, b) {
|
||||
if (a.indexOf(b) < 0) {
|
||||
a.push(b);
|
||||
}
|
||||
return a;
|
||||
}, []);
|
||||
return set;
|
||||
};
|
||||
/*
|
||||
Removes all duplicate items from the current list
|
||||
*/
|
||||
exports.unique = function (source, operator) {
|
||||
var results = prepare_results(source);
|
||||
var set = results.reduce(function (a, b) {
|
||||
if (a.indexOf(b) < 0) {
|
||||
a.push(b);
|
||||
}
|
||||
return a;
|
||||
}, []);
|
||||
return set;
|
||||
};
|
||||
|
||||
var cycleValueInArray = function(results,operands,stepSize) {
|
||||
var resultsIndex,
|
||||
step = stepSize || 1,
|
||||
i = 0,
|
||||
opLength = operands.length,
|
||||
nextOperandIndex;
|
||||
for(i; i < opLength; i++) {
|
||||
resultsIndex = results.indexOf(operands[i]);
|
||||
if(resultsIndex !== -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(resultsIndex !== -1) {
|
||||
i = i + step;
|
||||
nextOperandIndex = (i < opLength ? i : i - opLength);
|
||||
if(operands.length > 1) {
|
||||
results.splice(resultsIndex,1,operands[nextOperandIndex]);
|
||||
} else {
|
||||
results.splice(resultsIndex,1);
|
||||
}
|
||||
} else {
|
||||
results.push(operands[0]);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/*
|
||||
Toggles an item in the current list.
|
||||
*/
|
||||
exports.toggle = function(source,operator) {
|
||||
return cycleValueInArray(prepare_results(source),operator.operands);
|
||||
}
|
||||
|
||||
exports.cycle = function(source,operator) {
|
||||
var results = prepare_results(source),
|
||||
operands = (operator.operand.length ? $tw.utils.parseStringArray(operator.operand, "true") : [""]),
|
||||
step = $tw.utils.getInt(operator.operands[1]||"",1);
|
||||
if(step < 0) {
|
||||
operands.reverse();
|
||||
step = Math.abs(step);
|
||||
}
|
||||
return cycleValueInArray(results,operands,step);
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
@@ -12,12 +12,13 @@ Initialise basic platform $:/info/ tiddlers
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.getInfoTiddlerFields = function() {
|
||||
exports.getInfoTiddlerFields = function(updateInfoTiddlersCallback) {
|
||||
var mapBoolean = function(value) {return value ? "yes" : "no";},
|
||||
infoTiddlerFields = [];
|
||||
// Basics
|
||||
infoTiddlerFields.push({title: "$:/info/browser", text: mapBoolean(!!$tw.browser)});
|
||||
infoTiddlerFields.push({title: "$:/info/node", text: mapBoolean(!!$tw.node)});
|
||||
infoTiddlerFields.push({title: "$:/info/startup-timestamp", text: $tw.utils.stringifyDate(new Date())});
|
||||
if($tw.browser) {
|
||||
// Document location
|
||||
var setLocationProperty = function(name,value) {
|
||||
@@ -35,6 +36,13 @@ exports.getInfoTiddlerFields = function() {
|
||||
// Screen size
|
||||
infoTiddlerFields.push({title: "$:/info/browser/screen/width", text: window.screen.width.toString()});
|
||||
infoTiddlerFields.push({title: "$:/info/browser/screen/height", text: window.screen.height.toString()});
|
||||
// Dark mode through event listener on MediaQueryList
|
||||
var mqList = window.matchMedia("(prefers-color-scheme: dark)"),
|
||||
getDarkModeTiddler = function() {return {title: "$:/info/darkmode", text: mqList.matches ? "yes" : "no"};};
|
||||
infoTiddlerFields.push(getDarkModeTiddler());
|
||||
mqList.addListener(function(event) {
|
||||
updateInfoTiddlersCallback([getDarkModeTiddler()]);
|
||||
});
|
||||
// Language
|
||||
infoTiddlerFields.push({title: "$:/info/browser/language", text: navigator.language || ""});
|
||||
}
|
||||
|
||||
@@ -284,6 +284,20 @@ KeyboardManager.prototype.checkKeyDescriptors = function(event,keyInfoArray) {
|
||||
return false;
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.getEventModifierKeyDescriptor = function(event) {
|
||||
return event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey ? "ctrl" :
|
||||
event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey ? "shift" :
|
||||
event.ctrlKey && event.shiftKey && !event.altKey && !event.metaKey ? "ctrl-shift" :
|
||||
event.altKey && !event.shiftKey && !event.ctrlKey && !event.metaKey ? "alt" :
|
||||
event.altKey && event.shiftKey && !event.ctrlKey && !event.metaKey ? "alt-shift" :
|
||||
event.altKey && event.ctrlKey && !event.shiftKey && !event.metaKey ? "ctrl-alt" :
|
||||
event.altKey && event.shiftKey && event.ctrlKey && !event.metaKey ? "ctrl-alt-shift" :
|
||||
event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey ? "meta" :
|
||||
event.metaKey && event.ctrlKey && !event.shiftKey && !event.altKey ? "meta-ctrl" :
|
||||
event.metaKey && event.ctrlKey && event.shiftKey && !event.altKey ? "meta-ctrl-shift" :
|
||||
event.metaKey && event.ctrlKey & event.shiftKey && event.altKey ? "meta-ctrl-alt-shift" : "normal";
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.getShortcutTiddlerList = function() {
|
||||
return $tw.wiki.getTiddlersWithTag("$:/tags/KeyboardShortcut");
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ exports.params = [
|
||||
Run the macro
|
||||
*/
|
||||
exports.run = function(filter,spaces) {
|
||||
return this.wiki.getTiddlersAsJson(filter,spaces);
|
||||
return this.wiki.getTiddlersAsJson(filter,$tw.utils.parseInt(spaces));
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -60,7 +60,7 @@ var listTypes = {
|
||||
"#": {listTag: "ol", itemTag: "li"},
|
||||
";": {listTag: "dl", itemTag: "dt"},
|
||||
":": {listTag: "dl", itemTag: "dd"},
|
||||
">": {listTag: "blockquote", itemTag: "p"}
|
||||
">": {listTag: "blockquote", itemTag: "div"}
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -386,22 +386,18 @@ Amend the rules used by this instance of the parser
|
||||
WikiParser.prototype.amendRules = function(type,names) {
|
||||
names = names || [];
|
||||
// Define the filter function
|
||||
var keepFilter;
|
||||
var target;
|
||||
if(type === "only") {
|
||||
keepFilter = function(name) {
|
||||
return names.indexOf(name) !== -1;
|
||||
};
|
||||
target = true;
|
||||
} else if(type === "except") {
|
||||
keepFilter = function(name) {
|
||||
return names.indexOf(name) === -1;
|
||||
};
|
||||
target = false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
// Define a function to process each of our rule arrays
|
||||
var processRuleArray = function(ruleArray) {
|
||||
for(var t=ruleArray.length-1; t>=0; t--) {
|
||||
if(!keepFilter(ruleArray[t].rule.name)) {
|
||||
if((names.indexOf(ruleArray[t].rule.name) === -1) === target) {
|
||||
ruleArray.splice(t,1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ SaverHandler.prototype.saveWiki = function(options) {
|
||||
var self = this,
|
||||
method = options.method || "save";
|
||||
// Ignore autosave if disabled
|
||||
if(method === "autosave" && this.wiki.getTiddlerText(this.titleAutoSave,"yes") !== "yes") {
|
||||
if(method === "autosave" && ($tw.config.disableAutoSave || this.wiki.getTiddlerText(this.titleAutoSave,"yes") !== "yes")) {
|
||||
return false;
|
||||
}
|
||||
var variables = options.variables || {},
|
||||
@@ -197,8 +197,12 @@ SaverHandler.prototype.isDirty = function() {
|
||||
Update the document body with the class "tc-dirty" if the wiki has unsaved/unsynced changes
|
||||
*/
|
||||
SaverHandler.prototype.updateDirtyStatus = function() {
|
||||
var self = this;
|
||||
if($tw.browser) {
|
||||
$tw.utils.toggleClass(document.body,"tc-dirty",this.isDirty());
|
||||
$tw.utils.each($tw.windows,function(win) {
|
||||
$tw.utils.toggleClass(win.document.body,"tc-dirty",self.isDirty());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
60
core/modules/savers/custom.js
Normal file
60
core/modules/savers/custom.js
Normal file
@@ -0,0 +1,60 @@
|
||||
/*\
|
||||
title: $:/core/modules/savers/custom.js
|
||||
type: application/javascript
|
||||
module-type: saver
|
||||
|
||||
Looks for `window.$tw.customSaver` first on the current window, then
|
||||
on the parent window (of an iframe). If present, the saver must define
|
||||
save: function(text,method,callback) { ... }
|
||||
and the saver may define
|
||||
priority: number
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var findSaver = function(window) {
|
||||
try {
|
||||
return window && window.$tw && window.$tw.customSaver;
|
||||
} catch (err) {
|
||||
// Catching the exception is the most reliable way to detect cross-origin iframe errors.
|
||||
// For example, instead of saying that `window.parent.$tw` is undefined, Firefox will throw
|
||||
// Uncaught DOMException: Permission denied to access property "$tw" on cross-origin object
|
||||
console.log({ msg: "custom saver is disabled", reason: err });
|
||||
return null;
|
||||
}
|
||||
}
|
||||
var saver = findSaver(window) || findSaver(window.parent) || {};
|
||||
|
||||
var CustomSaver = function(wiki) {
|
||||
};
|
||||
|
||||
CustomSaver.prototype.save = function(text,method,callback) {
|
||||
return saver.save(text, method, callback);
|
||||
};
|
||||
|
||||
/*
|
||||
Information about this saver
|
||||
*/
|
||||
CustomSaver.prototype.info = {
|
||||
name: "custom",
|
||||
priority: saver.priority || 4000,
|
||||
capabilities: ["save","autosave"]
|
||||
};
|
||||
|
||||
/*
|
||||
Static method that returns true if this saver is capable of working
|
||||
*/
|
||||
exports.canSave = function(wiki) {
|
||||
return !!(saver.save);
|
||||
};
|
||||
|
||||
/*
|
||||
Create an instance of this saver
|
||||
*/
|
||||
exports.create = function(wiki) {
|
||||
return new CustomSaver(wiki);
|
||||
};
|
||||
})();
|
||||
@@ -31,10 +31,10 @@ GiteaSaver.prototype.save = function(text,method,callback) {
|
||||
headers = {
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json;charset=UTF-8",
|
||||
"Authorization": "Basic " + window.btoa(username + ":" + password)
|
||||
"Authorization": "token " + password
|
||||
};
|
||||
// Bail if we don't have everything we need
|
||||
if(!username || !password || !repo || !path || !filename) {
|
||||
if(!username || !password || !repo || !filename) {
|
||||
return false;
|
||||
}
|
||||
// Make sure the path start and ends with a slash
|
||||
|
||||
@@ -26,15 +26,16 @@ GitHubSaver.prototype.save = function(text,method,callback) {
|
||||
repo = this.wiki.getTiddlerText("$:/GitHub/Repo"),
|
||||
path = this.wiki.getTiddlerText("$:/GitHub/Path",""),
|
||||
filename = this.wiki.getTiddlerText("$:/GitHub/Filename"),
|
||||
branch = this.wiki.getTiddlerText("$:/GitHub/Branch") || "master",
|
||||
branch = this.wiki.getTiddlerText("$:/GitHub/Branch") || "main",
|
||||
endpoint = this.wiki.getTiddlerText("$:/GitHub/ServerURL") || "https://api.github.com",
|
||||
headers = {
|
||||
"Accept": "application/vnd.github.v3+json",
|
||||
"Content-Type": "application/json;charset=UTF-8",
|
||||
"Authorization": "Basic " + window.btoa(username + ":" + password)
|
||||
"Authorization": "Basic " + window.btoa(username + ":" + password),
|
||||
"If-None-Match": ""
|
||||
};
|
||||
// Bail if we don't have everything we need
|
||||
if(!username || !password || !repo || !path || !filename) {
|
||||
if(!username || !password || !repo || !filename) {
|
||||
return false;
|
||||
}
|
||||
// Make sure the path start and ends with a slash
|
||||
|
||||
@@ -34,7 +34,7 @@ GitLabSaver.prototype.save = function(text,method,callback) {
|
||||
"Private-Token": password
|
||||
};
|
||||
// Bail if we don't have everything we need
|
||||
if(!username || !password || !repo || !path || !filename) {
|
||||
if(!username || !password || !repo || !filename) {
|
||||
return false;
|
||||
}
|
||||
// Make sure the path start and ends with a slash
|
||||
|
||||
64
core/modules/savers/hyperdrive.js
Normal file
64
core/modules/savers/hyperdrive.js
Normal file
@@ -0,0 +1,64 @@
|
||||
/*\
|
||||
title: $:/core/modules/savers/hyperdrive.js
|
||||
type: application/javascript
|
||||
module-type: saver
|
||||
|
||||
Saves files using the Hyperdrive Protocol (https://hypercore-protocol.org/#hyperdrive) Beaker browser beta-1.0 and later (https://beakerbrowser.com)
|
||||
Compatible with beaker >= V1.0.0
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Set up the saver
|
||||
*/
|
||||
var HyperdriveSaver = function(wiki) {
|
||||
this.wiki = wiki;
|
||||
};
|
||||
|
||||
HyperdriveSaver.prototype.save = function(text,method,callback) {
|
||||
var dat = beaker.hyperdrive.drive("" + window.location),
|
||||
pathname = ("" + window.location.pathname).split("#")[0];
|
||||
dat.stat(pathname).then(function(value) {
|
||||
if(value.isDirectory()) {
|
||||
pathname = pathname + "/index.html";
|
||||
}
|
||||
dat.writeFile(pathname,text,"utf8").then(function(value) {
|
||||
callback(null);
|
||||
},function(reason) {
|
||||
callback("Hyperdrive Saver Write Error: " + reason);
|
||||
});
|
||||
},function(reason) {
|
||||
callback("Hyperdrive Saver Stat Error: " + reason);
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
Information about this saver
|
||||
*/
|
||||
HyperdriveSaver.prototype.info = {
|
||||
name: "beaker-1.x",
|
||||
priority: 3000,
|
||||
capabilities: ["save", "autosave"]
|
||||
};
|
||||
|
||||
/*
|
||||
Static method that returns true if this saver is capable of working
|
||||
*/
|
||||
exports.canSave = function(wiki) {
|
||||
return !!window.beaker && !!beaker.hyperdrive && location.protocol==="hyper:";
|
||||
};
|
||||
|
||||
/*
|
||||
Create an instance of this saver
|
||||
*/
|
||||
exports.create = function(wiki) {
|
||||
return new HyperdriveSaver(wiki);
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -31,7 +31,7 @@ BasicAuthenticator.prototype.init = function() {
|
||||
// Read the credentials data
|
||||
this.credentialsFilepath = this.server.get("credentials");
|
||||
if(this.credentialsFilepath) {
|
||||
var resolveCredentialsFilepath = path.resolve($tw.boot.wikiPath,this.credentialsFilepath);
|
||||
var resolveCredentialsFilepath = path.resolve(this.server.boot.wikiPath,this.credentialsFilepath);
|
||||
if(fs.existsSync(resolveCredentialsFilepath) && !fs.statSync(resolveCredentialsFilepath).isDirectory()) {
|
||||
var credentialsText = fs.readFileSync(resolveCredentialsFilepath,"utf8"),
|
||||
credentialsData = $tw.utils.parseCsvStringWithHeader(credentialsText);
|
||||
|
||||
@@ -14,7 +14,7 @@ Authenticator for trusted header authentication
|
||||
|
||||
function HeaderAuthenticator(server) {
|
||||
this.server = server;
|
||||
this.header = server.get("authenticated-user-header");
|
||||
this.header = server.get("authenticated-user-header") ? server.get("authenticated-user-header").toLowerCase() : undefined;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -21,7 +21,7 @@ exports.handler = function(request,response,state) {
|
||||
fs = require("fs"),
|
||||
util = require("util"),
|
||||
suppliedFilename = decodeURIComponent(state.params[0]),
|
||||
filename = path.resolve($tw.boot.wikiPath,"files",suppliedFilename),
|
||||
filename = path.resolve(state.boot.wikiPath,"files",suppliedFilename),
|
||||
extension = path.extname(filename);
|
||||
fs.readFile(filename,function(err,content) {
|
||||
var status,content,type = "text/plain";
|
||||
|
||||
@@ -3,7 +3,7 @@ title: $:/core/modules/server/routes/get-tiddlers-json.js
|
||||
type: application/javascript
|
||||
module-type: route
|
||||
|
||||
GET /recipes/default/tiddlers/tiddlers.json?filter=<filter>
|
||||
GET /recipes/default/tiddlers.json?filter=<filter>
|
||||
|
||||
\*/
|
||||
(function() {
|
||||
@@ -20,14 +20,17 @@ exports.path = /^\/recipes\/default\/tiddlers.json$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var filter = state.queryParameters.filter || DEFAULT_FILTER;
|
||||
if($tw.wiki.getTiddlerText("$:/config/Server/AllowAllExternalFilters") !== "yes") {
|
||||
if($tw.wiki.getTiddlerText("$:/config/Server/ExternalFilters/" + filter) !== "yes") {
|
||||
console.log("Blocked attempt to GET /recipes/default/tiddlers/tiddlers.json with filter: " + filter);
|
||||
if(state.wiki.getTiddlerText("$:/config/Server/AllowAllExternalFilters") !== "yes") {
|
||||
if(state.wiki.getTiddlerText("$:/config/Server/ExternalFilters/" + filter) !== "yes") {
|
||||
console.log("Blocked attempt to GET /recipes/default/tiddlers.json with filter: " + filter);
|
||||
response.writeHead(403);
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(state.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "no") {
|
||||
filter += "+[!is[system]]";
|
||||
}
|
||||
var excludeFields = (state.queryParameters.exclude || "text").split(","),
|
||||
titles = state.wiki.filterTiddlers(filter);
|
||||
response.writeHead(200, {"Content-Type": "application/json"});
|
||||
|
||||
@@ -31,6 +31,7 @@ function Server(options) {
|
||||
this.routes = options.routes || [];
|
||||
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);
|
||||
@@ -69,8 +70,8 @@ function Server(options) {
|
||||
tlsCertFilepath = this.get("tls-cert");
|
||||
if(tlsCertFilepath && tlsKeyFilepath) {
|
||||
this.listenOptions = {
|
||||
key: fs.readFileSync(path.resolve($tw.boot.wikiPath,tlsKeyFilepath),"utf8"),
|
||||
cert: fs.readFileSync(path.resolve($tw.boot.wikiPath,tlsCertFilepath),"utf8")
|
||||
key: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsKeyFilepath),"utf8"),
|
||||
cert: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsCertFilepath),"utf8")
|
||||
};
|
||||
this.protocol = "https";
|
||||
}
|
||||
@@ -112,15 +113,14 @@ Server.prototype.addAuthenticator = function(AuthenticatorClass) {
|
||||
};
|
||||
|
||||
Server.prototype.findMatchingRoute = function(request,state) {
|
||||
var pathprefix = this.get("path-prefix") || "";
|
||||
for(var t=0; t<this.routes.length; t++) {
|
||||
var potentialRoute = this.routes[t],
|
||||
pathRegExp = potentialRoute.path,
|
||||
pathname = state.urlInfo.pathname,
|
||||
match;
|
||||
if(pathprefix) {
|
||||
if(pathname.substr(0,pathprefix.length) === pathprefix) {
|
||||
pathname = pathname.substr(pathprefix.length) || "/";
|
||||
if(state.pathPrefix) {
|
||||
if(pathname.substr(0,state.pathPrefix.length) === state.pathPrefix) {
|
||||
pathname = pathname.substr(state.pathPrefix.length) || "/";
|
||||
match = potentialRoute.path.exec(pathname);
|
||||
} else {
|
||||
match = false;
|
||||
@@ -156,14 +156,17 @@ Server.prototype.isAuthorized = function(authorizationType,username) {
|
||||
return principals.indexOf("(anon)") !== -1 || (username && (principals.indexOf("(authenticated)") !== -1 || principals.indexOf(username) !== -1));
|
||||
}
|
||||
|
||||
Server.prototype.requestHandler = function(request,response) {
|
||||
Server.prototype.requestHandler = function(request,response,options) {
|
||||
options = options || {};
|
||||
// Compose the state object
|
||||
var self = this;
|
||||
var state = {};
|
||||
state.wiki = self.wiki;
|
||||
state.wiki = options.wiki || self.wiki;
|
||||
state.boot = options.boot || self.boot;
|
||||
state.server = self;
|
||||
state.urlInfo = url.parse(request.url);
|
||||
state.queryParameters = querystring.parse(state.urlInfo.query);
|
||||
state.pathPrefix = options.pathPrefix || this.get("path-prefix") || "";
|
||||
// Get the principals authorized to access this resource
|
||||
var authorizationType = this.methodMappings[request.method] || "readers";
|
||||
// Check for the CSRF header if this is a write
|
||||
@@ -248,7 +251,7 @@ Server.prototype.listen = function(port,host,prefix) {
|
||||
port = process.env[port] || 8080;
|
||||
}
|
||||
// Warn if required plugins are missing
|
||||
if(!$tw.wiki.getTiddler("$:/plugins/tiddlywiki/tiddlyweb") || !$tw.wiki.getTiddler("$:/plugins/tiddlywiki/filesystem")) {
|
||||
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");
|
||||
}
|
||||
// Create the server
|
||||
|
||||
@@ -36,7 +36,7 @@ function setFavicon() {
|
||||
var tiddler = $tw.wiki.getTiddler(FAVICON_TITLE);
|
||||
if(tiddler) {
|
||||
var faviconLink = document.getElementById("faviconLink");
|
||||
faviconLink.setAttribute("href","data:" + tiddler.fields.type + ";base64," + tiddler.fields.text);
|
||||
faviconLink.setAttribute("href",$tw.utils.makeDataUri(tiddler.fields.text,tiddler.fields.type,tiddler.fields._canonical_uri));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,29 +21,37 @@ exports.synchronous = true;
|
||||
var TITLE_INFO_PLUGIN = "$:/temp/info-plugin";
|
||||
|
||||
exports.startup = function() {
|
||||
// Function to bake the info plugin with new tiddlers
|
||||
var updateInfoPlugin = function(tiddlerFieldsArray) {
|
||||
// Get the existing tiddlers
|
||||
var json = $tw.wiki.getTiddlerData(TITLE_INFO_PLUGIN,{tiddlers: {}});
|
||||
// Add the new ones
|
||||
$tw.utils.each(tiddlerFieldsArray,function(fields) {
|
||||
if(fields && fields.title) {
|
||||
json.tiddlers[fields.title] = fields;
|
||||
}
|
||||
});
|
||||
// Bake the info tiddlers into a plugin. We use the non-standard plugin-type "info" because ordinary plugins are only registered asynchronously after being loaded dynamically
|
||||
var fields = {
|
||||
title: TITLE_INFO_PLUGIN,
|
||||
type: "application/json",
|
||||
"plugin-type": "info",
|
||||
text: JSON.stringify(json,null,$tw.config.preferences.jsonSpaces)
|
||||
};
|
||||
$tw.wiki.addTiddler(new $tw.Tiddler(fields));
|
||||
|
||||
};
|
||||
// Collect up the info tiddlers
|
||||
var infoTiddlerFields = {};
|
||||
// Give each info module a chance to fill in as many info tiddlers as they want
|
||||
var tiddlerFieldsArray = [];
|
||||
// Give each info module a chance to provide as many info tiddlers as they want as an array, and give them a callback for dynamically updating them
|
||||
$tw.modules.forEachModuleOfType("info",function(title,moduleExports) {
|
||||
if(moduleExports && moduleExports.getInfoTiddlerFields) {
|
||||
var tiddlerFieldsArray = moduleExports.getInfoTiddlerFields(infoTiddlerFields);
|
||||
$tw.utils.each(tiddlerFieldsArray,function(fields) {
|
||||
if(fields) {
|
||||
infoTiddlerFields[fields.title] = fields;
|
||||
}
|
||||
});
|
||||
Array.prototype.push.apply(tiddlerFieldsArray,moduleExports.getInfoTiddlerFields(updateInfoPlugin));
|
||||
}
|
||||
});
|
||||
// Bake the info tiddlers into a plugin. We use the non-standard plugin-type "info" because ordinary plugins are only registered asynchronously after being loaded dynamically
|
||||
var fields = {
|
||||
title: TITLE_INFO_PLUGIN,
|
||||
type: "application/json",
|
||||
"plugin-type": "info",
|
||||
text: JSON.stringify({tiddlers: infoTiddlerFields},null,$tw.config.preferences.jsonSpaces)
|
||||
};
|
||||
$tw.wiki.addTiddler(new $tw.Tiddler(fields));
|
||||
$tw.wiki.readPluginInfo([TITLE_INFO_PLUGIN]);
|
||||
$tw.wiki.registerPluginTiddlers("info");
|
||||
updateInfoPlugin(tiddlerFieldsArray);
|
||||
var changes = $tw.wiki.readPluginInfo([TITLE_INFO_PLUGIN]);
|
||||
$tw.wiki.registerPluginTiddlers("info",[TITLE_INFO_PLUGIN]);
|
||||
$tw.wiki.unpackPluginTiddlers();
|
||||
};
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ var PREFIX_CONFIG_REGISTER_PLUGIN_TYPE = "$:/config/RegisterPluginType/";
|
||||
exports.startup = function() {
|
||||
$tw.wiki.addTiddler({title: TITLE_REQUIRE_RELOAD_DUE_TO_PLUGIN_CHANGE,text: "no"});
|
||||
$tw.wiki.addEventListener("change",function(changes) {
|
||||
// Work out which of the changed tiddlers are plugins that we need to reregister
|
||||
var changesToProcess = [],
|
||||
requireReloadDueToPluginChange = false;
|
||||
$tw.utils.each(Object.keys(changes),function(title) {
|
||||
@@ -38,6 +39,7 @@ exports.startup = function() {
|
||||
}
|
||||
}
|
||||
});
|
||||
// Issue warning if any of the tiddlers require a reload
|
||||
if(requireReloadDueToPluginChange) {
|
||||
$tw.wiki.addTiddler({title: TITLE_REQUIRE_RELOAD_DUE_TO_PLUGIN_CHANGE,text: "yes"});
|
||||
}
|
||||
@@ -45,12 +47,35 @@ exports.startup = function() {
|
||||
if(changesToProcess.length > 0) {
|
||||
var changes = $tw.wiki.readPluginInfo(changesToProcess);
|
||||
if(changes.modifiedPlugins.length > 0 || changes.deletedPlugins.length > 0) {
|
||||
var changedShadowTiddlers = {};
|
||||
// Collect the shadow tiddlers of any deleted plugins
|
||||
$tw.utils.each(changes.deletedPlugins,function(pluginTitle) {
|
||||
var pluginInfo = $tw.wiki.getPluginInfo(pluginTitle);
|
||||
if(pluginInfo) {
|
||||
$tw.utils.each(Object.keys(pluginInfo.tiddlers),function(title) {
|
||||
changedShadowTiddlers[title] = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
// Collect the shadow tiddlers of any modified plugins
|
||||
$tw.utils.each(changes.modifiedPlugins,function(pluginTitle) {
|
||||
var pluginInfo = $tw.wiki.getPluginInfo(pluginTitle);
|
||||
if(pluginInfo) {
|
||||
$tw.utils.each(Object.keys(pluginInfo.tiddlers),function(title) {
|
||||
changedShadowTiddlers[title] = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
// (Re-)register any modified plugins
|
||||
$tw.wiki.registerPluginTiddlers(null,changes.modifiedPlugins);
|
||||
// Unregister any deleted plugins
|
||||
$tw.wiki.unregisterPluginTiddlers(null,changes.deletedPlugins);
|
||||
// Unpack the shadow tiddlers
|
||||
$tw.wiki.unpackPluginTiddlers();
|
||||
// Queue change events for the changed shadow tiddlers
|
||||
$tw.utils.each(Object.keys(changedShadowTiddlers),function(title) {
|
||||
$tw.wiki.enqueueTiddlerEvent(title,changedShadowTiddlers[title]);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ exports.synchronous = true;
|
||||
// Default story and history lists
|
||||
var PAGE_TITLE_TITLE = "$:/core/wiki/title";
|
||||
var PAGE_STYLESHEET_TITLE = "$:/core/ui/PageStylesheet";
|
||||
var PAGE_TEMPLATE_TITLE = "$:/core/ui/PageTemplate";
|
||||
var PAGE_TEMPLATE_TITLE = "$:/core/ui/RootTemplate";
|
||||
|
||||
// Time (in ms) that we defer refreshing changes to draft tiddlers
|
||||
var DRAFT_TIDDLER_TIMEOUT_TITLE = "$:/config/Drafts/TypingTimeout";
|
||||
@@ -52,7 +52,7 @@ exports.startup = function() {
|
||||
}));
|
||||
// Display the $:/core/ui/PageTemplate tiddler to kick off the display
|
||||
$tw.perf.report("mainRender",function() {
|
||||
$tw.pageWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_TEMPLATE_TITLE,{document: document, parentWidget: $tw.rootWidget});
|
||||
$tw.pageWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_TEMPLATE_TITLE,{document: document, parentWidget: $tw.rootWidget, recursionMarker: "no"});
|
||||
$tw.pageContainer = document.createElement("div");
|
||||
$tw.utils.addClass($tw.pageContainer,"tc-page-container-wrapper");
|
||||
document.body.insertBefore($tw.pageContainer,document.body.firstChild);
|
||||
@@ -106,6 +106,8 @@ exports.startup = function() {
|
||||
// Fix up the link between the root widget and the page container
|
||||
$tw.rootWidget.domNodes = [$tw.pageContainer];
|
||||
$tw.rootWidget.children = [$tw.pageWidgetNode];
|
||||
// Run any post-render startup actions
|
||||
$tw.rootWidget.invokeActionsByTag("$:/tags/StartupAction/PostRender");
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -25,6 +25,9 @@ exports.startup = function() {
|
||||
$tw.rootWidget.addEventListener("tm-modal",function(event) {
|
||||
$tw.modal.display(event.param,{variables: event.paramObject, event: event});
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tm-show-switcher",function(event) {
|
||||
$tw.modal.display("$:/core/ui/SwitcherModal",{variables: event.paramObject, event: event});
|
||||
});
|
||||
// Install the notification mechanism
|
||||
$tw.notifier = new $tw.utils.Notifier($tw.wiki);
|
||||
$tw.rootWidget.addEventListener("tm-notify",function(event) {
|
||||
|
||||
@@ -64,17 +64,12 @@ exports.startup = function() {
|
||||
document: $tw.browser ? document : $tw.fakeDocument
|
||||
});
|
||||
// Execute any startup actions
|
||||
var executeStartupTiddlers = function(tag) {
|
||||
$tw.utils.each($tw.wiki.filterTiddlers("[all[shadows+tiddlers]tag[" + tag + "]!has[draft.of]]"),function(title) {
|
||||
$tw.rootWidget.invokeActionString($tw.wiki.getTiddlerText(title),$tw.rootWidget);
|
||||
});
|
||||
};
|
||||
executeStartupTiddlers("$:/tags/StartupAction");
|
||||
$tw.rootWidget.invokeActionsByTag("$:/tags/StartupAction");
|
||||
if($tw.browser) {
|
||||
executeStartupTiddlers("$:/tags/StartupAction/Browser");
|
||||
$tw.rootWidget.invokeActionsByTag("$:/tags/StartupAction/Browser");
|
||||
}
|
||||
if($tw.node) {
|
||||
executeStartupTiddlers("$:/tags/StartupAction/Node");
|
||||
$tw.rootWidget.invokeActionsByTag("$:/tags/StartupAction/Node");
|
||||
}
|
||||
// Kick off the language manager and switcher
|
||||
$tw.language = new $tw.Language();
|
||||
|
||||
@@ -150,6 +150,11 @@ function openStartupTiddlers(options) {
|
||||
// Save the story list
|
||||
$tw.wiki.addTiddler({title: DEFAULT_STORY_TITLE, text: "", list: storyList},$tw.wiki.getModificationFields());
|
||||
// Update history
|
||||
var story = new $tw.Story({
|
||||
wiki: $tw.wiki,
|
||||
storyTitle: DEFAULT_STORY_TITLE,
|
||||
historyTitle: DEFAULT_HISTORY_TITLE
|
||||
});
|
||||
if(!options.disableHistory) {
|
||||
// If a target tiddler was specified add it to the history stack
|
||||
if(target && target !== "") {
|
||||
@@ -157,9 +162,9 @@ function openStartupTiddlers(options) {
|
||||
if(target.indexOf("[[") === 0 && target.substr(-2) === "]]") {
|
||||
target = target.substr(2,target.length - 4);
|
||||
}
|
||||
$tw.wiki.addToHistory(target);
|
||||
story.addToHistory(target);
|
||||
} else if(storyList.length > 0) {
|
||||
$tw.wiki.addToHistory(storyList[0]);
|
||||
story.addToHistory(storyList[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ exports.after = ["startup"];
|
||||
exports.synchronous = true;
|
||||
|
||||
// Global to keep track of open windows (hashmap by title)
|
||||
var windows = {};
|
||||
$tw.windows = {};
|
||||
|
||||
exports.startup = function() {
|
||||
// Handle open window message
|
||||
@@ -44,7 +44,7 @@ exports.startup = function() {
|
||||
catch(e) {
|
||||
return;
|
||||
}
|
||||
windows[title] = srcWindow;
|
||||
$tw.windows[title] = srcWindow;
|
||||
// Check for reopening the same window
|
||||
if(srcWindow.haveInitialisedWindow) {
|
||||
return;
|
||||
@@ -54,7 +54,7 @@ exports.startup = function() {
|
||||
srcDocument.close();
|
||||
srcDocument.title = windowTitle;
|
||||
srcWindow.addEventListener("beforeunload",function(event) {
|
||||
delete windows[title];
|
||||
delete $tw.windows[title];
|
||||
$tw.wiki.removeEventListener("change",refreshHandler);
|
||||
},false);
|
||||
// Set up the styles
|
||||
@@ -84,16 +84,13 @@ exports.startup = function() {
|
||||
name: "keydown",
|
||||
handlerObject: $tw.keyboardManager,
|
||||
handlerMethod: "handleKeydownEvent"
|
||||
},{
|
||||
name: "click",
|
||||
handlerObject: $tw.popup,
|
||||
handlerMethod: "handleEvent"
|
||||
}]);
|
||||
srcWindow.document.documentElement.addEventListener("click",$tw.popup,true);
|
||||
srcWindow.haveInitialisedWindow = true;
|
||||
});
|
||||
// Close open windows when unloading main window
|
||||
$tw.addUnloadTask(function() {
|
||||
$tw.utils.each(windows,function(win) {
|
||||
$tw.utils.each($tw.windows,function(win) {
|
||||
win.close();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,48 +37,44 @@ Story.prototype.getStoryList = function() {
|
||||
Story.prototype.addToStory = function(navigateTo,navigateFromTitle,options) {
|
||||
options = options || {};
|
||||
var storyList = this.getStoryList();
|
||||
if(options.singleTiddlerMode) {
|
||||
storyList = [navigateTo];
|
||||
} else {
|
||||
// See if the tiddler is already there
|
||||
var slot = storyList.indexOf(navigateTo);
|
||||
// Quit if it already exists in the story river
|
||||
if(slot >= 0) {
|
||||
return;
|
||||
}
|
||||
// First we try to find the position of the story element we navigated from
|
||||
var fromIndex = storyList.indexOf(navigateFromTitle);
|
||||
if(fromIndex >= 0) {
|
||||
// The tiddler is added from inside the river
|
||||
// Determine where to insert the tiddler; Fallback is "below"
|
||||
switch(options.openLinkFromInsideRiver) {
|
||||
case "top":
|
||||
slot = 0;
|
||||
break;
|
||||
case "bottom":
|
||||
slot = storyList.length;
|
||||
break;
|
||||
case "above":
|
||||
slot = fromIndex;
|
||||
break;
|
||||
case "below": // Intentional fall-through
|
||||
default:
|
||||
slot = fromIndex + 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// The tiddler is opened from outside the river. Determine where to insert the tiddler; default is "top"
|
||||
if(options.openLinkFromOutsideRiver === "bottom") {
|
||||
// Insert at bottom
|
||||
slot = storyList.length;
|
||||
} else {
|
||||
// Insert at top
|
||||
slot = 0;
|
||||
}
|
||||
}
|
||||
// Add the tiddler
|
||||
storyList.splice(slot,0,navigateTo);
|
||||
// See if the tiddler is already there
|
||||
var slot = storyList.indexOf(navigateTo);
|
||||
// Quit if it already exists in the story river
|
||||
if(slot >= 0) {
|
||||
return;
|
||||
}
|
||||
// First we try to find the position of the story element we navigated from
|
||||
var fromIndex = storyList.indexOf(navigateFromTitle);
|
||||
if(fromIndex >= 0) {
|
||||
// The tiddler is added from inside the river
|
||||
// Determine where to insert the tiddler; Fallback is "below"
|
||||
switch(options.openLinkFromInsideRiver) {
|
||||
case "top":
|
||||
slot = 0;
|
||||
break;
|
||||
case "bottom":
|
||||
slot = storyList.length;
|
||||
break;
|
||||
case "above":
|
||||
slot = fromIndex;
|
||||
break;
|
||||
case "below": // Intentional fall-through
|
||||
default:
|
||||
slot = fromIndex + 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// The tiddler is opened from outside the river. Determine where to insert the tiddler; default is "top"
|
||||
if(options.openLinkFromOutsideRiver === "bottom") {
|
||||
// Insert at bottom
|
||||
slot = storyList.length;
|
||||
} else {
|
||||
// Insert at top
|
||||
slot = 0;
|
||||
}
|
||||
}
|
||||
// Add the tiddler
|
||||
storyList.splice(slot,0,navigateTo);
|
||||
// Save the story
|
||||
this.saveStoryList(storyList);
|
||||
};
|
||||
@@ -97,20 +93,11 @@ Story.prototype.saveStoryList = function(storyList) {
|
||||
Story.prototype.addToHistory = function(navigateTo,navigateFromClientRect) {
|
||||
var titles = $tw.utils.isArray(navigateTo) ? navigateTo : [navigateTo];
|
||||
// Add a new record to the top of the history stack
|
||||
var historyList = this.wiki.getTiddlerData(this.historyTitle,[]),
|
||||
historyTitles = this.wiki.getTiddlerList(this.historyTitle);
|
||||
var historyList = this.wiki.getTiddlerData(this.historyTitle,[]);
|
||||
$tw.utils.each(titles,function(title) {
|
||||
historyList.push({title: title, fromPageRect: navigateFromClientRect});
|
||||
var p;
|
||||
do {
|
||||
p = historyTitles.indexOf(title);
|
||||
if(p !== -1) {
|
||||
historyTitles.splice(p,1);
|
||||
}
|
||||
} while(p !== -1);
|
||||
historyTitles.unshift(title);
|
||||
});
|
||||
this.wiki.setTiddlerData(this.historyTitle,historyList,{"current-tiddler": titles[titles.length-1], list: historyTitles});
|
||||
this.wiki.setTiddlerData(this.historyTitle,historyList,{"current-tiddler": titles[titles.length-1]});
|
||||
};
|
||||
|
||||
Story.prototype.storyCloseTiddler = function(targetTitle) {
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/storyviews/solo.js
|
||||
type: application/javascript
|
||||
module-type: storyview
|
||||
|
||||
Flip between individual tiddlers
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var SoloListView = function(listWidget) {
|
||||
};
|
||||
|
||||
// Engage single tiddler mode
|
||||
SoloListView.singleTiddlerMode = true;
|
||||
|
||||
exports.solo = SoloListView;
|
||||
|
||||
})();
|
||||
@@ -39,9 +39,6 @@ var ZoominListView = function(listWidget) {
|
||||
});
|
||||
};
|
||||
|
||||
// Engage single tiddler mode
|
||||
ZoominListView.singleTiddlerMode = true;
|
||||
|
||||
ZoominListView.prototype.navigateTo = function(historyInfo) {
|
||||
var duration = $tw.utils.getAnimationDuration(),
|
||||
listElementIndex = this.listWidget.findListItem(0,historyInfo.title);
|
||||
|
||||
@@ -113,8 +113,16 @@ function Syncer(options) {
|
||||
return confirmationMessage;
|
||||
});
|
||||
// Listen out for login/logout/refresh events in the browser
|
||||
$tw.rootWidget.addEventListener("tm-login",function() {
|
||||
self.handleLoginEvent();
|
||||
$tw.rootWidget.addEventListener("tm-login",function(event) {
|
||||
var username = event && event.paramObject && event.paramObject.username,
|
||||
password = event && event.paramObject && event.paramObject.password;
|
||||
if(username && password) {
|
||||
// Login with username and password
|
||||
self.login(username,password,function() {});
|
||||
} else {
|
||||
// No username and password, so we display a prompt
|
||||
self.handleLoginEvent();
|
||||
}
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tm-logout",function() {
|
||||
self.handleLogoutEvent();
|
||||
@@ -127,7 +135,7 @@ function Syncer(options) {
|
||||
});
|
||||
}
|
||||
// Listen out for lazyLoad events
|
||||
if(!this.disableUI && $tw.wiki.getTiddlerText(this.titleSyncDisableLazyLoading) !== "yes") {
|
||||
if(!this.disableUI && this.wiki.getTiddlerText(this.titleSyncDisableLazyLoading) !== "yes") {
|
||||
this.wiki.addEventListener("lazyLoad",function(title) {
|
||||
self.handleLazyLoadEvent(title);
|
||||
});
|
||||
@@ -180,12 +188,14 @@ Syncer.prototype.readTiddlerInfo = function() {
|
||||
var self = this,
|
||||
tiddlers = this.getSyncedTiddlers();
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
var tiddler = self.wiki.tiddlerExists(title) && self.wiki.getTiddler(title);
|
||||
self.tiddlerInfo[title] = {
|
||||
revision: self.getTiddlerRevision(title),
|
||||
adaptorInfo: self.syncadaptor && self.syncadaptor.getTiddlerInfo(tiddler),
|
||||
changeCount: self.wiki.getChangeCount(title)
|
||||
};
|
||||
var tiddler = self.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
self.tiddlerInfo[title] = {
|
||||
revision: self.getTiddlerRevision(title),
|
||||
adaptorInfo: self.syncadaptor && self.syncadaptor.getTiddlerInfo(tiddler),
|
||||
changeCount: self.wiki.getChangeCount(title)
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -202,7 +212,7 @@ Syncer.prototype.isDirty = function() {
|
||||
if(this.wiki.tiddlerExists(title)) {
|
||||
if(tiddlerInfo) {
|
||||
// If the tiddler is known on the server and has been modified locally then it needs to be saved to the server
|
||||
if($tw.wiki.getChangeCount(title) > tiddlerInfo.changeCount) {
|
||||
if(this.wiki.getChangeCount(title) > tiddlerInfo.changeCount) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
@@ -295,7 +305,8 @@ Syncer.prototype.syncFromServer = function() {
|
||||
self.pollTimerId = null;
|
||||
self.syncFromServer.call(self);
|
||||
},self.pollTimerInterval);
|
||||
};
|
||||
},
|
||||
syncSystemFromServer = (self.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "yes" ? true : false);
|
||||
if(this.syncadaptor && this.syncadaptor.getUpdatedTiddlers) {
|
||||
this.logger.log("Retrieving updated tiddler list");
|
||||
cancelNextSync();
|
||||
@@ -310,9 +321,11 @@ Syncer.prototype.syncFromServer = function() {
|
||||
self.titlesToBeLoaded[title] = true;
|
||||
});
|
||||
$tw.utils.each(updates.deletions,function(title) {
|
||||
delete self.tiddlerInfo[title];
|
||||
self.logger.log("Deleting tiddler missing from server:",title);
|
||||
self.wiki.deleteTiddler(title);
|
||||
if(syncSystemFromServer || !self.wiki.isSystemTiddler(title)) {
|
||||
delete self.tiddlerInfo[title];
|
||||
self.logger.log("Deleting tiddler missing from server:",title);
|
||||
self.wiki.deleteTiddler(title);
|
||||
}
|
||||
});
|
||||
if(updates.modifications.length > 0 || updates.deletions.length > 0) {
|
||||
self.processTaskQueue();
|
||||
@@ -355,9 +368,11 @@ Syncer.prototype.syncFromServer = function() {
|
||||
}
|
||||
// Delete any tiddlers that were previously reported but missing this time
|
||||
$tw.utils.each(previousTitles,function(title) {
|
||||
delete self.tiddlerInfo[title];
|
||||
self.logger.log("Deleting tiddler missing from server:",title);
|
||||
self.wiki.deleteTiddler(title);
|
||||
if(syncSystemFromServer || !self.wiki.isSystemTiddler(title)) {
|
||||
delete self.tiddlerInfo[title];
|
||||
self.logger.log("Deleting tiddler missing from server:",title);
|
||||
self.wiki.deleteTiddler(title);
|
||||
}
|
||||
});
|
||||
self.processTaskQueue();
|
||||
});
|
||||
@@ -398,15 +413,27 @@ Syncer.prototype.handleLoginEvent = function() {
|
||||
var self = this;
|
||||
this.getStatus(function(err,isLoggedIn,username) {
|
||||
if(!err && !isLoggedIn) {
|
||||
$tw.passwordPrompt.createPrompt({
|
||||
serviceName: $tw.language.getString("LoginToTiddlySpace"),
|
||||
callback: function(data) {
|
||||
self.login(data.username,data.password,function(err,isLoggedIn) {
|
||||
self.syncFromServer();
|
||||
});
|
||||
return true; // Get rid of the password prompt
|
||||
}
|
||||
if(self.syncadaptor && self.syncadaptor.displayLoginPrompt) {
|
||||
self.syncadaptor.displayLoginPrompt(self);
|
||||
} else {
|
||||
self.displayLoginPrompt();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Dispay a password prompt
|
||||
*/
|
||||
Syncer.prototype.displayLoginPrompt = function() {
|
||||
var self = this;
|
||||
var promptInfo = $tw.passwordPrompt.createPrompt({
|
||||
serviceName: $tw.language.getString("LoginToTiddlySpace"),
|
||||
callback: function(data) {
|
||||
self.login(data.username,data.password,function(err,isLoggedIn) {
|
||||
self.syncFromServer();
|
||||
});
|
||||
return true; // Get rid of the password prompt
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -524,7 +551,7 @@ Syncer.prototype.chooseNextTask = function() {
|
||||
tiddlerInfo = this.tiddlerInfo[title];
|
||||
if(tiddler) {
|
||||
// If the tiddler is not known on the server, or has been modified locally no more recently than the threshold then it needs to be saved to the server
|
||||
var hasChanged = !tiddlerInfo || $tw.wiki.getChangeCount(title) > tiddlerInfo.changeCount,
|
||||
var hasChanged = !tiddlerInfo || this.wiki.getChangeCount(title) > tiddlerInfo.changeCount,
|
||||
isReadyToSave = !tiddlerInfo || !tiddlerInfo.timestampLastSaved || tiddlerInfo.timestampLastSaved < thresholdLastSaved;
|
||||
if(hasChanged) {
|
||||
if(isReadyToSave) {
|
||||
@@ -581,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");
|
||||
@@ -604,6 +633,10 @@ DeleteTiddlerTask.prototype.run = function(callback) {
|
||||
}
|
||||
// Remove the info stored about this tiddler
|
||||
delete self.syncer.tiddlerInfo[self.title];
|
||||
if($tw.boot.files){
|
||||
// Remove the tiddler from $tw.boot.files
|
||||
delete $tw.boot.files[self.title];
|
||||
}
|
||||
// Invoke the callback
|
||||
callback(null);
|
||||
},{
|
||||
|
||||
@@ -41,7 +41,7 @@ exports.upgrade = function(wiki,titles,tiddlers) {
|
||||
// Check if we're dealing with a plugin
|
||||
if(incomingTiddler && incomingTiddler["plugin-type"]) {
|
||||
// Check whether the plugin contains JS modules
|
||||
var requiresReload = $tw.wiki.doesPluginInfoRequireReload(JSON.parse(incomingTiddler.text)) ? ($tw.wiki.getTiddlerText("$:/language/ControlPanel/Plugins/PluginWillRequireReload") + " ") : "";
|
||||
var requiresReload = wiki.doesPluginInfoRequireReload(JSON.parse(incomingTiddler.text)) ? (wiki.getTiddlerText("$:/language/ControlPanel/Plugins/PluginWillRequireReload") + " ") : "";
|
||||
messages[title] = requiresReload;
|
||||
if(incomingTiddler.version) {
|
||||
// Upgrade the incoming plugin if it is in the upgrade library
|
||||
@@ -57,7 +57,7 @@ exports.upgrade = function(wiki,titles,tiddlers) {
|
||||
// Reject the incoming plugin by blanking all its fields
|
||||
if($tw.utils.checkVersions(existingTiddler.fields.version,incomingTiddler.version)) {
|
||||
tiddlers[title] = Object.create(null);
|
||||
messages[title] = requiresReload + $tw.language.getString("Import/Upgrader/Plugins/Suppressed/Version",{variables: {incoming: incomingTiddler.version, existing: existingTiddler.fields.version}});
|
||||
messages[title] = $tw.language.getString("Import/Upgrader/Plugins/Suppressed/Version",{variables: {incoming: incomingTiddler.version, existing: existingTiddler.fields.version}});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,15 +20,27 @@
|
||||
for (i; i < string.length; i++) {
|
||||
charCode = string.charCodeAt(i);
|
||||
|
||||
if (charCode < 128)
|
||||
if (charCode < 128) {
|
||||
output += String.fromCharCode(charCode);
|
||||
else if ((charCode > 127) && (charCode < 2048))
|
||||
output += String.fromCharCode((charCode >> 6) | 192),
|
||||
} else if ((charCode > 127) && (charCode < 2048)) {
|
||||
output += String.fromCharCode((charCode >> 6) | 192);
|
||||
output += String.fromCharCode((charCode & 63) | 128);
|
||||
else
|
||||
output += String.fromCharCode((charCode >> 12) | 224),
|
||||
output += String.fromCharCode(((charCode >> 6) & 63) | 128),
|
||||
} else if ((charCode > 55295) && (charCode < 57344) && string.length > i+1) {
|
||||
// Surrogate pair
|
||||
var hiSurrogate = charCode;
|
||||
var loSurrogate = string.charCodeAt(i+1);
|
||||
i++; // Skip the low surrogate on the next loop pass
|
||||
var codePoint = (((hiSurrogate - 55296) << 10) | (loSurrogate - 56320)) + 65536;
|
||||
output += String.fromCharCode((codePoint >> 18) | 240);
|
||||
output += String.fromCharCode(((codePoint >> 12) & 63) | 128);
|
||||
output += String.fromCharCode(((codePoint >> 6) & 63) | 128);
|
||||
output += String.fromCharCode((codePoint & 63) | 128);
|
||||
} else {
|
||||
// Not a surrogate pair, or a dangling surrogate without its partner that we'll just encode as-is
|
||||
output += String.fromCharCode((charCode >> 12) | 224);
|
||||
output += String.fromCharCode(((charCode >> 6) & 63) | 128);
|
||||
output += String.fromCharCode((charCode & 63) | 128);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
@@ -41,15 +53,21 @@
|
||||
while (i < string.length) {
|
||||
charCode = string.charCodeAt(i);
|
||||
|
||||
if (charCode < 128)
|
||||
if (charCode < 128) {
|
||||
output += String.fromCharCode(charCode),
|
||||
i++;
|
||||
else if ((charCode > 191) && (charCode < 224))
|
||||
output += String.fromCharCode(((charCode & 31) << 6) | (string.charCodeAt(i + 1) & 63)),
|
||||
} else if ((charCode > 191) && (charCode < 224)) {
|
||||
output += String.fromCharCode(((charCode & 31) << 6) | (string.charCodeAt(i + 1) & 63));
|
||||
i += 2;
|
||||
else
|
||||
output += String.fromCharCode(((charCode & 15) << 12) | ((string.charCodeAt(i + 1) & 63) << 6) | (string.charCodeAt(i + 2) & 63)),
|
||||
} else if ((charCode > 223) && (charCode < 240)) {
|
||||
output += String.fromCharCode(((charCode & 15) << 12) | ((string.charCodeAt(i + 1) & 63) << 6) | (string.charCodeAt(i + 2) & 63));
|
||||
i += 3;
|
||||
} else {
|
||||
var codePoint = ((charCode & 7) << 18) | ((string.charCodeAt(i + 1) & 63) << 12) | ((string.charCodeAt(i + 2) & 63) << 6) | (string.charCodeAt(i + 3) & 63);
|
||||
// output += String.fromCodePoint(codePoint); // Can't do this because Internet Explorer doesn't have String.fromCodePoint
|
||||
output += String.fromCharCode(((codePoint - 65536) >> 10) + 55296) + String.fromCharCode(((codePoint - 65536) & 1023) + 56320); // So we do this instead
|
||||
i += 4;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
//
|
||||
// copyright: MIT
|
||||
// author: Nijiko Yonskai, @nijikokun, nijikokun@gmail.com
|
||||
!function(r,e,o,t){void 0!==o.module&&o.module.exports?o.module.exports=e.apply(o):void 0!==o.define&&"function"===o.define&&o.define.amd?define("utf8",[],e):o.utf8=e.apply(o)}(0,function(){return{encode:function(r){if("string"!=typeof r)return r;r=r.replace(/\r\n/g,"\n");for(var e,o="",t=0;t<r.length;t++)(e=r.charCodeAt(t))<128?o+=String.fromCharCode(e):e>127&&e<2048?(o+=String.fromCharCode(e>>6|192),o+=String.fromCharCode(63&e|128)):(o+=String.fromCharCode(e>>12|224),o+=String.fromCharCode(e>>6&63|128),o+=String.fromCharCode(63&e|128));return o},decode:function(r){if("string"!=typeof r)return r;for(var e="",o=0,t=0;o<r.length;)(t=r.charCodeAt(o))<128?(e+=String.fromCharCode(t),o++):t>191&&t<224?(e+=String.fromCharCode((31&t)<<6|63&r.charCodeAt(o+1)),o+=2):(e+=String.fromCharCode((15&t)<<12|(63&r.charCodeAt(o+1))<<6|63&r.charCodeAt(o+2)),o+=3);return e}}},this),function(r,e,o,t){if(void 0!==o.module&&o.module.exports){if(t&&o.require)for(var n=0;n<t.length;n++)o[t[n]]=o.require(t[n]);o.module.exports=e.apply(o)}else void 0!==o.define&&"function"===o.define&&o.define.amd?define("base64",t||[],e):o.base64=e.apply(o)}(0,function(r){var e=r||this.utf8,o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";return{encode:function(r){if(void 0===e)throw{error:"MissingMethod",message:"UTF8 Module is missing."};if("string"!=typeof r)return r;r=e.encode(r);for(var t,n,i,d,f,a,h,c="",u=0;u<r.length;)d=(t=r.charCodeAt(u++))>>2,f=(3&t)<<4|(n=r.charCodeAt(u++))>>4,a=(15&n)<<2|(i=r.charCodeAt(u++))>>6,h=63&i,isNaN(n)?a=h=64:isNaN(i)&&(h=64),c+=o.charAt(d)+o.charAt(f)+o.charAt(a)+o.charAt(h);return c},decode:function(r){if(void 0===e)throw{error:"MissingMethod",message:"UTF8 Module is missing."};if("string"!=typeof r)return r;r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");for(var t,n,i,d,f,a,h="",c=0;c<r.length;)t=o.indexOf(r.charAt(c++))<<2|(d=o.indexOf(r.charAt(c++)))>>4,n=(15&d)<<4|(f=o.indexOf(r.charAt(c++)))>>2,i=(3&f)<<6|(a=o.indexOf(r.charAt(c++))),h+=String.fromCharCode(t),64!=f&&(h+=String.fromCharCode(n)),64!=a&&(h+=String.fromCharCode(i));return e.decode(h)}}},this,["utf8"]);
|
||||
!function(r,e,o,t){void 0!==o.module&&o.module.exports?o.module.exports=e.apply(o):void 0!==o.define&&"function"===o.define&&o.define.amd?define("utf8",[],e):o.utf8=e.apply(o)}(0,function(){return{encode:function(r){if("string"!=typeof r)return r;r=r.replace(/\r\n/g,"\n");for(var e,o="",t=0;t<r.length;t++)if((e=r.charCodeAt(t))<128)o+=String.fromCharCode(e);else if(e>127&&e<2048)o+=String.fromCharCode(e>>6|192),o+=String.fromCharCode(63&e|128);else if(e>55295&&e<57344&&r.length>t+1){var i=e,n=r.charCodeAt(t+1);t++;var d=65536+(i-55296<<10|n-56320);o+=String.fromCharCode(d>>18|240),o+=String.fromCharCode(d>>12&63|128),o+=String.fromCharCode(d>>6&63|128),o+=String.fromCharCode(63&d|128)}else o+=String.fromCharCode(e>>12|224),o+=String.fromCharCode(e>>6&63|128),o+=String.fromCharCode(63&e|128);return o},decode:function(r){if("string"!=typeof r)return r;for(var e="",o=0,t=0;o<r.length;)if((t=r.charCodeAt(o))<128)e+=String.fromCharCode(t),o++;else if(t>191&&t<224)e+=String.fromCharCode((31&t)<<6|63&r.charCodeAt(o+1)),o+=2;else if(t>223&&t<240)e+=String.fromCharCode((15&t)<<12|(63&r.charCodeAt(o+1))<<6|63&r.charCodeAt(o+2)),o+=3;else{var i=(7&t)<<18|(63&r.charCodeAt(o+1))<<12|(63&r.charCodeAt(o+2))<<6|63&r.charCodeAt(o+3);e+=String.fromCharCode(55296+(i-65536>>10))+String.fromCharCode(56320+(i-65536&1023)),o+=4}return e}}},this),function(r,e,o,t){if(void 0!==o.module&&o.module.exports){if(t&&o.require)for(var i=0;i<t.length;i++)o[t[i]]=o.require(t[i]);o.module.exports=e.apply(o)}else void 0!==o.define&&"function"===o.define&&o.define.amd?define("base64",t||[],e):o.base64=e.apply(o)}(0,function(r){var e=r||this.utf8,o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";return{encode:function(r){if(void 0===e)throw{error:"MissingMethod",message:"UTF8 Module is missing."};if("string"!=typeof r)return r;r=e.encode(r);for(var t,i,n,d,f,a,h,C="",c=0;c<r.length;)d=(t=r.charCodeAt(c++))>>2,f=(3&t)<<4|(i=r.charCodeAt(c++))>>4,a=(15&i)<<2|(n=r.charCodeAt(c++))>>6,h=63&n,isNaN(i)?a=h=64:isNaN(n)&&(h=64),C+=o.charAt(d)+o.charAt(f)+o.charAt(a)+o.charAt(h);return C},decode:function(r){if(void 0===e)throw{error:"MissingMethod",message:"UTF8 Module is missing."};if("string"!=typeof r)return r;r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");for(var t,i,n,d,f,a,h="",C=0;C<r.length;)t=o.indexOf(r.charAt(C++))<<2|(d=o.indexOf(r.charAt(C++)))>>4,i=(15&d)<<4|(f=o.indexOf(r.charAt(C++)))>>2,n=(3&f)<<6|(a=o.indexOf(r.charAt(C++))),h+=String.fromCharCode(t),64!=f&&(h+=String.fromCharCode(i)),64!=a&&(h+=String.fromCharCode(n));return e.decode(h)}}},this,["utf8"]);
|
||||
@@ -29,23 +29,23 @@ exports.removeChildren = function(node) {
|
||||
};
|
||||
|
||||
exports.hasClass = function(el,className) {
|
||||
return el && el.className && el.className.toString().split(" ").indexOf(className) !== -1;
|
||||
return el && el.hasAttribute && el.hasAttribute("class") && el.getAttribute("class").split(" ").indexOf(className) !== -1;
|
||||
};
|
||||
|
||||
exports.addClass = function(el,className) {
|
||||
var c = el.className.split(" ");
|
||||
var c = (el.getAttribute("class") || "").split(" ");
|
||||
if(c.indexOf(className) === -1) {
|
||||
c.push(className);
|
||||
el.className = c.join(" ");
|
||||
el.setAttribute("class",c.join(" "));
|
||||
}
|
||||
};
|
||||
|
||||
exports.removeClass = function(el,className) {
|
||||
var c = el.className.split(" "),
|
||||
var c = (el.getAttribute("class") || "").split(" "),
|
||||
p = c.indexOf(className);
|
||||
if(p !== -1) {
|
||||
c.splice(p,1);
|
||||
el.className = c.join(" ");
|
||||
el.setAttribute("class",c.join(" "));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -24,6 +24,16 @@ exports.httpRequest = function(options) {
|
||||
var type = options.type || "GET",
|
||||
url = options.url,
|
||||
headers = options.headers || {accept: "application/json"},
|
||||
hasHeader = function(targetHeader) {
|
||||
targetHeader = targetHeader.toLowerCase();
|
||||
var result = false;
|
||||
$tw.utils.each(headers,function(header,headerTitle,object) {
|
||||
if(headerTitle.toLowerCase() === targetHeader) {
|
||||
result = true;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
},
|
||||
returnProp = options.returnProp || "responseText",
|
||||
request = new XMLHttpRequest(),
|
||||
data = "",
|
||||
@@ -63,10 +73,10 @@ exports.httpRequest = function(options) {
|
||||
request.setRequestHeader(headerTitle,header);
|
||||
});
|
||||
}
|
||||
if(data && !$tw.utils.hop(headers,"Content-type")) {
|
||||
request.setRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8");
|
||||
if(data && !hasHeader("Content-Type")) {
|
||||
request.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
|
||||
}
|
||||
if(!$tw.utils.hop(headers,"X-Requested-With")) {
|
||||
if(!hasHeader("X-Requested-With")) {
|
||||
request.setRequestHeader("X-Requested-With","TiddlyWiki");
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -13,6 +13,7 @@ Modal message mechanism
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
var navigator = require("$:/core/modules/widgets/navigator.js");
|
||||
|
||||
var Modal = function(wiki) {
|
||||
this.wiki = wiki;
|
||||
@@ -41,7 +42,12 @@ Modal.prototype.display = function(title,options) {
|
||||
return;
|
||||
}
|
||||
// Create the variables
|
||||
var variables = $tw.utils.extend({currentTiddler: title},options.variables);
|
||||
var variables = $tw.utils.extend({
|
||||
currentTiddler: title,
|
||||
"tv-story-list": (options.event && options.event.widget ? options.event.widget.getVariable("tv-story-list") : ""),
|
||||
"tv-history-list": (options.event && options.event.widget ? options.event.widget.getVariable("tv-history-list") : "")
|
||||
},options.variables);
|
||||
|
||||
// Create the wrapper divs
|
||||
var wrapper = this.srcDocument.createElement("div"),
|
||||
modalBackdrop = this.srcDocument.createElement("div"),
|
||||
@@ -75,6 +81,31 @@ Modal.prototype.display = function(title,options) {
|
||||
modalFooter.appendChild(modalFooterHelp);
|
||||
modalFooter.appendChild(modalFooterButtons);
|
||||
modalWrapper.appendChild(modalFooter);
|
||||
var navigatorTree = {
|
||||
"type": "navigator",
|
||||
"attributes": {
|
||||
"story": {
|
||||
"name": "story",
|
||||
"type": "string",
|
||||
"value": variables["tv-story-list"]
|
||||
},
|
||||
"history": {
|
||||
"name": "history",
|
||||
"type": "string",
|
||||
"value": variables["tv-history-list"]
|
||||
}
|
||||
},
|
||||
"tag": "$navigator",
|
||||
"isBlock": true,
|
||||
"children": []
|
||||
};
|
||||
var navigatorWidgetNode = new navigator.navigator(navigatorTree, {
|
||||
wiki: this.wiki,
|
||||
document : this.srcDocument,
|
||||
parentWidget: $tw.rootWidget
|
||||
});
|
||||
navigatorWidgetNode.render(modalBody,null);
|
||||
|
||||
// Render the title of the message
|
||||
var headerWidgetNode = this.wiki.makeTranscludeWidget(title,{
|
||||
field: "subtitle",
|
||||
@@ -86,7 +117,7 @@ Modal.prototype.display = function(title,options) {
|
||||
type: "string",
|
||||
value: title
|
||||
}}}],
|
||||
parentWidget: $tw.rootWidget,
|
||||
parentWidget: navigatorWidgetNode,
|
||||
document: this.srcDocument,
|
||||
variables: variables,
|
||||
importPageMacros: true
|
||||
@@ -94,11 +125,12 @@ Modal.prototype.display = function(title,options) {
|
||||
headerWidgetNode.render(headerTitle,null);
|
||||
// Render the body of the message
|
||||
var bodyWidgetNode = this.wiki.makeTranscludeWidget(title,{
|
||||
parentWidget: $tw.rootWidget,
|
||||
parentWidget: navigatorWidgetNode,
|
||||
document: this.srcDocument,
|
||||
variables: variables,
|
||||
importPageMacros: true
|
||||
});
|
||||
|
||||
bodyWidgetNode.render(modalBody,null);
|
||||
// Setup the link if present
|
||||
if(options.downloadLink) {
|
||||
@@ -135,7 +167,7 @@ Modal.prototype.display = function(title,options) {
|
||||
value: $tw.language.getString("Buttons/Close/Caption")
|
||||
}}}
|
||||
]}],
|
||||
parentWidget: $tw.rootWidget,
|
||||
parentWidget: navigatorWidgetNode,
|
||||
document: this.srcDocument,
|
||||
variables: variables,
|
||||
importPageMacros: true
|
||||
|
||||
@@ -49,7 +49,12 @@ Handle an event
|
||||
*/
|
||||
PageScroller.prototype.handleEvent = function(event) {
|
||||
if(event.type === "tm-scroll") {
|
||||
return this.scrollIntoView(event.target);
|
||||
if(event.paramObject && event.paramObject.selector) {
|
||||
this.scrollSelectorIntoView(null,event.paramObject.selector);
|
||||
} else {
|
||||
this.scrollIntoView(event.target);
|
||||
}
|
||||
return false; // Event was handled
|
||||
}
|
||||
return true;
|
||||
};
|
||||
@@ -117,6 +122,14 @@ PageScroller.prototype.scrollIntoView = function(element,callback) {
|
||||
drawFrame();
|
||||
};
|
||||
|
||||
PageScroller.prototype.scrollSelectorIntoView = function(baseElement,selector,callback) {
|
||||
baseElement = baseElement || document.body;
|
||||
var element = baseElement.querySelector(selector);
|
||||
if(element) {
|
||||
this.scrollIntoView(element,callback);
|
||||
}
|
||||
};
|
||||
|
||||
exports.PageScroller = PageScroller;
|
||||
|
||||
})();
|
||||
|
||||
@@ -21,14 +21,32 @@ var bumpSequenceNumber = function(object) {
|
||||
}
|
||||
};
|
||||
|
||||
var TW_Node = function (){
|
||||
throw TypeError("Illegal constructor");
|
||||
};
|
||||
|
||||
Object.defineProperty(TW_Node.prototype, 'ELEMENT_NODE', {
|
||||
get: function() {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(TW_Node.prototype, 'TEXT_NODE', {
|
||||
get: function() {
|
||||
return 3;
|
||||
}
|
||||
});
|
||||
|
||||
var TW_TextNode = function(text) {
|
||||
bumpSequenceNumber(this);
|
||||
this.textContent = text + "";
|
||||
};
|
||||
|
||||
TW_TextNode.prototype = Object.create(TW_Node.prototype);
|
||||
|
||||
Object.defineProperty(TW_TextNode.prototype, "nodeType", {
|
||||
get: function() {
|
||||
return 3;
|
||||
return this.TEXT_NODE;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -49,6 +67,8 @@ var TW_Element = function(tag,namespace) {
|
||||
this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml";
|
||||
};
|
||||
|
||||
TW_Element.prototype = Object.create(TW_Node.prototype);
|
||||
|
||||
Object.defineProperty(TW_Element.prototype, "style", {
|
||||
get: function() {
|
||||
return this._style;
|
||||
@@ -69,7 +89,7 @@ Object.defineProperty(TW_Element.prototype, "style", {
|
||||
|
||||
Object.defineProperty(TW_Element.prototype, "nodeType", {
|
||||
get: function() {
|
||||
return 1;
|
||||
return this.ELEMENT_NODE;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -15,13 +15,33 @@ File system utilities
|
||||
var fs = require("fs"),
|
||||
path = require("path");
|
||||
|
||||
/*
|
||||
Return the subdirectories of a path
|
||||
*/
|
||||
exports.getSubdirectories = function(dirPath) {
|
||||
if(!$tw.utils.isDirectory(dirPath)) {
|
||||
return null;
|
||||
}
|
||||
var subdirs = [];
|
||||
$tw.utils.each(fs.readdirSync(dirPath),function(item) {
|
||||
if($tw.utils.isDirectory(path.resolve(dirPath,item))) {
|
||||
subdirs.push(item);
|
||||
}
|
||||
});
|
||||
return subdirs;
|
||||
}
|
||||
|
||||
/*
|
||||
Recursively (and synchronously) copy a directory and all its content
|
||||
*/
|
||||
exports.copyDirectory = function(srcPath,dstPath) {
|
||||
// Remove any trailing path separators
|
||||
srcPath = $tw.utils.removeTrailingSeparator(srcPath);
|
||||
dstPath = $tw.utils.removeTrailingSeparator(dstPath);
|
||||
srcPath = path.resolve($tw.utils.removeTrailingSeparator(srcPath));
|
||||
dstPath = path.resolve($tw.utils.removeTrailingSeparator(dstPath));
|
||||
// Check that neither director is within the other
|
||||
if(srcPath.substring(0,dstPath.length) === dstPath || dstPath.substring(0,srcPath.length) === srcPath) {
|
||||
return "Cannot copy nested directories";
|
||||
}
|
||||
// Create the destination directory
|
||||
var err = $tw.utils.createDirectory(dstPath);
|
||||
if(err) {
|
||||
@@ -184,15 +204,23 @@ exports.deleteEmptyDirs = function(dirpath,callback) {
|
||||
/*
|
||||
Create a fileInfo object for saving a tiddler:
|
||||
filepath: the absolute path to the file containing the tiddler
|
||||
type: the type of the tiddler file (NOT the type of the tiddler)
|
||||
type: the type of the tiddler file on disk (NOT the type of the tiddler)
|
||||
hasMetaFile: true if the file also has a companion .meta file
|
||||
isEditableFile: true if the tiddler was loaded via non-standard options & marked editable
|
||||
Options include:
|
||||
directory: absolute path of root directory to which we are saving
|
||||
pathFilters: optional array of filters to be used to generate the base path
|
||||
wiki: optional wiki for evaluating the pathFilters
|
||||
extFilters: optional array of filters to be used to generate the base path
|
||||
wiki: optional wiki for evaluating the pathFilters,
|
||||
fileInfo: an existing fileInfo to check against
|
||||
originalpath: a preferred filepath if no pathFilters match
|
||||
*/
|
||||
exports.generateTiddlerFileInfo = function(tiddler,options) {
|
||||
var fileInfo = {};
|
||||
var fileInfo = {}, metaExt;
|
||||
// Propagate the isEditableFile flag
|
||||
if(options.fileInfo) {
|
||||
fileInfo.isEditableFile = options.fileInfo.isEditableFile || false;
|
||||
}
|
||||
// Check if the tiddler has any unsafe fields that can't be expressed in a .tid or .meta file: containing control characters, or leading/trailing whitespace
|
||||
var hasUnsafeFields = false;
|
||||
$tw.utils.each(tiddler.getFieldStrings(),function(value,fieldName) {
|
||||
@@ -218,19 +246,69 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
|
||||
fileInfo.type = tiddlerType;
|
||||
fileInfo.hasMetaFile = true;
|
||||
}
|
||||
if(options.extFilters) {
|
||||
// Check for extension override
|
||||
metaExt = $tw.utils.generateTiddlerExtension(tiddler.fields.title,{
|
||||
extFilters: options.extFilters,
|
||||
wiki: options.wiki
|
||||
});
|
||||
if(metaExt){
|
||||
if(metaExt === ".tid") {
|
||||
// Overriding to the .tid extension needs special handling
|
||||
fileInfo.type = "application/x-tiddler";
|
||||
fileInfo.hasMetaFile = false;
|
||||
} else if (metaExt === ".json") {
|
||||
// Overriding to the .json extension needs special handling
|
||||
fileInfo.type = "application/json";
|
||||
fileInfo.hasMetaFile = false;
|
||||
} else {
|
||||
//If the new type matches a known extention, use that MIME type's encoding
|
||||
var extInfo = $tw.utils.getFileExtensionInfo(metaExt);
|
||||
fileInfo.type = extInfo ? extInfo.type : null;
|
||||
fileInfo.encoding = $tw.utils.getTypeEncoding(metaExt);
|
||||
fileInfo.hasMetaFile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Take the file extension from the tiddler content type
|
||||
// Take the file extension from the tiddler content type or metaExt
|
||||
var contentTypeInfo = $tw.config.contentTypeInfo[fileInfo.type] || {extension: ""};
|
||||
// Generate the filepath
|
||||
fileInfo.filepath = $tw.utils.generateTiddlerFilepath(tiddler.fields.title,{
|
||||
extension: contentTypeInfo.extension,
|
||||
extension: metaExt || contentTypeInfo.extension,
|
||||
directory: options.directory,
|
||||
pathFilters: options.pathFilters,
|
||||
wiki: options.wiki
|
||||
wiki: options.wiki,
|
||||
fileInfo: options.fileInfo,
|
||||
originalpath: options.originalpath
|
||||
});
|
||||
return fileInfo;
|
||||
};
|
||||
|
||||
/*
|
||||
Generate the file extension for saving a tiddler
|
||||
Options include:
|
||||
extFilters: optional array of filters to be used to generate the extention
|
||||
wiki: optional wiki for evaluating the extFilters
|
||||
*/
|
||||
exports.generateTiddlerExtension = function(title,options) {
|
||||
var self = this,
|
||||
extension;
|
||||
// Check if any of the extFilters applies
|
||||
if(options.extFilters && options.wiki) {
|
||||
$tw.utils.each(options.extFilters,function(filter) {
|
||||
if(!extension) {
|
||||
var source = options.wiki.makeTiddlerIterator([title]),
|
||||
result = options.wiki.filterTiddlers(filter,null,source);
|
||||
if(result.length > 0) {
|
||||
extension = result[0];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return extension;
|
||||
};
|
||||
|
||||
/*
|
||||
Generate the filepath for saving a tiddler
|
||||
Options include:
|
||||
@@ -238,12 +316,14 @@ Options include:
|
||||
directory: absolute path of root directory to which we are saving
|
||||
pathFilters: optional array of filters to be used to generate the base path
|
||||
wiki: optional wiki for evaluating the pathFilters
|
||||
fileInfo: an existing fileInfo object to check against
|
||||
*/
|
||||
exports.generateTiddlerFilepath = function(title,options) {
|
||||
var self = this,
|
||||
directory = options.directory || "",
|
||||
extension = options.extension || "",
|
||||
filepath;
|
||||
originalpath = options.originalpath || "",
|
||||
filepath;
|
||||
// Check if any of the pathFilters applies
|
||||
if(options.pathFilters && options.wiki) {
|
||||
$tw.utils.each(options.pathFilters,function(filter) {
|
||||
@@ -256,8 +336,11 @@ exports.generateTiddlerFilepath = function(title,options) {
|
||||
}
|
||||
});
|
||||
}
|
||||
// If not, generate a base pathname
|
||||
if(!filepath) {
|
||||
if(!filepath && originalpath !== "") {
|
||||
//Use the originalpath without the extension
|
||||
var ext = path.extname(originalpath);
|
||||
filepath = originalpath.substring(0,originalpath.length - ext.length);
|
||||
} else if(!filepath) {
|
||||
filepath = title;
|
||||
// If the filepath already ends in the extension then remove it
|
||||
if(filepath.substring(filepath.length - extension.length) === extension) {
|
||||
@@ -266,10 +349,13 @@ exports.generateTiddlerFilepath = function(title,options) {
|
||||
// Remove any forward or backward slashes so we don't create directories
|
||||
filepath = filepath.replace(/\/|\\/g,"_");
|
||||
}
|
||||
// Don't let the filename start with a dot because such files are invisible on *nix
|
||||
filepath = filepath.replace(/^\./g,"_");
|
||||
//If the path does not start with "." or ".." and a path seperator, then
|
||||
if(!/^\.{1,2}[/\\]/g.test(filepath)) {
|
||||
// Don't let the filename start with any dots because such files are invisible on *nix
|
||||
filepath = filepath.replace(/^\.+/g,"_");
|
||||
}
|
||||
// Remove any characters that can't be used in cross-platform filenames
|
||||
filepath = $tw.utils.transliterate(filepath.replace(/<|>|\:|\"|\||\?|\*|\^/g,"_"));
|
||||
filepath = $tw.utils.transliterate(filepath.replace(/<|>|~|\:|\"|\||\?|\*|\^/g,"_"));
|
||||
// Truncate the filename if it is too long
|
||||
if(filepath.length > 200) {
|
||||
filepath = filepath.substr(0,200);
|
||||
@@ -286,12 +372,30 @@ exports.generateTiddlerFilepath = function(title,options) {
|
||||
});
|
||||
}
|
||||
// Add a uniquifier if the file already exists
|
||||
var fullPath,
|
||||
var fullPath, oldPath = (options.fileInfo) ? options.fileInfo.filepath : undefined,
|
||||
count = 0;
|
||||
do {
|
||||
fullPath = path.resolve(directory,filepath + (count ? "_" + count : "") + extension);
|
||||
if(oldPath && oldPath == fullPath) {
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
} while(fs.existsSync(fullPath));
|
||||
// If the last write failed with an error, or if path does not start with:
|
||||
// the resolved options.directory, the resolved wikiPath directory, or the wikiTiddlersPath directory,
|
||||
// then encodeURIComponent() and resolve to tiddler directory
|
||||
var newPath = fullPath,
|
||||
encode = (options.fileInfo || {writeError: false}).writeError == true;
|
||||
if(!encode){
|
||||
encode = !(fullPath.indexOf(path.resolve(directory)) == 0 ||
|
||||
fullPath.indexOf(path.resolve($tw.boot.wikiPath)) == 0 ||
|
||||
fullPath.indexOf($tw.boot.wikiTiddlersPath) == 0);
|
||||
}
|
||||
if(encode){
|
||||
fullPath = path.resolve(directory, encodeURIComponent(fullPath));
|
||||
}
|
||||
// Call hook to allow plugins to modify the final path
|
||||
fullPath = $tw.hooks.invokeHook("th-make-tiddler-path", newPath, fullPath);
|
||||
// Return the full path to the file
|
||||
return fullPath;
|
||||
};
|
||||
@@ -346,4 +450,58 @@ exports.saveTiddlerToFileSync = function(tiddler,fileInfo) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Delete a file described by the fileInfo if it exits
|
||||
*/
|
||||
exports.deleteTiddlerFile = function(fileInfo, callback) {
|
||||
//Only attempt to delete files that exist on disk
|
||||
if(!fileInfo.filepath || !fs.existsSync(fileInfo.filepath)) {
|
||||
return callback(null);
|
||||
}
|
||||
// Delete the file
|
||||
fs.unlink(fileInfo.filepath,function(err) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
// Delete the metafile if present
|
||||
if(fileInfo.hasMetaFile && fs.existsSync(fileInfo.filepath + ".meta")) {
|
||||
fs.unlink(fileInfo.filepath + ".meta",function(err) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
return $tw.utils.deleteEmptyDirs(path.dirname(fileInfo.filepath),callback);
|
||||
});
|
||||
} else {
|
||||
return $tw.utils.deleteEmptyDirs(path.dirname(fileInfo.filepath),callback);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Cleanup old files on disk, by comparing the options values:
|
||||
adaptorInfo from $tw.syncer.tiddlerInfo
|
||||
bootInfo from $tw.boot.files
|
||||
*/
|
||||
exports.cleanupTiddlerFiles = function(options, callback) {
|
||||
var adaptorInfo = options.adaptorInfo || {},
|
||||
bootInfo = options.bootInfo || {},
|
||||
title = options.title || "undefined";
|
||||
if(adaptorInfo.filepath && bootInfo.filepath && adaptorInfo.filepath !== bootInfo.filepath) {
|
||||
return $tw.utils.deleteTiddlerFile(adaptorInfo, function(err){
|
||||
if(err) {
|
||||
if ((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "unlink") {
|
||||
// Error deleting the previous file on disk, should fail gracefully
|
||||
$tw.syncer.displayError("Server desynchronized. Error cleaning up previous file for tiddler: "+title, err);
|
||||
return callback(null);
|
||||
} else {
|
||||
return callback(err);
|
||||
}
|
||||
}
|
||||
return callback(null);
|
||||
});
|
||||
} else {
|
||||
return callback(null);
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
118
core/modules/utils/linked-list.js
Normal file
118
core/modules/utils/linked-list.js
Normal file
@@ -0,0 +1,118 @@
|
||||
/*\
|
||||
module-type: utils
|
||||
title: $:/core/modules/utils/linkedlist.js
|
||||
type: application/javascript
|
||||
|
||||
This is a doubly-linked indexed list intended for manipulation, particularly
|
||||
pushTop, which it does with significantly better performance than an array.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
function LinkedList() {
|
||||
this.clear();
|
||||
};
|
||||
|
||||
LinkedList.prototype.clear = function() {
|
||||
this.index = Object.create(null);
|
||||
// LinkedList performs the duty of both the head and tail node
|
||||
this.next = this;
|
||||
this.prev = this;
|
||||
this.length = 0;
|
||||
};
|
||||
|
||||
LinkedList.prototype.remove = function(value) {
|
||||
if($tw.utils.isArray(value)) {
|
||||
for(var t=0; t<value.length; t++) {
|
||||
_removeOne(this,value[t]);
|
||||
}
|
||||
} else {
|
||||
_removeOne(this,value);
|
||||
}
|
||||
};
|
||||
|
||||
LinkedList.prototype.push = function(/* values */) {
|
||||
for(var i = 0; i < arguments.length; i++) {
|
||||
var value = arguments[i];
|
||||
var node = {value: value};
|
||||
var preexistingNode = this.index[value];
|
||||
_linkToEnd(this,node);
|
||||
if(preexistingNode) {
|
||||
// We want to keep pointing to the first instance, but we want
|
||||
// to have that instance (or chain of instances) point to the
|
||||
// new one.
|
||||
while (preexistingNode.copy) {
|
||||
preexistingNode = preexistingNode.copy;
|
||||
}
|
||||
preexistingNode.copy = node;
|
||||
} else {
|
||||
this.index[value] = node;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
LinkedList.prototype.pushTop = function(value) {
|
||||
if($tw.utils.isArray(value)) {
|
||||
for(var t=0; t<value.length; t++) {
|
||||
_removeOne(this,value[t]);
|
||||
}
|
||||
this.push.apply(this,value);
|
||||
} else {
|
||||
var node = _removeOne(this,value);
|
||||
if(!node) {
|
||||
node = {value: value};
|
||||
this.index[value] = node;
|
||||
} else {
|
||||
// Put this node at the end of the copy chain.
|
||||
var preexistingNode = node;
|
||||
while(preexistingNode.copy) {
|
||||
preexistingNode = preexistingNode.copy;
|
||||
}
|
||||
// The order of these three statements is important,
|
||||
// because sometimes preexistingNode == node.
|
||||
preexistingNode.copy = node;
|
||||
this.index[value] = node.copy;
|
||||
node.copy = undefined;
|
||||
}
|
||||
_linkToEnd(this,node);
|
||||
}
|
||||
};
|
||||
|
||||
LinkedList.prototype.each = function(callback) {
|
||||
for(var ptr = this.next; ptr !== this; ptr = ptr.next) {
|
||||
callback(ptr.value);
|
||||
}
|
||||
};
|
||||
|
||||
LinkedList.prototype.toArray = function() {
|
||||
var output = [];
|
||||
for(var ptr = this.next; ptr !== this; ptr = ptr.next) {
|
||||
output.push(ptr.value);
|
||||
}
|
||||
return output;
|
||||
};
|
||||
|
||||
function _removeOne(list,value) {
|
||||
var node = list.index[value];
|
||||
if(node) {
|
||||
node.prev.next = node.next;
|
||||
node.next.prev = node.prev;
|
||||
list.length -= 1;
|
||||
// Point index to the next instance of the same value, maybe nothing.
|
||||
list.index[value] = node.copy;
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
function _linkToEnd(list,node) {
|
||||
// Sticks the given node onto the end of the list.
|
||||
list.prev.next = node;
|
||||
node.prev = list.prev;
|
||||
list.prev = node;
|
||||
node.next = list;
|
||||
list.length += 1;
|
||||
};
|
||||
|
||||
exports.LinkedList = LinkedList;
|
||||
|
||||
})();
|
||||
@@ -53,6 +53,19 @@ exports.warning = function(text) {
|
||||
exports.log(text,"brown/orange");
|
||||
};
|
||||
|
||||
/*
|
||||
Log a table of name: value pairs
|
||||
*/
|
||||
exports.logTable = function(data) {
|
||||
if(console.table) {
|
||||
console.table(data);
|
||||
} else {
|
||||
$tw.utils.each(data,function(value,name) {
|
||||
console.log(name + ": " + value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Return the integer represented by the str (string).
|
||||
Return the dflt (default) parameter if str is not a base-10 number.
|
||||
@@ -94,6 +107,36 @@ exports.trim = function(str) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.trimPrefix = function(str,unwanted) {
|
||||
if(typeof str === "string" && typeof unwanted === "string") {
|
||||
if(unwanted === "") {
|
||||
return str.replace(/^\s\s*/, '');
|
||||
} else {
|
||||
// Safely regexp-escape the unwanted text
|
||||
unwanted = unwanted.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||
var regex = new RegExp('^(' + unwanted + ')+');
|
||||
return str.replace(regex, '');
|
||||
}
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
exports.trimSuffix = function(str,unwanted) {
|
||||
if(typeof str === "string" && typeof unwanted === "string") {
|
||||
if(unwanted === "") {
|
||||
return str.replace(/\s\s*$/, '');
|
||||
} else {
|
||||
// Safely regexp-escape the unwanted text
|
||||
unwanted = unwanted.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||
var regex = new RegExp('(' + unwanted + ')+$');
|
||||
return str.replace(regex, '');
|
||||
}
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Convert a string to sentence case (ie capitalise first letter)
|
||||
*/
|
||||
@@ -259,7 +302,7 @@ exports.formatDateString = function(date,template) {
|
||||
return $tw.utils.pad($tw.utils.getHours12(date));
|
||||
}],
|
||||
[/^wYYYY/, function() {
|
||||
return $tw.utils.getYearForWeekNo(date);
|
||||
return $tw.utils.pad($tw.utils.getYearForWeekNo(date),4);
|
||||
}],
|
||||
[/^hh12/, function() {
|
||||
return $tw.utils.getHours12(date);
|
||||
@@ -268,7 +311,14 @@ exports.formatDateString = function(date,template) {
|
||||
return date.getDate() + $tw.utils.getDaySuffix(date);
|
||||
}],
|
||||
[/^YYYY/, function() {
|
||||
return date.getFullYear();
|
||||
return $tw.utils.pad(date.getFullYear(),4);
|
||||
}],
|
||||
[/^aYYYY/, function() {
|
||||
return $tw.utils.pad(Math.abs(date.getFullYear()),4);
|
||||
}],
|
||||
[/^\{era:([^,\|}]*)\|([^}\|]*)\|([^}]*)\}/, function(match) {
|
||||
var year = date.getFullYear();
|
||||
return year === 0 ? match[2] : (year < 0 ? match[1] : match[3]);
|
||||
}],
|
||||
[/^0hh/, function() {
|
||||
return $tw.utils.pad(date.getHours());
|
||||
@@ -357,7 +407,7 @@ exports.formatDateString = function(date,template) {
|
||||
$tw.utils.each(matches, function(m) {
|
||||
var match = m[0].exec(t);
|
||||
if(match) {
|
||||
matchString = m[1].call();
|
||||
matchString = m[1].call(null,match);
|
||||
t = t.substr(match[0].length);
|
||||
return false;
|
||||
}
|
||||
@@ -514,7 +564,7 @@ exports.escape = function(ch) {
|
||||
|
||||
// Turns a string into a legal JavaScript string
|
||||
// Copied from peg.js, thanks to David Majda
|
||||
exports.stringify = function(s) {
|
||||
exports.stringify = function(s, rawUnicode) {
|
||||
/*
|
||||
* ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a string
|
||||
* literal except for the closing quote character, backslash, carriage return,
|
||||
@@ -523,19 +573,21 @@ exports.stringify = function(s) {
|
||||
*
|
||||
* For portability, we also escape all non-ASCII characters.
|
||||
*/
|
||||
var regex = rawUnicode ? /[\x00-\x1f]/g : /[\x00-\x1f\x80-\uFFFF]/g;
|
||||
return (s || "")
|
||||
.replace(/\\/g, '\\\\') // backslash
|
||||
.replace(/"/g, '\\"') // double quote character
|
||||
.replace(/'/g, "\\'") // single quote character
|
||||
.replace(/\r/g, '\\r') // carriage return
|
||||
.replace(/\n/g, '\\n') // line feed
|
||||
.replace(/[\x00-\x1f\x80-\uFFFF]/g, exports.escape); // non-ASCII characters
|
||||
.replace(regex, exports.escape); // non-ASCII characters
|
||||
};
|
||||
|
||||
// Turns a string into a legal JSON string
|
||||
// Derived from peg.js, thanks to David Majda
|
||||
exports.jsonStringify = function(s) {
|
||||
exports.jsonStringify = function(s, rawUnicode) {
|
||||
// See http://www.json.org/
|
||||
var regex = rawUnicode ? /[\x00-\x1f]/g : /[\x00-\x1f\x80-\uFFFF]/g;
|
||||
return (s || "")
|
||||
.replace(/\\/g, '\\\\') // backslash
|
||||
.replace(/"/g, '\\"') // double quote character
|
||||
@@ -544,7 +596,7 @@ exports.jsonStringify = function(s) {
|
||||
.replace(/\x08/g, '\\b') // backspace
|
||||
.replace(/\x0c/g, '\\f') // formfeed
|
||||
.replace(/\t/g, '\\t') // tab
|
||||
.replace(/[\x00-\x1f\x80-\uFFFF]/g,function(s) {
|
||||
.replace(regex,function(s) {
|
||||
return '\\u' + $tw.utils.pad(s.charCodeAt(0).toString(16).toUpperCase(),4);
|
||||
}); // non-ASCII characters
|
||||
};
|
||||
@@ -801,4 +853,57 @@ exports.getSystemInfo = function(str,ending,position) {
|
||||
return results.join("\n");
|
||||
};
|
||||
|
||||
exports.parseNumber = function(str) {
|
||||
return parseFloat(str) || 0;
|
||||
};
|
||||
|
||||
exports.parseInt = function(str) {
|
||||
return parseInt(str,10) || 0;
|
||||
};
|
||||
|
||||
exports.stringifyNumber = function(num) {
|
||||
return num + "";
|
||||
};
|
||||
|
||||
exports.makeCompareFunction = function(type,options) {
|
||||
options = options || {};
|
||||
var gt = options.invert ? -1 : +1,
|
||||
lt = options.invert ? +1 : -1,
|
||||
compare = function(a,b) {
|
||||
if(a > b) {
|
||||
return gt ;
|
||||
} else if(a < b) {
|
||||
return lt;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
types = {
|
||||
"number": function(a,b) {
|
||||
return compare($tw.utils.parseNumber(a),$tw.utils.parseNumber(b));
|
||||
},
|
||||
"integer": function(a,b) {
|
||||
return compare($tw.utils.parseInt(a),$tw.utils.parseInt(b));
|
||||
},
|
||||
"string": function(a,b) {
|
||||
return compare("" + a,"" +b);
|
||||
},
|
||||
"date": function(a,b) {
|
||||
var dateA = $tw.utils.parseDate(a),
|
||||
dateB = $tw.utils.parseDate(b);
|
||||
if(!isFinite(dateA)) {
|
||||
dateA = new Date(0);
|
||||
}
|
||||
if(!isFinite(dateB)) {
|
||||
dateB = new Date(0);
|
||||
}
|
||||
return compare(dateA,dateB);
|
||||
},
|
||||
"version": function(a,b) {
|
||||
return $tw.utils.compareVersions(a,b);
|
||||
}
|
||||
};
|
||||
return (types[type] || types[options.defaultType] || types.number);
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
77
core/modules/widgets/action-confirm.js
Normal file
77
core/modules/widgets/action-confirm.js
Normal file
@@ -0,0 +1,77 @@
|
||||
/*\
|
||||
|
||||
title: $:/core/modules/widgets/action-confirm.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var ConfirmWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
ConfirmWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
ConfirmWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
this.parentDomNode = parent;
|
||||
this.renderChildren(parent,nextSibling);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
ConfirmWidget.prototype.execute = function() {
|
||||
this.message = this.getAttribute("$message",$tw.language.getString("ConfirmAction"));
|
||||
this.prompt = (this.getAttribute("$prompt","yes") == "no" ? false : true);
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
/*
|
||||
Refresh the widget by ensuring our attributes are up to date
|
||||
*/
|
||||
ConfirmWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes["$message"] || changedAttributes["$prompt"]) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
/*
|
||||
Invoke the action associated with this widget
|
||||
*/
|
||||
ConfirmWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
var invokeActions = true,
|
||||
handled = true;
|
||||
if(this.prompt) {
|
||||
invokeActions = confirm(this.message);
|
||||
}
|
||||
if(invokeActions) {
|
||||
handled = this.invokeActions(triggeringWidget,event);
|
||||
}
|
||||
return handled;
|
||||
};
|
||||
|
||||
ConfirmWidget.prototype.allowActionPropagation = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
exports["action-confirm"] = ConfirmWidget;
|
||||
|
||||
})();
|
||||
@@ -9,7 +9,7 @@ Action widget to create a new tiddler with a unique name and specified fields.
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
/*global $tw:false, require:false, exports:false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
@@ -36,9 +36,15 @@ Compute the internal state of the widget
|
||||
*/
|
||||
CreateTiddlerWidget.prototype.execute = function() {
|
||||
this.actionBaseTitle = this.getAttribute("$basetitle");
|
||||
this.hasBase = !!this.actionBaseTitle;
|
||||
this.actionSaveTitle = this.getAttribute("$savetitle");
|
||||
this.actionSaveDraftTitle = this.getAttribute("$savedrafttitle");
|
||||
this.actionTimestamp = this.getAttribute("$timestamp","yes") === "yes";
|
||||
//Following params are new since 5.1.22
|
||||
this.actionTemplate = this.getAttribute("$template");
|
||||
this.useTemplate = !!this.actionTemplate;
|
||||
this.actionOverwrite = this.getAttribute("$overwrite","no");
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -57,7 +63,7 @@ CreateTiddlerWidget.prototype.refresh = function(changedTiddlers) {
|
||||
Invoke the action associated with this widget
|
||||
*/
|
||||
CreateTiddlerWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
var title = this.wiki.generateNewTitle(this.actionBaseTitle),
|
||||
var title = this.wiki.getTiddlerText("$:/language/DefaultNewTiddlerTitle"), // Get the initial new-tiddler title
|
||||
fields = {},
|
||||
creationFields,
|
||||
modificationFields;
|
||||
@@ -70,7 +76,22 @@ CreateTiddlerWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
creationFields = this.wiki.getCreationFields();
|
||||
modificationFields = this.wiki.getModificationFields();
|
||||
}
|
||||
var tiddler = this.wiki.addTiddler(new $tw.Tiddler(creationFields,fields,modificationFields,{title: title}));
|
||||
if(this.hasBase && this.actionOverwrite === "no") {
|
||||
title = this.wiki.generateNewTitle(this.actionBaseTitle);
|
||||
} else if (this.hasBase && this.actionOverwrite === "yes") {
|
||||
title = this.actionBaseTitle
|
||||
}
|
||||
// NO $basetitle BUT $template parameter is available
|
||||
// the title MUST be unique, otherwise the template would be overwritten
|
||||
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
|
||||
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}));
|
||||
if(this.actionSaveTitle) {
|
||||
this.wiki.setTextReference(this.actionSaveTitle,title,this.getVariable("currentTiddler"));
|
||||
}
|
||||
|
||||
93
core/modules/widgets/action-log.js
Normal file
93
core/modules/widgets/action-log.js
Normal file
@@ -0,0 +1,93 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/action-log.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Action widget to log debug messages
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var LogWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
LogWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
LogWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
};
|
||||
|
||||
LogWidget.prototype.execute = function(){
|
||||
this.message = this.getAttribute("$$message","debug");
|
||||
this.logAll = this.getAttribute("$$all","no") === "yes" ? true : false;
|
||||
this.filter = this.getAttribute("$$filter");
|
||||
}
|
||||
|
||||
/*
|
||||
Refresh the widget by ensuring our attributes are up to date
|
||||
*/
|
||||
LogWidget.prototype.refresh = function(changedTiddlers) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
Invoke the action associated with this widget
|
||||
*/
|
||||
LogWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
this.log();
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
LogWidget.prototype.log = function() {
|
||||
var data = {},
|
||||
dataCount,
|
||||
allVars = {},
|
||||
filteredVars;
|
||||
|
||||
$tw.utils.each(this.attributes,function(attribute,name) {
|
||||
if(name.substring(0,2) !== "$$") {
|
||||
data[name] = attribute;
|
||||
}
|
||||
});
|
||||
|
||||
for(var v in this.variables) {
|
||||
allVars[v] = this.getVariable(v,{defaultValue:""});
|
||||
}
|
||||
if(this.filter) {
|
||||
filteredVars = this.wiki.compileFilter(this.filter).call(this.wiki,this.wiki.makeTiddlerIterator(allVars));
|
||||
$tw.utils.each(filteredVars,function(name) {
|
||||
data[name] = allVars[name];
|
||||
});
|
||||
}
|
||||
dataCount = $tw.utils.count(data);
|
||||
|
||||
console.group(this.message);
|
||||
if(dataCount > 0) {
|
||||
$tw.utils.logTable(data);
|
||||
}
|
||||
if(this.logAll || !dataCount) {
|
||||
console.groupCollapsed("All variables");
|
||||
$tw.utils.logTable(allVars);
|
||||
console.groupEnd();
|
||||
}
|
||||
console.groupEnd();
|
||||
}
|
||||
|
||||
exports["action-log"] = LogWidget;
|
||||
|
||||
})();
|
||||
@@ -57,7 +57,7 @@ Invoke the action associated with this widget
|
||||
ActionPopupWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
// Trigger the popup
|
||||
var popupLocationRegExp = /^\((-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+)\)$/,
|
||||
match = popupLocationRegExp.exec(this.actionCoords);
|
||||
match = popupLocationRegExp.exec(this.actionCoords || "");
|
||||
if(match) {
|
||||
$tw.popup.triggerPopup({
|
||||
domNode: null,
|
||||
@@ -70,6 +70,8 @@ ActionPopupWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
title: this.actionState,
|
||||
wiki: this.wiki
|
||||
});
|
||||
} else {
|
||||
$tw.popup.cancel(0);
|
||||
}
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user