mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-25 20:33:41 +00:00
Compare commits
555 Commits
dynannotat
...
diff-match
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3605543078 | ||
|
|
b548b29b2b | ||
|
|
0eb6569674 | ||
|
|
0c7e06a10c | ||
|
|
d5f0d834bc | ||
|
|
8c378e0d24 | ||
|
|
925ce2b505 | ||
|
|
eb8f4d66b9 | ||
|
|
ef03a4a5df | ||
|
|
51a4d39c19 | ||
|
|
95dc56d850 | ||
|
|
77b418004a | ||
|
|
028dfe39b7 | ||
|
|
81f5141166 | ||
|
|
3da3318396 | ||
|
|
89fd8871b6 | ||
|
|
f249b79e81 | ||
|
|
524cee1489 | ||
|
|
93abe5e3a6 | ||
|
|
c0bca18cab | ||
|
|
d70b6a7d6c | ||
|
|
6404d5652e | ||
|
|
fe2c677ac4 | ||
|
|
3faadd69c0 | ||
|
|
4e5c957e97 | ||
|
|
3d0ec5b1bd | ||
|
|
fb8e5d1417 | ||
|
|
2426cc668d | ||
|
|
75a399a389 | ||
|
|
4c4399c32d | ||
|
|
194df33de3 | ||
|
|
6718f82b4c | ||
|
|
8ef6d78bef | ||
|
|
e6189078ff | ||
|
|
c20c35c0a6 | ||
|
|
51cbf83c23 | ||
|
|
1441138d5c | ||
|
|
a5894946de | ||
|
|
a3a1eceb4a | ||
|
|
aa8f7f77d6 | ||
|
|
5d650e87dd | ||
|
|
67a8f7aeba | ||
|
|
485bf19c3c | ||
|
|
586d44f6ce | ||
|
|
18c790152f | ||
|
|
9541f3c283 | ||
|
|
5aa5fc72b1 | ||
|
|
005dfdadf0 | ||
|
|
af1cc56c0c | ||
|
|
5bf60cd26f | ||
|
|
4546828541 | ||
|
|
1a69fb7e5c | ||
|
|
db88eed88f | ||
|
|
c51816e826 | ||
|
|
e41511c652 | ||
|
|
8f7441f296 | ||
|
|
c8d99c8aad | ||
|
|
166f68cc15 | ||
|
|
fecb7edca4 | ||
|
|
7632a3317a | ||
|
|
0039c2134b | ||
|
|
34643a4279 | ||
|
|
4d040d2499 | ||
|
|
c0615e20ec | ||
|
|
c39ef398bf | ||
|
|
02d28c100b | ||
|
|
dc225da1ff | ||
|
|
aeec6aee23 | ||
|
|
f9efbd93b1 | ||
|
|
b7c420393c | ||
|
|
9574506a89 | ||
|
|
13c0f3c5e2 | ||
|
|
301a0ecec7 | ||
|
|
917975b464 | ||
|
|
c9691bdb27 | ||
|
|
5ea9743cd5 | ||
|
|
0c328a1696 | ||
|
|
b5134951e5 | ||
|
|
6e10918a28 | ||
|
|
0ee53bbc01 | ||
|
|
a52da67563 | ||
|
|
494ee984f8 | ||
|
|
9c70ee34d4 | ||
|
|
c7612ff4ce | ||
|
|
51acc24b0a | ||
|
|
c5ce1d78a2 | ||
|
|
dd6e00687b | ||
|
|
7b7063a7b2 | ||
|
|
f3ebb258f7 | ||
|
|
67beafe359 | ||
|
|
8ca0bf10e4 | ||
|
|
6f9cf20e77 | ||
|
|
fb8df29948 | ||
|
|
b33b41e1fc | ||
|
|
04810667e6 | ||
|
|
50971db392 | ||
|
|
d57abcbb23 | ||
|
|
8a2fad2499 | ||
|
|
666e2a795f | ||
|
|
42a408146d | ||
|
|
bf8e1ca5b0 | ||
|
|
3bdc18ab84 | ||
|
|
43214c1cc6 | ||
|
|
0b39e47ce8 | ||
|
|
87c3e53299 | ||
|
|
3a7a3d64c2 | ||
|
|
c819b2d365 | ||
|
|
119813529d | ||
|
|
9f69161709 | ||
|
|
18d3ea9d14 | ||
|
|
ae18c2e19b | ||
|
|
95e6168839 | ||
|
|
73507ca8b5 | ||
|
|
4a6e3d4281 | ||
|
|
d217826375 | ||
|
|
a5afed9384 | ||
|
|
b37a356b5e | ||
|
|
55d9a5e16d | ||
|
|
3bab996acd | ||
|
|
7e8380a8df | ||
|
|
44de7918ab | ||
|
|
5ee6af0632 | ||
|
|
ccf444c834 | ||
|
|
ecaa288fc5 | ||
|
|
ceb6999dd6 | ||
|
|
e51dd406b1 | ||
|
|
6ea61ac94f | ||
|
|
caf01f10d6 | ||
|
|
1bd7924e1b | ||
|
|
25b8f26073 | ||
|
|
9160d81cc6 | ||
|
|
0b1a4f3a4d | ||
|
|
8d48964aca | ||
|
|
6cd2fc029d | ||
|
|
6235f29749 | ||
|
|
6385534638 | ||
|
|
ba3cba6170 | ||
|
|
34c9e83bec | ||
|
|
ed9cc84fb2 | ||
|
|
22bc826247 | ||
|
|
6e6efcafc9 | ||
|
|
3c81558d74 | ||
|
|
cc47bb0330 | ||
|
|
0ce5788747 | ||
|
|
1118de319e | ||
|
|
c2d82ccb32 | ||
|
|
a899aac92c | ||
|
|
bef11fe6a2 | ||
|
|
17a1ae23eb | ||
|
|
9f867ad51e | ||
|
|
28c1e6bfc3 | ||
|
|
2db886793e | ||
|
|
8d050e0e69 | ||
|
|
e77006de63 | ||
|
|
80442b7f7f | ||
|
|
10bb3ba09d | ||
|
|
58013ba435 | ||
|
|
ee7bde58a2 | ||
|
|
229159fea7 | ||
|
|
a311e5ebac | ||
|
|
9ff479ce87 | ||
|
|
77053cfe13 | ||
|
|
1bd58db944 | ||
|
|
4be0c17dd0 | ||
|
|
595da5f9f6 | ||
|
|
ff674b9117 | ||
|
|
38dce175d6 | ||
|
|
1ab9f457b4 | ||
|
|
1eddb52de5 | ||
|
|
52fd6ce9c2 | ||
|
|
62308792c8 | ||
|
|
272ba6a4b7 | ||
|
|
90449c9458 | ||
|
|
5b8f36a594 | ||
|
|
acc7224758 | ||
|
|
0db987da60 | ||
|
|
a93a499684 | ||
|
|
2c33502a4a | ||
|
|
451a3454b5 | ||
|
|
45a7eb1c03 | ||
|
|
d03da6085b | ||
|
|
fa4dc2a4e9 | ||
|
|
3918e59cc1 | ||
|
|
f7ccba4c25 | ||
|
|
319d7fbe9c | ||
|
|
67c8f29160 | ||
|
|
856aca2f92 | ||
|
|
34a20463c7 | ||
|
|
56f13133d8 | ||
|
|
684673cbff | ||
|
|
bea1a6b14f | ||
|
|
32a033bb50 | ||
|
|
97f7db169a | ||
|
|
850a4dd351 | ||
|
|
d707e6f825 | ||
|
|
5c378855ab | ||
|
|
ebc1f7e4ce | ||
|
|
2fcbf3b521 | ||
|
|
00927d2e13 | ||
|
|
882e040e62 | ||
|
|
026739e2e0 | ||
|
|
fba9efcf4a | ||
|
|
acfea3a212 | ||
|
|
0dc30086e9 | ||
|
|
cb0d0cfa6d | ||
|
|
d32d559f93 | ||
|
|
8ead7e0624 | ||
|
|
4f7b10e055 | ||
|
|
b8a30091ee | ||
|
|
6955f14c3c | ||
|
|
994c5a2970 | ||
|
|
ea150029f5 | ||
|
|
c663d2ba00 | ||
|
|
39e8c8b125 | ||
|
|
3713ee4fa9 | ||
|
|
a99f934371 | ||
|
|
63803fd99d | ||
|
|
79ec96cb59 | ||
|
|
419b3b3534 | ||
|
|
368963def0 | ||
|
|
830ffe64de | ||
|
|
1483195cd5 | ||
|
|
9b9ff1e843 | ||
|
|
ea3503e30c | ||
|
|
5e116d2a57 | ||
|
|
aa5183a08e | ||
|
|
10cb585dae | ||
|
|
029203dbc0 | ||
|
|
832868ecae | ||
|
|
7f48b6c6ce | ||
|
|
b263ee3c80 | ||
|
|
b097d2ec48 | ||
|
|
ef779c11e8 | ||
|
|
06520c8994 | ||
|
|
710e51fe04 | ||
|
|
af6c017086 | ||
|
|
34353f4065 | ||
|
|
fedc23d73c | ||
|
|
344110e289 | ||
|
|
72f06581b6 | ||
|
|
ae12e8fb69 | ||
|
|
e8148ff978 | ||
|
|
965bd090a9 | ||
|
|
3be9b13814 | ||
|
|
62f26d6630 | ||
|
|
8fe2f6086d | ||
|
|
30af537b91 | ||
|
|
f54ecc23f3 | ||
|
|
67dd3f06bf | ||
|
|
6af3eb539b | ||
|
|
3f55f827a6 | ||
|
|
b9d27e9fd5 | ||
|
|
5b85786f73 | ||
|
|
24dbf69180 | ||
|
|
7b408c7adf | ||
|
|
c19d6d6328 | ||
|
|
941c09fae2 | ||
|
|
b531984f50 | ||
|
|
8f079e2d45 | ||
|
|
cfd894e6fb | ||
|
|
91327c1af0 | ||
|
|
6f98edd6bd | ||
|
|
23e0eeb556 | ||
|
|
f33c7e2aef | ||
|
|
fc586481a9 | ||
|
|
09179d2f62 | ||
|
|
d6ff38095b | ||
|
|
3bbbe77471 | ||
|
|
5657dfec0e | ||
|
|
31ab6dce77 | ||
|
|
4007610d52 | ||
|
|
fb34df84ed | ||
|
|
79e2e317cf | ||
|
|
36896c3db8 | ||
|
|
82de7c9b1a | ||
|
|
1841b0fa4f | ||
|
|
47f80339b2 | ||
|
|
db6abb9703 | ||
|
|
8d1e6b5d23 | ||
|
|
1df4c29d73 | ||
|
|
81e4745c56 | ||
|
|
87597ea273 | ||
|
|
4e9267ea58 | ||
|
|
dd66fcc759 | ||
|
|
8ebb9ef442 | ||
|
|
81ac987484 | ||
|
|
0a00da6db9 | ||
|
|
53d229592d | ||
|
|
166a156584 | ||
|
|
c5d3d4c26e | ||
|
|
51bdf60ee8 | ||
|
|
50f54ba6ca | ||
|
|
1a0ab68dec | ||
|
|
bb67f96562 | ||
|
|
a981f8ccfe | ||
|
|
859d15a446 | ||
|
|
debfd42d51 | ||
|
|
fe365354d0 | ||
|
|
d825f1c875 | ||
|
|
fe74a776e9 | ||
|
|
93e1a632b8 | ||
|
|
9b7edfc1a7 | ||
|
|
3b2c64a85b | ||
|
|
35b9faaa89 | ||
|
|
11b258a14b | ||
|
|
7652aa5fed | ||
|
|
d62a16ee46 | ||
|
|
0b1fc8e574 | ||
|
|
127f660c91 | ||
|
|
668f443fc2 | ||
|
|
c8ad385947 | ||
|
|
c1f6e02d14 | ||
|
|
f0423c20b9 | ||
|
|
953b89fd6b | ||
|
|
f87ab06414 | ||
|
|
2ff5bd5a0f | ||
|
|
d7b9e6fb02 | ||
|
|
8420f8430f | ||
|
|
a572979cc4 | ||
|
|
90d6a0f1a6 | ||
|
|
406dbd0883 | ||
|
|
3fd2cfc339 | ||
|
|
f690458792 | ||
|
|
6bc18570f2 | ||
|
|
1f4b12cd0e | ||
|
|
608aa3378a | ||
|
|
bff7dc88e8 | ||
|
|
667da96c97 | ||
|
|
fb037de091 | ||
|
|
75865385a6 | ||
|
|
091a6a9dc1 | ||
|
|
38f0337207 | ||
|
|
a3b294470f | ||
|
|
53c5cc535e | ||
|
|
9e6713d3e0 | ||
|
|
1acad41574 | ||
|
|
9a5f6558fe | ||
|
|
5d9b71771a | ||
|
|
f891eacddc | ||
|
|
178e652a5d | ||
|
|
daf4eec702 | ||
|
|
34b1b8128f | ||
|
|
a453121e96 | ||
|
|
e849aaab4d | ||
|
|
453d91caeb | ||
|
|
0ad0001e29 | ||
|
|
2441819c70 | ||
|
|
ca762ab7a6 | ||
|
|
28070f847c | ||
|
|
8f85fbca33 | ||
|
|
655cf4729a | ||
|
|
55f3ee5eab | ||
|
|
63bba13758 | ||
|
|
c22d52c046 | ||
|
|
8c57cfdf26 | ||
|
|
4f38903c7b | ||
|
|
ab1e85e01e | ||
|
|
065911259b | ||
|
|
6497633859 | ||
|
|
9cc4c3ead7 | ||
|
|
613b3df367 | ||
|
|
39996c7a2f | ||
|
|
0237d9ed94 | ||
|
|
7e9c2a1a10 | ||
|
|
d4fc8f585e | ||
|
|
caa6b888e9 | ||
|
|
a1b240de2f | ||
|
|
7a98ab1677 | ||
|
|
c49d5a3b08 | ||
|
|
93717560dc | ||
|
|
abc3af16c3 | ||
|
|
97eaec88d1 | ||
|
|
2275255c2b | ||
|
|
fe1147c6fd | ||
|
|
eceacc23c8 | ||
|
|
1ca6305acb | ||
|
|
19331cc6f9 | ||
|
|
f6e021d70f | ||
|
|
2da117484c | ||
|
|
1c1dd2a4cf | ||
|
|
f957874d18 | ||
|
|
aa4a284b88 | ||
|
|
338dc11436 | ||
|
|
22d8fdd259 | ||
|
|
c270e3cd6b | ||
|
|
18d8173dcc | ||
|
|
4cd3c065e7 | ||
|
|
45895bd560 | ||
|
|
af86080943 | ||
|
|
94b02ba3a0 | ||
|
|
bbae2ab6da | ||
|
|
3b778c156b | ||
|
|
2f817e4293 | ||
|
|
0112d04033 | ||
|
|
56d8f47710 | ||
|
|
f818fd96cd | ||
|
|
c5821326d0 | ||
|
|
add14ef65a | ||
|
|
f93fe50044 | ||
|
|
ceec7b5737 | ||
|
|
76bc2f7524 | ||
|
|
a59ec3ebf7 | ||
|
|
20df381cf3 | ||
|
|
4185d9a26c | ||
|
|
bf6d5fa767 | ||
|
|
92c4c82005 | ||
|
|
1110fd50cf | ||
|
|
2c607ee8e6 | ||
|
|
dfebd69d8f | ||
|
|
926b7808b3 | ||
|
|
7ac7d26f86 | ||
|
|
f02bd2392f | ||
|
|
2b45bbc4c4 | ||
|
|
bce3ec6e6f | ||
|
|
5e35c8dda6 | ||
|
|
8af7054efa | ||
|
|
10bc84ba6c | ||
|
|
0391e1855c | ||
|
|
a29889a741 | ||
|
|
27609d2619 | ||
|
|
d5030eb87b | ||
|
|
35b0833e0c | ||
|
|
45f5ba7d38 | ||
|
|
8e64e21039 | ||
|
|
bb47cc97f5 | ||
|
|
7e4722f07a | ||
|
|
df7416d16b | ||
|
|
a226975b3e | ||
|
|
2a62da1498 | ||
|
|
696c5c9c7a | ||
|
|
c808764254 | ||
|
|
a9b0c5d7ff | ||
|
|
9e3c233686 | ||
|
|
8fabcabebb | ||
|
|
96cb66a27e | ||
|
|
6eb4fbeead | ||
|
|
7cbe1e1d83 | ||
|
|
5ea315fb98 | ||
|
|
855b6719d6 | ||
|
|
91cfb217d8 | ||
|
|
1a377a485b | ||
|
|
71ee271eac | ||
|
|
95e0fac655 | ||
|
|
084a5cb0f0 | ||
|
|
e9405ac810 | ||
|
|
775c7f0074 | ||
|
|
34f9cd952c | ||
|
|
e37f36f387 | ||
|
|
7a7d3571cc | ||
|
|
bc8c011eb3 | ||
|
|
b4deb7cc45 | ||
|
|
4b8594c4a8 | ||
|
|
9b9e443c73 | ||
|
|
f3bf5b6e85 | ||
|
|
5d55850c73 | ||
|
|
873ce4823f | ||
|
|
03910fce66 | ||
|
|
0bffae2108 | ||
|
|
bdd99edfe8 | ||
|
|
9bcbb9131e | ||
|
|
1410488a23 | ||
|
|
e2ef5c933b | ||
|
|
3cf078faeb | ||
|
|
9bad66f02e | ||
|
|
ed4ccc4290 | ||
|
|
6e3f4c8772 | ||
|
|
400936920a | ||
|
|
c78bff5bb2 | ||
|
|
8b309ecb42 | ||
|
|
e2869e6ede | ||
|
|
8e25f693c6 | ||
|
|
42bf203758 | ||
|
|
f0416964fa | ||
|
|
8dec674121 | ||
|
|
16f56af873 | ||
|
|
e9fa861418 | ||
|
|
5ab2148807 | ||
|
|
396e7e6921 | ||
|
|
3d2663c900 | ||
|
|
d31839d1e8 | ||
|
|
7d404e4ec5 | ||
|
|
5356345f19 | ||
|
|
f3ee7f429c | ||
|
|
59417f0896 | ||
|
|
2ab0f762e0 | ||
|
|
deeef27cff | ||
|
|
7459ccfed5 | ||
|
|
8d5c94e028 | ||
|
|
6d2d3396ac | ||
|
|
dc2c4635c1 | ||
|
|
fd0b985ac5 | ||
|
|
eb0b2a8d8e | ||
|
|
7d6923f3d6 | ||
|
|
05375e093c | ||
|
|
cc25e1f5b4 | ||
|
|
b3b3020d99 | ||
|
|
383c8b5e49 | ||
|
|
2fd17e864c | ||
|
|
030155ec27 | ||
|
|
58dd47d128 | ||
|
|
8a9d48e055 | ||
|
|
6c505ebc49 | ||
|
|
ae9a183a53 | ||
|
|
b9fec0c669 | ||
|
|
73138b79aa | ||
|
|
6624ce3716 | ||
|
|
c5ea6628f5 | ||
|
|
ad512be04e | ||
|
|
39e4e69ae7 | ||
|
|
8990423374 | ||
|
|
e28af8d594 | ||
|
|
2ab4e965b2 | ||
|
|
4b100503da | ||
|
|
1f14969ab8 | ||
|
|
0b6a345208 | ||
|
|
f97b25676e | ||
|
|
b5ad5c3421 | ||
|
|
2391675e9c | ||
|
|
def8e6d354 | ||
|
|
6701683ddf | ||
|
|
4a9cf67a25 | ||
|
|
5e38f1b0b8 | ||
|
|
73a9625b81 | ||
|
|
bc242cf83a | ||
|
|
051b29c5b3 | ||
|
|
e4b2698380 | ||
|
|
6e89ecd13a | ||
|
|
55eb37222a | ||
|
|
ff42a9e4d4 | ||
|
|
778581b4ff | ||
|
|
dafb3f1c4f | ||
|
|
adcef4f803 | ||
|
|
321f417d58 | ||
|
|
08d9c90dc5 | ||
|
|
6dbb3ee36e | ||
|
|
c920960942 | ||
|
|
ad490017f8 | ||
|
|
e84acf97de | ||
|
|
6a5d73dae6 | ||
|
|
98a509dbf3 | ||
|
|
5d69fe7bef | ||
|
|
b9ae6607c0 | ||
|
|
758d590837 | ||
|
|
1c16f12d6f | ||
|
|
9922701304 | ||
|
|
76236f5ebe | ||
|
|
aec2ad2d12 | ||
|
|
bd6ea2d6a9 | ||
|
|
74d63c7003 | ||
|
|
e26a4d8cb5 | ||
|
|
d1bc079138 | ||
|
|
ffd3599369 | ||
|
|
bfa5882175 | ||
|
|
258f4acb10 | ||
|
|
7e85ec35d3 |
43
.github/ISSUE_TEMPLATE/bug_report.md
vendored
43
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,43 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
|
|
||||||
**TiddlyWiki Configuration (please complete the following information):**
|
|
||||||
- Version [e.g. v5.1.24]
|
|
||||||
- Saving mechanism [e.g. Node.js, TiddlyDesktop, TiddlyHost etc]
|
|
||||||
- Plugins installed [e.g. Freelinks, TiddlyMap]
|
|
||||||
|
|
||||||
**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.
|
|
||||||
67
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
67
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
name: Bug report
|
||||||
|
description: Create a report to help us improve TiddlyWiki 5
|
||||||
|
title: "[BUG] "
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: Describe
|
||||||
|
attributes:
|
||||||
|
label: Describe the bug
|
||||||
|
description: A clear and concise description of what the bug is.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: Expected
|
||||||
|
attributes:
|
||||||
|
label: Expected behavior
|
||||||
|
description: A clear and concise description of what you expected to happen.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
id: Reproduce
|
||||||
|
attributes:
|
||||||
|
label: To Reproduce
|
||||||
|
description: "Steps to reproduce the behavior:"
|
||||||
|
value: |
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
id: Screenshots
|
||||||
|
attributes:
|
||||||
|
label: Screenshots
|
||||||
|
description: If applicable, add screenshots to help explain your problem.
|
||||||
|
placeholder: Drag image here to upload screenshot!
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
id: Configuration
|
||||||
|
attributes:
|
||||||
|
label: TiddlyWiki Configuration
|
||||||
|
description: please complete the following information
|
||||||
|
value: |
|
||||||
|
- Version [e.g. v5.1.24]
|
||||||
|
- Saving mechanism [e.g. Node.js, TiddlyDesktop, TiddlyHost etc]
|
||||||
|
- Plugins installed [e.g. Freelinks, TiddlyMap]
|
||||||
|
|
||||||
|
### 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]
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: Context
|
||||||
|
attributes:
|
||||||
|
label: Additional context
|
||||||
|
description: Add any other context about the problem here.
|
||||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: Discuss feature request
|
||||||
|
url: https://github.com/Jermolene/TiddlyWiki5/discussions
|
||||||
|
about: Open new discussion about new feature
|
||||||
|
- name: Talk.Tiddlywiki Forum
|
||||||
|
url: https://talk.tiddlywiki.org
|
||||||
|
about: Join the Forum
|
||||||
@@ -20,3 +20,11 @@ A clear and concise description of any alternative solutions or features you've
|
|||||||
Add any other context or screenshots about the feature request here.
|
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.
|
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.
|
||||||
|
|
||||||
|
## Checklist before requesting a review
|
||||||
|
|
||||||
|
- [ ] Illustrate any visual changes (however minor) with before/after screenshots
|
||||||
|
- [ ] Self-review of code
|
||||||
|
- [ ] Documentation updates (for user-visible changes)
|
||||||
|
- [ ] Tests (for core code changes)
|
||||||
|
- [ ] Complies with coding style guidelines (for JavaScript code)
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,7 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
.c9/
|
.c9/
|
||||||
|
.vscode/
|
||||||
tmp/
|
tmp/
|
||||||
output/
|
output/
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
# Default to the current version number for building the plugin library
|
# Default to the current version number for building the plugin library
|
||||||
|
|
||||||
if [ -z "$TW5_BUILD_VERSION" ]; then
|
if [ -z "$TW5_BUILD_VERSION" ]; then
|
||||||
TW5_BUILD_VERSION=v5.2.2
|
TW5_BUILD_VERSION=v5.2.6
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
||||||
@@ -233,6 +233,15 @@ node $TW5_BUILD_TIDDLYWIKI \
|
|||||||
--build index \
|
--build index \
|
||||||
|| exit 1
|
|| exit 1
|
||||||
|
|
||||||
|
# /editions/twitter-archivist/index.html Twitter Archivist edition
|
||||||
|
node $TW5_BUILD_TIDDLYWIKI \
|
||||||
|
./editions/twitter-archivist \
|
||||||
|
--verbose \
|
||||||
|
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||||
|
--output $TW5_BUILD_OUTPUT/editions/twitter-archivist/ \
|
||||||
|
--build index \
|
||||||
|
|| exit 1
|
||||||
|
|
||||||
######################################################
|
######################################################
|
||||||
#
|
#
|
||||||
# Plugin demos
|
# Plugin demos
|
||||||
@@ -350,14 +359,14 @@ node $TW5_BUILD_TIDDLYWIKI \
|
|||||||
|
|
||||||
# Delete any existing static content
|
# Delete any existing static content
|
||||||
|
|
||||||
rm $TW5_BUILD_OUTPUT/languages/de-AT/static/*
|
rm -rf $TW5_BUILD_OUTPUT/languages/de-AT/static/*
|
||||||
rm $TW5_BUILD_OUTPUT/languages/de-DE/static/*
|
rm -rf $TW5_BUILD_OUTPUT/languages/de-DE/static/*
|
||||||
rm $TW5_BUILD_OUTPUT/languages/es-ES/static/*
|
rm -rf $TW5_BUILD_OUTPUT/languages/es-ES/static/*
|
||||||
rm $TW5_BUILD_OUTPUT/languages/fr-FR/static/*
|
rm -rf $TW5_BUILD_OUTPUT/languages/fr-FR/static/*
|
||||||
rm $TW5_BUILD_OUTPUT/languages/ja-JP/static/*
|
rm -rf $TW5_BUILD_OUTPUT/languages/ja-JP/static/*
|
||||||
rm $TW5_BUILD_OUTPUT/languages/ko-KR/static/*
|
rm -rf $TW5_BUILD_OUTPUT/languages/ko-KR/static/*
|
||||||
rm $TW5_BUILD_OUTPUT/languages/zh-Hans/static/*
|
rm -rf $TW5_BUILD_OUTPUT/languages/zh-Hans/static/*
|
||||||
rm $TW5_BUILD_OUTPUT/languages/zh-Hant/static/*
|
rm -rf $TW5_BUILD_OUTPUT/languages/zh-Hant/static/*
|
||||||
|
|
||||||
# /languages/de-AT/index.html Demo wiki with de-AT language
|
# /languages/de-AT/index.html Demo wiki with de-AT language
|
||||||
# /languages/de-AT/empty.html Empty wiki with de-AT language
|
# /languages/de-AT/empty.html Empty wiki with de-AT language
|
||||||
@@ -450,7 +459,7 @@ node $TW5_BUILD_TIDDLYWIKI \
|
|||||||
--verbose \
|
--verbose \
|
||||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||||
--output $TW5_BUILD_OUTPUT/library/$TW5_BUILD_VERSION \
|
--output $TW5_BUILD_OUTPUT/library/$TW5_BUILD_VERSION \
|
||||||
--build \
|
--build library\
|
||||||
|| exit 1
|
|| exit 1
|
||||||
|
|
||||||
# Delete the temporary build tiddler
|
# Delete the temporary build tiddler
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ node ./tiddlywiki.js \
|
|||||||
--verbose \
|
--verbose \
|
||||||
--version \
|
--version \
|
||||||
--rendertiddler $:/core/save/all test.html text/plain \
|
--rendertiddler $:/core/save/all test.html text/plain \
|
||||||
|
--test \
|
||||||
|| exit 1
|
|| exit 1
|
||||||
|
|
||||||
echo To run the tests in a browser, open "editions/test/output/test.html"
|
echo To run the tests in a browser, open "editions/test/output/test.html"
|
||||||
|
|||||||
24
boot/boot.js
24
boot/boot.js
@@ -313,7 +313,7 @@ $tw.utils.getLocationHash = function() {
|
|||||||
var idx = href.indexOf('#');
|
var idx = href.indexOf('#');
|
||||||
if(idx === -1) {
|
if(idx === -1) {
|
||||||
return "#";
|
return "#";
|
||||||
} else if(idx < href.length-1 && href[idx+1] === '#') {
|
} else if(href.substr(idx + 1,1) === "#" || href.substr(idx + 1,3) === "%23") {
|
||||||
// Special case: ignore location hash if it itself starts with a #
|
// Special case: ignore location hash if it itself starts with a #
|
||||||
return "#";
|
return "#";
|
||||||
} else {
|
} else {
|
||||||
@@ -375,7 +375,7 @@ $tw.utils.stringifyList = function(value) {
|
|||||||
var result = new Array(value.length);
|
var result = new Array(value.length);
|
||||||
for(var t=0, l=value.length; t<l; t++) {
|
for(var t=0, l=value.length; t<l; t++) {
|
||||||
var entry = value[t] || "";
|
var entry = value[t] || "";
|
||||||
if(entry.indexOf(" ") !== -1) {
|
if(entry.match(/[^\S\xA0]/mg)) {
|
||||||
result[t] = "[[" + entry + "]]";
|
result[t] = "[[" + entry + "]]";
|
||||||
} else {
|
} else {
|
||||||
result[t] = entry;
|
result[t] = entry;
|
||||||
@@ -1230,13 +1230,16 @@ $tw.Wiki = function(options) {
|
|||||||
this.getTiddler = function(title) {
|
this.getTiddler = function(title) {
|
||||||
if(title) {
|
if(title) {
|
||||||
var t = tiddlers[title];
|
var t = tiddlers[title];
|
||||||
if(t instanceof $tw.Tiddler) {
|
if(t !== undefined) {
|
||||||
return t;
|
return t;
|
||||||
} else if(title !== undefined && shadowTiddlers[title]) {
|
} else {
|
||||||
return shadowTiddlers[title].tiddler;
|
var s = shadowTiddlers[title];
|
||||||
|
if(s !== undefined) {
|
||||||
|
return s.tiddler;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get an array of all tiddler titles
|
// Get an array of all tiddler titles
|
||||||
@@ -1878,7 +1881,7 @@ A default set of files for TiddlyWiki to ignore during load.
|
|||||||
This matches what NPM ignores, and adds "*.meta" to ignore tiddler
|
This matches what NPM ignores, and adds "*.meta" to ignore tiddler
|
||||||
metadata files.
|
metadata files.
|
||||||
*/
|
*/
|
||||||
$tw.boot.excludeRegExp = /^\.DS_Store$|^.*\.meta$|^\..*\.swp$|^\._.*$|^\.git$|^\.hg$|^\.lock-wscript$|^\.svn$|^\.wafpickle-.*$|^CVS$|^npm-debug\.log$/;
|
$tw.boot.excludeRegExp = /^\.DS_Store$|^.*\.meta$|^\..*\.swp$|^\._.*$|^\.git$|^\.github$|^\.vscode$|^\.hg$|^\.lock-wscript$|^\.svn$|^\.wafpickle-.*$|^CVS$|^npm-debug\.log$/;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Load all the tiddlers recursively from a directory, including honouring `tiddlywiki.files` files for drawing in external files. Returns an array of {filepath:,type:,tiddlers: [{..fields...}],hasMetaFile:}. Note that no file information is returned for externally loaded tiddlers, just the `tiddlers` property.
|
Load all the tiddlers recursively from a directory, including honouring `tiddlywiki.files` files for drawing in external files. Returns an array of {filepath:,type:,tiddlers: [{..fields...}],hasMetaFile:}. Note that no file information is returned for externally loaded tiddlers, just the `tiddlers` property.
|
||||||
@@ -2400,11 +2403,12 @@ $tw.boot.initStartup = function(options) {
|
|||||||
$tw.utils.registerFileType("application/x-font-ttf","base64",".woff");
|
$tw.utils.registerFileType("application/x-font-ttf","base64",".woff");
|
||||||
$tw.utils.registerFileType("application/font-woff2","base64",".woff2");
|
$tw.utils.registerFileType("application/font-woff2","base64",".woff2");
|
||||||
$tw.utils.registerFileType("audio/ogg","base64",".ogg");
|
$tw.utils.registerFileType("audio/ogg","base64",".ogg");
|
||||||
|
$tw.utils.registerFileType("audio/mp4","base64",[".mp4",".m4a"]);
|
||||||
$tw.utils.registerFileType("video/ogg","base64",[".ogm",".ogv",".ogg"]);
|
$tw.utils.registerFileType("video/ogg","base64",[".ogm",".ogv",".ogg"]);
|
||||||
$tw.utils.registerFileType("video/webm","base64",".webm");
|
$tw.utils.registerFileType("video/webm","base64",".webm");
|
||||||
$tw.utils.registerFileType("video/mp4","base64",".mp4");
|
$tw.utils.registerFileType("video/mp4","base64",".mp4");
|
||||||
$tw.utils.registerFileType("audio/mp3","base64",".mp3");
|
$tw.utils.registerFileType("audio/mp3","base64",".mp3");
|
||||||
$tw.utils.registerFileType("audio/mp4","base64",[".mp4",".m4a"]);
|
$tw.utils.registerFileType("audio/mpeg","base64");
|
||||||
$tw.utils.registerFileType("text/markdown","utf8",[".md",".markdown"],{deserializerType:"text/x-markdown"});
|
$tw.utils.registerFileType("text/markdown","utf8",[".md",".markdown"],{deserializerType:"text/x-markdown"});
|
||||||
$tw.utils.registerFileType("text/x-markdown","utf8",[".md",".markdown"]);
|
$tw.utils.registerFileType("text/x-markdown","utf8",[".md",".markdown"]);
|
||||||
$tw.utils.registerFileType("application/enex+xml","utf8",".enex");
|
$tw.utils.registerFileType("application/enex+xml","utf8",".enex");
|
||||||
@@ -2416,7 +2420,7 @@ $tw.boot.initStartup = function(options) {
|
|||||||
$tw.utils.registerFileType("application/epub+zip","base64",".epub");
|
$tw.utils.registerFileType("application/epub+zip","base64",".epub");
|
||||||
$tw.utils.registerFileType("application/octet-stream","base64",".octet-stream");
|
$tw.utils.registerFileType("application/octet-stream","base64",".octet-stream");
|
||||||
// Create the wiki store for the app
|
// Create the wiki store for the app
|
||||||
$tw.wiki = new $tw.Wiki();
|
$tw.wiki = new $tw.Wiki($tw.safeMode && {enableIndexers: []});
|
||||||
// Install built in tiddler fields modules
|
// Install built in tiddler fields modules
|
||||||
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
|
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
|
||||||
// Install the tiddler deserializer modules
|
// Install the tiddler deserializer modules
|
||||||
@@ -2596,7 +2600,7 @@ $tw.boot.isStartupTaskEligible = function(taskModule) {
|
|||||||
for(t=0; t<remaining.length; t++) {
|
for(t=0; t<remaining.length; t++) {
|
||||||
var task = remaining[t];
|
var task = remaining[t];
|
||||||
if(task.before && task.before.indexOf(name) !== -1) {
|
if(task.before && task.before.indexOf(name) !== -1) {
|
||||||
if($tw.boot.doesTaskMatchPlatform(task) || (task.name && $tw.boot.disabledStartupModules.indexOf(name) !== -1)) {
|
if($tw.boot.doesTaskMatchPlatform(task) && (!task.name || $tw.boot.disabledStartupModules.indexOf(task.name) === -1)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@ type: text/plain
|
|||||||
TiddlyWiki created by Jeremy Ruston, (jeremy [at] jermolene [dot] com)
|
TiddlyWiki created by Jeremy Ruston, (jeremy [at] jermolene [dot] com)
|
||||||
|
|
||||||
Copyright (c) 2004-2007, Jeremy Ruston
|
Copyright (c) 2004-2007, Jeremy Ruston
|
||||||
Copyright (c) 2007-2022, UnaMesa Association
|
Copyright (c) 2007-2023, UnaMesa Association
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
|||||||
4
core/images/layout-button.tid
Executable file
4
core/images/layout-button.tid
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
title: $:/core/images/layout-button
|
||||||
|
tags: $:/tags/Image
|
||||||
|
|
||||||
|
<svg width="22pt" height="22pt" class="tc-image-layout-button tc-image-button" viewBox="0 0 24 24" stroke-width="1" stroke="none"><path d="M0 0h24v24H0z" fill="none"/><rect x="2" y="2" width="7" height="7" rx="2"/><rect x="2" y="13" width="7" height="9" rx="2"/><rect x="12" y="2" width="10" height="20" rx="2"/></svg>
|
||||||
6
core/images/mastodon.tid
Normal file
6
core/images/mastodon.tid
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
title: $:/core/images/mastodon
|
||||||
|
tags: $:/tags/Image
|
||||||
|
|
||||||
|
<svg width="22pt" height="22pt" class="tc-image-mastodon tc-image-button" viewBox="0 0 128 128">
|
||||||
|
<path d="M112.716,76.735C111.231,85.764 99.411,95.646 85.836,97.561C78.757,98.559 71.787,99.476 64.355,99.073C52.201,98.415 42.61,95.646 42.61,95.646C42.61,97.044 42.683,98.374 42.829,99.619C44.409,113.79 54.723,114.639 64.493,115.035C74.354,115.434 83.134,112.163 83.134,112.163L83.539,122.695C83.539,122.695 76.642,127.071 64.355,127.875C57.58,128.315 49.167,127.674 39.369,124.61C18.118,117.965 14.463,91.202 13.904,64.048C13.733,55.985 13.839,48.383 13.839,42.024C13.839,14.257 29.238,6.118 29.238,6.118C37.002,1.905 50.326,0.134 64.177,-0L64.517,-0C78.369,0.134 91.701,1.905 99.465,6.118C99.465,6.118 114.864,14.257 114.864,42.024C114.864,42.024 115.057,62.511 112.716,76.735ZM96.7,44.179C96.7,37.307 95.219,31.847 92.245,27.807C89.177,23.767 85.16,21.696 80.174,21.696C74.403,21.696 70.034,24.316 67.146,29.556L64.337,35.118L61.529,29.556C58.64,24.316 54.271,21.696 48.501,21.696C43.514,21.696 39.497,23.767 36.43,27.807C33.455,31.847 31.974,37.307 31.974,44.179L31.974,77.8L43.249,77.8L43.249,45.167C43.249,38.288 45.699,34.796 50.599,34.796C56.017,34.796 58.733,38.938 58.733,47.128L58.733,64.99L69.941,64.99L69.941,47.128C69.941,38.938 72.657,34.796 78.075,34.796C82.975,34.796 85.425,38.288 85.425,45.167L85.425,77.8L96.7,77.8L96.7,44.179Z"/>
|
||||||
|
</svg>
|
||||||
12
core/images/save-button-dynamic.tid
Normal file
12
core/images/save-button-dynamic.tid
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
title: $:/core/images/save-button-dynamic
|
||||||
|
tags: $:/tags/Image
|
||||||
|
|
||||||
|
<svg width="22pt" height="22pt" class="tc-image-save-button-dynamic tc-image-button" viewBox="0 0 128 128">
|
||||||
|
<g class="tc-image-save-button-dynamic-clean">
|
||||||
|
<path fill-rule="evenodd" d="M120.783 34.33c4.641 8.862 7.266 18.948 7.266 29.646 0 35.347-28.653 64-64 64-35.346 0-64-28.653-64-64 0-35.346 28.654-64 64-64 18.808 0 35.72 8.113 47.43 21.03l2.68-2.68c3.13-3.13 8.197-3.132 11.321-.008 3.118 3.118 3.121 8.193-.007 11.32l-4.69 4.691zm-12.058 12.058a47.876 47.876 0 013.324 17.588c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48c14.39 0 27.3 6.332 36.098 16.362L58.941 73.544 41.976 56.578c-3.127-3.127-8.201-3.123-11.32-.005-3.123 3.124-3.119 8.194.006 11.319l22.617 22.617a7.992 7.992 0 005.659 2.347c2.05 0 4.101-.783 5.667-2.349l44.12-44.12z"/>
|
||||||
|
</g>
|
||||||
|
<g class="tc-image-save-button-dynamic-dirty">
|
||||||
|
<path d="M64.856912,0 C100.203136,0 128.856912,28.653776 128.856912,64 C128.856912,99.346224 100.203136,128 64.856912,128 C29.510688,128 0.856911958,99.346224 0.856911958,64 C0.856911958,28.653776 29.510688,0 64.856912,0 Z M64.856912,16 C38.347244,16 16.856912,37.490332 16.856912,64 C16.856912,90.509668 38.347244,112 64.856912,112 C91.3665799,112 112.856912,90.509668 112.856912,64 C112.856912,37.490332 91.3665799,16 64.856912,16 Z"></path>
|
||||||
|
<circle cx="65" cy="64" r="32"></circle>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
@@ -18,6 +18,8 @@ CopyToClipboard/Caption: copy to clipboard
|
|||||||
CopyToClipboard/Hint: Copy this text to the clipboard
|
CopyToClipboard/Hint: Copy this text to the clipboard
|
||||||
Delete/Caption: delete
|
Delete/Caption: delete
|
||||||
Delete/Hint: Delete this tiddler
|
Delete/Hint: Delete this tiddler
|
||||||
|
DeleteTiddlers/Caption: delete tiddlers
|
||||||
|
DeleteTiddlers/Hint: Delete tiddlers
|
||||||
Edit/Caption: edit
|
Edit/Caption: edit
|
||||||
Edit/Hint: Edit this tiddler
|
Edit/Hint: Edit this tiddler
|
||||||
Encryption/Caption: encryption
|
Encryption/Caption: encryption
|
||||||
@@ -57,6 +59,8 @@ Home/Caption: home
|
|||||||
Home/Hint: Open the default tiddlers
|
Home/Hint: Open the default tiddlers
|
||||||
Language/Caption: language
|
Language/Caption: language
|
||||||
Language/Hint: Choose the user interface language
|
Language/Hint: Choose the user interface language
|
||||||
|
LayoutSwitcher/Hint: Open layout switcher
|
||||||
|
LayoutSwitcher/Caption: layout
|
||||||
Manager/Caption: tiddler manager
|
Manager/Caption: tiddler manager
|
||||||
Manager/Hint: Open tiddler manager
|
Manager/Hint: Open tiddler manager
|
||||||
More/Caption: more
|
More/Caption: more
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Appearance/Hint: Ways to customise the appearance of your TiddlyWiki.
|
|||||||
Basics/AnimDuration/Prompt: Animation duration
|
Basics/AnimDuration/Prompt: Animation duration
|
||||||
Basics/AutoFocus/Prompt: Default focus field for new tiddlers
|
Basics/AutoFocus/Prompt: Default focus field for new tiddlers
|
||||||
Basics/Caption: Basics
|
Basics/Caption: Basics
|
||||||
Basics/DefaultTiddlers/BottomHint: Use [[double square brackets]] for titles with spaces. Or you can choose to <$button set="$:/DefaultTiddlers" setTo="[list[$:/StoryList]]">retain story ordering</$button>
|
Basics/DefaultTiddlers/BottomHint: Use [[double square brackets]] for titles with spaces. Or you can choose to {{retain story ordering||$:/snippets/retain-story-ordering-button}}
|
||||||
Basics/DefaultTiddlers/Prompt: Default tiddlers
|
Basics/DefaultTiddlers/Prompt: Default tiddlers
|
||||||
Basics/DefaultTiddlers/TopHint: Choose which tiddlers are displayed at startup
|
Basics/DefaultTiddlers/TopHint: Choose which tiddlers are displayed at startup
|
||||||
Basics/Language/Prompt: Hello! Current language:
|
Basics/Language/Prompt: Hello! Current language:
|
||||||
@@ -90,8 +90,8 @@ Plugins/Languages/Caption: Languages
|
|||||||
Plugins/Languages/Hint: Language pack plugins
|
Plugins/Languages/Hint: Language pack plugins
|
||||||
Plugins/NoInfoFound/Hint: No ''"<$text text=<<currentTab>>/>"'' found
|
Plugins/NoInfoFound/Hint: No ''"<$text text=<<currentTab>>/>"'' found
|
||||||
Plugins/NotInstalled/Hint: This plugin is not currently installed
|
Plugins/NotInstalled/Hint: This plugin is not currently installed
|
||||||
Plugins/OpenPluginLibrary: open plugin library
|
Plugins/OpenPluginLibrary: Open plugin library
|
||||||
Plugins/ClosePluginLibrary: close plugin library
|
Plugins/ClosePluginLibrary: Close plugin library
|
||||||
Plugins/PluginWillRequireReload: (requires reload)
|
Plugins/PluginWillRequireReload: (requires reload)
|
||||||
Plugins/Plugins/Caption: Plugins
|
Plugins/Plugins/Caption: Plugins
|
||||||
Plugins/Plugins/Hint: Plugins
|
Plugins/Plugins/Hint: Plugins
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
title: $:/language/EditTemplate/
|
title: $:/language/EditTemplate/
|
||||||
|
|
||||||
|
Caption: Editor
|
||||||
Body/External/Hint: This tiddler shows content stored outside of the main TiddlyWiki file. You can edit the tags and fields but cannot directly edit the content itself
|
Body/External/Hint: This tiddler shows content stored outside of the main TiddlyWiki file. You can edit the tags and fields but cannot directly edit the content itself
|
||||||
Body/Placeholder: Type the text for this tiddler
|
Body/Placeholder: Type the text for this tiddler
|
||||||
Body/Preview/Type/Output: output
|
Body/Preview/Type/Output: output
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
title: $:/language/Docs/Fields/
|
title: $:/language/Docs/Fields/
|
||||||
|
|
||||||
_canonical_uri: The full URI of an external image tiddler
|
_canonical_uri: The full URI of an external image tiddler
|
||||||
|
author: Name of the author of a plugin
|
||||||
bag: The name of the bag from which a tiddler came
|
bag: The name of the bag from which a tiddler came
|
||||||
caption: The text to be displayed on a tab or button
|
caption: The text to be displayed on a tab or button
|
||||||
code-body: The view template will display the tiddler as code if set to ''yes''
|
code-body: The view template will display the tiddler as code if set to ''yes''
|
||||||
color: The CSS color value associated with a tiddler
|
color: The CSS color value associated with a tiddler
|
||||||
component: The name of the component responsible for an [[alert tiddler|AlertMechanism]]
|
component: The name of the component responsible for an [[alert tiddler|AlertMechanism]]
|
||||||
|
core-version: For a plugin, indicates what version of TiddlyWiki with which it is compatible
|
||||||
current-tiddler: Used to cache the top tiddler in a [[history list|HistoryMechanism]]
|
current-tiddler: Used to cache the top tiddler in a [[history list|HistoryMechanism]]
|
||||||
created: The date a tiddler was created
|
created: The date a tiddler was created
|
||||||
creator: The name of the person who created a tiddler
|
creator: The name of the person who created a tiddler
|
||||||
@@ -13,7 +15,7 @@ dependents: For a plugin, lists the dependent plugin titles
|
|||||||
description: The descriptive text for a plugin, or a modal dialogue
|
description: The descriptive text for a plugin, or a modal dialogue
|
||||||
draft.of: For draft tiddlers, contains the title of the tiddler of which this is a draft
|
draft.of: For draft tiddlers, contains the title of the tiddler of which this is a draft
|
||||||
draft.title: For draft tiddlers, contains the proposed new title of the tiddler
|
draft.title: For draft tiddlers, contains the proposed new title of the tiddler
|
||||||
footer: The footer text for a wizard
|
footer: The footer text for a modal
|
||||||
hide-body: The view template will hide bodies of tiddlers if set to ''yes''
|
hide-body: The view template will hide bodies of tiddlers if set to ''yes''
|
||||||
icon: The title of the tiddler containing the icon associated with a tiddler
|
icon: The title of the tiddler containing the icon associated with a tiddler
|
||||||
library: Indicates that a tiddler should be saved as a JavaScript library if set to ''yes''
|
library: Indicates that a tiddler should be saved as a JavaScript library if set to ''yes''
|
||||||
@@ -22,13 +24,15 @@ list-before: If set, the title of a tiddler before which this tiddler should be
|
|||||||
list-after: If set, the title of the tiddler after which this tiddler should be added to the ordered list of tiddler titles, or at the end of the list if this field is present but empty
|
list-after: If set, the title of the tiddler after which this tiddler should be added to the ordered list of tiddler titles, or at the end of the list if this field is present but empty
|
||||||
modified: The date and time at which a tiddler was last modified
|
modified: The date and time at which a tiddler was last modified
|
||||||
modifier: The tiddler title associated with the person who last modified a tiddler
|
modifier: The tiddler title associated with the person who last modified a tiddler
|
||||||
|
module-type: For javascript tiddlers, specifies what kind of module it is
|
||||||
name: The human readable name associated with a plugin tiddler
|
name: The human readable name associated with a plugin tiddler
|
||||||
|
parent-plugin: For a plugin, specifies which plugin of which it is a sub-plugin
|
||||||
plugin-priority: A numerical value indicating the priority of a plugin tiddler
|
plugin-priority: A numerical value indicating the priority of a plugin tiddler
|
||||||
plugin-type: The type of plugin in a plugin tiddler
|
plugin-type: The type of plugin in a plugin tiddler
|
||||||
revision: The revision of the tiddler held at the server
|
revision: The revision of the tiddler held at the server
|
||||||
released: Date of a TiddlyWiki release
|
released: Date of a TiddlyWiki release
|
||||||
source: The source URL associated with a tiddler
|
source: The source URL associated with a tiddler
|
||||||
subtitle: The subtitle text for a wizard
|
subtitle: The subtitle text for a modal
|
||||||
tags: A list of tags associated with a tiddler
|
tags: A list of tags associated with a tiddler
|
||||||
text: The body text of a tiddler
|
text: The body text of a tiddler
|
||||||
throttle.refresh: If present, throttles refreshes of this tiddler
|
throttle.refresh: If present, throttles refreshes of this tiddler
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ Before you start storing important information in ~TiddlyWiki it is vital to mak
|
|||||||
|
|
||||||
<div class="tc-control-panel">
|
<div class="tc-control-panel">
|
||||||
|
|
||||||
|<$link to="$:/SiteTitle"><<lingo Title/Prompt>></$link> |<$edit-text tiddler="$:/SiteTitle" default="" tag="input"/> |
|
|tc-table-no-border tc-first-col-min-width tc-first-link-nowrap|k
|
||||||
|<$link to="$:/SiteSubtitle"><<lingo Subtitle/Prompt>></$link> |<$edit-text tiddler="$:/SiteSubtitle" default="" tag="input"/> |
|
| <$link to="$:/SiteTitle"><<lingo Title/Prompt>></$link>|<$edit-text tiddler="$:/SiteTitle" default="" tag="input"/> |
|
||||||
|<$link to="$:/DefaultTiddlers"><<lingo DefaultTiddlers/Prompt>></$link> |<<lingo DefaultTiddlers/TopHint>><br> <$edit tag="textarea" tiddler="$:/DefaultTiddlers"/><br>//<<lingo DefaultTiddlers/BottomHint>>// |
|
| <$link to="$:/SiteSubtitle"><<lingo Subtitle/Prompt>></$link>|<$edit-text tiddler="$:/SiteSubtitle" default="" tag="input"/> |
|
||||||
|
|^ <$link to="$:/DefaultTiddlers"><<lingo DefaultTiddlers/Prompt>></$link><br><<lingo DefaultTiddlers/TopHint>>|<$edit tag="textarea" tiddler="$:/DefaultTiddlers"/><br>//<<lingo DefaultTiddlers/BottomHint>>// |
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
See the [[control panel|$:/ControlPanel]] for more options.
|
See the [[control panel|$:/ControlPanel]] for more options.
|
||||||
|
|||||||
18
core/language/en-GB/Help/commands.tid
Normal file
18
core/language/en-GB/Help/commands.tid
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
title: $:/language/Help/commands
|
||||||
|
description: Run commands returned from a filter
|
||||||
|
|
||||||
|
Sequentially run the command tokens returned from a filter
|
||||||
|
|
||||||
|
```
|
||||||
|
--commands <filter>
|
||||||
|
```
|
||||||
|
|
||||||
|
Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
--commands "[enlist{$:/build-commands-as-text}]"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
--commands "[{$:/build-commands-as-json}jsonindexes[]] :map[{$:/build-commands-as-json}jsonget<currentTiddler>]"
|
||||||
|
```
|
||||||
@@ -3,6 +3,7 @@ title: $:/language/Help/default
|
|||||||
\define commandTitle()
|
\define commandTitle()
|
||||||
$:/language/Help/$(command)$
|
$:/language/Help/$(command)$
|
||||||
\end
|
\end
|
||||||
|
\whitespace trim
|
||||||
```
|
```
|
||||||
usage: tiddlywiki [<wikifolder>] [--<command> [<args>...]...]
|
usage: tiddlywiki [<wikifolder>] [--<command> [<args>...]...]
|
||||||
```
|
```
|
||||||
@@ -11,7 +12,9 @@ Available commands:
|
|||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<$list filter="[commands[]sort[title]]" variable="command">
|
<$list filter="[commands[]sort[title]]" variable="command">
|
||||||
<li><$link to=<<commandTitle>>><$macrocall $name="command" $type="text/plain" $output="text/plain"/></$link>: <$transclude tiddler=<<commandTitle>> field="description"/></li>
|
<li><$link to=<<commandTitle>>><$macrocall $name="command" $type="text/plain" $output="text/plain"/></$link>:
|
||||||
|
 
|
||||||
|
<$transclude tiddler=<<commandTitle>> field="description"/></li>
|
||||||
</$list>
|
</$list>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@@ -31,5 +31,5 @@ Notes:
|
|||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
* `--render "[!is[system]]" "[encodeuricomponent[]addprefix[tiddlers/]addsuffix[.html]]"` -- renders all non-system tiddlers as files in the subdirectory "tiddlers" with URL-encoded titles and the extension HTML
|
* `--render '[!is[system]]' '[encodeuricomponent[]addprefix[tiddlers/]addsuffix[.html]]'` -- renders all non-system tiddlers as files in the subdirectory "tiddlers" with URL-encoded titles and the extension HTML
|
||||||
|
* `--render '.' 'tiddlers.json' 'text/plain' '$:/core/templates/exporters/JsonFile' 'exportFilter' '[tag[HelloThere]]'` -- renders the tiddlers tagged "HelloThere" to a JSON file named "tiddlers.json"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ CloseAll/Button: close all
|
|||||||
ColourPicker/Recent: Recent:
|
ColourPicker/Recent: Recent:
|
||||||
ConfirmCancelTiddler: Do you wish to discard changes to the tiddler "<$text text=<<title>>/>"?
|
ConfirmCancelTiddler: Do you wish to discard changes to the tiddler "<$text text=<<title>>/>"?
|
||||||
ConfirmDeleteTiddler: Do you wish to delete the tiddler "<$text text=<<title>>/>"?
|
ConfirmDeleteTiddler: Do you wish to delete the tiddler "<$text text=<<title>>/>"?
|
||||||
|
ConfirmDeleteTiddlers: Are you sure you wish to delete <<resultCount>> tiddler(s)?
|
||||||
ConfirmOverwriteTiddler: Do you wish to overwrite 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>>/>"?
|
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?
|
ConfirmAction: Do you wish to proceed?
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
title: $:/language/SideBar/
|
title: $:/language/SideBar/
|
||||||
|
|
||||||
|
Caption: Sidebar
|
||||||
All/Caption: All
|
All/Caption: All
|
||||||
Contents/Caption: Contents
|
Contents/Caption: Contents
|
||||||
Drafts/Caption: Drafts
|
Drafts/Caption: Drafts
|
||||||
|
|||||||
42
core/modules/commands/commands.js
Normal file
42
core/modules/commands/commands.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/commands/commands.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: command
|
||||||
|
|
||||||
|
Runs the commands returned from a filter
|
||||||
|
|
||||||
|
\*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
name: "commands",
|
||||||
|
synchronous: true
|
||||||
|
};
|
||||||
|
|
||||||
|
var Command = function(params, commander) {
|
||||||
|
this.params = params;
|
||||||
|
this.commander = commander;
|
||||||
|
};
|
||||||
|
|
||||||
|
Command.prototype.execute = function() {
|
||||||
|
// Parse the filter
|
||||||
|
var filter = this.params[0];
|
||||||
|
if(!filter) {
|
||||||
|
return "No filter specified";
|
||||||
|
}
|
||||||
|
var commands = this.commander.wiki.filterTiddlers(filter)
|
||||||
|
if(commands.length === 0) {
|
||||||
|
return "No tiddlers found for filter '" + filter + "'";
|
||||||
|
}
|
||||||
|
this.commander.addCommandTokens(commands);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.Command = Command;
|
||||||
|
|
||||||
|
})();
|
||||||
@@ -50,7 +50,7 @@ Render individual tiddlers and save the results to the specified files
|
|||||||
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
|
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
|
||||||
}
|
}
|
||||||
var parser = wiki.parseTiddler(template || title),
|
var parser = wiki.parseTiddler(template || title),
|
||||||
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title})}),
|
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title,storyTiddler: title})}),
|
||||||
container = $tw.fakeDocument.createElement("div");
|
container = $tw.fakeDocument.createElement("div");
|
||||||
widgetNode.render(container,null);
|
widgetNode.render(container,null);
|
||||||
var text = type === "text/html" ? container.innerHTML : container.textContent;
|
var text = type === "text/html" ? container.innerHTML : container.textContent;
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ Command.prototype.execute = function() {
|
|||||||
$tw.utils.createFileDirectories(filename);
|
$tw.utils.createFileDirectories(filename);
|
||||||
if(template) {
|
if(template) {
|
||||||
variables.currentTiddler = title;
|
variables.currentTiddler = title;
|
||||||
|
variables.storyTiddler = title;
|
||||||
title = template;
|
title = template;
|
||||||
}
|
}
|
||||||
if(name && value) {
|
if(name && value) {
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ Command.prototype.execute = function() {
|
|||||||
}
|
}
|
||||||
$tw.utils.each(tiddlers,function(title) {
|
$tw.utils.each(tiddlers,function(title) {
|
||||||
var parser = wiki.parseTiddler(template),
|
var parser = wiki.parseTiddler(template),
|
||||||
widgetNode = wiki.makeWidget(parser,{variables: {currentTiddler: title}}),
|
widgetNode = wiki.makeWidget(parser,{variables: {currentTiddler: title, storyTiddler: title}}),
|
||||||
container = $tw.fakeDocument.createElement("div");
|
container = $tw.fakeDocument.createElement("div");
|
||||||
widgetNode.render(container,null);
|
widgetNode.render(container,null);
|
||||||
var text = type === "text/html" ? container.innerHTML : container.textContent,
|
var text = type === "text/html" ? container.innerHTML : container.textContent,
|
||||||
@@ -57,7 +57,7 @@ Command.prototype.execute = function() {
|
|||||||
exportPath = path.resolve(outputPath,macroPath + extension);
|
exportPath = path.resolve(outputPath,macroPath + extension);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var finalPath = exportPath || path.resolve(pathname,encodeURIComponent(title) + extension);
|
var finalPath = exportPath || path.resolve(pathname,$tw.utils.encodeURIComponentExtended(title) + extension);
|
||||||
$tw.utils.createFileDirectories(finalPath);
|
$tw.utils.createFileDirectories(finalPath);
|
||||||
fs.writeFileSync(finalPath,text,"utf8");
|
fs.writeFileSync(finalPath,text,"utf8");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,46 +8,60 @@ Saves individual tiddlers in their raw text or binary format to the specified fi
|
|||||||
\*/
|
\*/
|
||||||
(function(){
|
(function(){
|
||||||
|
|
||||||
/*jslint node: true, browser: true */
|
/*jslint node: true, browser: true */
|
||||||
/*global $tw: false */
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.info = {
|
exports.info = {
|
||||||
name: "save",
|
name: "save",
|
||||||
synchronous: true
|
synchronous: true
|
||||||
};
|
};
|
||||||
|
|
||||||
var Command = function(params,commander,callback) {
|
var Command = function(params,commander,callback) {
|
||||||
this.params = params;
|
this.params = params;
|
||||||
this.commander = commander;
|
this.commander = commander;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
Command.prototype.execute = function() {
|
Command.prototype.execute = function() {
|
||||||
if(this.params.length < 1) {
|
if(this.params.length < 1) {
|
||||||
return "Missing filename filter";
|
return "Missing filename filter";
|
||||||
}
|
|
||||||
var self = this,
|
|
||||||
fs = require("fs"),
|
|
||||||
path = require("path"),
|
|
||||||
wiki = this.commander.wiki,
|
|
||||||
tiddlerFilter = this.params[0],
|
|
||||||
filenameFilter = this.params[1] || "[is[tiddler]]",
|
|
||||||
tiddlers = wiki.filterTiddlers(tiddlerFilter);
|
|
||||||
$tw.utils.each(tiddlers,function(title) {
|
|
||||||
var tiddler = self.commander.wiki.getTiddler(title),
|
|
||||||
type = tiddler.fields.type || "text/vnd.tiddlywiki",
|
|
||||||
contentTypeInfo = $tw.config.contentTypeInfo[type] || {encoding: "utf8"},
|
|
||||||
filepath = path.resolve(self.commander.outputPath,wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]))[0]);
|
|
||||||
if(self.commander.verbose) {
|
|
||||||
console.log("Saving \"" + title + "\" to \"" + filepath + "\"");
|
|
||||||
}
|
}
|
||||||
$tw.utils.createFileDirectories(filepath);
|
var self = this,
|
||||||
fs.writeFileSync(filepath,tiddler.fields.text,contentTypeInfo.encoding);
|
fs = require("fs"),
|
||||||
});
|
path = require("path"),
|
||||||
return null;
|
result = null,
|
||||||
};
|
wiki = this.commander.wiki,
|
||||||
|
tiddlerFilter = this.params[0],
|
||||||
exports.Command = Command;
|
filenameFilter = this.params[1] || "[is[tiddler]]",
|
||||||
|
tiddlers = wiki.filterTiddlers(tiddlerFilter);
|
||||||
})();
|
$tw.utils.each(tiddlers,function(title) {
|
||||||
|
if(!result) {
|
||||||
|
var tiddler = self.commander.wiki.getTiddler(title);
|
||||||
|
if(tiddler) {
|
||||||
|
var fileInfo = $tw.utils.generateTiddlerFileInfo(tiddler,{
|
||||||
|
directory: path.resolve(self.commander.outputPath),
|
||||||
|
pathFilters: [filenameFilter],
|
||||||
|
wiki: wiki,
|
||||||
|
fileInfo: {}
|
||||||
|
});
|
||||||
|
if(self.commander.verbose) {
|
||||||
|
console.log("Saving \"" + title + "\" to \"" + fileInfo.filepath + "\"");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$tw.utils.saveTiddlerToFileSync(tiddler,fileInfo);
|
||||||
|
} catch (err) {
|
||||||
|
result = "Error saving tiddler \"" + title + "\", to file: \"" + fileInfo.filepath + "\"";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = "Tiddler '" + title + "' not found";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.Command = Command;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ Command.prototype.execute = function() {
|
|||||||
$tw.utils.each(filteredPluginList,function(title) {
|
$tw.utils.each(filteredPluginList,function(title) {
|
||||||
var tiddler = containerData.tiddlers[title];
|
var tiddler = containerData.tiddlers[title];
|
||||||
// Save each JSON file and collect the skinny data
|
// Save each JSON file and collect the skinny data
|
||||||
var pathname = path.resolve(self.commander.outputPath,basepath + encodeURIComponent(title) + ".json");
|
var pathname = path.resolve(self.commander.outputPath,basepath + $tw.utils.encodeURIComponentExtended(title) + ".json");
|
||||||
$tw.utils.createFileDirectories(pathname);
|
$tw.utils.createFileDirectories(pathname);
|
||||||
fs.writeFileSync(pathname,JSON.stringify(tiddler),"utf8");
|
fs.writeFileSync(pathname,JSON.stringify(tiddler),"utf8");
|
||||||
// Collect the skinny list data
|
// Collect the skinny list data
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ Command.prototype.execute = function() {
|
|||||||
var tiddler = self.commander.wiki.getTiddler(title),
|
var tiddler = self.commander.wiki.getTiddler(title),
|
||||||
type = tiddler.fields.type || "text/vnd.tiddlywiki",
|
type = tiddler.fields.type || "text/vnd.tiddlywiki",
|
||||||
contentTypeInfo = $tw.config.contentTypeInfo[type] || {encoding: "utf8"},
|
contentTypeInfo = $tw.config.contentTypeInfo[type] || {encoding: "utf8"},
|
||||||
filename = path.resolve(pathname,encodeURIComponent(title));
|
filename = path.resolve(pathname,$tw.utils.encodeURIComponentExtended(title));
|
||||||
fs.writeFileSync(filename,tiddler.fields.text,contentTypeInfo.encoding);
|
fs.writeFileSync(filename,tiddler.fields.text,contentTypeInfo.encoding);
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -34,8 +34,10 @@ function FramedEngine(options) {
|
|||||||
this.parentNode.insertBefore(this.iframeNode,this.nextSibling);
|
this.parentNode.insertBefore(this.iframeNode,this.nextSibling);
|
||||||
this.iframeDoc = this.iframeNode.contentWindow.document;
|
this.iframeDoc = this.iframeNode.contentWindow.document;
|
||||||
// (Firefox requires us to put some empty content in the iframe)
|
// (Firefox requires us to put some empty content in the iframe)
|
||||||
|
var paletteTitle = this.widget.wiki.getTiddlerText("$:/palette");
|
||||||
|
var colorScheme = (this.widget.wiki.getTiddler(paletteTitle) || {fields: {}}).fields["color-scheme"] || "light";
|
||||||
this.iframeDoc.open();
|
this.iframeDoc.open();
|
||||||
this.iframeDoc.write("");
|
this.iframeDoc.write("<meta name='color-scheme' content='" + colorScheme + "'>");
|
||||||
this.iframeDoc.close();
|
this.iframeDoc.close();
|
||||||
// Style the iframe
|
// Style the iframe
|
||||||
this.iframeNode.className = this.dummyTextArea.className;
|
this.iframeNode.className = this.dummyTextArea.className;
|
||||||
@@ -85,7 +87,7 @@ function FramedEngine(options) {
|
|||||||
$tw.utils.addEventListeners(this.domNode,[
|
$tw.utils.addEventListeners(this.domNode,[
|
||||||
{name: "click",handlerObject: this,handlerMethod: "handleClickEvent"},
|
{name: "click",handlerObject: this,handlerMethod: "handleClickEvent"},
|
||||||
{name: "input",handlerObject: this,handlerMethod: "handleInputEvent"},
|
{name: "input",handlerObject: this,handlerMethod: "handleInputEvent"},
|
||||||
{name: "keydown",handlerObject: this.widget,handlerMethod: "handleKeydownEvent"},
|
{name: "keydown",handlerObject: this,handlerMethod: "handleKeydownEvent"},
|
||||||
{name: "focus",handlerObject: this,handlerMethod: "handleFocusEvent"}
|
{name: "focus",handlerObject: this,handlerMethod: "handleFocusEvent"}
|
||||||
]);
|
]);
|
||||||
// Add drag and drop event listeners if fileDrop is enabled
|
// Add drag and drop event listeners if fileDrop is enabled
|
||||||
@@ -190,6 +192,17 @@ FramedEngine.prototype.handleFocusEvent = function(event) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Handle a keydown event
|
||||||
|
*/
|
||||||
|
FramedEngine.prototype.handleKeydownEvent = function(event) {
|
||||||
|
if ($tw.keyboardManager.handleKeydownEvent(event, {onlyPriority: true})) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.widget.handleKeydownEvent(event);
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Handle a click
|
Handle a click
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
|||||||
// Otherwise, we need to construct a default value for the editor
|
// Otherwise, we need to construct a default value for the editor
|
||||||
switch(this.editField) {
|
switch(this.editField) {
|
||||||
case "text":
|
case "text":
|
||||||
value = "Type the text for the tiddler '" + this.editTitle + "'";
|
value = "";
|
||||||
type = "text/vnd.tiddlywiki";
|
type = "text/vnd.tiddlywiki";
|
||||||
break;
|
break;
|
||||||
case "title":
|
case "title":
|
||||||
@@ -218,7 +218,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
|||||||
EditTextWidget.prototype.refresh = function(changedTiddlers) {
|
EditTextWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
var changedAttributes = this.computeAttributes();
|
var changedAttributes = this.computeAttributes();
|
||||||
// Completely rerender if any of our attributes have changed
|
// 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 || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedAttributes.disabled || changedAttributes.fileDrop) {
|
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] || changedTiddlers["$:/palette"] || changedAttributes.disabled || changedAttributes.fileDrop) {
|
||||||
this.refreshSelf();
|
this.refreshSelf();
|
||||||
return true;
|
return true;
|
||||||
} else if (changedTiddlers[this.editRefreshTitle]) {
|
} else if (changedTiddlers[this.editRefreshTitle]) {
|
||||||
@@ -298,7 +298,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
|||||||
Propogate keydown events to our container for the keyboard widgets benefit
|
Propogate keydown events to our container for the keyboard widgets benefit
|
||||||
*/
|
*/
|
||||||
EditTextWidget.prototype.propogateKeydownEvent = function(event) {
|
EditTextWidget.prototype.propogateKeydownEvent = function(event) {
|
||||||
var newEvent = this.cloneEvent(event,["keyCode","which","metaKey","ctrlKey","altKey","shiftKey"]);
|
var newEvent = this.cloneEvent(event,["keyCode","code","which","key","metaKey","ctrlKey","altKey","shiftKey"]);
|
||||||
return !this.parentDomNode.dispatchEvent(newEvent);
|
return !this.parentDomNode.dispatchEvent(newEvent);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ exports["prefix-lines"] = function(event,operation) {
|
|||||||
$tw.utils.each(lines,function(line,index) {
|
$tw.utils.each(lines,function(line,index) {
|
||||||
// Remove and count any existing prefix characters
|
// Remove and count any existing prefix characters
|
||||||
var count = 0;
|
var count = 0;
|
||||||
while(line.charAt(0) === event.paramObject.character) {
|
while($tw.utils.startsWith(line,event.paramObject.character)) {
|
||||||
line = line.substring(1);
|
line = line.substring(event.paramObject.character.length);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
// Remove any whitespace
|
// Remove any whitespace
|
||||||
|
|||||||
@@ -15,16 +15,33 @@ Text editor operation to wrap the selected lines with a prefix and suffix
|
|||||||
exports["wrap-lines"] = function(event,operation) {
|
exports["wrap-lines"] = function(event,operation) {
|
||||||
var prefix = event.paramObject.prefix || "",
|
var prefix = event.paramObject.prefix || "",
|
||||||
suffix = event.paramObject.suffix || "";
|
suffix = event.paramObject.suffix || "";
|
||||||
// Cut just past the preceding line break, or the start of the text
|
if($tw.utils.endsWith(operation.text.substring(0,operation.selStart), prefix + "\n") &&
|
||||||
operation.cutStart = $tw.utils.findPrecedingLineBreak(operation.text,operation.selStart);
|
$tw.utils.startsWith(operation.text.substring(operation.selEnd), "\n" + suffix)) {
|
||||||
// Cut to just past the following line break, or to the end of the text
|
// Selected text is already surrounded by prefix and suffix: Remove them
|
||||||
operation.cutEnd = $tw.utils.findFollowingLineBreak(operation.text,operation.selEnd);
|
// Cut selected text plus prefix and suffix
|
||||||
// Add the prefix and suffix
|
operation.cutStart = operation.selStart - (prefix.length + 1);
|
||||||
operation.replacement = prefix + "\n" +
|
operation.cutEnd = operation.selEnd + suffix.length + 1;
|
||||||
operation.text.substring(operation.cutStart,operation.cutEnd) + "\n" +
|
// Also cut the following newline (if there is any)
|
||||||
suffix + "\n";
|
if (operation.text[operation.cutEnd] === "\n") {
|
||||||
operation.newSelStart = operation.cutStart + prefix.length + 1;
|
operation.cutEnd++;
|
||||||
operation.newSelEnd = operation.newSelStart + (operation.cutEnd - operation.cutStart);
|
}
|
||||||
|
// Replace with selection
|
||||||
|
operation.replacement = operation.text.substring(operation.selStart,operation.selEnd);
|
||||||
|
// Select text that was in between prefix and suffix
|
||||||
|
operation.newSelStart = operation.cutStart;
|
||||||
|
operation.newSelEnd = operation.selEnd - (prefix.length + 1);
|
||||||
|
} else {
|
||||||
|
// Cut just past the preceding line break, or the start of the text
|
||||||
|
operation.cutStart = $tw.utils.findPrecedingLineBreak(operation.text,operation.selStart);
|
||||||
|
// Cut to just past the following line break, or to the end of the text
|
||||||
|
operation.cutEnd = $tw.utils.findFollowingLineBreak(operation.text,operation.selEnd);
|
||||||
|
// Add the prefix and suffix
|
||||||
|
operation.replacement = prefix + "\n" +
|
||||||
|
operation.text.substring(operation.cutStart,operation.cutEnd) + "\n" +
|
||||||
|
suffix + "\n";
|
||||||
|
operation.newSelStart = operation.cutStart + prefix.length + 1;
|
||||||
|
operation.newSelEnd = operation.newSelStart + (operation.cutEnd - operation.cutStart);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ exports.map = function(operationSubFunction,options) {
|
|||||||
return function(results,source,widget) {
|
return function(results,source,widget) {
|
||||||
if(results.length > 0) {
|
if(results.length > 0) {
|
||||||
var inputTitles = results.toArray(),
|
var inputTitles = results.toArray(),
|
||||||
index = 0;
|
index = 0,
|
||||||
|
suffixes = options.suffixes,
|
||||||
|
flatten = (suffixes[0] && suffixes[0][0] === "flat") ? true : false;
|
||||||
results.clear();
|
results.clear();
|
||||||
$tw.utils.each(inputTitles,function(title) {
|
$tw.utils.each(inputTitles,function(title) {
|
||||||
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||||
@@ -36,7 +38,13 @@ exports.map = function(operationSubFunction,options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
results.push(filtered[0] || "");
|
if(filtered.length && flatten) {
|
||||||
|
$tw.utils.each(filtered,function(value) {
|
||||||
|
results.push(value);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
results.push(filtered[0]||"");
|
||||||
|
}
|
||||||
++index;
|
++index;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ Adds tiddler filtering methods to the $tw.Wiki object.
|
|||||||
/*global $tw: false */
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
/* Maximum permitted filter recursion depth */
|
||||||
|
var MAX_FILTER_DEPTH = 300;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Parses an operation (i.e. a run) within a filter string
|
Parses an operation (i.e. a run) within a filter string
|
||||||
operators: Array of array of operator nodes into which results should be inserted
|
operators: Array of array of operator nodes into which results should be inserted
|
||||||
@@ -220,10 +223,18 @@ source: an iterator function for the source tiddlers, called source(iterator), w
|
|||||||
widget: an optional widget node for retrieving the current tiddler etc.
|
widget: an optional widget node for retrieving the current tiddler etc.
|
||||||
*/
|
*/
|
||||||
exports.compileFilter = function(filterString) {
|
exports.compileFilter = function(filterString) {
|
||||||
|
if(!this.filterCache) {
|
||||||
|
this.filterCache = Object.create(null);
|
||||||
|
this.filterCacheCount = 0;
|
||||||
|
}
|
||||||
|
if(this.filterCache[filterString] !== undefined) {
|
||||||
|
return this.filterCache[filterString];
|
||||||
|
}
|
||||||
var filterParseTree;
|
var filterParseTree;
|
||||||
try {
|
try {
|
||||||
filterParseTree = this.parseFilter(filterString);
|
filterParseTree = this.parseFilter(filterString);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
|
// We do not cache this result, so it adjusts along with localization changes
|
||||||
return function(source,widget) {
|
return function(source,widget) {
|
||||||
return [$tw.language.getString("Error/Filter") + ": " + e];
|
return [$tw.language.getString("Error/Filter") + ": " + e];
|
||||||
};
|
};
|
||||||
@@ -320,7 +331,7 @@ exports.compileFilter = function(filterString) {
|
|||||||
})());
|
})());
|
||||||
});
|
});
|
||||||
// Return a function that applies the operations to a source iterator of tiddler titles
|
// Return a function that applies the operations to a source iterator of tiddler titles
|
||||||
return $tw.perf.measure("filter: " + filterString,function filterFunction(source,widget) {
|
var fnMeasured = $tw.perf.measure("filter: " + filterString,function filterFunction(source,widget) {
|
||||||
if(!source) {
|
if(!source) {
|
||||||
source = self.each;
|
source = self.each;
|
||||||
} else if(typeof source === "object") { // Array or hashmap
|
} else if(typeof source === "object") { // Array or hashmap
|
||||||
@@ -330,11 +341,27 @@ exports.compileFilter = function(filterString) {
|
|||||||
widget = $tw.rootWidget;
|
widget = $tw.rootWidget;
|
||||||
}
|
}
|
||||||
var results = new $tw.utils.LinkedList();
|
var results = new $tw.utils.LinkedList();
|
||||||
$tw.utils.each(operationFunctions,function(operationFunction) {
|
self.filterRecursionCount = (self.filterRecursionCount || 0) + 1;
|
||||||
operationFunction(results,source,widget);
|
if(self.filterRecursionCount < MAX_FILTER_DEPTH) {
|
||||||
});
|
$tw.utils.each(operationFunctions,function(operationFunction) {
|
||||||
|
operationFunction(results,source,widget);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
results.push("/**-- Excessive filter recursion --**/");
|
||||||
|
}
|
||||||
|
self.filterRecursionCount = self.filterRecursionCount - 1;
|
||||||
return results.toArray();
|
return results.toArray();
|
||||||
});
|
});
|
||||||
|
if(this.filterCacheCount >= 2000) {
|
||||||
|
// To prevent memory leak, we maintain an upper limit for cache size.
|
||||||
|
// Reset if exceeded. This should give us 95% of the benefit
|
||||||
|
// that no cache limit would give us.
|
||||||
|
this.filterCache = Object.create(null);
|
||||||
|
this.filterCacheCount = 0;
|
||||||
|
}
|
||||||
|
this.filterCache[filterString] = fnMeasured;
|
||||||
|
this.filterCacheCount++;
|
||||||
|
return fnMeasured;
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -16,6 +16,22 @@ Filter operator for applying decodeURIComponent() to each item.
|
|||||||
Export our filter functions
|
Export our filter functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
exports.decodebase64 = function(source,operator,options) {
|
||||||
|
var results = [];
|
||||||
|
source(function(tiddler,title) {
|
||||||
|
results.push($tw.utils.base64Decode(title));
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.encodebase64 = function(source,operator,options) {
|
||||||
|
var results = [];
|
||||||
|
source(function(tiddler,title) {
|
||||||
|
results.push($tw.utils.base64Encode(title));
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
exports.decodeuricomponent = function(source,operator,options) {
|
exports.decodeuricomponent = function(source,operator,options) {
|
||||||
var results = [];
|
var results = [];
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
@@ -27,7 +43,7 @@ exports.decodeuricomponent = function(source,operator,options) {
|
|||||||
exports.encodeuricomponent = function(source,operator,options) {
|
exports.encodeuricomponent = function(source,operator,options) {
|
||||||
var results = [];
|
var results = [];
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
results.push(encodeURIComponent(title));
|
results.push($tw.utils.encodeURIComponentExtended(title));
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,14 +21,15 @@ exports.filter = function(source,operator,options) {
|
|||||||
target = operator.prefix !== "!";
|
target = operator.prefix !== "!";
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),{
|
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),{
|
||||||
getVariable: function(name) {
|
getVariable: function(name,opts) {
|
||||||
|
opts = opts || {};
|
||||||
switch(name) {
|
switch(name) {
|
||||||
case "currentTiddler":
|
case "currentTiddler":
|
||||||
return "" + title;
|
return "" + title;
|
||||||
case "..currentTiddler":
|
case "..currentTiddler":
|
||||||
return options.widget.getVariable("currentTiddler");
|
return options.widget.getVariable("currentTiddler");
|
||||||
default:
|
default:
|
||||||
return options.widget.getVariable(name);
|
return options.widget.getVariable(name,opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
35
core/modules/filters/format/json.js
Normal file
35
core/modules/filters/format/json.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/filters/format/json.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: formatfilteroperator
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Export our filter function
|
||||||
|
*/
|
||||||
|
exports.json = function(source,operand,options) {
|
||||||
|
var results = [],
|
||||||
|
spaces = null;
|
||||||
|
if(operand) {
|
||||||
|
spaces = /^\d+$/.test(operand) ? parseInt(operand,10) : operand;
|
||||||
|
}
|
||||||
|
source(function(tiddler,title) {
|
||||||
|
var data = $tw.utils.parseJSONSafe(title);
|
||||||
|
try {
|
||||||
|
data = JSON.parse(title);
|
||||||
|
} catch(e) {
|
||||||
|
data = undefined;
|
||||||
|
}
|
||||||
|
if(data !== undefined) {
|
||||||
|
results.push(JSON.stringify(data,null,spaces));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
||||||
46
core/modules/filters/insertafter.js
Normal file
46
core/modules/filters/insertafter.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/filters/insertafter.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: filteroperator
|
||||||
|
|
||||||
|
Insert an item after another item in a list
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Order a list
|
||||||
|
*/
|
||||||
|
exports.insertafter = function(source,operator,options) {
|
||||||
|
var results = [];
|
||||||
|
source(function(tiddler,title) {
|
||||||
|
results.push(title);
|
||||||
|
});
|
||||||
|
var target = operator.operands[1] || (options.widget && options.widget.getVariable(operator.suffix || "currentTiddler"));
|
||||||
|
if(target !== operator.operand) {
|
||||||
|
// Remove the entry from the list if it is present
|
||||||
|
var pos = results.indexOf(operator.operand);
|
||||||
|
if(pos !== -1) {
|
||||||
|
results.splice(pos,1);
|
||||||
|
}
|
||||||
|
// Insert the entry after the target marker
|
||||||
|
pos = results.indexOf(target);
|
||||||
|
if(pos !== -1) {
|
||||||
|
results.splice(pos+1,0,operator.operand);
|
||||||
|
} else {
|
||||||
|
var suffix = operator.operands.length > 1 ? operator.suffix : "";
|
||||||
|
if(suffix === "start") {
|
||||||
|
results.splice(0,0,operator.operand);
|
||||||
|
} else {
|
||||||
|
results.push(operator.operand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
||||||
@@ -32,7 +32,12 @@ exports.insertbefore = function(source,operator,options) {
|
|||||||
if(pos !== -1) {
|
if(pos !== -1) {
|
||||||
results.splice(pos,0,operator.operand);
|
results.splice(pos,0,operator.operand);
|
||||||
} else {
|
} else {
|
||||||
results.push(operator.operand);
|
var suffix = operator.operands.length > 1 ? operator.suffix : "";
|
||||||
|
if(suffix == "start") {
|
||||||
|
results.splice(0,0,operator.operand);
|
||||||
|
} else {
|
||||||
|
results.push(operator.operand);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ exports.variable = function(source,prefix,options) {
|
|||||||
var results = [];
|
var results = [];
|
||||||
if(prefix === "!") {
|
if(prefix === "!") {
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
if(!(title in options.widget.variables)) {
|
if(options.widget.getVariable(title) === undefined) {
|
||||||
results.push(title);
|
results.push(title);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
if(title in options.widget.variables) {
|
if(options.widget.getVariable(title) !== undefined) {
|
||||||
results.push(title);
|
results.push(title);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,38 +12,52 @@ Filter operators for JSON operations
|
|||||||
/*global $tw: false */
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports["getjson"] = function(source,operator,options) {
|
exports["jsonget"] = function(source,operator,options) {
|
||||||
var results = [];
|
var results = [];
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
var data = options.wiki.getTiddlerDataCached(title);
|
var data = $tw.utils.parseJSONSafe(title,title);
|
||||||
if(data) {
|
if(data) {
|
||||||
var item = getDataItemValueAsStrings(data,operator.operands);
|
var items = getDataItemValueAsStrings(data,operator.operands);
|
||||||
if(item !== undefined) {
|
if(items !== undefined) {
|
||||||
results.push.apply(results,item);
|
results.push.apply(results,items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports["indexesjson"] = function(source,operator,options) {
|
exports["jsonextract"] = function(source,operator,options) {
|
||||||
var results = [];
|
var results = [];
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
var data = options.wiki.getTiddlerDataCached(title);
|
var data = $tw.utils.parseJSONSafe(title,title);
|
||||||
if(data) {
|
if(data) {
|
||||||
var item = getDataItemKeysAsStrings(data,operator.operands);
|
var item = getDataItem(data,operator.operands);
|
||||||
if(item !== undefined) {
|
if(item !== undefined) {
|
||||||
results.push.apply(results,item);
|
results.push(JSON.stringify(item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports["typejson"] = function(source,operator,options) {
|
exports["jsonindexes"] = function(source,operator,options) {
|
||||||
var results = [];
|
var results = [];
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
var data = options.wiki.getTiddlerDataCached(title);
|
var data = $tw.utils.parseJSONSafe(title,title);
|
||||||
|
if(data) {
|
||||||
|
var items = getDataItemKeysAsStrings(data,operator.operands);
|
||||||
|
if(items !== undefined) {
|
||||||
|
results.push.apply(results,items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports["jsontype"] = function(source,operator,options) {
|
||||||
|
var results = [];
|
||||||
|
source(function(tiddler,title) {
|
||||||
|
var data = $tw.utils.parseJSONSafe(title,title);
|
||||||
if(data) {
|
if(data) {
|
||||||
var item = getDataItemType(data,operator.operands);
|
var item = getDataItemType(data,operator.operands);
|
||||||
if(item !== undefined) {
|
if(item !== undefined) {
|
||||||
@@ -60,7 +74,7 @@ Given a JSON data structure and an array of index strings, return an array of th
|
|||||||
function getDataItemValueAsStrings(data,indexes) {
|
function getDataItemValueAsStrings(data,indexes) {
|
||||||
// Get the item
|
// Get the item
|
||||||
var item = getDataItem(data,indexes);
|
var item = getDataItem(data,indexes);
|
||||||
// Return the item as a string
|
// Return the item as a string list
|
||||||
return convertDataItemValueToStrings(item);
|
return convertDataItemValueToStrings(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,24 +94,29 @@ Return an array of the string representation of the values of a data item, or "u
|
|||||||
function convertDataItemValueToStrings(item) {
|
function convertDataItemValueToStrings(item) {
|
||||||
// Return the item as a string
|
// Return the item as a string
|
||||||
if(item === undefined) {
|
if(item === undefined) {
|
||||||
return item;
|
return undefined;
|
||||||
}
|
} else if(item === null) {
|
||||||
if(typeof item === "object") {
|
return ["null"]
|
||||||
if(item === null) {
|
} else if(typeof item === "object") {
|
||||||
return ["null"];
|
var results = [],i,t;
|
||||||
}
|
|
||||||
var results = [];
|
|
||||||
if($tw.utils.isArray(item)) {
|
if($tw.utils.isArray(item)) {
|
||||||
$tw.utils.each(item,function(value) {
|
// Return all the items in arrays recursively
|
||||||
results.push.apply(results,convertDataItemValueToStrings(value));
|
for(i=0; i<item.length; i++) {
|
||||||
});
|
t = convertDataItemValueToStrings(item[i])
|
||||||
return results;
|
if(t !== undefined) {
|
||||||
|
results.push.apply(results,t);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Return all the values in objects recursively
|
||||||
$tw.utils.each(Object.keys(item).sort(),function(key) {
|
$tw.utils.each(Object.keys(item).sort(),function(key) {
|
||||||
results.push.apply(results,convertDataItemValueToStrings(item[key]));
|
t = convertDataItemValueToStrings(item[key]);
|
||||||
|
if(t !== undefined) {
|
||||||
|
results.push.apply(results,t);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
return results;
|
||||||
}
|
}
|
||||||
return [item.toString()];
|
return [item.toString()];
|
||||||
}
|
}
|
||||||
@@ -157,7 +176,11 @@ function getDataItem(data,indexes) {
|
|||||||
var item = data;
|
var item = data;
|
||||||
for(var i=0; i<indexes.length; i++) {
|
for(var i=0; i<indexes.length; i++) {
|
||||||
if(item !== undefined) {
|
if(item !== undefined) {
|
||||||
item = item[indexes[i]];
|
if(item !== null && ["number","string","boolean"].indexOf(typeof item) === -1) {
|
||||||
|
item = item[indexes[i]];
|
||||||
|
} else {
|
||||||
|
item = undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ exports.reduce = function(source,operator,options) {
|
|||||||
for(var index=0; index<results.length; index++) {
|
for(var index=0; index<results.length; index++) {
|
||||||
var title = results[index],
|
var title = results[index],
|
||||||
list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),{
|
list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),{
|
||||||
getVariable: function(name) {
|
getVariable: function(name,opts) {
|
||||||
|
opts = opts || {};
|
||||||
switch(name) {
|
switch(name) {
|
||||||
case "currentTiddler":
|
case "currentTiddler":
|
||||||
return "" + title;
|
return "" + title;
|
||||||
@@ -42,7 +43,7 @@ exports.reduce = function(source,operator,options) {
|
|||||||
case "length":
|
case "length":
|
||||||
return "" + results.length;
|
return "" + results.length;
|
||||||
default:
|
default:
|
||||||
return options.widget.getVariable(name);
|
return options.widget.getVariable(name,opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,14 +26,15 @@ exports.sortsub = function(source,operator,options) {
|
|||||||
var r = filterFn.call(options.wiki,function(iterator) {
|
var r = filterFn.call(options.wiki,function(iterator) {
|
||||||
iterator(options.wiki.getTiddler(title),title);
|
iterator(options.wiki.getTiddler(title),title);
|
||||||
},{
|
},{
|
||||||
getVariable: function(name) {
|
getVariable: function(name,opts) {
|
||||||
|
opts = opts || {};
|
||||||
switch(name) {
|
switch(name) {
|
||||||
case "currentTiddler":
|
case "currentTiddler":
|
||||||
return "" + title;
|
return "" + title;
|
||||||
case "..currentTiddler":
|
case "..currentTiddler":
|
||||||
return options.widget.getVariable("currentTiddler");
|
return options.widget.getVariable("currentTiddler");
|
||||||
default:
|
default:
|
||||||
return options.widget.getVariable(name);
|
return options.widget.getVariable(name,opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -74,6 +74,113 @@ exports.join = makeStringReducingOperator(
|
|||||||
},null
|
},null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
|
||||||
|
|
||||||
|
exports.levenshtein = makeStringBinaryOperator(
|
||||||
|
function(a,b) {
|
||||||
|
var dmpObject = new dmp.diff_match_patch(),
|
||||||
|
diffs = dmpObject.diff_main(a,b);
|
||||||
|
return [dmpObject.diff_levenshtein(diffs) + ""];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// these two functions are adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
|
||||||
|
function diffLineWordMode(text1,text2,mode) {
|
||||||
|
var dmpObject = new dmp.diff_match_patch();
|
||||||
|
var a = diffPartsToChars(text1,text2,mode);
|
||||||
|
var lineText1 = a.chars1;
|
||||||
|
var lineText2 = a.chars2;
|
||||||
|
var lineArray = a.lineArray;
|
||||||
|
var diffs = dmpObject.diff_main(lineText1,lineText2,false);
|
||||||
|
dmpObject.diff_charsToLines_(diffs,lineArray);
|
||||||
|
return diffs;
|
||||||
|
}
|
||||||
|
|
||||||
|
function diffPartsToChars(text1,text2,mode) {
|
||||||
|
var lineArray = [];
|
||||||
|
var lineHash = {};
|
||||||
|
lineArray[0] = '';
|
||||||
|
|
||||||
|
function diff_linesToPartsMunge_(text,mode) {
|
||||||
|
var chars = '';
|
||||||
|
var lineStart = 0;
|
||||||
|
var lineEnd = -1;
|
||||||
|
var lineArrayLength = lineArray.length,
|
||||||
|
regexpResult;
|
||||||
|
const searchRegexp = /\W+/g;
|
||||||
|
while(lineEnd < text.length - 1) {
|
||||||
|
if(mode === "words") {
|
||||||
|
regexpResult = searchRegexp.exec(text);
|
||||||
|
lineEnd = searchRegexp.lastIndex;
|
||||||
|
if(regexpResult === null) {
|
||||||
|
lineEnd = text.length;
|
||||||
|
}
|
||||||
|
lineEnd = --lineEnd;
|
||||||
|
} else {
|
||||||
|
lineEnd = text.indexOf('\n', lineStart);
|
||||||
|
if(lineEnd == -1) {
|
||||||
|
lineEnd = text.length - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var line = text.substring(lineStart, lineEnd + 1);
|
||||||
|
|
||||||
|
if(lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : (lineHash[line] !== undefined)) {
|
||||||
|
chars += String.fromCharCode(lineHash[line]);
|
||||||
|
} else {
|
||||||
|
if (lineArrayLength == maxLines) {
|
||||||
|
line = text.substring(lineStart);
|
||||||
|
lineEnd = text.length;
|
||||||
|
}
|
||||||
|
chars += String.fromCharCode(lineArrayLength);
|
||||||
|
lineHash[line] = lineArrayLength;
|
||||||
|
lineArray[lineArrayLength++] = line;
|
||||||
|
}
|
||||||
|
lineStart = lineEnd + 1;
|
||||||
|
}
|
||||||
|
return chars;
|
||||||
|
}
|
||||||
|
var maxLines = 40000;
|
||||||
|
var chars1 = diff_linesToPartsMunge_(text1,mode);
|
||||||
|
maxLines = 65535;
|
||||||
|
var chars2 = diff_linesToPartsMunge_(text2,mode);
|
||||||
|
return {chars1: chars1, chars2: chars2, lineArray: lineArray};
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.makepatches = function(source,operator,options) {
|
||||||
|
var dmpObject = new dmp.diff_match_patch(),
|
||||||
|
suffix = operator.suffix || "",
|
||||||
|
result = [];
|
||||||
|
|
||||||
|
source(function(tiddler,title) {
|
||||||
|
var diffs, patches;
|
||||||
|
if(suffix === "lines" || suffix === "words") {
|
||||||
|
diffs = diffLineWordMode(title,operator.operand,suffix);
|
||||||
|
patches = dmpObject.patch_make(title,diffs);
|
||||||
|
} else {
|
||||||
|
patches = dmpObject.patch_make(title,operator.operand);
|
||||||
|
}
|
||||||
|
Array.prototype.push.apply(result,[dmpObject.patch_toText(patches)]);
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.applypatches = makeStringBinaryOperator(
|
||||||
|
function(a,b) {
|
||||||
|
var dmpObject = new dmp.diff_match_patch(),
|
||||||
|
patches;
|
||||||
|
try {
|
||||||
|
patches = dmpObject.patch_fromText(b);
|
||||||
|
} catch(e) {
|
||||||
|
}
|
||||||
|
if(patches) {
|
||||||
|
return [dmpObject.patch_apply(patches,a)[0]];
|
||||||
|
} else {
|
||||||
|
return [a];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
function makeStringBinaryOperator(fnCalc) {
|
function makeStringBinaryOperator(fnCalc) {
|
||||||
return function(source,operator,options) {
|
return function(source,operator,options) {
|
||||||
var result = [];
|
var result = [];
|
||||||
@@ -184,4 +291,4 @@ exports.charcode = function(source,operator,options) {
|
|||||||
return [chars.join("")];
|
return [chars.join("")];
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
@@ -16,9 +16,15 @@ Filter operator for returning the names of the active variables
|
|||||||
Export our filter function
|
Export our filter function
|
||||||
*/
|
*/
|
||||||
exports.variables = function(source,operator,options) {
|
exports.variables = function(source,operator,options) {
|
||||||
var names = [];
|
var names = [],
|
||||||
for(var variable in options.widget.variables) {
|
widget = options.widget;
|
||||||
names.push(variable);
|
while(widget && !widget.hasOwnProperty("variables")) {
|
||||||
|
widget = widget.parentWidget;
|
||||||
|
}
|
||||||
|
if(widget && widget.variables) {
|
||||||
|
for(var variable in widget.variables) {
|
||||||
|
names.push(variable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return names.sort();
|
return names.sort();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ function KeyboardManager(options) {
|
|||||||
this.shortcutKeysList = [], // Stores the shortcut-key descriptors
|
this.shortcutKeysList = [], // Stores the shortcut-key descriptors
|
||||||
this.shortcutActionList = [], // Stores the corresponding action strings
|
this.shortcutActionList = [], // Stores the corresponding action strings
|
||||||
this.shortcutParsedList = []; // Stores the parsed key descriptors
|
this.shortcutParsedList = []; // Stores the parsed key descriptors
|
||||||
|
this.shortcutPriorityList = []; // Stores the parsed shortcut priority
|
||||||
this.lookupNames = ["shortcuts"];
|
this.lookupNames = ["shortcuts"];
|
||||||
this.lookupNames.push($tw.platform.isMac ? "shortcuts-mac" : "shortcuts-not-mac")
|
this.lookupNames.push($tw.platform.isMac ? "shortcuts-mac" : "shortcuts-not-mac")
|
||||||
this.lookupNames.push($tw.platform.isWindows ? "shortcuts-windows" : "shortcuts-not-windows");
|
this.lookupNames.push($tw.platform.isWindows ? "shortcuts-windows" : "shortcuts-not-windows");
|
||||||
@@ -318,12 +319,23 @@ KeyboardManager.prototype.updateShortcutLists = function(tiddlerList) {
|
|||||||
this.shortcutKeysList[i] = tiddlerFields.key !== undefined ? tiddlerFields.key : undefined;
|
this.shortcutKeysList[i] = tiddlerFields.key !== undefined ? tiddlerFields.key : undefined;
|
||||||
this.shortcutActionList[i] = tiddlerFields.text;
|
this.shortcutActionList[i] = tiddlerFields.text;
|
||||||
this.shortcutParsedList[i] = this.shortcutKeysList[i] !== undefined ? this.parseKeyDescriptors(this.shortcutKeysList[i]) : undefined;
|
this.shortcutParsedList[i] = this.shortcutKeysList[i] !== undefined ? this.parseKeyDescriptors(this.shortcutKeysList[i]) : undefined;
|
||||||
|
this.shortcutPriorityList[i] = tiddlerFields.priority === "yes" ? true : false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
KeyboardManager.prototype.handleKeydownEvent = function(event) {
|
/*
|
||||||
|
event: the keyboard event object
|
||||||
|
options:
|
||||||
|
onlyPriority: true if only priority global shortcuts should be invoked
|
||||||
|
*/
|
||||||
|
KeyboardManager.prototype.handleKeydownEvent = function(event, options) {
|
||||||
|
options = options || {};
|
||||||
var key, action;
|
var key, action;
|
||||||
for(var i=0; i<this.shortcutTiddlers.length; i++) {
|
for(var i=0; i<this.shortcutTiddlers.length; i++) {
|
||||||
|
if(options.onlyPriority && this.shortcutPriorityList[i] !== true) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(this.shortcutParsedList[i] !== undefined && this.checkKeyDescriptors(event,this.shortcutParsedList[i])) {
|
if(this.shortcutParsedList[i] !== undefined && this.checkKeyDescriptors(event,this.shortcutParsedList[i])) {
|
||||||
key = this.shortcutParsedList[i];
|
key = this.shortcutParsedList[i];
|
||||||
action = this.shortcutActionList[i];
|
action = this.shortcutActionList[i];
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ The CSV text parser processes CSV files into a table wrapped in a scrollable wid
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var CsvParser = function(type,text,options) {
|
var CsvParser = function(type,text,options) {
|
||||||
|
// Special handler for tab-delimited files
|
||||||
|
if (type === 'text/tab-delimited-values' && !options.separator) {
|
||||||
|
options.separator = "\t";
|
||||||
|
}
|
||||||
|
|
||||||
// Table framework
|
// Table framework
|
||||||
this.tree = [{
|
this.tree = [{
|
||||||
"type": "scrollable", "children": [{
|
"type": "scrollable", "children": [{
|
||||||
@@ -24,30 +29,33 @@ var CsvParser = function(type,text,options) {
|
|||||||
}]
|
}]
|
||||||
}];
|
}];
|
||||||
// Split the text into lines
|
// Split the text into lines
|
||||||
var lines = text.split(/\r?\n/mg),
|
var lines = $tw.utils.parseCsvString(text, options),
|
||||||
tag = "th";
|
tag = "th";
|
||||||
|
var maxColumns = 0;
|
||||||
|
$tw.utils.each(lines, function(columns) {
|
||||||
|
maxColumns = Math.max(columns.length, maxColumns);
|
||||||
|
});
|
||||||
|
|
||||||
for(var line=0; line<lines.length; line++) {
|
for(var line=0; line<lines.length; line++) {
|
||||||
var lineText = lines[line];
|
var columns = lines[line];
|
||||||
if(lineText) {
|
var row = {
|
||||||
var row = {
|
"type": "element", "tag": "tr", "children": []
|
||||||
"type": "element", "tag": "tr", "children": []
|
};
|
||||||
};
|
for(var column=0; column<maxColumns; column++) {
|
||||||
var columns = lineText.split(",");
|
row.children.push({
|
||||||
for(var column=0; column<columns.length; column++) {
|
"type": "element", "tag": tag, "children": [{
|
||||||
row.children.push({
|
"type": "text",
|
||||||
"type": "element", "tag": tag, "children": [{
|
"text": columns[column] || ''
|
||||||
"type": "text",
|
}]
|
||||||
"text": columns[column]
|
});
|
||||||
}]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
tag = "td";
|
|
||||||
this.tree[0].children[0].children[0].children.push(row);
|
|
||||||
}
|
}
|
||||||
|
tag = "td";
|
||||||
|
this.tree[0].children[0].children[0].children.push(row);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports["text/csv"] = CsvParser;
|
exports["text/csv"] = CsvParser;
|
||||||
|
exports["text/tab-delimited-values"] = CsvParser;
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ The PDF parser embeds a PDF viewer
|
|||||||
var ImageParser = function(type,text,options) {
|
var ImageParser = function(type,text,options) {
|
||||||
var element = {
|
var element = {
|
||||||
type: "element",
|
type: "element",
|
||||||
tag: "embed",
|
tag: "iframe",
|
||||||
attributes: {}
|
attributes: {}
|
||||||
},
|
},
|
||||||
src;
|
src;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ Instantiate parse rule
|
|||||||
exports.init = function(parser) {
|
exports.init = function(parser) {
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
// Regexp to match
|
// Regexp to match
|
||||||
this.matchRegExp = /^\\import[^\S\n]/mg;
|
this.matchRegExp = /\\import[^\S\n]/mg;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ Instantiate parse rule
|
|||||||
exports.init = function(parser) {
|
exports.init = function(parser) {
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
// Regexp to match
|
// Regexp to match
|
||||||
this.matchRegExp = /^\\define\s+([^(\s]+)\(\s*([^)]*)\)(\s*\r?\n)?/mg;
|
this.matchRegExp = /\\define\s+([^(\s]+)\(\s*([^)]*)\)(\s*\r?\n)?/mg;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -58,7 +58,7 @@ exports.parse = function() {
|
|||||||
var reEnd;
|
var reEnd;
|
||||||
if(this.match[3]) {
|
if(this.match[3]) {
|
||||||
// If so, the end of the body is marked with \end
|
// If so, the end of the body is marked with \end
|
||||||
reEnd = /(\r?\n\\end[^\S\n\r]*(?:$|\r?\n))/mg;
|
reEnd = new RegExp("(\\r?\\n\\s*\\\\end[^\\S\\n\\r]*(?:" + $tw.utils.escapeRegExp(this.match[1]) + ")?(?:$|\\r?\\n))","mg");
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, the end of the definition is marked by the end of the line
|
// Otherwise, the end of the definition is marked by the end of the line
|
||||||
reEnd = /($|\r?\n)/mg;
|
reEnd = /($|\r?\n)/mg;
|
||||||
|
|||||||
68
core/modules/parsers/wikiparser/rules/parsermode.js
Normal file
68
core/modules/parsers/wikiparser/rules/parsermode.js
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/parsers/wikiparser/rules/parsermode.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: wikirule
|
||||||
|
|
||||||
|
Wiki pragma rule for parser mode specifications
|
||||||
|
|
||||||
|
```
|
||||||
|
\parsermode block
|
||||||
|
\parsermode inline
|
||||||
|
```
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
exports.name = "parsermode";
|
||||||
|
exports.types = {pragma: true};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Instantiate parse rule
|
||||||
|
*/
|
||||||
|
exports.init = function(parser) {
|
||||||
|
this.parser = parser;
|
||||||
|
// Regexp to match
|
||||||
|
this.matchRegExp = /\\parsermode[^\S\n]/mg;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Parse the most recent match
|
||||||
|
*/
|
||||||
|
exports.parse = function() {
|
||||||
|
// Move past the pragma invocation
|
||||||
|
this.parser.pos = this.matchRegExp.lastIndex;
|
||||||
|
// Parse whitespace delimited tokens terminated by a line break
|
||||||
|
var reMatch = /[^\S\n]*(\S+)|(\r?\n)/mg,
|
||||||
|
parserMode = undefined;
|
||||||
|
reMatch.lastIndex = this.parser.pos;
|
||||||
|
var match = reMatch.exec(this.parser.source);
|
||||||
|
while(match && match.index === this.parser.pos) {
|
||||||
|
this.parser.pos = reMatch.lastIndex;
|
||||||
|
// Exit if we've got the line break
|
||||||
|
if(match[2]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Process the token
|
||||||
|
if(match[1]) {
|
||||||
|
parserMode = match[1];
|
||||||
|
}
|
||||||
|
// Match the next token
|
||||||
|
match = reMatch.exec(this.parser.source);
|
||||||
|
}
|
||||||
|
// Process the tokens
|
||||||
|
if(parserMode !== undefined) {
|
||||||
|
if(parserMode === "block") {
|
||||||
|
this.parser.parseAsInline = false;
|
||||||
|
} else if(parserMode === "inline") {
|
||||||
|
this.parser.parseAsInline = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No parse tree nodes to return
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
||||||
@@ -26,7 +26,7 @@ Instantiate parse rule
|
|||||||
exports.init = function(parser) {
|
exports.init = function(parser) {
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
// Regexp to match
|
// Regexp to match
|
||||||
this.matchRegExp = /^\\rules[^\S\n]/mg;
|
this.matchRegExp = /\\rules[^\S\n]/mg;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -41,9 +41,6 @@ exports.parse = function() {
|
|||||||
var node = {
|
var node = {
|
||||||
type: "element",
|
type: "element",
|
||||||
tag: "span",
|
tag: "span",
|
||||||
attributes: {
|
|
||||||
"class": {type: "string", value: "tc-inline-style"}
|
|
||||||
},
|
|
||||||
children: tree
|
children: tree
|
||||||
};
|
};
|
||||||
if(classString) {
|
if(classString) {
|
||||||
@@ -52,6 +49,9 @@ exports.parse = function() {
|
|||||||
if(stylesString) {
|
if(stylesString) {
|
||||||
$tw.utils.addAttributeToParseTreeNode(node,"style",stylesString);
|
$tw.utils.addAttributeToParseTreeNode(node,"style",stylesString);
|
||||||
}
|
}
|
||||||
|
if(!classString && !stylesString) {
|
||||||
|
$tw.utils.addClassToParseTreeNode(node,"tc-inline-style");
|
||||||
|
}
|
||||||
return [node];
|
return [node];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ Instantiate parse rule
|
|||||||
exports.init = function(parser) {
|
exports.init = function(parser) {
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
// Regexp to match
|
// Regexp to match
|
||||||
this.matchRegExp = /^\\whitespace[^\S\n]/mg;
|
this.matchRegExp = /\\whitespace[^\S\n]/mg;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ var WikiParser = function(type,text,options) {
|
|||||||
this.sourceLength = this.source.length;
|
this.sourceLength = this.source.length;
|
||||||
// Flag for ignoring whitespace
|
// Flag for ignoring whitespace
|
||||||
this.configTrimWhiteSpace = false;
|
this.configTrimWhiteSpace = false;
|
||||||
|
// Parser mode
|
||||||
|
this.parseAsInline = options.parseAsInline;
|
||||||
// Set current parse position
|
// Set current parse position
|
||||||
this.pos = 0;
|
this.pos = 0;
|
||||||
// Start with empty output
|
// Start with empty output
|
||||||
@@ -83,7 +85,7 @@ var WikiParser = function(type,text,options) {
|
|||||||
// Parse any pragmas
|
// Parse any pragmas
|
||||||
var topBranch = this.parsePragmas();
|
var topBranch = this.parsePragmas();
|
||||||
// Parse the text into inline runs or blocks
|
// Parse the text into inline runs or blocks
|
||||||
if(options.parseAsInline) {
|
if(this.parseAsInline) {
|
||||||
topBranch.push.apply(topBranch,this.parseInlineRun());
|
topBranch.push.apply(topBranch,this.parseInlineRun());
|
||||||
} else {
|
} else {
|
||||||
topBranch.push.apply(topBranch,this.parseBlocks());
|
topBranch.push.apply(topBranch,this.parseBlocks());
|
||||||
@@ -116,7 +118,7 @@ WikiParser.prototype.loadRemoteTiddler = function(url) {
|
|||||||
*/
|
*/
|
||||||
WikiParser.prototype.setupRules = function(proto,configPrefix) {
|
WikiParser.prototype.setupRules = function(proto,configPrefix) {
|
||||||
var self = this;
|
var self = this;
|
||||||
if(!$tw.safemode) {
|
if(!$tw.safeMode) {
|
||||||
$tw.utils.each(proto,function(object,name) {
|
$tw.utils.each(proto,function(object,name) {
|
||||||
if(self.wiki.getTiddlerText(configPrefix + name,"enable") !== "enable") {
|
if(self.wiki.getTiddlerText(configPrefix + name,"enable") !== "enable") {
|
||||||
delete proto[name];
|
delete proto[name];
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
/*\
|
|
||||||
title: $:/core/modules/savers/beaker.js
|
|
||||||
type: application/javascript
|
|
||||||
module-type: saver
|
|
||||||
|
|
||||||
Saves files using the Beaker browser's (https://beakerbrowser.com) Dat protocol (https://datproject.org/)
|
|
||||||
Compatible with beaker >= V0.7.2
|
|
||||||
|
|
||||||
\*/
|
|
||||||
(function(){
|
|
||||||
|
|
||||||
/*jslint node: true, browser: true */
|
|
||||||
/*global $tw: false */
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/*
|
|
||||||
Set up the saver
|
|
||||||
*/
|
|
||||||
var BeakerSaver = function(wiki) {
|
|
||||||
this.wiki = wiki;
|
|
||||||
};
|
|
||||||
|
|
||||||
BeakerSaver.prototype.save = function(text,method,callback) {
|
|
||||||
var dat = new DatArchive("" + 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("Beaker Saver Write Error: " + reason);
|
|
||||||
});
|
|
||||||
},function(reason) {
|
|
||||||
callback("Beaker Saver Stat Error: " + reason);
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Information about this saver
|
|
||||||
*/
|
|
||||||
BeakerSaver.prototype.info = {
|
|
||||||
name: "beaker",
|
|
||||||
priority: 3000,
|
|
||||||
capabilities: ["save", "autosave"]
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Static method that returns true if this saver is capable of working
|
|
||||||
*/
|
|
||||||
exports.canSave = function(wiki) {
|
|
||||||
return !!window.DatArchive && location.protocol==="dat:";
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Create an instance of this saver
|
|
||||||
*/
|
|
||||||
exports.create = function(wiki) {
|
|
||||||
return new BeakerSaver(wiki);
|
|
||||||
};
|
|
||||||
|
|
||||||
})();
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
/*\
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
})();
|
|
||||||
@@ -80,6 +80,7 @@ PutSaver.prototype.save = function(text,method,callback) {
|
|||||||
if(this.etag) {
|
if(this.etag) {
|
||||||
headers["If-Match"] = this.etag;
|
headers["If-Match"] = this.etag;
|
||||||
}
|
}
|
||||||
|
$tw.notifier.display("$:/language/Notifications/Save/Starting");
|
||||||
$tw.utils.httpRequest({
|
$tw.utils.httpRequest({
|
||||||
url: this.uri(),
|
url: this.uri(),
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
@@ -87,17 +88,20 @@ PutSaver.prototype.save = function(text,method,callback) {
|
|||||||
data: text,
|
data: text,
|
||||||
callback: function(err,data,xhr) {
|
callback: function(err,data,xhr) {
|
||||||
if(err) {
|
if(err) {
|
||||||
// response is textual: "XMLHttpRequest error code: 412"
|
var status = xhr.status,
|
||||||
var status = Number(err.substring(err.indexOf(':') + 2, err.length))
|
errorMsg = err;
|
||||||
if(status === 412) { // file changed on server
|
if(status === 412) { // file changed on server
|
||||||
callback($tw.language.getString("Error/PutEditConflict"));
|
errorMsg = $tw.language.getString("Error/PutEditConflict");
|
||||||
} else if(status === 401) { // authentication required
|
} else if(status === 401) { // authentication required
|
||||||
callback($tw.language.getString("Error/PutUnauthorized"));
|
errorMsg = $tw.language.getString("Error/PutUnauthorized");
|
||||||
} else if(status === 403) { // permission denied
|
} else if(status === 403) { // permission denied
|
||||||
callback($tw.language.getString("Error/PutForbidden"));
|
errorMsg = $tw.language.getString("Error/PutForbidden");
|
||||||
} else {
|
|
||||||
callback(err); // fail
|
|
||||||
}
|
}
|
||||||
|
if (xhr.responseText) {
|
||||||
|
// treat any server response like a plain text error explanation
|
||||||
|
errorMsg = errorMsg + "\n\n" + xhr.responseText;
|
||||||
|
}
|
||||||
|
callback(errorMsg); // fail
|
||||||
} else {
|
} else {
|
||||||
self.etag = xhr.getResponseHeader("ETag");
|
self.etag = xhr.getResponseHeader("ETag");
|
||||||
if(self.etag == null) {
|
if(self.etag == null) {
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ UploadSaver.prototype.save = function(text,method,callback) {
|
|||||||
var tail = "\r\n--" + boundary + "--\r\n",
|
var tail = "\r\n--" + boundary + "--\r\n",
|
||||||
data = head.join("\r\n") + text + tail;
|
data = head.join("\r\n") + text + tail;
|
||||||
// Do the HTTP post
|
// Do the HTTP post
|
||||||
|
$tw.notifier.display("$:/language/Notifications/Save/Starting");
|
||||||
var http = new XMLHttpRequest();
|
var http = new XMLHttpRequest();
|
||||||
http.open("POST",url,true,username,password);
|
http.open("POST",url,true,username,password);
|
||||||
http.setRequestHeader("Content-Type","multipart/form-data; charset=UTF-8; boundary=" + boundary);
|
http.setRequestHeader("Content-Type","multipart/form-data; charset=UTF-8; boundary=" + boundary);
|
||||||
@@ -81,7 +82,6 @@ UploadSaver.prototype.save = function(text,method,callback) {
|
|||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
return callback($tw.language.getString("Error/Caption") + ":" + ex);
|
return callback($tw.language.getString("Error/Caption") + ":" + ex);
|
||||||
}
|
}
|
||||||
$tw.notifier.display("$:/language/Notifications/Save/Starting");
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ exports.handler = function(request,response,state) {
|
|||||||
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
||||||
anonymous: !state.authenticatedUsername,
|
anonymous: !state.authenticatedUsername,
|
||||||
read_only: !state.server.isAuthorized("writers",state.authenticatedUsername),
|
read_only: !state.server.isAuthorized("writers",state.authenticatedUsername),
|
||||||
|
logout_is_available: false,
|
||||||
space: {
|
space: {
|
||||||
recipe: "default"
|
recipe: "default"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -30,6 +30,16 @@ exports.handler = function(request,response,state) {
|
|||||||
if(fields.revision) {
|
if(fields.revision) {
|
||||||
delete fields.revision;
|
delete fields.revision;
|
||||||
}
|
}
|
||||||
|
// If this is a skinny tiddler, it means the client never got the full
|
||||||
|
// version of the tiddler to edit. So we must preserve whatever text
|
||||||
|
// already exists on the server, or else we'll inadvertently delete it.
|
||||||
|
if(fields._is_skinny !== undefined) {
|
||||||
|
var tiddler = state.wiki.getTiddler(title);
|
||||||
|
if(tiddler) {
|
||||||
|
fields.text = tiddler.fields.text;
|
||||||
|
}
|
||||||
|
delete fields._is_skinny;
|
||||||
|
}
|
||||||
state.wiki.addTiddler(new $tw.Tiddler(fields,{title: title}));
|
state.wiki.addTiddler(new $tw.Tiddler(fields,{title: title}));
|
||||||
var changeCount = state.wiki.getChangeCount(title).toString();
|
var changeCount = state.wiki.getChangeCount(title).toString();
|
||||||
response.writeHead(204, "OK",{
|
response.writeHead(204, "OK",{
|
||||||
|
|||||||
@@ -359,8 +359,9 @@ Server.prototype.listen = function(port,host,prefix) {
|
|||||||
}
|
}
|
||||||
// Display the port number after we've started listening (the port number might have been specified as zero, in which case we will get an assigned port)
|
// Display the port number after we've started listening (the port number might have been specified as zero, in which case we will get an assigned port)
|
||||||
server.on("listening",function() {
|
server.on("listening",function() {
|
||||||
var address = server.address();
|
var address = server.address(),
|
||||||
$tw.utils.log("Serving on " + self.protocol + "://" + address.address + ":" + address.port + prefix,"brown/orange");
|
url = self.protocol + "://" + (address.family === "IPv6" ? "[" + address.address + "]" : address.address) + ":" + address.port + prefix;
|
||||||
|
$tw.utils.log("Serving on " + url,"brown/orange");
|
||||||
$tw.utils.log("(press ctrl-C to exit)","red");
|
$tw.utils.log("(press ctrl-C to exit)","red");
|
||||||
});
|
});
|
||||||
// Listen
|
// Listen
|
||||||
|
|||||||
@@ -62,12 +62,14 @@ function loadIFrame(url,callback) {
|
|||||||
Unload library iframe for given url
|
Unload library iframe for given url
|
||||||
*/
|
*/
|
||||||
function unloadIFrame(url){
|
function unloadIFrame(url){
|
||||||
$tw.utils.each(document.getElementsByTagName('iframe'), function(iframe) {
|
var iframes = document.getElementsByTagName('iframe');
|
||||||
|
for(var t=iframes.length-1; t--; t>=0) {
|
||||||
|
var iframe = iframes[t];
|
||||||
if(iframe.getAttribute("library") === "true" &&
|
if(iframe.getAttribute("library") === "true" &&
|
||||||
iframe.getAttribute("src") === url) {
|
iframe.getAttribute("src") === url) {
|
||||||
iframe.parentNode.removeChild(iframe);
|
iframe.parentNode.removeChild(iframe);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveIFrameInfoTiddler(iframeInfo) {
|
function saveIFrameInfoTiddler(iframeInfo) {
|
||||||
|
|||||||
@@ -121,7 +121,11 @@ exports.startup = function() {
|
|||||||
});
|
});
|
||||||
// Set up the syncer object if we've got a syncadaptor
|
// Set up the syncer object if we've got a syncadaptor
|
||||||
if($tw.syncadaptor) {
|
if($tw.syncadaptor) {
|
||||||
$tw.syncer = new $tw.Syncer({wiki: $tw.wiki, syncadaptor: $tw.syncadaptor});
|
$tw.syncer = new $tw.Syncer({
|
||||||
|
wiki: $tw.wiki,
|
||||||
|
syncadaptor: $tw.syncadaptor,
|
||||||
|
logging: $tw.wiki.getTiddlerText('$:/config/SyncLogging', "yes") === "yes"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// Setup the saver handler
|
// Setup the saver handler
|
||||||
$tw.saverHandler = new $tw.SaverHandler({
|
$tw.saverHandler = new $tw.SaverHandler({
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ exports.startup = function() {
|
|||||||
var hash = $tw.utils.getLocationHash();
|
var hash = $tw.utils.getLocationHash();
|
||||||
if(hash !== $tw.locationHash) {
|
if(hash !== $tw.locationHash) {
|
||||||
$tw.locationHash = hash;
|
$tw.locationHash = hash;
|
||||||
openStartupTiddlers({defaultToCurrentStory: true});
|
if(hash !== "#") {
|
||||||
|
openStartupTiddlers({defaultToCurrentStory: true});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},false);
|
},false);
|
||||||
// Listen for the tm-browser-refresh message
|
// Listen for the tm-browser-refresh message
|
||||||
|
|||||||
@@ -402,6 +402,7 @@ Syncer.prototype.handleLazyLoadEvent = function(title) {
|
|||||||
// Mark the tiddler as needing loading, and having already been lazily loaded
|
// Mark the tiddler as needing loading, and having already been lazily loaded
|
||||||
this.titlesToBeLoaded[title] = true;
|
this.titlesToBeLoaded[title] = true;
|
||||||
this.titlesHaveBeenLazyLoaded[title] = true;
|
this.titlesHaveBeenLazyLoaded[title] = true;
|
||||||
|
this.processTaskQueue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,35 +12,113 @@ A barebones CSV parser
|
|||||||
/*global $tw: false */
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var QUOTE = '"';
|
||||||
|
|
||||||
|
var getCellInfo = function(text, start, length, SEPARATOR) {
|
||||||
|
var isCellQuoted = text.charAt(start) === QUOTE;
|
||||||
|
var cellStart = isCellQuoted ? start + 1 : start;
|
||||||
|
|
||||||
|
if (text.charAt(i) === SEPARATOR) {
|
||||||
|
return [cellStart, cellStart, false];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = cellStart; i < length; i++) {
|
||||||
|
var cellCharacter = text.charAt(i);
|
||||||
|
var isEOL = cellCharacter === "\n" || cellCharacter === "\r";
|
||||||
|
|
||||||
|
if (isEOL && !isCellQuoted) {
|
||||||
|
return [cellStart, i, false];
|
||||||
|
|
||||||
|
} else if (cellCharacter === SEPARATOR && !isCellQuoted) {
|
||||||
|
return [cellStart, i, false];
|
||||||
|
|
||||||
|
} else if (cellCharacter === QUOTE && isCellQuoted) {
|
||||||
|
var nextCharacter = i + 1 < length ? text.charAt(i + 1) : '';
|
||||||
|
if (nextCharacter !== QUOTE) {
|
||||||
|
return [cellStart, i, true];
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [cellStart, i, isCellQuoted];
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.parseCsvString = function(text, options) {
|
||||||
|
if (!text) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
var SEPARATOR = options.separator || ",",
|
||||||
|
length = text.length,
|
||||||
|
rows = [],
|
||||||
|
nextRow = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < length; i++) {
|
||||||
|
var cellInfo = getCellInfo(text, i, length, SEPARATOR);
|
||||||
|
var cellText = text.substring(cellInfo[0], cellInfo[1]);
|
||||||
|
if (cellInfo[2]) {
|
||||||
|
cellText = cellText.replace(/""/g, '"');
|
||||||
|
cellInfo[1]++;
|
||||||
|
}
|
||||||
|
nextRow.push(cellText);
|
||||||
|
|
||||||
|
i = cellInfo[1];
|
||||||
|
|
||||||
|
var character = text.charAt(i);
|
||||||
|
var nextCharacter = i + 1 < length ? text.charAt(i + 1) : '';
|
||||||
|
|
||||||
|
if (character === "\r" || character === "\n") {
|
||||||
|
// Edge case for empty rows
|
||||||
|
if (nextRow.length === 1 && nextRow[0] === '') {
|
||||||
|
nextRow.length = 0;
|
||||||
|
}
|
||||||
|
rows.push(nextRow);
|
||||||
|
nextRow = [];
|
||||||
|
|
||||||
|
if (character === "\r") {
|
||||||
|
var nextCharacter = i + 1 < length ? text.charAt(i + 1) : '';
|
||||||
|
|
||||||
|
if (nextCharacter === "\n") {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case if last cell in last row is an empty cell
|
||||||
|
if (text.charAt(length - 1) === SEPARATOR) {
|
||||||
|
nextRow.push("");
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.push(nextRow);
|
||||||
|
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Parse a CSV string with a header row and return an array of hashmaps.
|
Parse a CSV string with a header row and return an array of hashmaps.
|
||||||
*/
|
*/
|
||||||
exports.parseCsvStringWithHeader = function(text,options) {
|
exports.parseCsvStringWithHeader = function(text,options) {
|
||||||
options = options || {};
|
var csv = $tw.utils.parseCsvString(text, options);
|
||||||
var separator = options.separator || ",",
|
var headers = csv[0];
|
||||||
rows = text.split(/\r?\n/mg).map(function(row) {
|
|
||||||
return $tw.utils.trim(row);
|
csv = csv.slice(1);
|
||||||
}).filter(function(row) {
|
for (var i = 0; i < csv.length; i++) {
|
||||||
return row !== "";
|
var row = csv[i];
|
||||||
});
|
var rowObject = Object.create(null);
|
||||||
if(rows.length < 1) {
|
|
||||||
return "Missing header row";
|
for(var columnIndex=0; columnIndex<headers.length; columnIndex++) {
|
||||||
}
|
var columnName = headers[columnIndex];
|
||||||
var headings = rows[0].split(separator),
|
if (columnName) {
|
||||||
results = [];
|
rowObject[columnName] = $tw.utils.trim(row[columnIndex] || "");
|
||||||
for(var row=1; row<rows.length; row++) {
|
}
|
||||||
var columns = rows[row].split(separator),
|
|
||||||
columnResult = Object.create(null);
|
|
||||||
if(columns.length !== headings.length) {
|
|
||||||
return "Malformed CSV row '" + rows[row] + "'";
|
|
||||||
}
|
}
|
||||||
for(var column=0; column<columns.length; column++) {
|
csv[i] = rowObject;
|
||||||
var columnName = headings[column];
|
|
||||||
columnResult[columnName] = $tw.utils.trim(columns[column] || "");
|
|
||||||
}
|
|
||||||
results.push(columnResult);
|
|
||||||
}
|
}
|
||||||
return results;
|
return csv;
|
||||||
}
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ Various static DOM-related utility functions.
|
|||||||
/*global $tw: false */
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var Popup = require("$:/core/modules/utils/dom/popup.js");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Determines whether element 'a' contains element 'b'
|
Determines whether element 'a' contains element 'b'
|
||||||
Code thanks to John Resig, http://ejohn.org/blog/comparing-document-position/
|
Code thanks to John Resig, http://ejohn.org/blog/comparing-document-position/
|
||||||
@@ -281,5 +283,69 @@ exports.getLocationPath = function() {
|
|||||||
return window.location.toString().split("#")[0];
|
return window.location.toString().split("#")[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Collect DOM variables
|
||||||
|
*/
|
||||||
|
exports.collectDOMVariables = function(selectedNode,domNode,event) {
|
||||||
|
var variables = {},
|
||||||
|
selectedNodeRect,
|
||||||
|
domNodeRect;
|
||||||
|
if(selectedNode) {
|
||||||
|
$tw.utils.each(selectedNode.attributes,function(attribute) {
|
||||||
|
variables["dom-" + attribute.name] = attribute.value.toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
if(selectedNode.offsetLeft) {
|
||||||
|
// Add variables with a (relative and absolute) popup coordinate string for the selected node
|
||||||
|
var nodeRect = {
|
||||||
|
left: selectedNode.offsetLeft,
|
||||||
|
top: selectedNode.offsetTop,
|
||||||
|
width: selectedNode.offsetWidth,
|
||||||
|
height: selectedNode.offsetHeight
|
||||||
|
};
|
||||||
|
variables["tv-popup-coords"] = Popup.buildCoordinates(Popup.coordinatePrefix.csOffsetParent,nodeRect);
|
||||||
|
|
||||||
|
var absRect = $tw.utils.extend({}, nodeRect);
|
||||||
|
for (var currentNode = selectedNode.offsetParent; currentNode; currentNode = currentNode.offsetParent) {
|
||||||
|
absRect.left += currentNode.offsetLeft;
|
||||||
|
absRect.top += currentNode.offsetTop;
|
||||||
|
}
|
||||||
|
variables["tv-popup-abs-coords"] = Popup.buildCoordinates(Popup.coordinatePrefix.csAbsolute,absRect);
|
||||||
|
|
||||||
|
// Add variables for offset of selected node
|
||||||
|
variables["tv-selectednode-posx"] = selectedNode.offsetLeft.toString();
|
||||||
|
variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString();
|
||||||
|
variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString();
|
||||||
|
variables["tv-selectednode-height"] = selectedNode.offsetHeight.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(domNode && domNode.offsetWidth) {
|
||||||
|
variables["tv-widgetnode-width"] = domNode.offsetWidth.toString();
|
||||||
|
variables["tv-widgetnode-height"] = domNode.offsetHeight.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(event && event.clientX && event.clientY) {
|
||||||
|
if(selectedNode) {
|
||||||
|
// Add variables for event X and Y position relative to selected node
|
||||||
|
selectedNodeRect = selectedNode.getBoundingClientRect();
|
||||||
|
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
|
||||||
|
variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(domNode) {
|
||||||
|
// Add variables for event X and Y position relative to event catcher node
|
||||||
|
domNodeRect = domNode.getBoundingClientRect();
|
||||||
|
variables["event-fromcatcher-posx"] = (event.clientX - domNodeRect.left).toString();
|
||||||
|
variables["event-fromcatcher-posy"] = (event.clientY - domNodeRect.top).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add variables for event X and Y position relative to the viewport
|
||||||
|
variables["event-fromviewport-posx"] = event.clientX.toString();
|
||||||
|
variables["event-fromviewport-posy"] = event.clientY.toString();
|
||||||
|
}
|
||||||
|
return variables;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -25,14 +25,13 @@ widget: widget to use as the context for the filter
|
|||||||
exports.makeDraggable = function(options) {
|
exports.makeDraggable = function(options) {
|
||||||
var dragImageType = options.dragImageType || "dom",
|
var dragImageType = options.dragImageType || "dom",
|
||||||
dragImage,
|
dragImage,
|
||||||
domNode = options.domNode,
|
domNode = options.domNode;
|
||||||
dragHandle = options.selector && domNode.querySelector(options.selector) || domNode;
|
|
||||||
// Make the dom node draggable (not necessary for anchor tags)
|
// Make the dom node draggable (not necessary for anchor tags)
|
||||||
if((domNode.tagName || "").toLowerCase() !== "a") {
|
if(!options.selector && ((domNode.tagName || "").toLowerCase() !== "a")) {
|
||||||
dragHandle.setAttribute("draggable","true");
|
domNode.setAttribute("draggable","true");
|
||||||
}
|
}
|
||||||
// Add event handlers
|
// Add event handlers
|
||||||
$tw.utils.addEventListeners(dragHandle,[
|
$tw.utils.addEventListeners(domNode,[
|
||||||
{name: "dragstart", handlerFunction: function(event) {
|
{name: "dragstart", handlerFunction: function(event) {
|
||||||
if(event.dataTransfer === undefined) {
|
if(event.dataTransfer === undefined) {
|
||||||
return false;
|
return false;
|
||||||
@@ -41,20 +40,26 @@ exports.makeDraggable = function(options) {
|
|||||||
var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(),
|
var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(),
|
||||||
dragFilter = options.dragFilterFn && options.dragFilterFn(),
|
dragFilter = options.dragFilterFn && options.dragFilterFn(),
|
||||||
titles = dragTiddler ? [dragTiddler] : [],
|
titles = dragTiddler ? [dragTiddler] : [],
|
||||||
startActions = options.startActions;
|
startActions = options.startActions,
|
||||||
|
variables,
|
||||||
|
domNodeRect;
|
||||||
if(dragFilter) {
|
if(dragFilter) {
|
||||||
titles.push.apply(titles,options.widget.wiki.filterTiddlers(dragFilter,options.widget));
|
titles.push.apply(titles,options.widget.wiki.filterTiddlers(dragFilter,options.widget));
|
||||||
}
|
}
|
||||||
var titleString = $tw.utils.stringifyList(titles);
|
var titleString = $tw.utils.stringifyList(titles);
|
||||||
// Check that we've something to drag
|
// Check that we've something to drag
|
||||||
if(titles.length > 0 && event.target === dragHandle) {
|
if(titles.length > 0 && (options.selector && $tw.utils.domMatchesSelector(event.target,options.selector) || event.target === domNode)) {
|
||||||
// Mark the drag in progress
|
// Mark the drag in progress
|
||||||
$tw.dragInProgress = domNode;
|
$tw.dragInProgress = domNode;
|
||||||
// Set the dragging class on the element being dragged
|
// Set the dragging class on the element being dragged
|
||||||
$tw.utils.addClass(event.target,"tc-dragging");
|
$tw.utils.addClass(domNode,"tc-dragging");
|
||||||
// Invoke drag-start actions if given
|
// Invoke drag-start actions if given
|
||||||
if(startActions !== undefined) {
|
if(startActions !== undefined) {
|
||||||
options.widget.invokeActionString(startActions,options.widget,event,{actionTiddler: titleString});
|
// Collect our variables
|
||||||
|
variables = $tw.utils.collectDOMVariables(domNode,null,event);
|
||||||
|
variables.modifier = $tw.keyboardManager.getEventModifierKeyDescriptor(event);
|
||||||
|
variables["actionTiddler"] = titleString;
|
||||||
|
options.widget.invokeActionString(startActions,options.widget,event,variables);
|
||||||
}
|
}
|
||||||
// Create the drag image elements
|
// Create the drag image elements
|
||||||
dragImage = options.widget.document.createElement("div");
|
dragImage = options.widget.document.createElement("div");
|
||||||
@@ -101,20 +106,22 @@ exports.makeDraggable = function(options) {
|
|||||||
dataTransfer.setData("text/vnd.tiddler",jsonData);
|
dataTransfer.setData("text/vnd.tiddler",jsonData);
|
||||||
dataTransfer.setData("text/plain",titleString);
|
dataTransfer.setData("text/plain",titleString);
|
||||||
dataTransfer.setData("text/x-moz-url","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
dataTransfer.setData("text/x-moz-url","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
||||||
|
} else {
|
||||||
|
dataTransfer.setData("URL","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
||||||
}
|
}
|
||||||
dataTransfer.setData("URL","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
|
||||||
dataTransfer.setData("Text",titleString);
|
dataTransfer.setData("Text",titleString);
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}},
|
}},
|
||||||
{name: "dragend", handlerFunction: function(event) {
|
{name: "dragend", handlerFunction: function(event) {
|
||||||
if(event.target === domNode) {
|
if((options.selector && $tw.utils.domMatchesSelector(event.target,options.selector)) || event.target === domNode) {
|
||||||
// Collect the tiddlers being dragged
|
// Collect the tiddlers being dragged
|
||||||
var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(),
|
var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(),
|
||||||
dragFilter = options.dragFilterFn && options.dragFilterFn(),
|
dragFilter = options.dragFilterFn && options.dragFilterFn(),
|
||||||
titles = dragTiddler ? [dragTiddler] : [],
|
titles = dragTiddler ? [dragTiddler] : [],
|
||||||
endActions = options.endActions;
|
endActions = options.endActions,
|
||||||
|
variables;
|
||||||
if(dragFilter) {
|
if(dragFilter) {
|
||||||
titles.push.apply(titles,options.widget.wiki.filterTiddlers(dragFilter,options.widget));
|
titles.push.apply(titles,options.widget.wiki.filterTiddlers(dragFilter,options.widget));
|
||||||
}
|
}
|
||||||
@@ -122,10 +129,13 @@ exports.makeDraggable = function(options) {
|
|||||||
$tw.dragInProgress = null;
|
$tw.dragInProgress = null;
|
||||||
// Invoke drag-end actions if given
|
// Invoke drag-end actions if given
|
||||||
if(endActions !== undefined) {
|
if(endActions !== undefined) {
|
||||||
options.widget.invokeActionString(endActions,options.widget,event,{actionTiddler: titleString});
|
variables = $tw.utils.collectDOMVariables(domNode,null,event);
|
||||||
|
variables.modifier = $tw.keyboardManager.getEventModifierKeyDescriptor(event);
|
||||||
|
variables["actionTiddler"] = titleString;
|
||||||
|
options.widget.invokeActionString(endActions,options.widget,event,variables);
|
||||||
}
|
}
|
||||||
// Remove the dragging class on the element being dragged
|
// Remove the dragging class on the element being dragged
|
||||||
$tw.utils.removeClass(event.target,"tc-dragging");
|
$tw.utils.removeClass(domNode,"tc-dragging");
|
||||||
// Delete the drag image element
|
// Delete the drag image element
|
||||||
if(dragImage) {
|
if(dragImage) {
|
||||||
dragImage.parentNode.removeChild(dragImage);
|
dragImage.parentNode.removeChild(dragImage);
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ Display a modal dialogue
|
|||||||
options: see below
|
options: see below
|
||||||
Options include:
|
Options include:
|
||||||
downloadLink: Text of a big download link to include
|
downloadLink: Text of a big download link to include
|
||||||
|
event: widget event
|
||||||
|
variables: from event.paramObject
|
||||||
*/
|
*/
|
||||||
Modal.prototype.display = function(title,options) {
|
Modal.prototype.display = function(title,options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
@@ -209,6 +211,10 @@ Modal.prototype.display = function(title,options) {
|
|||||||
headerWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false);
|
headerWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false);
|
||||||
bodyWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false);
|
bodyWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false);
|
||||||
footerWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false);
|
footerWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false);
|
||||||
|
// Whether to close the modal dialog when the mask (area outside the modal) is clicked
|
||||||
|
if(tiddler.fields && (tiddler.fields["mask-closable"] === "yes" || tiddler.fields["mask-closable"] === "true")) {
|
||||||
|
modalBackdrop.addEventListener("click",closeHandler,false);
|
||||||
|
}
|
||||||
// Set the initial styles for the message
|
// Set the initial styles for the message
|
||||||
$tw.utils.setStyle(modalBackdrop,[
|
$tw.utils.setStyle(modalBackdrop,[
|
||||||
{opacity: "0"}
|
{opacity: "0"}
|
||||||
|
|||||||
@@ -36,8 +36,9 @@ Notifier.prototype.display = function(title,options) {
|
|||||||
if(!tiddler) {
|
if(!tiddler) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Add classes
|
// Add classes and roles
|
||||||
$tw.utils.addClass(notification,"tc-notification");
|
$tw.utils.addClass(notification,"tc-notification");
|
||||||
|
notification.setAttribute("role","alert");
|
||||||
// Create the variables
|
// Create the variables
|
||||||
var variables = $tw.utils.extend({currentTiddler: title},options.variables);
|
var variables = $tw.utils.extend({currentTiddler: title},options.variables);
|
||||||
// Render the body of the notification
|
// Render the body of the notification
|
||||||
|
|||||||
@@ -22,6 +22,19 @@ var Popup = function(options) {
|
|||||||
this.popups = []; // Array of {title:,wiki:,domNode:} objects
|
this.popups = []; // Array of {title:,wiki:,domNode:} objects
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Global regular expression for parsing the location of a popup.
|
||||||
|
This is also used by the Reveal widget.
|
||||||
|
*/
|
||||||
|
exports.popupLocationRegExp = /^(@?)\((-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+)\)$/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Objekt containing the available prefixes for coordinates build with the `buildCoordinates` function:
|
||||||
|
- csOffsetParent: Uses a coordinate system based on the offset parent (no prefix).
|
||||||
|
- csAbsolute: Use an absolute coordinate system (prefix "@").
|
||||||
|
*/
|
||||||
|
exports.coordinatePrefix = { csOffsetParent: "", csAbsolute: "@" }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Trigger a popup open or closed. Parameters are in a hashmap:
|
Trigger a popup open or closed. Parameters are in a hashmap:
|
||||||
title: title of the tiddler where the popup details are stored
|
title: title of the tiddler where the popup details are stored
|
||||||
@@ -136,8 +149,17 @@ Popup.prototype.show = function(options) {
|
|||||||
height: options.domNode.offsetHeight
|
height: options.domNode.offsetHeight
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
var popupRect = "(" + rect.left + "," + rect.top + "," +
|
if(options.absolute && options.domNode) {
|
||||||
rect.width + "," + rect.height + ")";
|
// Walk the offsetParent chain and add the position of the offsetParents to make
|
||||||
|
// the position absolute to the root node of the page.
|
||||||
|
var currentNode = options.domNode.offsetParent;
|
||||||
|
while(currentNode) {
|
||||||
|
rect.left += currentNode.offsetLeft;
|
||||||
|
rect.top += currentNode.offsetTop;
|
||||||
|
currentNode = currentNode.offsetParent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var popupRect = exports.buildCoordinates(options.absolute?exports.coordinatePrefix.csAbsolute:exports.coordinatePrefix.csOffsetParent,rect);
|
||||||
if(options.noStateReference) {
|
if(options.noStateReference) {
|
||||||
options.wiki.setText(options.title,"text",undefined,popupRect);
|
options.wiki.setText(options.title,"text",undefined,popupRect);
|
||||||
} else {
|
} else {
|
||||||
@@ -172,13 +194,54 @@ Popup.prototype.cancel = function(level) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Returns true if the specified title and text identifies an active popup
|
Returns true if the specified title and text identifies an active popup.
|
||||||
|
This function is safe to call, even if the popup class was not initialized.
|
||||||
*/
|
*/
|
||||||
Popup.prototype.readPopupState = function(text) {
|
exports.readPopupState = function(text) {
|
||||||
var popupLocationRegExp = /^\((-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+)\)$/;
|
return exports.popupLocationRegExp.test(text);
|
||||||
return popupLocationRegExp.test(text);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Parses a coordinate string in the format `(x,y,w,h)` or `@(x,y,z,h)` and returns
|
||||||
|
an object containing the position, width and height. The absolute-Mark is boolean
|
||||||
|
value that indicates the coordinate system of the coordinates. If they start with
|
||||||
|
an `@`, `absolute` is set to true and the coordinates are relative to the root
|
||||||
|
element. If the initial `@` is missing, they are relative to the offset parent
|
||||||
|
element and `absoute` is false.
|
||||||
|
This function is safe to call, even if the popup class was not initialized.
|
||||||
|
*/
|
||||||
|
exports.parseCoordinates = function(coordinates) {
|
||||||
|
var match = exports.popupLocationRegExp.exec(coordinates);
|
||||||
|
if(match) {
|
||||||
|
return {
|
||||||
|
absolute: (match[1] === "@"),
|
||||||
|
left: parseFloat(match[2]),
|
||||||
|
top: parseFloat(match[3]),
|
||||||
|
width: parseFloat(match[4]),
|
||||||
|
height: parseFloat(match[5])
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Builds a coordinate string from a coordinate system identifier and an object
|
||||||
|
containing the left, top, width and height values.
|
||||||
|
Use constants defined in coordinatePrefix to specify a coordinate system.
|
||||||
|
If one of the parameters is invalid for building a coordinate string `(0,0,0,0)`
|
||||||
|
will be returned.
|
||||||
|
This function is safe to call, even if the popup class was not initialized.
|
||||||
|
*/
|
||||||
|
exports.buildCoordinates = function(prefix,position) {
|
||||||
|
var coord = prefix + "(" + position.left + "," + position.top + "," + position.width + "," + position.height + ")";
|
||||||
|
if (exports.popupLocationRegExp.test(coord)) {
|
||||||
|
return coord;
|
||||||
|
} else {
|
||||||
|
return "(0,0,0,0)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
exports.Popup = Popup;
|
exports.Popup = Popup;
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ var TW_TextNode = function(text) {
|
|||||||
this.textContent = text + "";
|
this.textContent = text + "";
|
||||||
};
|
};
|
||||||
|
|
||||||
TW_TextNode.prototype = Object.create(TW_Node.prototype);
|
Object.setPrototypeOf(TW_TextNode,TW_Node.prototype);
|
||||||
|
|
||||||
Object.defineProperty(TW_TextNode.prototype, "nodeType", {
|
Object.defineProperty(TW_TextNode.prototype, "nodeType", {
|
||||||
get: function() {
|
get: function() {
|
||||||
@@ -67,7 +67,7 @@ var TW_Element = function(tag,namespace) {
|
|||||||
this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml";
|
this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml";
|
||||||
};
|
};
|
||||||
|
|
||||||
TW_Element.prototype = Object.create(TW_Node.prototype);
|
Object.setPrototypeOf(TW_Element,TW_Node.prototype);
|
||||||
|
|
||||||
Object.defineProperty(TW_Element.prototype, "style", {
|
Object.defineProperty(TW_Element.prototype, "style", {
|
||||||
get: function() {
|
get: function() {
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
|
|||||||
hasUnsafeFields = hasUnsafeFields || /[\x00-\x1F]/mg.test(value);
|
hasUnsafeFields = hasUnsafeFields || /[\x00-\x1F]/mg.test(value);
|
||||||
hasUnsafeFields = hasUnsafeFields || ($tw.utils.trim(value) !== value);
|
hasUnsafeFields = hasUnsafeFields || ($tw.utils.trim(value) !== value);
|
||||||
}
|
}
|
||||||
hasUnsafeFields = hasUnsafeFields || /:/mg.test(fieldName);
|
hasUnsafeFields = hasUnsafeFields || /:|#/mg.test(fieldName);
|
||||||
});
|
});
|
||||||
// Check for field values
|
// Check for field values
|
||||||
if(hasUnsafeFields) {
|
if(hasUnsafeFields) {
|
||||||
@@ -238,7 +238,7 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
|
|||||||
} else {
|
} else {
|
||||||
// Save as a .tid or a text/binary file plus a .meta file
|
// Save as a .tid or a text/binary file plus a .meta file
|
||||||
var tiddlerType = tiddler.fields.type || "text/vnd.tiddlywiki";
|
var tiddlerType = tiddler.fields.type || "text/vnd.tiddlywiki";
|
||||||
if(tiddlerType === "text/vnd.tiddlywiki") {
|
if(tiddlerType === "text/vnd.tiddlywiki" || tiddler.hasField("_canonical_uri")) {
|
||||||
// Save as a .tid file
|
// Save as a .tid file
|
||||||
fileInfo.type = "application/x-tiddler";
|
fileInfo.type = "application/x-tiddler";
|
||||||
fileInfo.hasMetaFile = false;
|
fileInfo.hasMetaFile = false;
|
||||||
@@ -393,7 +393,7 @@ exports.generateTiddlerFilepath = function(title,options) {
|
|||||||
} while(fs.existsSync(fullPath));
|
} while(fs.existsSync(fullPath));
|
||||||
// If the last write failed with an error, or if path does not start with:
|
// If the last write failed with an error, or if path does not start with:
|
||||||
// the resolved options.directory, the resolved wikiPath directory, the wikiTiddlersPath directory,
|
// the resolved options.directory, the resolved wikiPath directory, the wikiTiddlersPath directory,
|
||||||
// or the 'originalpath' directory, then encodeURIComponent() and resolve to tiddler directory.
|
// or the 'originalpath' directory, then $tw.utils.encodeURIComponentExtended() and resolve to tiddler directory.
|
||||||
var writePath = $tw.hooks.invokeHook("th-make-tiddler-path",fullPath,fullPath),
|
var writePath = $tw.hooks.invokeHook("th-make-tiddler-path",fullPath,fullPath),
|
||||||
encode = (options.fileInfo || {writeError: false}).writeError == true;
|
encode = (options.fileInfo || {writeError: false}).writeError == true;
|
||||||
if(!encode) {
|
if(!encode) {
|
||||||
@@ -403,7 +403,7 @@ exports.generateTiddlerFilepath = function(title,options) {
|
|||||||
writePath.indexOf(path.resolve($tw.boot.wikiTiddlersPath,originalpath)) == 0 );
|
writePath.indexOf(path.resolve($tw.boot.wikiTiddlersPath,originalpath)) == 0 );
|
||||||
}
|
}
|
||||||
if(encode) {
|
if(encode) {
|
||||||
writePath = path.resolve(directory,encodeURIComponent(fullPath));
|
writePath = path.resolve(directory,$tw.utils.encodeURIComponentExtended(fullPath));
|
||||||
}
|
}
|
||||||
// Return the full path to the file
|
// Return the full path to the file
|
||||||
return writePath;
|
return writePath;
|
||||||
|
|||||||
@@ -15,10 +15,11 @@ function LinkedList() {
|
|||||||
|
|
||||||
LinkedList.prototype.clear = function() {
|
LinkedList.prototype.clear = function() {
|
||||||
// LinkedList performs the duty of both the head and tail node
|
// LinkedList performs the duty of both the head and tail node
|
||||||
this.next = Object.create(null);
|
this.next = new LLMap();
|
||||||
this.prev = Object.create(null);
|
this.prev = new LLMap();
|
||||||
this.first = undefined;
|
// Linked list head initially points to itself
|
||||||
this.last = undefined;
|
this.next.set(null, null);
|
||||||
|
this.prev.set(null, null);
|
||||||
this.length = 0;
|
this.length = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -41,28 +42,29 @@ Push behaves like array.push and accepts multiple string arguments. But it also
|
|||||||
accepts a single array argument too, to be consistent with its other methods.
|
accepts a single array argument too, to be consistent with its other methods.
|
||||||
*/
|
*/
|
||||||
LinkedList.prototype.push = function(/* values */) {
|
LinkedList.prototype.push = function(/* values */) {
|
||||||
var values = arguments;
|
var i, values = arguments;
|
||||||
if($tw.utils.isArray(values[0])) {
|
if($tw.utils.isArray(values[0])) {
|
||||||
values = values[0];
|
values = values[0];
|
||||||
}
|
}
|
||||||
for(var i = 0; i < values.length; i++) {
|
for(i = 0; i < values.length; i++) {
|
||||||
_assertString(values[i]);
|
_assertString(values[i]);
|
||||||
}
|
}
|
||||||
for(var i = 0; i < values.length; i++) {
|
for(i = 0; i < values.length; i++) {
|
||||||
_linkToEnd(this,values[i]);
|
_linkToEnd(this,values[i]);
|
||||||
}
|
}
|
||||||
return this.length;
|
return this.length;
|
||||||
};
|
};
|
||||||
|
|
||||||
LinkedList.prototype.pushTop = function(value) {
|
LinkedList.prototype.pushTop = function(value) {
|
||||||
|
var t;
|
||||||
if($tw.utils.isArray(value)) {
|
if($tw.utils.isArray(value)) {
|
||||||
for (var t=0; t<value.length; t++) {
|
for (t=0; t<value.length; t++) {
|
||||||
_assertString(value[t]);
|
_assertString(value[t]);
|
||||||
}
|
}
|
||||||
for(var t=0; t<value.length; t++) {
|
for(t=0; t<value.length; t++) {
|
||||||
_removeOne(this,value[t]);
|
_removeOne(this,value[t]);
|
||||||
}
|
}
|
||||||
for(var t=0; t<value.length; t++) {
|
for(t=0; t<value.length; t++) {
|
||||||
_linkToEnd(this,value[t]);
|
_linkToEnd(this,value[t]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -74,11 +76,11 @@ LinkedList.prototype.pushTop = function(value) {
|
|||||||
|
|
||||||
LinkedList.prototype.each = function(callback) {
|
LinkedList.prototype.each = function(callback) {
|
||||||
var visits = Object.create(null),
|
var visits = Object.create(null),
|
||||||
value = this.first;
|
value = this.next.get(null);
|
||||||
while(value !== undefined) {
|
while(value !== null) {
|
||||||
callback(value);
|
callback(value);
|
||||||
var next = this.next[value];
|
var next = this.next.get(value);
|
||||||
if(typeof next === "object") {
|
if(Array.isArray(next)) {
|
||||||
var i = visits[value] || 0;
|
var i = visits[value] || 0;
|
||||||
visits[value] = i+1;
|
visits[value] = i+1;
|
||||||
value = next[i];
|
value = next[i];
|
||||||
@@ -105,91 +107,79 @@ LinkedList.prototype.makeTiddlerIterator = function(wiki) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function _removeOne(list,value) {
|
function _removeOne(list,value) {
|
||||||
var prevEntry = list.prev[value],
|
var nextEntry = list.next.get(value);
|
||||||
nextEntry = list.next[value],
|
if(nextEntry === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var prevEntry = list.prev.get(value),
|
||||||
prev = prevEntry,
|
prev = prevEntry,
|
||||||
next = nextEntry;
|
next = nextEntry,
|
||||||
if(typeof nextEntry === "object") {
|
ref;
|
||||||
|
if(Array.isArray(nextEntry)) {
|
||||||
next = nextEntry[0];
|
next = nextEntry[0];
|
||||||
prev = prevEntry[0];
|
prev = prevEntry[0];
|
||||||
}
|
}
|
||||||
// Relink preceding element.
|
// Relink preceding element.
|
||||||
if(list.first === value) {
|
ref = list.next.get(prev);
|
||||||
list.first = next
|
if(Array.isArray(ref)) {
|
||||||
} else if(prev !== undefined) {
|
var i = ref.indexOf(value);
|
||||||
if(typeof list.next[prev] === "object") {
|
ref[i] = next;
|
||||||
if(next === undefined) {
|
|
||||||
// Must have been last, and 'i' would be last element.
|
|
||||||
list.next[prev].pop();
|
|
||||||
} else {
|
|
||||||
var i = list.next[prev].indexOf(value);
|
|
||||||
list.next[prev][i] = next;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
list.next[prev] = next;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return;
|
list.next.set(prev,next);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now relink following element
|
// Now relink following element
|
||||||
// Check "next !== undefined" rather than "list.last === value" because
|
ref = list.prev.get(next);
|
||||||
// we need to know if the FIRST value is the last in the list, not the last.
|
if(Array.isArray(ref)) {
|
||||||
if(next !== undefined) {
|
var i = ref.indexOf(value);
|
||||||
if(typeof list.prev[next] === "object") {
|
ref[i] = prev;
|
||||||
if(prev === undefined) {
|
|
||||||
// Must have been first, and 'i' would be 0.
|
|
||||||
list.prev[next].shift();
|
|
||||||
} else {
|
|
||||||
var i = list.prev[next].indexOf(value);
|
|
||||||
list.prev[next][i] = prev;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
list.prev[next] = prev;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
list.last = prev;
|
list.prev.set(next,prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delink actual value. If it uses arrays, just remove first entries.
|
// Delink actual value. If it uses arrays, just remove first entries.
|
||||||
if(typeof nextEntry === "object") {
|
if(Array.isArray(nextEntry) && nextEntry.length > 1) {
|
||||||
nextEntry.shift();
|
nextEntry.shift();
|
||||||
prevEntry.shift();
|
prevEntry.shift();
|
||||||
} else {
|
} else {
|
||||||
list.next[value] = undefined;
|
list.next.set(value,undefined);
|
||||||
list.prev[value] = undefined;
|
list.prev.set(value,undefined);
|
||||||
}
|
}
|
||||||
list.length -= 1;
|
list.length -= 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sticks the given node onto the end of the list.
|
// Sticks the given node onto the end of the list.
|
||||||
function _linkToEnd(list,value) {
|
function _linkToEnd(list,value) {
|
||||||
if(list.first === undefined) {
|
var old = list.next.get(value);
|
||||||
list.first = value;
|
var last = list.prev.get(null);
|
||||||
|
// Does it already exists?
|
||||||
|
if(old !== undefined) {
|
||||||
|
if(!Array.isArray(old)) {
|
||||||
|
old = [old];
|
||||||
|
list.next.set(value,old);
|
||||||
|
list.prev.set(value,[list.prev.get(value)]);
|
||||||
|
}
|
||||||
|
old.push(null);
|
||||||
|
list.prev.get(value).push(last);
|
||||||
} else {
|
} else {
|
||||||
// Does it already exists?
|
list.next.set(value,null);
|
||||||
if(list.first === value || list.prev[value] !== undefined) {
|
list.prev.set(value,last);
|
||||||
if(typeof list.next[value] === "string") {
|
}
|
||||||
list.next[value] = [list.next[value]];
|
// Make the old last point to this new one.
|
||||||
list.prev[value] = [list.prev[value]];
|
if(value !== last) {
|
||||||
} else if(typeof list.next[value] === "undefined") {
|
var array = list.next.get(last);
|
||||||
// list.next[value] must be undefined.
|
if(Array.isArray(array)) {
|
||||||
// Special case. List already has 1 value. It's at the end.
|
array[array.length-1] = value;
|
||||||
list.next[value] = [];
|
} else {
|
||||||
list.prev[value] = [list.prev[value]];
|
list.next.set(last,value);
|
||||||
}
|
}
|
||||||
list.prev[value].push(list.last);
|
list.prev.set(null,value);
|
||||||
// We do NOT append a new value onto "next" list. Iteration will
|
} else {
|
||||||
// figure out it must point to End-of-List on its own.
|
// Edge case, the pushed value was already the last value.
|
||||||
} else {
|
// The second-to-last nextPtr for that value must point to itself now.
|
||||||
list.prev[value] = list.last;
|
var array = list.next.get(last);
|
||||||
}
|
array[array.length-2] = value;
|
||||||
// Make the old last point to this new one.
|
|
||||||
if(typeof list.next[list.last] === "object") {
|
|
||||||
list.next[list.last].push(value);
|
|
||||||
} else {
|
|
||||||
list.next[list.last] = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
list.last = value;
|
|
||||||
list.length += 1;
|
list.length += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -199,6 +189,20 @@ function _assertString(value) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var LLMap = function() {
|
||||||
|
this.map = Object.create(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Just a wrapper so our object map can also accept null.
|
||||||
|
LLMap.prototype = {
|
||||||
|
set: function(key,val) {
|
||||||
|
(key === null) ? (this.null = val) : (this.map[key] = val);
|
||||||
|
},
|
||||||
|
get: function(key) {
|
||||||
|
return (key === null) ? this.null : this.map[key];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
exports.LinkedList = LinkedList;
|
exports.LinkedList = LinkedList;
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -48,7 +48,9 @@ Logger.prototype.log = function(/* args */) {
|
|||||||
this.saveBufferLogger.buffer = this.saveBufferLogger.buffer.slice(-this.saveBufferLogger.saveLimit);
|
this.saveBufferLogger.buffer = this.saveBufferLogger.buffer.slice(-this.saveBufferLogger.saveLimit);
|
||||||
}
|
}
|
||||||
if(console !== undefined && console.log !== undefined) {
|
if(console !== undefined && console.log !== undefined) {
|
||||||
return Function.apply.call(console.log, console, [$tw.utils.terminalColour(this.colour),this.componentName + ":"].concat(Array.prototype.slice.call(arguments,0)).concat($tw.utils.terminalColour()));
|
var logMessage = [$tw.utils.terminalColour(this.colour) + this.componentName + ":"].concat(Array.prototype.slice.call(arguments,0));
|
||||||
|
logMessage[logMessage.length-1] += $tw.utils.terminalColour();
|
||||||
|
return Function.apply.call(console.log, console, logMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,9 +12,41 @@ Parse tree utility functions.
|
|||||||
/*global $tw: false */
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add attribute to parse tree node
|
||||||
|
Can be invoked as (node,name,value) or (node,attr)
|
||||||
|
*/
|
||||||
exports.addAttributeToParseTreeNode = function(node,name,value) {
|
exports.addAttributeToParseTreeNode = function(node,name,value) {
|
||||||
|
var attribute = typeof name === "object" ? name : {name: name, type: "string", value: value};
|
||||||
|
name = attribute.name;
|
||||||
node.attributes = node.attributes || {};
|
node.attributes = node.attributes || {};
|
||||||
node.attributes[name] = {type: "string", value: value};
|
node.orderedAttributes = node.orderedAttributes || [];
|
||||||
|
node.attributes[name] = attribute;
|
||||||
|
var foundIndex = -1;
|
||||||
|
$tw.utils.each(node.orderedAttributes,function(attr,index) {
|
||||||
|
if(attr.name === name) {
|
||||||
|
foundIndex = index;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(foundIndex === -1) {
|
||||||
|
node.orderedAttributes.push(attribute);
|
||||||
|
} else {
|
||||||
|
node.orderedAttributes[foundIndex] = attribute;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getOrderedAttributesFromParseTreeNode = function(node) {
|
||||||
|
if(node.orderedAttributes) {
|
||||||
|
return node.orderedAttributes;
|
||||||
|
} else {
|
||||||
|
var attributes = [];
|
||||||
|
$tw.utils.each(node.attributes,function(attribute) {
|
||||||
|
attributes.push(attribute);
|
||||||
|
});
|
||||||
|
return attributes.sort(function(a,b) {
|
||||||
|
return a.name < b.name ? -1 : (a.name > b.name ? 1 : 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.getAttributeValueFromParseTreeNode = function(node,name,defaultValue) {
|
exports.getAttributeValueFromParseTreeNode = function(node,name,defaultValue) {
|
||||||
@@ -25,26 +57,41 @@ exports.getAttributeValueFromParseTreeNode = function(node,name,defaultValue) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
exports.addClassToParseTreeNode = function(node,classString) {
|
exports.addClassToParseTreeNode = function(node,classString) {
|
||||||
var classes = [];
|
var classes = [],
|
||||||
|
attribute;
|
||||||
node.attributes = node.attributes || {};
|
node.attributes = node.attributes || {};
|
||||||
node.attributes["class"] = node.attributes["class"] || {type: "string", value: ""};
|
attribute = node.attributes["class"];
|
||||||
if(node.attributes["class"].type === "string") {
|
if(!attribute) {
|
||||||
if(node.attributes["class"].value !== "") {
|
// If the class attribute does not exist, we must create it first.
|
||||||
classes = node.attributes["class"].value.split(" ");
|
attribute = {name: "class", type: "string", value: ""};
|
||||||
|
node.attributes["class"] = attribute;
|
||||||
|
node.orderedAttributes = node.orderedAttributes || [];
|
||||||
|
node.orderedAttributes.push(attribute);
|
||||||
|
}
|
||||||
|
if(attribute.type === "string") {
|
||||||
|
if(attribute.value !== "") {
|
||||||
|
classes = attribute.value.split(" ");
|
||||||
}
|
}
|
||||||
if(classString !== "") {
|
if(classString !== "") {
|
||||||
$tw.utils.pushTop(classes,classString.split(" "));
|
$tw.utils.pushTop(classes,classString.split(" "));
|
||||||
}
|
}
|
||||||
node.attributes["class"].value = classes.join(" ");
|
attribute.value = classes.join(" ");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.addStyleToParseTreeNode = function(node,name,value) {
|
exports.addStyleToParseTreeNode = function(node,name,value) {
|
||||||
node.attributes = node.attributes || {};
|
var attribute;
|
||||||
node.attributes.style = node.attributes.style || {type: "string", value: ""};
|
node.attributes = node.attributes || {};
|
||||||
if(node.attributes.style.type === "string") {
|
attribute = node.attributes.style;
|
||||||
node.attributes.style.value += name + ":" + value + ";";
|
if(!attribute) {
|
||||||
}
|
attribute = {name: "style", type: "string", value: ""};
|
||||||
|
node.attributes.style = attribute;
|
||||||
|
node.orderedAttributes = node.orderedAttributes || [];
|
||||||
|
node.orderedAttributes.push(attribute);
|
||||||
|
}
|
||||||
|
if(attribute.type === "string") {
|
||||||
|
attribute.value += name + ":" + value + ";";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.findParseTreeNode = function(nodeArray,search) {
|
exports.findParseTreeNode = function(nodeArray,search) {
|
||||||
|
|||||||
@@ -95,6 +95,20 @@ exports.repeat = function(str,count) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if a string starts with another string
|
||||||
|
*/
|
||||||
|
exports.startsWith = function(str,search) {
|
||||||
|
return str.substring(0, search.length) === search;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if a string ends with another string
|
||||||
|
*/
|
||||||
|
exports.endsWith = function(str,search) {
|
||||||
|
return str.substring(str.length - search.length) === search;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Trim whitespace from the start and end of a string
|
Trim whitespace from the start and end of a string
|
||||||
Thanks to Steven Levithan, http://blog.stevenlevithan.com/archives/faster-trim-javascript
|
Thanks to Steven Levithan, http://blog.stevenlevithan.com/archives/faster-trim-javascript
|
||||||
@@ -340,6 +354,9 @@ exports.formatDateString = function(date,template) {
|
|||||||
var result = "",
|
var result = "",
|
||||||
t = template,
|
t = template,
|
||||||
matches = [
|
matches = [
|
||||||
|
[/^TIMESTAMP/, function() {
|
||||||
|
return date.getTime();
|
||||||
|
}],
|
||||||
[/^0hh12/, function() {
|
[/^0hh12/, function() {
|
||||||
return $tw.utils.pad($tw.utils.getHours12(date));
|
return $tw.utils.pad($tw.utils.getHours12(date));
|
||||||
}],
|
}],
|
||||||
@@ -448,7 +465,7 @@ exports.formatDateString = function(date,template) {
|
|||||||
// 'return raw UTC (tiddlywiki style) date string.'
|
// 'return raw UTC (tiddlywiki style) date string.'
|
||||||
if(t.indexOf("[UTC]") == 0 ) {
|
if(t.indexOf("[UTC]") == 0 ) {
|
||||||
if(t == "[UTC]YYYY0MM0DD0hh0mm0ssXXX")
|
if(t == "[UTC]YYYY0MM0DD0hh0mm0ssXXX")
|
||||||
return $tw.utils.stringifyDate(new Date());
|
return $tw.utils.stringifyDate(date || new Date());
|
||||||
var offset = date.getTimezoneOffset() ; // in minutes
|
var offset = date.getTimezoneOffset() ; // in minutes
|
||||||
date = new Date(date.getTime()+offset*60*1000) ;
|
date = new Date(date.getTime()+offset*60*1000) ;
|
||||||
t = t.substr(5) ;
|
t = t.substr(5) ;
|
||||||
@@ -668,9 +685,19 @@ exports.escapeRegExp = function(s) {
|
|||||||
return s.replace(/[\-\/\\\^\$\*\+\?\.\(\)\|\[\]\{\}]/g, '\\$&');
|
return s.replace(/[\-\/\\\^\$\*\+\?\.\(\)\|\[\]\{\}]/g, '\\$&');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Extended version of encodeURIComponent that encodes additional characters including
|
||||||
|
those that are illegal within filepaths on various platforms including Windows
|
||||||
|
*/
|
||||||
|
exports.encodeURIComponentExtended = function(s) {
|
||||||
|
return encodeURIComponent(s).replace(/[!'()*]/g,function(c) {
|
||||||
|
return "%" + c.charCodeAt(0).toString(16).toUpperCase();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Checks whether a link target is external, i.e. not a tiddler title
|
// Checks whether a link target is external, i.e. not a tiddler title
|
||||||
exports.isLinkExternal = function(to) {
|
exports.isLinkExternal = function(to) {
|
||||||
var externalRegExp = /^(?:file|http|https|mailto|ftp|irc|news|data|skype):[^\s<>{}\[\]`|"\\^]+(?:\/|\b)/i;
|
var externalRegExp = /^(?:file|http|https|mailto|ftp|irc|news|obsidian|data|skype):[^\s<>{}\[\]`|"\\^]+(?:\/|\b)/i;
|
||||||
return externalRegExp.test(to);
|
return externalRegExp.test(to);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ Compute the internal state of the widget
|
|||||||
*/
|
*/
|
||||||
DeleteFieldWidget.prototype.execute = function() {
|
DeleteFieldWidget.prototype.execute = function() {
|
||||||
this.actionTiddler = this.getAttribute("$tiddler",this.getVariable("currentTiddler"));
|
this.actionTiddler = this.getAttribute("$tiddler",this.getVariable("currentTiddler"));
|
||||||
this.actionField = this.getAttribute("$field");
|
this.actionField = this.getAttribute("$field",null);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -59,7 +59,7 @@ DeleteFieldWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
|||||||
tiddler = this.wiki.getTiddler(self.actionTiddler),
|
tiddler = this.wiki.getTiddler(self.actionTiddler),
|
||||||
removeFields = {},
|
removeFields = {},
|
||||||
hasChanged = false;
|
hasChanged = false;
|
||||||
if(this.actionField && tiddler) {
|
if((this.actionField !== null) && tiddler) {
|
||||||
removeFields[this.actionField] = undefined;
|
removeFields[this.actionField] = undefined;
|
||||||
if(this.actionField in tiddler.fields) {
|
if(this.actionField in tiddler.fields) {
|
||||||
hasChanged = true;
|
hasChanged = true;
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ Action widget to trigger a popup.
|
|||||||
|
|
||||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||||
|
|
||||||
|
var Popup = require("$:/core/modules/utils/dom/popup.js");
|
||||||
|
|
||||||
var ActionPopupWidget = function(parseTreeNode,options) {
|
var ActionPopupWidget = function(parseTreeNode,options) {
|
||||||
this.initialise(parseTreeNode,options);
|
this.initialise(parseTreeNode,options);
|
||||||
};
|
};
|
||||||
@@ -57,20 +59,20 @@ Invoke the action associated with this widget
|
|||||||
*/
|
*/
|
||||||
ActionPopupWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
ActionPopupWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||||
// Trigger the popup
|
// Trigger the popup
|
||||||
var popupLocationRegExp = /^\((-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+)\)$/,
|
var coordinates = Popup.parseCoordinates(this.actionCoords || "");
|
||||||
match = popupLocationRegExp.exec(this.actionCoords || "");
|
if(coordinates) {
|
||||||
if(match) {
|
|
||||||
$tw.popup.triggerPopup({
|
$tw.popup.triggerPopup({
|
||||||
domNode: null,
|
domNode: null,
|
||||||
domNodeRect: {
|
domNodeRect: {
|
||||||
left: parseFloat(match[1]),
|
left: coordinates.left,
|
||||||
top: parseFloat(match[2]),
|
top: coordinates.top,
|
||||||
width: parseFloat(match[3]),
|
width: coordinates.width,
|
||||||
height: parseFloat(match[4])
|
height: coordinates.height
|
||||||
},
|
},
|
||||||
title: this.actionState,
|
title: this.actionState,
|
||||||
wiki: this.wiki,
|
wiki: this.wiki,
|
||||||
floating: this.floating
|
floating: this.floating,
|
||||||
|
absolute: coordinates.absolute
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$tw.popup.cancel(0);
|
$tw.popup.cancel(0);
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ SetFieldWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
Compute the internal state of the widget
|
Compute the internal state of the widget
|
||||||
*/
|
*/
|
||||||
SetFieldWidget.prototype.execute = function() {
|
SetFieldWidget.prototype.execute = function() {
|
||||||
this.actionTiddler = this.getAttribute("$tiddler",this.getVariable("currentTiddler"));
|
this.actionTiddler = this.getAttribute("$tiddler") || (!this.hasParseTreeNodeAttribute("$tiddler") && this.getVariable("currentTiddler"));
|
||||||
this.actionField = this.getAttribute("$field");
|
this.actionField = this.getAttribute("$field");
|
||||||
this.actionIndex = this.getAttribute("$index");
|
this.actionIndex = this.getAttribute("$index");
|
||||||
this.actionValue = this.getAttribute("$value");
|
this.actionValue = this.getAttribute("$value");
|
||||||
@@ -46,11 +46,7 @@ SetFieldWidget.prototype.execute = function() {
|
|||||||
Refresh the widget by ensuring our attributes are up to date
|
Refresh the widget by ensuring our attributes are up to date
|
||||||
*/
|
*/
|
||||||
SetFieldWidget.prototype.refresh = function(changedTiddlers) {
|
SetFieldWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
var changedAttributes = this.computeAttributes();
|
// Nothing to refresh
|
||||||
if(changedAttributes["$tiddler"] || changedAttributes["$field"] || changedAttributes["$index"] || changedAttributes["$value"]) {
|
|
||||||
this.refreshSelf();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return this.refreshChildren(changedTiddlers);
|
return this.refreshChildren(changedTiddlers);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -60,15 +56,17 @@ Invoke the action associated with this widget
|
|||||||
SetFieldWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
SetFieldWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||||
var self = this,
|
var self = this,
|
||||||
options = {};
|
options = {};
|
||||||
options.suppressTimestamp = !this.actionTimestamp;
|
if(this.actionTiddler) {
|
||||||
if((typeof this.actionField == "string") || (typeof this.actionIndex == "string") || (typeof this.actionValue == "string")) {
|
options.suppressTimestamp = !this.actionTimestamp;
|
||||||
this.wiki.setText(this.actionTiddler,this.actionField,this.actionIndex,this.actionValue,options);
|
if((typeof this.actionField == "string") || (typeof this.actionIndex == "string") || (typeof this.actionValue == "string")) {
|
||||||
}
|
this.wiki.setText(this.actionTiddler,this.actionField,this.actionIndex,this.actionValue,options);
|
||||||
$tw.utils.each(this.attributes,function(attribute,name) {
|
|
||||||
if(name.charAt(0) !== "$") {
|
|
||||||
self.wiki.setText(self.actionTiddler,name,undefined,attribute,options);
|
|
||||||
}
|
}
|
||||||
});
|
$tw.utils.each(this.attributes,function(attribute,name) {
|
||||||
|
if(name.charAt(0) !== "$") {
|
||||||
|
self.wiki.setText(self.actionTiddler,name,undefined,attribute,options);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
return true; // Action was invoked
|
return true; // Action was invoked
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ Button widget
|
|||||||
|
|
||||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||||
|
|
||||||
|
var Popup = require("$:/core/modules/utils/dom/popup.js");
|
||||||
|
|
||||||
var ButtonWidget = function(parseTreeNode,options) {
|
var ButtonWidget = function(parseTreeNode,options) {
|
||||||
this.initialise(parseTreeNode,options);
|
this.initialise(parseTreeNode,options);
|
||||||
};
|
};
|
||||||
@@ -46,7 +48,8 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
isPoppedUp = (this.popup || this.popupTitle) && this.isPoppedUp();
|
isPoppedUp = (this.popup || this.popupTitle) && this.isPoppedUp();
|
||||||
if(this.selectedClass) {
|
if(this.selectedClass) {
|
||||||
if((this.set || this.setTitle) && this.setTo && this.isSelected()) {
|
if((this.set || this.setTitle) && this.setTo && this.isSelected()) {
|
||||||
$tw.utils.pushTop(classes,this.selectedClass.split(" "));
|
$tw.utils.pushTop(classes, this.selectedClass.split(" "));
|
||||||
|
domNode.setAttribute("aria-checked", "true");
|
||||||
}
|
}
|
||||||
if(isPoppedUp) {
|
if(isPoppedUp) {
|
||||||
$tw.utils.pushTop(classes,this.selectedClass.split(" "));
|
$tw.utils.pushTop(classes,this.selectedClass.split(" "));
|
||||||
@@ -66,6 +69,9 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
if(this["aria-label"]) {
|
if(this["aria-label"]) {
|
||||||
domNode.setAttribute("aria-label",this["aria-label"]);
|
domNode.setAttribute("aria-label",this["aria-label"]);
|
||||||
}
|
}
|
||||||
|
if (this.role) {
|
||||||
|
domNode.setAttribute("role", this.role);
|
||||||
|
}
|
||||||
if(this.popup || this.popupTitle) {
|
if(this.popup || this.popupTitle) {
|
||||||
domNode.setAttribute("aria-expanded",isPoppedUp ? "true" : "false");
|
domNode.setAttribute("aria-expanded",isPoppedUp ? "true" : "false");
|
||||||
}
|
}
|
||||||
@@ -143,7 +149,7 @@ ButtonWidget.prototype.isSelected = function() {
|
|||||||
|
|
||||||
ButtonWidget.prototype.isPoppedUp = function() {
|
ButtonWidget.prototype.isPoppedUp = function() {
|
||||||
var tiddler = this.popupTitle ? this.wiki.getTiddler(this.popupTitle) : this.wiki.getTiddler(this.popup);
|
var tiddler = this.popupTitle ? this.wiki.getTiddler(this.popupTitle) : this.wiki.getTiddler(this.popup);
|
||||||
var result = tiddler && tiddler.fields.text ? $tw.popup.readPopupState(tiddler.fields.text) : false;
|
var result = tiddler && tiddler.fields.text ? Popup.readPopupState(tiddler.fields.text) : false;
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -169,6 +175,7 @@ ButtonWidget.prototype.triggerPopup = function(event) {
|
|||||||
if(this.popupTitle) {
|
if(this.popupTitle) {
|
||||||
$tw.popup.triggerPopup({
|
$tw.popup.triggerPopup({
|
||||||
domNode: this.domNodes[0],
|
domNode: this.domNodes[0],
|
||||||
|
absolute: (this.popupAbsCoords === "yes"),
|
||||||
title: this.popupTitle,
|
title: this.popupTitle,
|
||||||
wiki: this.wiki,
|
wiki: this.wiki,
|
||||||
noStateReference: true
|
noStateReference: true
|
||||||
@@ -176,6 +183,7 @@ ButtonWidget.prototype.triggerPopup = function(event) {
|
|||||||
} else {
|
} else {
|
||||||
$tw.popup.triggerPopup({
|
$tw.popup.triggerPopup({
|
||||||
domNode: this.domNodes[0],
|
domNode: this.domNodes[0],
|
||||||
|
absolute: (this.popupAbsCoords === "yes"),
|
||||||
title: this.popup,
|
title: this.popup,
|
||||||
wiki: this.wiki
|
wiki: this.wiki
|
||||||
});
|
});
|
||||||
@@ -206,6 +214,7 @@ ButtonWidget.prototype.execute = function() {
|
|||||||
this.popup = this.getAttribute("popup");
|
this.popup = this.getAttribute("popup");
|
||||||
this.hover = this.getAttribute("hover");
|
this.hover = this.getAttribute("hover");
|
||||||
this["aria-label"] = this.getAttribute("aria-label");
|
this["aria-label"] = this.getAttribute("aria-label");
|
||||||
|
this.role = this.getAttribute("role");
|
||||||
this.tooltip = this.getAttribute("tooltip");
|
this.tooltip = this.getAttribute("tooltip");
|
||||||
this.style = this.getAttribute("style");
|
this.style = this.getAttribute("style");
|
||||||
this["class"] = this.getAttribute("class","");
|
this["class"] = this.getAttribute("class","");
|
||||||
@@ -218,6 +227,7 @@ ButtonWidget.prototype.execute = function() {
|
|||||||
this.setField = this.getAttribute("setField");
|
this.setField = this.getAttribute("setField");
|
||||||
this.setIndex = this.getAttribute("setIndex");
|
this.setIndex = this.getAttribute("setIndex");
|
||||||
this.popupTitle = this.getAttribute("popupTitle");
|
this.popupTitle = this.getAttribute("popupTitle");
|
||||||
|
this.popupAbsCoords = this.getAttribute("popupAbsCoords", "no");
|
||||||
this.tabIndex = this.getAttribute("tabindex");
|
this.tabIndex = this.getAttribute("tabindex");
|
||||||
this.isDisabled = this.getAttribute("disabled","no");
|
this.isDisabled = this.getAttribute("disabled","no");
|
||||||
// Make child widgets
|
// Make child widgets
|
||||||
@@ -247,7 +257,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
|||||||
*/
|
*/
|
||||||
ButtonWidget.prototype.refresh = function(changedTiddlers) {
|
ButtonWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
var changedAttributes = this.computeAttributes();
|
var changedAttributes = this.computeAttributes();
|
||||||
if(changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled || changedAttributes["default"]) {
|
if(changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.popupAbsCoords || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled || changedAttributes["default"]) {
|
||||||
this.refreshSelf();
|
this.refreshSelf();
|
||||||
return true;
|
return true;
|
||||||
} else if(changedAttributes["class"]) {
|
} else if(changedAttributes["class"]) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ CheckboxWidget.prototype = new Widget();
|
|||||||
Render this widget into the DOM
|
Render this widget into the DOM
|
||||||
*/
|
*/
|
||||||
CheckboxWidget.prototype.render = function(parent,nextSibling) {
|
CheckboxWidget.prototype.render = function(parent,nextSibling) {
|
||||||
|
var isChecked;
|
||||||
// Save the parent dom node
|
// Save the parent dom node
|
||||||
this.parentDomNode = parent;
|
this.parentDomNode = parent;
|
||||||
// Compute our attributes
|
// Compute our attributes
|
||||||
@@ -35,11 +36,16 @@ CheckboxWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
this.execute();
|
this.execute();
|
||||||
// Create our elements
|
// Create our elements
|
||||||
this.labelDomNode = this.document.createElement("label");
|
this.labelDomNode = this.document.createElement("label");
|
||||||
this.labelDomNode.setAttribute("class",this.checkboxClass);
|
this.labelDomNode.setAttribute("class","tc-checkbox " + this.checkboxClass);
|
||||||
this.inputDomNode = this.document.createElement("input");
|
this.inputDomNode = this.document.createElement("input");
|
||||||
this.inputDomNode.setAttribute("type","checkbox");
|
this.inputDomNode.setAttribute("type","checkbox");
|
||||||
if(this.getValue()) {
|
isChecked = this.getValue();
|
||||||
|
if(isChecked) {
|
||||||
this.inputDomNode.setAttribute("checked","true");
|
this.inputDomNode.setAttribute("checked","true");
|
||||||
|
$tw.utils.addClass(this.labelDomNode,"tc-checkbox-checked");
|
||||||
|
}
|
||||||
|
if(isChecked === undefined && this.checkboxIndeterminate === "yes") {
|
||||||
|
this.inputDomNode.indeterminate = true;
|
||||||
}
|
}
|
||||||
if(this.isDisabled === "yes") {
|
if(this.isDisabled === "yes") {
|
||||||
this.inputDomNode.setAttribute("disabled",true);
|
this.inputDomNode.setAttribute("disabled",true);
|
||||||
@@ -59,20 +65,25 @@ CheckboxWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
|
|
||||||
CheckboxWidget.prototype.getValue = function() {
|
CheckboxWidget.prototype.getValue = function() {
|
||||||
var tiddler = this.wiki.getTiddler(this.checkboxTitle);
|
var tiddler = this.wiki.getTiddler(this.checkboxTitle);
|
||||||
if(tiddler) {
|
if(tiddler || this.checkboxFilter) {
|
||||||
if(this.checkboxTag) {
|
if(tiddler && this.checkboxTag) {
|
||||||
if(this.checkboxInvertTag) {
|
if(this.checkboxInvertTag === "yes") {
|
||||||
return !tiddler.hasTag(this.checkboxTag);
|
return !tiddler.hasTag(this.checkboxTag);
|
||||||
} else {
|
} else {
|
||||||
return tiddler.hasTag(this.checkboxTag);
|
return tiddler.hasTag(this.checkboxTag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(this.checkboxField) {
|
if(tiddler && (this.checkboxField || this.checkboxIndex)) {
|
||||||
|
// Same logic applies to fields and indexes
|
||||||
var value;
|
var value;
|
||||||
if($tw.utils.hop(tiddler.fields,this.checkboxField)) {
|
if(this.checkboxField) {
|
||||||
value = tiddler.fields[this.checkboxField] || "";
|
if($tw.utils.hop(tiddler.fields,this.checkboxField)) {
|
||||||
|
value = tiddler.fields[this.checkboxField] || "";
|
||||||
|
} else {
|
||||||
|
value = this.checkboxDefault || "";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
value = this.checkboxDefault || "";
|
value = this.wiki.extractTiddlerDataItem(tiddler,this.checkboxIndex,this.checkboxDefault || "");
|
||||||
}
|
}
|
||||||
if(value === this.checkboxChecked) {
|
if(value === this.checkboxChecked) {
|
||||||
return true;
|
return true;
|
||||||
@@ -80,15 +91,59 @@ CheckboxWidget.prototype.getValue = function() {
|
|||||||
if(value === this.checkboxUnchecked) {
|
if(value === this.checkboxUnchecked) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// Neither value found: were both specified?
|
||||||
|
if(this.checkboxChecked && !this.checkboxUnchecked) {
|
||||||
|
return false; // Absence of checked value
|
||||||
|
}
|
||||||
|
if(this.checkboxUnchecked && !this.checkboxChecked) {
|
||||||
|
return true; // Absence of unchecked value
|
||||||
|
}
|
||||||
|
if(this.checkboxChecked && this.checkboxUnchecked) {
|
||||||
|
// Both specified but neither found: indeterminate or false, depending
|
||||||
|
if(this.checkboxIndeterminate === "yes") {
|
||||||
|
return undefined;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(this.checkboxIndex) {
|
if(this.checkboxListField || this.checkboxListIndex || this.checkboxFilter) {
|
||||||
var value = this.wiki.extractTiddlerDataItem(tiddler,this.checkboxIndex,this.checkboxDefault || "");
|
// Same logic applies to lists and filters
|
||||||
if(value === this.checkboxChecked) {
|
var list;
|
||||||
|
if(this.checkboxListField) {
|
||||||
|
if($tw.utils.hop(tiddler.fields,this.checkboxListField)) {
|
||||||
|
list = tiddler.getFieldList(this.checkboxListField);
|
||||||
|
} else {
|
||||||
|
list = $tw.utils.parseStringArray(this.checkboxDefault || "") || [];
|
||||||
|
}
|
||||||
|
} else if (this.checkboxListIndex) {
|
||||||
|
list = $tw.utils.parseStringArray(this.wiki.extractTiddlerDataItem(tiddler,this.checkboxListIndex,this.checkboxDefault || "")) || [];
|
||||||
|
} else {
|
||||||
|
list = this.wiki.filterTiddlers(this.checkboxFilter,this) || [];
|
||||||
|
}
|
||||||
|
if(list.indexOf(this.checkboxChecked) !== -1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(value === this.checkboxUnchecked) {
|
if(list.indexOf(this.checkboxUnchecked) !== -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// Neither one present
|
||||||
|
if(this.checkboxChecked && !this.checkboxUnchecked) {
|
||||||
|
return false; // Absence of checked value
|
||||||
|
}
|
||||||
|
if(this.checkboxUnchecked && !this.checkboxChecked) {
|
||||||
|
return true; // Absence of unchecked value
|
||||||
|
}
|
||||||
|
if(this.checkboxChecked && this.checkboxUnchecked) {
|
||||||
|
// Both specified but neither found: indeterminate or false, depending
|
||||||
|
if(this.checkboxIndeterminate === "yes") {
|
||||||
|
return undefined;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Neither specified, so empty list is false, non-empty is true
|
||||||
|
return !!list.length;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(this.checkboxTag) {
|
if(this.checkboxTag) {
|
||||||
@@ -114,7 +169,8 @@ CheckboxWidget.prototype.handleChangeEvent = function(event) {
|
|||||||
hasChanged = false,
|
hasChanged = false,
|
||||||
tagCheck = false,
|
tagCheck = false,
|
||||||
hasTag = tiddler && tiddler.hasTag(this.checkboxTag),
|
hasTag = tiddler && tiddler.hasTag(this.checkboxTag),
|
||||||
value = checked ? this.checkboxChecked : this.checkboxUnchecked;
|
value = checked ? this.checkboxChecked : this.checkboxUnchecked,
|
||||||
|
notValue = checked ? this.checkboxUnchecked : this.checkboxChecked;
|
||||||
if(this.checkboxTag && this.checkboxInvertTag === "yes") {
|
if(this.checkboxTag && this.checkboxInvertTag === "yes") {
|
||||||
tagCheck = hasTag === checked;
|
tagCheck = hasTag === checked;
|
||||||
} else {
|
} else {
|
||||||
@@ -148,9 +204,58 @@ CheckboxWidget.prototype.handleChangeEvent = function(event) {
|
|||||||
hasChanged = true;
|
hasChanged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Set the list field (or index) if specified
|
||||||
|
if(this.checkboxListField || this.checkboxListIndex) {
|
||||||
|
var fieldContents, listContents, oldPos, newPos;
|
||||||
|
if(this.checkboxListField) {
|
||||||
|
fieldContents = tiddler ? tiddler.fields[this.checkboxListField] : undefined;
|
||||||
|
} else {
|
||||||
|
fieldContents = this.wiki.extractTiddlerDataItem(this.checkboxTitle,this.checkboxListIndex);
|
||||||
|
}
|
||||||
|
if($tw.utils.isArray(fieldContents)) {
|
||||||
|
// Make a copy so we can modify it without changing original that's refrenced elsewhere
|
||||||
|
listContents = fieldContents.slice(0);
|
||||||
|
} else {
|
||||||
|
listContents = $tw.utils.parseStringArray(fieldContents) || [];
|
||||||
|
// No need to copy since parseStringArray returns a fresh array, not refrenced elsewhere
|
||||||
|
}
|
||||||
|
oldPos = notValue ? listContents.indexOf(notValue) : -1;
|
||||||
|
newPos = value ? listContents.indexOf(value) : -1;
|
||||||
|
if(oldPos === -1 && newPos !== -1) {
|
||||||
|
// old value absent, new value present: no change needed
|
||||||
|
} else if(oldPos === -1) {
|
||||||
|
// neither one was present
|
||||||
|
if(value) {
|
||||||
|
listContents.push(value);
|
||||||
|
hasChanged = true;
|
||||||
|
} else {
|
||||||
|
// value unspecified? then leave list unchanged
|
||||||
|
}
|
||||||
|
} else if(newPos === -1) {
|
||||||
|
// old value present, new value absent
|
||||||
|
if(value) {
|
||||||
|
listContents[oldPos] = value;
|
||||||
|
hasChanged = true;
|
||||||
|
} else {
|
||||||
|
listContents.splice(oldPos, 1)
|
||||||
|
hasChanged = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// both were present: just remove the old one, leave new alone
|
||||||
|
listContents.splice(oldPos, 1)
|
||||||
|
hasChanged = true;
|
||||||
|
}
|
||||||
|
if(this.checkboxListField) {
|
||||||
|
newFields[this.checkboxListField] = $tw.utils.stringifyList(listContents);
|
||||||
|
}
|
||||||
|
// The listIndex case will be handled in the if(hasChanged) block below
|
||||||
|
}
|
||||||
if(hasChanged) {
|
if(hasChanged) {
|
||||||
if(this.checkboxIndex) {
|
if(this.checkboxIndex) {
|
||||||
this.wiki.setText(this.checkboxTitle,"",this.checkboxIndex,value);
|
this.wiki.setText(this.checkboxTitle,"",this.checkboxIndex,value);
|
||||||
|
} else if(this.checkboxListIndex) {
|
||||||
|
var listIndexValue = (listContents && listContents.length) ? $tw.utils.stringifyList(listContents) : undefined;
|
||||||
|
this.wiki.setText(this.checkboxTitle,"",this.checkboxListIndex,listIndexValue);
|
||||||
} else {
|
} else {
|
||||||
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getCreationFields(),fallbackFields,tiddler,newFields,this.wiki.getModificationFields()));
|
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getCreationFields(),fallbackFields,tiddler,newFields,this.wiki.getModificationFields()));
|
||||||
}
|
}
|
||||||
@@ -179,9 +284,13 @@ CheckboxWidget.prototype.execute = function() {
|
|||||||
this.checkboxTag = this.getAttribute("tag");
|
this.checkboxTag = this.getAttribute("tag");
|
||||||
this.checkboxField = this.getAttribute("field");
|
this.checkboxField = this.getAttribute("field");
|
||||||
this.checkboxIndex = this.getAttribute("index");
|
this.checkboxIndex = this.getAttribute("index");
|
||||||
|
this.checkboxListField = this.getAttribute("listField");
|
||||||
|
this.checkboxListIndex = this.getAttribute("listIndex");
|
||||||
|
this.checkboxFilter = this.getAttribute("filter");
|
||||||
this.checkboxChecked = this.getAttribute("checked");
|
this.checkboxChecked = this.getAttribute("checked");
|
||||||
this.checkboxUnchecked = this.getAttribute("unchecked");
|
this.checkboxUnchecked = this.getAttribute("unchecked");
|
||||||
this.checkboxDefault = this.getAttribute("default");
|
this.checkboxDefault = this.getAttribute("default");
|
||||||
|
this.checkboxIndeterminate = this.getAttribute("indeterminate","no");
|
||||||
this.checkboxClass = this.getAttribute("class","");
|
this.checkboxClass = this.getAttribute("class","");
|
||||||
this.checkboxInvertTag = this.getAttribute("invertTag","");
|
this.checkboxInvertTag = this.getAttribute("invertTag","");
|
||||||
this.isDisabled = this.getAttribute("disabled","no");
|
this.isDisabled = this.getAttribute("disabled","no");
|
||||||
@@ -194,14 +303,21 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
|||||||
*/
|
*/
|
||||||
CheckboxWidget.prototype.refresh = function(changedTiddlers) {
|
CheckboxWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
var changedAttributes = this.computeAttributes();
|
var changedAttributes = this.computeAttributes();
|
||||||
if(changedAttributes.tiddler || changedAttributes.tag || changedAttributes.invertTag || changedAttributes.field || changedAttributes.index || changedAttributes.checked || changedAttributes.unchecked || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.disabled) {
|
if(changedAttributes.tiddler || changedAttributes.tag || changedAttributes.invertTag || changedAttributes.field || changedAttributes.index || changedAttributes.listField || changedAttributes.listIndex || changedAttributes.filter || changedAttributes.checked || changedAttributes.unchecked || changedAttributes["default"] || changedAttributes.indeterminate || changedAttributes["class"] || changedAttributes.disabled) {
|
||||||
this.refreshSelf();
|
this.refreshSelf();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
var refreshed = false;
|
var refreshed = false;
|
||||||
if(changedTiddlers[this.checkboxTitle]) {
|
if(changedTiddlers[this.checkboxTitle]) {
|
||||||
this.inputDomNode.checked = this.getValue();
|
var isChecked = this.getValue();
|
||||||
|
this.inputDomNode.checked = !!isChecked;
|
||||||
|
this.inputDomNode.indeterminate = (isChecked === undefined);
|
||||||
refreshed = true;
|
refreshed = true;
|
||||||
|
if(isChecked) {
|
||||||
|
$tw.utils.addClass(this.labelDomNode,"tc-checkbox-checked");
|
||||||
|
} else {
|
||||||
|
$tw.utils.removeClass(this.labelDomNode,"tc-checkbox-checked");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this.refreshChildren(changedTiddlers) || refreshed;
|
return this.refreshChildren(changedTiddlers) || refreshed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ DraggableWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
if(this.draggableClasses) {
|
if(this.draggableClasses) {
|
||||||
classes.push(this.draggableClasses);
|
classes.push(this.draggableClasses);
|
||||||
}
|
}
|
||||||
if(!this.dragHandleSelector) {
|
if(!this.dragHandleSelector && this.dragEnable) {
|
||||||
classes.push("tc-draggable");
|
classes.push("tc-draggable");
|
||||||
}
|
}
|
||||||
domNode.setAttribute("class",classes.join(" "));
|
domNode.setAttribute("class",classes.join(" "));
|
||||||
@@ -56,16 +56,18 @@ DraggableWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
parent.insertBefore(domNode,nextSibling);
|
parent.insertBefore(domNode,nextSibling);
|
||||||
this.renderChildren(domNode,null);
|
this.renderChildren(domNode,null);
|
||||||
// Add event handlers
|
// Add event handlers
|
||||||
$tw.utils.makeDraggable({
|
if(this.dragEnable) {
|
||||||
domNode: domNode,
|
$tw.utils.makeDraggable({
|
||||||
dragTiddlerFn: function() {return self.getAttribute("tiddler");},
|
domNode: domNode,
|
||||||
dragFilterFn: function() {return self.getAttribute("filter");},
|
dragTiddlerFn: function() {return self.getAttribute("tiddler");},
|
||||||
startActions: self.startActions,
|
dragFilterFn: function() {return self.getAttribute("filter");},
|
||||||
endActions: self.endActions,
|
startActions: self.startActions,
|
||||||
dragImageType: self.dragImageType,
|
endActions: self.endActions,
|
||||||
widget: this,
|
dragImageType: self.dragImageType,
|
||||||
selector: self.dragHandleSelector
|
widget: this,
|
||||||
});
|
selector: self.dragHandleSelector
|
||||||
|
});
|
||||||
|
}
|
||||||
this.domNodes.push(domNode);
|
this.domNodes.push(domNode);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -80,16 +82,37 @@ DraggableWidget.prototype.execute = function() {
|
|||||||
this.endActions = this.getAttribute("endactions");
|
this.endActions = this.getAttribute("endactions");
|
||||||
this.dragImageType = this.getAttribute("dragimagetype");
|
this.dragImageType = this.getAttribute("dragimagetype");
|
||||||
this.dragHandleSelector = this.getAttribute("selector");
|
this.dragHandleSelector = this.getAttribute("selector");
|
||||||
|
this.dragEnable = this.getAttribute("enable","yes") === "yes";
|
||||||
// Make the child widgets
|
// Make the child widgets
|
||||||
this.makeChildWidgets();
|
this.makeChildWidgets();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
DraggableWidget.prototype.updateDomNodeClasses = function() {
|
||||||
|
var domNodeClasses = this.domNodes[0].className.split(" "),
|
||||||
|
oldClasses = this.draggableClasses.split(" ");
|
||||||
|
this.draggableClasses = this.getAttribute("class");
|
||||||
|
//Remove classes assigned from the old value of class attribute
|
||||||
|
$tw.utils.each(oldClasses,function(oldClass){
|
||||||
|
var i = domNodeClasses.indexOf(oldClass);
|
||||||
|
if(i !== -1) {
|
||||||
|
domNodeClasses.splice(i,1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//Add new classes from updated class attribute.
|
||||||
|
$tw.utils.pushTop(domNodeClasses,this.draggableClasses);
|
||||||
|
this.domNodes[0].setAttribute("class",domNodeClasses.join(" "))
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||||
*/
|
*/
|
||||||
DraggableWidget.prototype.refresh = function(changedTiddlers) {
|
DraggableWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
var changedAttributes = this.computeAttributes();
|
var changedAttributes = this.computeAttributes(),
|
||||||
if(changedAttributes.tag || changedAttributes["class"]) {
|
changedAttributesCount = $tw.utils.count(changedAttributes);
|
||||||
|
if(changedAttributesCount === 1 && changedAttributes["class"]) {
|
||||||
|
this.updateDomNodeClasses();
|
||||||
|
} else if(changedAttributesCount > 0) {
|
||||||
this.refreshSelf();
|
this.refreshSelf();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -98,4 +121,4 @@ DraggableWidget.prototype.refresh = function(changedTiddlers) {
|
|||||||
|
|
||||||
exports.draggable = DraggableWidget;
|
exports.draggable = DraggableWidget;
|
||||||
|
|
||||||
})();
|
})();
|
||||||
@@ -232,10 +232,32 @@ DropZoneWidget.prototype.handleDropEvent = function(event) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
DropZoneWidget.prototype.handlePasteEvent = function(event) {
|
DropZoneWidget.prototype.handlePasteEvent = function(event) {
|
||||||
var self = this,
|
var self = this;
|
||||||
readFileCallback = function(tiddlerFieldsArray) {
|
var readFileCallback = function(tiddlerFieldsArray) {
|
||||||
self.readFileCallback(tiddlerFieldsArray);
|
self.readFileCallback(tiddlerFieldsArray);
|
||||||
};
|
};
|
||||||
|
var getItem = function(type) {
|
||||||
|
type = type || "text/plain";
|
||||||
|
return function(str) {
|
||||||
|
// Use the deserializer specified if any
|
||||||
|
if(self.dropzoneDeserializer) {
|
||||||
|
tiddlerFields = self.wiki.deserializeTiddlers(null,str,{title: self.wiki.generateNewTitle("Untitled " + type)},{deserializer:self.dropzoneDeserializer});
|
||||||
|
if(tiddlerFields && tiddlerFields.length) {
|
||||||
|
readFileCallback(tiddlerFields);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tiddlerFields = {
|
||||||
|
title: self.wiki.generateNewTitle("Untitled " + type),
|
||||||
|
text: str,
|
||||||
|
type: type
|
||||||
|
};
|
||||||
|
if($tw.log.IMPORT) {
|
||||||
|
console.log("Importing string '" + str + "', type: '" + type + "'");
|
||||||
|
}
|
||||||
|
readFileCallback([tiddlerFields]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
// Let the browser handle it if we're in a textarea or input box
|
// Let the browser handle it if we're in a textarea or input box
|
||||||
if(["TEXTAREA","INPUT"].indexOf(event.target.tagName) == -1 && !event.target.isContentEditable) {
|
if(["TEXTAREA","INPUT"].indexOf(event.target.tagName) == -1 && !event.target.isContentEditable) {
|
||||||
var self = this,
|
var self = this,
|
||||||
@@ -251,27 +273,10 @@ DropZoneWidget.prototype.handlePasteEvent = function(event) {
|
|||||||
});
|
});
|
||||||
} else if(item.kind === "string") {
|
} else if(item.kind === "string") {
|
||||||
// Create tiddlers from string items
|
// Create tiddlers from string items
|
||||||
var tiddlerFields,
|
var tiddlerFields;
|
||||||
type = item.type;
|
// It's important to give getAsString a closure with the right type
|
||||||
item.getAsString(function(str) {
|
// So it can be added to the import queue
|
||||||
// Use the deserializer specified if any
|
item.getAsString(getItem(item.type));
|
||||||
if(self.dropzoneDeserializer) {
|
|
||||||
tiddlerFields = self.wiki.deserializeTiddlers(null,str,{title: self.wiki.generateNewTitle("Untitled")},{deserializer:self.dropzoneDeserializer});
|
|
||||||
if(tiddlerFields && tiddlerFields.length) {
|
|
||||||
readFileCallback(tiddlerFields);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tiddlerFields = {
|
|
||||||
title: self.wiki.generateNewTitle("Untitled"),
|
|
||||||
text: str,
|
|
||||||
type: type
|
|
||||||
};
|
|
||||||
if($tw.log.IMPORT) {
|
|
||||||
console.log("Importing string '" + str + "', type: '" + type + "'");
|
|
||||||
}
|
|
||||||
readFileCallback([tiddlerFields]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Tell the browser that we've handled the paste
|
// Tell the browser that we've handled the paste
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ ElementWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
if($tw.config.htmlUnsafeElements.indexOf(this.tag) !== -1) {
|
if($tw.config.htmlUnsafeElements.indexOf(this.tag) !== -1) {
|
||||||
this.tag = "safe-" + this.tag;
|
this.tag = "safe-" + this.tag;
|
||||||
}
|
}
|
||||||
|
// Restrict tag name to digits, letts and dashes
|
||||||
|
this.tag = this.tag.replace(/[^0-9a-zA-Z\-]/mg,"");
|
||||||
|
// Default to a span
|
||||||
|
this.tag = this.tag || "span";
|
||||||
// Adjust headings by the current base level
|
// Adjust headings by the current base level
|
||||||
var headingLevel = ["h1","h2","h3","h4","h5","h6"].indexOf(this.tag);
|
var headingLevel = ["h1","h2","h3","h4","h5","h6"].indexOf(this.tag);
|
||||||
if(headingLevel !== -1) {
|
if(headingLevel !== -1) {
|
||||||
@@ -42,16 +46,22 @@ ElementWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
this.tag = "h" + headingLevel;
|
this.tag = "h" + headingLevel;
|
||||||
}
|
}
|
||||||
// Select the namespace for the tag
|
// Select the namespace for the tag
|
||||||
var tagNamespaces = {
|
var XHTML_NAMESPACE = "http://www.w3.org/1999/xhtml",
|
||||||
|
tagNamespaces = {
|
||||||
svg: "http://www.w3.org/2000/svg",
|
svg: "http://www.w3.org/2000/svg",
|
||||||
math: "http://www.w3.org/1998/Math/MathML",
|
math: "http://www.w3.org/1998/Math/MathML",
|
||||||
body: "http://www.w3.org/1999/xhtml"
|
body: XHTML_NAMESPACE
|
||||||
};
|
};
|
||||||
this.namespace = tagNamespaces[this.tag];
|
this.namespace = tagNamespaces[this.tag];
|
||||||
if(this.namespace) {
|
if(this.namespace) {
|
||||||
this.setVariable("namespace",this.namespace);
|
this.setVariable("namespace",this.namespace);
|
||||||
} else {
|
} else {
|
||||||
this.namespace = this.getVariable("namespace",{defaultValue: "http://www.w3.org/1999/xhtml"});
|
if(this.hasAttribute("xmlns")) {
|
||||||
|
this.namespace = this.getAttribute("xmlns");
|
||||||
|
this.setVariable("namespace",this.namespace);
|
||||||
|
} else {
|
||||||
|
this.namespace = this.getVariable("namespace",{defaultValue: XHTML_NAMESPACE});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Invoke the th-rendering-element hook
|
// Invoke the th-rendering-element hook
|
||||||
var parseTreeNodes = $tw.hooks.invokeHook("th-rendering-element",null,this);
|
var parseTreeNodes = $tw.hooks.invokeHook("th-rendering-element",null,this);
|
||||||
|
|||||||
63
core/modules/widgets/error.js
Normal file
63
core/modules/widgets/error.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/widgets/error.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: widget
|
||||||
|
|
||||||
|
Error widget
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||||
|
|
||||||
|
var ErrorWidget = function(parseTreeNode,options) {
|
||||||
|
this.initialise(parseTreeNode,options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Inherit from the base widget class
|
||||||
|
*/
|
||||||
|
ErrorWidget.prototype = new Widget();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Render this widget into the DOM
|
||||||
|
*/
|
||||||
|
ErrorWidget.prototype.render = function(parent,nextSibling) {
|
||||||
|
this.parentDomNode = parent;
|
||||||
|
this.computeAttributes();
|
||||||
|
this.execute();
|
||||||
|
var message = this.getAttribute("$message","Unknown error"),
|
||||||
|
domNode = this.document.createElement("span");
|
||||||
|
domNode.appendChild(this.document.createTextNode(message));
|
||||||
|
domNode.className = "tc-error";
|
||||||
|
parent.insertBefore(domNode,nextSibling);
|
||||||
|
this.domNodes.push(domNode);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Compute the internal state of the widget
|
||||||
|
*/
|
||||||
|
ErrorWidget.prototype.execute = function() {
|
||||||
|
// Nothing to do for a text node
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||||
|
*/
|
||||||
|
ErrorWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
|
var changedAttributes = this.computeAttributes();
|
||||||
|
if(changedAttributes["$message"]) {
|
||||||
|
this.refreshSelf();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.error = ErrorWidget;
|
||||||
|
|
||||||
|
})();
|
||||||
@@ -72,33 +72,7 @@ EventWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
}
|
}
|
||||||
// Only set up variables if we have actions to invoke
|
// Only set up variables if we have actions to invoke
|
||||||
if(actions) {
|
if(actions) {
|
||||||
$tw.utils.each(selectedNode.attributes,function(attribute) {
|
variables = $tw.utils.collectDOMVariables(selectedNode,self.domNode,event);
|
||||||
variables["dom-" + attribute.name] = attribute.value.toString();
|
|
||||||
});
|
|
||||||
//Add a variable with a popup coordinate string for the selected node
|
|
||||||
variables["tv-popup-coords"] = "(" + selectedNode.offsetLeft + "," + selectedNode.offsetTop +"," + selectedNode.offsetWidth + "," + selectedNode.offsetHeight + ")";
|
|
||||||
|
|
||||||
//Add variables for offset of selected node
|
|
||||||
variables["tv-selectednode-posx"] = selectedNode.offsetLeft.toString();
|
|
||||||
variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString();
|
|
||||||
variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString();
|
|
||||||
variables["tv-selectednode-height"] = selectedNode.offsetHeight.toString();
|
|
||||||
|
|
||||||
if(event.clientX && event.clientY) {
|
|
||||||
//Add variables for event X and Y position relative to selected node
|
|
||||||
selectedNodeRect = selectedNode.getBoundingClientRect();
|
|
||||||
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
|
|
||||||
variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();
|
|
||||||
|
|
||||||
//Add variables for event X and Y position relative to event catcher node
|
|
||||||
catcherNodeRect = self.domNode.getBoundingClientRect();
|
|
||||||
variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
|
|
||||||
variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
|
|
||||||
|
|
||||||
//Add variables for event X and Y position relative to the viewport
|
|
||||||
variables["event-fromviewport-posx"] = event.clientX.toString();
|
|
||||||
variables["event-fromviewport-posy"] = event.clientY.toString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Execute our actions with the variables
|
// Execute our actions with the variables
|
||||||
|
|||||||
115
core/modules/widgets/genesis.js
Normal file
115
core/modules/widgets/genesis.js
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/widgets/genesis.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: widget
|
||||||
|
|
||||||
|
Genesis widget for dynamically creating widgets
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||||
|
|
||||||
|
var GenesisWidget = function(parseTreeNode,options) {
|
||||||
|
this.initialise(parseTreeNode,options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Inherit from the base widget class
|
||||||
|
*/
|
||||||
|
GenesisWidget.prototype = new Widget();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Render this widget into the DOM
|
||||||
|
*/
|
||||||
|
GenesisWidget.prototype.render = function(parent,nextSibling) {
|
||||||
|
this.parentDomNode = parent;
|
||||||
|
this.computeAttributes({filterFn: function(name) {
|
||||||
|
// Only compute our own attributes which start with a single dollar
|
||||||
|
return name.charAt(0) === "$" && name.charAt(1) !== "$";
|
||||||
|
}});
|
||||||
|
this.execute();
|
||||||
|
this.renderChildren(parent,nextSibling);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Compute the internal state of the widget
|
||||||
|
*/
|
||||||
|
GenesisWidget.prototype.execute = function() {
|
||||||
|
var self = this;
|
||||||
|
// Collect attributes
|
||||||
|
this.genesisType = this.getAttribute("$type");
|
||||||
|
this.genesisRemappable = this.getAttribute("$remappable","yes") === "yes";
|
||||||
|
this.genesisNames = this.getAttribute("$names","");
|
||||||
|
this.genesisValues = this.getAttribute("$values","");
|
||||||
|
this.genesisIsBlock = this.getAttribute("$mode",this.parseTreeNode.isBlock && "block") === "block";
|
||||||
|
// Do not create a child widget if the $type attribute is missing or blank
|
||||||
|
if(!this.genesisType) {
|
||||||
|
this.makeChildWidgets(this.parseTreeNode.children);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Construct parse tree
|
||||||
|
var isElementWidget = this.genesisType.charAt(0) !== "$",
|
||||||
|
nodeType = isElementWidget ? "element" : this.genesisType.substr(1),
|
||||||
|
nodeTag = isElementWidget ? this.genesisType : undefined;
|
||||||
|
var parseTreeNodes = [{
|
||||||
|
type: nodeType,
|
||||||
|
tag: nodeTag,
|
||||||
|
attributes: {},
|
||||||
|
orderedAttributes: [],
|
||||||
|
isBlock: this.genesisIsBlock,
|
||||||
|
children: this.parseTreeNode.children || [],
|
||||||
|
isNotRemappable: !this.genesisRemappable
|
||||||
|
}];
|
||||||
|
// Apply explicit attributes
|
||||||
|
$tw.utils.each($tw.utils.getOrderedAttributesFromParseTreeNode(this.parseTreeNode),function(attribute) {
|
||||||
|
var name = attribute.name;
|
||||||
|
if(name.charAt(0) === "$") {
|
||||||
|
if(name.charAt(1) === "$") {
|
||||||
|
// Double $$ is changed to a single $
|
||||||
|
name = name.substr(1);
|
||||||
|
} else {
|
||||||
|
// Single dollar is ignored
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],$tw.utils.extend({},attribute,{name: name}));
|
||||||
|
});
|
||||||
|
// Apply attributes in $names/$values
|
||||||
|
this.attributeNames = [];
|
||||||
|
this.attributeValues = [];
|
||||||
|
if(this.genesisNames && this.genesisValues) {
|
||||||
|
this.attributeNames = this.wiki.filterTiddlers(self.genesisNames,this);
|
||||||
|
this.attributeValues = this.wiki.filterTiddlers(self.genesisValues,this);
|
||||||
|
$tw.utils.each(this.attributeNames,function(varname,index) {
|
||||||
|
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],varname,self.attributeValues[index] || "");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Construct the child widgets
|
||||||
|
this.makeChildWidgets(parseTreeNodes);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||||
|
*/
|
||||||
|
GenesisWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
|
var changedAttributes = this.computeAttributes(),
|
||||||
|
filterNames = this.getAttribute("$names",""),
|
||||||
|
filterValues = this.getAttribute("$values",""),
|
||||||
|
attributeNames = this.wiki.filterTiddlers(filterNames,this),
|
||||||
|
attributeValues = this.wiki.filterTiddlers(filterValues,this);
|
||||||
|
if($tw.utils.count(changedAttributes) > 0 || !$tw.utils.isArrayEqual(this.attributeNames,attributeNames) || !$tw.utils.isArrayEqual(this.attributeValues,attributeValues)) {
|
||||||
|
this.refreshSelf();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return this.refreshChildren(changedTiddlers);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.genesis = GenesisWidget;
|
||||||
|
|
||||||
|
})();
|
||||||
@@ -111,6 +111,9 @@ ImageWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
if(this.imageAlt) {
|
if(this.imageAlt) {
|
||||||
domNode.setAttribute("alt",this.imageAlt);
|
domNode.setAttribute("alt",this.imageAlt);
|
||||||
}
|
}
|
||||||
|
if(this.lazyLoading && tag === "img") {
|
||||||
|
domNode.setAttribute("loading",this.lazyLoading);
|
||||||
|
}
|
||||||
// Add classes when the image loads or fails
|
// Add classes when the image loads or fails
|
||||||
$tw.utils.addClass(domNode,"tc-image-loading");
|
$tw.utils.addClass(domNode,"tc-image-loading");
|
||||||
domNode.addEventListener("load",function() {
|
domNode.addEventListener("load",function() {
|
||||||
@@ -137,6 +140,7 @@ ImageWidget.prototype.execute = function() {
|
|||||||
this.imageClass = this.getAttribute("class");
|
this.imageClass = this.getAttribute("class");
|
||||||
this.imageTooltip = this.getAttribute("tooltip");
|
this.imageTooltip = this.getAttribute("tooltip");
|
||||||
this.imageAlt = this.getAttribute("alt");
|
this.imageAlt = this.getAttribute("alt");
|
||||||
|
this.lazyLoading = this.getAttribute("loading");
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -39,7 +39,10 @@ Compute the internal state of the widget
|
|||||||
ImportVariablesWidget.prototype.execute = function(tiddlerList) {
|
ImportVariablesWidget.prototype.execute = function(tiddlerList) {
|
||||||
var widgetPointer = this;
|
var widgetPointer = this;
|
||||||
// Got to flush all the accumulated variables
|
// Got to flush all the accumulated variables
|
||||||
this.variables = new this.variablesConstructor();
|
this.variables = Object.create(null);
|
||||||
|
if(this.parentWidget) {
|
||||||
|
Object.setPrototypeOf(this.variables,this.parentWidget.variables);
|
||||||
|
}
|
||||||
// Get our parameters
|
// Get our parameters
|
||||||
this.filter = this.getAttribute("filter");
|
this.filter = this.getAttribute("filter");
|
||||||
// Compute the filter
|
// Compute the filter
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ KeyboardWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
KeyboardWidget.prototype.handleChangeEvent = function(event) {
|
KeyboardWidget.prototype.handleChangeEvent = function(event) {
|
||||||
|
if ($tw.keyboardManager.handleKeydownEvent(event, {onlyPriority: true})) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
var keyInfo = $tw.keyboardManager.getMatchingKeyDescriptor(event,this.keyInfoArray);
|
var keyInfo = $tw.keyboardManager.getMatchingKeyDescriptor(event,this.keyInfoArray);
|
||||||
if(keyInfo) {
|
if(keyInfo) {
|
||||||
var handled = this.invokeActions(this,event);
|
var handled = this.invokeActions(this,event);
|
||||||
|
|||||||
@@ -48,14 +48,12 @@ LetWidget.prototype.computeAttributes = function() {
|
|||||||
var changedAttributes = {},
|
var changedAttributes = {},
|
||||||
self = this;
|
self = this;
|
||||||
this.currentValueFor = Object.create(null);
|
this.currentValueFor = Object.create(null);
|
||||||
$tw.utils.each(this.parseTreeNode.orderedAttributes,function(attribute,index) {
|
$tw.utils.each($tw.utils.getOrderedAttributesFromParseTreeNode(this.parseTreeNode),function(attribute) {
|
||||||
var value = self.computeAttribute(attribute),
|
var value = self.computeAttribute(attribute),
|
||||||
name = attribute.name;
|
name = attribute.name;
|
||||||
if(name.charAt(0) !== "$") {
|
// Now that it's prepped, we're allowed to look this variable up
|
||||||
// Now that it's prepped, we're allowed to look this variable up
|
// when defining later variables
|
||||||
// when defining later variables
|
self.currentValueFor[name] = value;
|
||||||
self.currentValueFor[name] = value;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
// Run through again, setting variables and looking for differences
|
// Run through again, setting variables and looking for differences
|
||||||
$tw.utils.each(this.currentValueFor,function(value,name) {
|
$tw.utils.each(this.currentValueFor,function(value,name) {
|
||||||
@@ -76,7 +74,9 @@ LetWidget.prototype.getVariableInfo = function(name,options) {
|
|||||||
text: this.currentValueFor[name]
|
text: this.currentValueFor[name]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return Widget.prototype.getVariableInfo.call(this,name,options);
|
return Widget.prototype.getVariableInfo.call(this,name,$tw.utils.extend(Object.create(null),options,{
|
||||||
|
defaultValue: ""
|
||||||
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -97,8 +97,8 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
|
|||||||
// Expand the tv-wikilink-template variable to construct the href
|
// Expand the tv-wikilink-template variable to construct the href
|
||||||
var wikiLinkTemplateMacro = this.getVariable("tv-wikilink-template"),
|
var wikiLinkTemplateMacro = this.getVariable("tv-wikilink-template"),
|
||||||
wikiLinkTemplate = wikiLinkTemplateMacro ? wikiLinkTemplateMacro.trim() : "#$uri_encoded$";
|
wikiLinkTemplate = wikiLinkTemplateMacro ? wikiLinkTemplateMacro.trim() : "#$uri_encoded$";
|
||||||
wikiLinkText = $tw.utils.replaceString(wikiLinkTemplate,"$uri_encoded$",encodeURIComponent(this.to));
|
wikiLinkText = $tw.utils.replaceString(wikiLinkTemplate,"$uri_encoded$",$tw.utils.encodeURIComponentExtended(this.to));
|
||||||
wikiLinkText = $tw.utils.replaceString(wikiLinkText,"$uri_doubleencoded$",encodeURIComponent(encodeURIComponent(this.to)));
|
wikiLinkText = $tw.utils.replaceString(wikiLinkText,"$uri_doubleencoded$",$tw.utils.encodeURIComponentExtended($tw.utils.encodeURIComponentExtended(this.to)));
|
||||||
}
|
}
|
||||||
// Override with the value of tv-get-export-link if defined
|
// Override with the value of tv-get-export-link if defined
|
||||||
wikiLinkText = this.getVariable("tv-get-export-link",{params: [{name: "to",value: this.to}],defaultValue: wikiLinkText});
|
wikiLinkText = this.getVariable("tv-get-export-link",{params: [{name: "to",value: this.to}],defaultValue: wikiLinkText});
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ MessageCatcherWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Render children
|
// Render children
|
||||||
this.renderChildren(parent,null);
|
this.renderChildren(parent,nextSibling);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -227,10 +227,7 @@ NavigatorWidget.prototype.handleDeleteTiddlerEvent = function(event) {
|
|||||||
originalTitle = tiddler ? tiddler.fields["draft.of"] : "",
|
originalTitle = tiddler ? tiddler.fields["draft.of"] : "",
|
||||||
originalTiddler = originalTitle ? this.wiki.getTiddler(originalTitle) : undefined,
|
originalTiddler = originalTitle ? this.wiki.getTiddler(originalTitle) : undefined,
|
||||||
confirmationTitle,
|
confirmationTitle,
|
||||||
win = event.event && event.event.view ? event.event.view : window;
|
win = event.event && event.event.view ? event.event.view : window;
|
||||||
if(!tiddler) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Check if the tiddler we're deleting is in draft mode
|
// Check if the tiddler we're deleting is in draft mode
|
||||||
if(originalTitle) {
|
if(originalTitle) {
|
||||||
// If so, we'll prompt for confirmation referencing the original tiddler
|
// If so, we'll prompt for confirmation referencing the original tiddler
|
||||||
@@ -240,7 +237,7 @@ NavigatorWidget.prototype.handleDeleteTiddlerEvent = function(event) {
|
|||||||
confirmationTitle = title;
|
confirmationTitle = title;
|
||||||
}
|
}
|
||||||
// Seek confirmation
|
// Seek confirmation
|
||||||
if((this.wiki.getTiddler(originalTitle) || (tiddler.fields.text || "") !== "") && !win.confirm($tw.language.getString(
|
if(((originalTitle && this.wiki.getTiddler(originalTitle)) || (tiddler && ((tiddler.fields.text || "") !== ""))) && !win.confirm($tw.language.getString(
|
||||||
"ConfirmDeleteTiddler",
|
"ConfirmDeleteTiddler",
|
||||||
{variables:
|
{variables:
|
||||||
{title: confirmationTitle}
|
{title: confirmationTitle}
|
||||||
@@ -257,8 +254,10 @@ NavigatorWidget.prototype.handleDeleteTiddlerEvent = function(event) {
|
|||||||
this.removeTitleFromStory(storyList,originalTitle);
|
this.removeTitleFromStory(storyList,originalTitle);
|
||||||
}
|
}
|
||||||
// Invoke the hook function and delete this tiddler
|
// Invoke the hook function and delete this tiddler
|
||||||
$tw.hooks.invokeHook("th-deleting-tiddler",tiddler);
|
if(tiddler) {
|
||||||
this.wiki.deleteTiddler(title);
|
$tw.hooks.invokeHook("th-deleting-tiddler",tiddler);
|
||||||
|
this.wiki.deleteTiddler(title);
|
||||||
|
}
|
||||||
// Remove the closed tiddler from the story
|
// Remove the closed tiddler from the story
|
||||||
this.removeTitleFromStory(storyList,title);
|
this.removeTitleFromStory(storyList,title);
|
||||||
this.saveStoryList(storyList);
|
this.saveStoryList(storyList);
|
||||||
@@ -500,7 +499,8 @@ NavigatorWidget.prototype.handleImportTiddlersEvent = function(event) {
|
|||||||
// Get the tiddlers
|
// Get the tiddlers
|
||||||
var tiddlers = $tw.utils.parseJSONSafe(event.param,[]);
|
var tiddlers = $tw.utils.parseJSONSafe(event.param,[]);
|
||||||
// Get the current $:/Import tiddler
|
// Get the current $:/Import tiddler
|
||||||
var importTitle = event.importTitle ? event.importTitle : IMPORT_TITLE,
|
var paramObject = event.paramObject || {},
|
||||||
|
importTitle = event.importTitle || paramObject.importTitle || IMPORT_TITLE,
|
||||||
importTiddler = this.wiki.getTiddler(importTitle),
|
importTiddler = this.wiki.getTiddler(importTitle),
|
||||||
importData = this.wiki.getTiddlerData(importTitle,{}),
|
importData = this.wiki.getTiddlerData(importTitle,{}),
|
||||||
newFields = new Object({
|
newFields = new Object({
|
||||||
@@ -541,7 +541,7 @@ NavigatorWidget.prototype.handleImportTiddlersEvent = function(event) {
|
|||||||
newFields.text = JSON.stringify(importData,null,$tw.config.preferences.jsonSpaces);
|
newFields.text = JSON.stringify(importData,null,$tw.config.preferences.jsonSpaces);
|
||||||
this.wiki.addTiddler(new $tw.Tiddler(importTiddler,newFields));
|
this.wiki.addTiddler(new $tw.Tiddler(importTiddler,newFields));
|
||||||
// Update the story and history details
|
// Update the story and history details
|
||||||
var autoOpenOnImport = event.autoOpenOnImport ? event.autoOpenOnImport : this.getVariable("tv-auto-open-on-import");
|
var autoOpenOnImport = event.autoOpenOnImport || paramObject.autoOpenOnImport || this.getVariable("tv-auto-open-on-import");
|
||||||
if(autoOpenOnImport !== "no") {
|
if(autoOpenOnImport !== "no") {
|
||||||
var storyList = this.getStoryList(),
|
var storyList = this.getStoryList(),
|
||||||
history = [];
|
history = [];
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ Reveal widget
|
|||||||
|
|
||||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||||
|
|
||||||
|
var Popup = require("$:/core/modules/utils/dom/popup.js");
|
||||||
|
|
||||||
var RevealWidget = function(parseTreeNode,options) {
|
var RevealWidget = function(parseTreeNode,options) {
|
||||||
this.initialise(parseTreeNode,options);
|
this.initialise(parseTreeNode,options);
|
||||||
};
|
};
|
||||||
@@ -94,6 +96,13 @@ RevealWidget.prototype.positionPopup = function(domNode) {
|
|||||||
left = Math.max(0,left);
|
left = Math.max(0,left);
|
||||||
top = Math.max(0,top);
|
top = Math.max(0,top);
|
||||||
}
|
}
|
||||||
|
if (this.popup.absolute) {
|
||||||
|
// Traverse the offsetParent chain and correct the offset to make it relative to the parent node.
|
||||||
|
for (var offsetParentDomNode = domNode.offsetParent; offsetParentDomNode; offsetParentDomNode = offsetParentDomNode.offsetParent) {
|
||||||
|
left -= offsetParentDomNode.offsetLeft;
|
||||||
|
top -= offsetParentDomNode.offsetTop;
|
||||||
|
}
|
||||||
|
}
|
||||||
domNode.style.left = left + "px";
|
domNode.style.left = left + "px";
|
||||||
domNode.style.top = top + "px";
|
domNode.style.top = top + "px";
|
||||||
};
|
};
|
||||||
@@ -183,19 +192,11 @@ RevealWidget.prototype.compareStateText = function(state) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
RevealWidget.prototype.readPopupState = function(state) {
|
RevealWidget.prototype.readPopupState = function(state) {
|
||||||
var popupLocationRegExp = /^\((-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+)\)$/,
|
this.popup = Popup.parseCoordinates(state);
|
||||||
match = popupLocationRegExp.exec(state);
|
|
||||||
// Check if the state matches the location regexp
|
// Check if the state matches the location regexp
|
||||||
if(match) {
|
if(this.popup) {
|
||||||
// If so, we're open
|
// If so, we're open
|
||||||
this.isOpen = true;
|
this.isOpen = true;
|
||||||
// Get the location
|
|
||||||
this.popup = {
|
|
||||||
left: parseFloat(match[1]),
|
|
||||||
top: parseFloat(match[2]),
|
|
||||||
width: parseFloat(match[3]),
|
|
||||||
height: parseFloat(match[4])
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
// If not, we're closed
|
// If not, we're closed
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
|
|||||||
@@ -159,6 +159,8 @@ ScrollableWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
// Create elements
|
// Create elements
|
||||||
this.outerDomNode = this.document.createElement("div");
|
this.outerDomNode = this.document.createElement("div");
|
||||||
$tw.utils.setStyle(this.outerDomNode,[
|
$tw.utils.setStyle(this.outerDomNode,[
|
||||||
|
{overflowY: "auto"},
|
||||||
|
{overflowX: "auto"},
|
||||||
{webkitOverflowScrolling: "touch"}
|
{webkitOverflowScrolling: "touch"}
|
||||||
]);
|
]);
|
||||||
this.innerDomNode = this.document.createElement("div");
|
this.innerDomNode = this.document.createElement("div");
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user