mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-24 11:54:41 +00:00
Compare commits
367 Commits
v5.0.9-bet
...
v5.0.13-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cca9092ef | ||
|
|
b594eb5b36 | ||
|
|
917c4404e5 | ||
|
|
6f3e31abe5 | ||
|
|
5962600cb6 | ||
|
|
cf3f11a4c0 | ||
|
|
bcf37c765f | ||
|
|
248029b53a | ||
|
|
57c534b97d | ||
|
|
6d1eaeb0fc | ||
|
|
680fe41ed7 | ||
|
|
32a1da7673 | ||
|
|
8d78336e9b | ||
|
|
9987e6de22 | ||
|
|
38530f14f2 | ||
|
|
0fae9ee992 | ||
|
|
12b5ebb946 | ||
|
|
5120a1b32b | ||
|
|
9a2d650868 | ||
|
|
ad74877dad | ||
|
|
b77ad3061d | ||
|
|
31b1e073a6 | ||
|
|
5d88f19ec6 | ||
|
|
133c24e9c7 | ||
|
|
f15eba66fe | ||
|
|
911a64221a | ||
|
|
424c0737a2 | ||
|
|
0b38cd640c | ||
|
|
32099b85d3 | ||
|
|
71aa2bbe5f | ||
|
|
fb5c44a875 | ||
|
|
f12d7bb6c0 | ||
|
|
665e490d33 | ||
|
|
76f637d57a | ||
|
|
2ccc13b936 | ||
|
|
0206358a1c | ||
|
|
f3a466ee86 | ||
|
|
0c48502e8e | ||
|
|
19061650de | ||
|
|
c2b08b43b5 | ||
|
|
a2ec4c55e3 | ||
|
|
5eae2f0fb6 | ||
|
|
b8aedf2ca3 | ||
|
|
2d24d05f61 | ||
|
|
44cb3bc100 | ||
|
|
0cf4e5514c | ||
|
|
1717c93d00 | ||
|
|
0bdc5b5c70 | ||
|
|
1945af0b2d | ||
|
|
e6b783154f | ||
|
|
d2d0b09235 | ||
|
|
e28c2e8b06 | ||
|
|
2e2d30bae9 | ||
|
|
a9b7df96c2 | ||
|
|
b2e48d00e9 | ||
|
|
9147cadd3c | ||
|
|
4951a53063 | ||
|
|
36556b817f | ||
|
|
8bd19c4e6a | ||
|
|
34e4166dc5 | ||
|
|
617963bd88 | ||
|
|
346b2f8611 | ||
|
|
6f859c8d44 | ||
|
|
325a93f3c3 | ||
|
|
06b0f9adb7 | ||
|
|
401349a1d6 | ||
|
|
bc9b67cbc3 | ||
|
|
6fb992690d | ||
|
|
57f3eb0b2c | ||
|
|
bf2f88ba8b | ||
|
|
00d041b778 | ||
|
|
eeedcb6d94 | ||
|
|
b4ddaccd1d | ||
|
|
d83c26fe3b | ||
|
|
1c484f59bd | ||
|
|
149ca0fc63 | ||
|
|
f467ae288b | ||
|
|
457764077b | ||
|
|
892900c9c5 | ||
|
|
d880cb135a | ||
|
|
a858329742 | ||
|
|
e44450edc4 | ||
|
|
f09d69d1b7 | ||
|
|
eee3a0cf8e | ||
|
|
4238af2a40 | ||
|
|
f54f0d1c3e | ||
|
|
ca34cc437c | ||
|
|
71c886e3a1 | ||
|
|
db147e3673 | ||
|
|
525613750b | ||
|
|
f751e2ecb4 | ||
|
|
ea5989048c | ||
|
|
eec849c69e | ||
|
|
666f243a82 | ||
|
|
4e5fa2c6e6 | ||
|
|
9ab0c84140 | ||
|
|
9261bdaa43 | ||
|
|
0e09fbf46a | ||
|
|
9547a1f01c | ||
|
|
0e4afc3986 | ||
|
|
10fa72d15e | ||
|
|
f131c37893 | ||
|
|
d2796d0c9c | ||
|
|
460f476aef | ||
|
|
2989c9b133 | ||
|
|
3105afe6e8 | ||
|
|
a03a15e7de | ||
|
|
305617b632 | ||
|
|
b446ef5d4e | ||
|
|
8dd30e97ac | ||
|
|
fc6d96672d | ||
|
|
78791192c3 | ||
|
|
9b576f2a8d | ||
|
|
08ed0017af | ||
|
|
450c646c31 | ||
|
|
0c6c5002c1 | ||
|
|
9b3b08a176 | ||
|
|
6386bf84a5 | ||
|
|
c3dfa3f27e | ||
|
|
50223562ea | ||
|
|
85c7da95bb | ||
|
|
c8e98c1567 | ||
|
|
13463a47c5 | ||
|
|
ffd9df670d | ||
|
|
d2edd9291e | ||
|
|
247eb04b11 | ||
|
|
954946352a | ||
|
|
0ccaedd7d2 | ||
|
|
3182a2d599 | ||
|
|
f999b2e931 | ||
|
|
4d70d5780e | ||
|
|
a330cb543e | ||
|
|
64a6544b02 | ||
|
|
3f25db0abe | ||
|
|
412cde6f53 | ||
|
|
f7b8813a27 | ||
|
|
62c602e9d2 | ||
|
|
d8a142fed5 | ||
|
|
1b37d660ea | ||
|
|
da273be054 | ||
|
|
a463859a28 | ||
|
|
9aaa000d3f | ||
|
|
f14ecf4eb8 | ||
|
|
128ad01866 | ||
|
|
ecbda326cb | ||
|
|
e24600f9bb | ||
|
|
6436dc22a7 | ||
|
|
f44f2b33ed | ||
|
|
86d182fd51 | ||
|
|
3fa4b00ede | ||
|
|
d30cb0f11d | ||
|
|
906d2db57e | ||
|
|
3e6de03f15 | ||
|
|
aaec1b2854 | ||
|
|
9edebc78e7 | ||
|
|
e228ac42db | ||
|
|
be0bc04929 | ||
|
|
b415b0e90e | ||
|
|
974aecba1f | ||
|
|
47fa18c2e0 | ||
|
|
d5094463f4 | ||
|
|
5951dc5901 | ||
|
|
1d15e4b7d3 | ||
|
|
67e66b4698 | ||
|
|
c00940f2d1 | ||
|
|
81ea326e16 | ||
|
|
c2f52f8a4b | ||
|
|
ca03984663 | ||
|
|
b2ff248d07 | ||
|
|
658bd2b8a3 | ||
|
|
a8b16c9c07 | ||
|
|
157ca0c8aa | ||
|
|
01b3962b2c | ||
|
|
19646c7f95 | ||
|
|
dfb8a07204 | ||
|
|
93566cdc33 | ||
|
|
ad8a20bfed | ||
|
|
00cddd3713 | ||
|
|
23c8902e70 | ||
|
|
818fd598dc | ||
|
|
31e1088aa7 | ||
|
|
f9f8ad725b | ||
|
|
81e1af1d35 | ||
|
|
c9c1b0fbb4 | ||
|
|
f7ce0c0b8d | ||
|
|
92aa1f24be | ||
|
|
e0a6c4e879 | ||
|
|
f72c177ba5 | ||
|
|
9a26c4259a | ||
|
|
6de6a43623 | ||
|
|
2fa3c8a4ed | ||
|
|
295094c9a3 | ||
|
|
da41879fc1 | ||
|
|
f8708874bc | ||
|
|
ad43958571 | ||
|
|
4e07b3335b | ||
|
|
b77d5f9725 | ||
|
|
75fee26b58 | ||
|
|
e8c9d78079 | ||
|
|
d972988a53 | ||
|
|
e83759e86d | ||
|
|
2633247492 | ||
|
|
b3032d452f | ||
|
|
e60fc9f81f | ||
|
|
6ab68e0fca | ||
|
|
e548dd35af | ||
|
|
8b20143b1b | ||
|
|
711b76307c | ||
|
|
b858e9dc69 | ||
|
|
a9411262f7 | ||
|
|
e676156b24 | ||
|
|
c592e658e7 | ||
|
|
6b03789e06 | ||
|
|
51f54b06f9 | ||
|
|
285ab41ccf | ||
|
|
854b739a35 | ||
|
|
abe0ce28b9 | ||
|
|
76e8640c31 | ||
|
|
cc3d44aec1 | ||
|
|
7b6cff0cca | ||
|
|
d1c85f53c0 | ||
|
|
e2b0da0b58 | ||
|
|
7c8c5cf745 | ||
|
|
38c60bd7d4 | ||
|
|
afb92c40fe | ||
|
|
6b45296ca9 | ||
|
|
b84c663215 | ||
|
|
4e101e240c | ||
|
|
56251dc1f8 | ||
|
|
f368175cb0 | ||
|
|
3e49dd65a0 | ||
|
|
f5ada72dac | ||
|
|
986a20b22b | ||
|
|
ffb6c8ab81 | ||
|
|
e58e68fa7c | ||
|
|
95def8b857 | ||
|
|
b24ec8009d | ||
|
|
9965c64b6f | ||
|
|
2a50277219 | ||
|
|
3cce12e13f | ||
|
|
887e9d978b | ||
|
|
a0022a1cd6 | ||
|
|
519e1b4a44 | ||
|
|
b9dec37fb7 | ||
|
|
09156af475 | ||
|
|
5b5621a600 | ||
|
|
78ba57d55d | ||
|
|
749582ede0 | ||
|
|
1c82348edb | ||
|
|
b96aade28a | ||
|
|
2f32621024 | ||
|
|
6ccf02ed96 | ||
|
|
b2c1331c11 | ||
|
|
f81df69395 | ||
|
|
a5e9ef9b5f | ||
|
|
7783378603 | ||
|
|
327b53a641 | ||
|
|
cb914ae853 | ||
|
|
a4294b55f0 | ||
|
|
bced7124e4 | ||
|
|
f5848c395a | ||
|
|
f6bd3b8c37 | ||
|
|
21b2d6fdc7 | ||
|
|
bd3e955821 | ||
|
|
fcb26419a6 | ||
|
|
a6f7da6c1c | ||
|
|
f82f8ae7c6 | ||
|
|
edb8c65d54 | ||
|
|
031c0f4146 | ||
|
|
e8316cf0ac | ||
|
|
0ac4c2b554 | ||
|
|
84cd296c58 | ||
|
|
a90339d1e5 | ||
|
|
d49495ab73 | ||
|
|
5fa6d001f8 | ||
|
|
f17dafefcb | ||
|
|
88314d968a | ||
|
|
28bab707b9 | ||
|
|
075cf544e4 | ||
|
|
a505b6ffc0 | ||
|
|
23a71b433e | ||
|
|
3bbe53a58e | ||
|
|
8556e0ea49 | ||
|
|
3be21853e1 | ||
|
|
d0636f2124 | ||
|
|
5226c7a2fa | ||
|
|
3a78465d2d | ||
|
|
23640d7af4 | ||
|
|
540681b2bc | ||
|
|
8611867930 | ||
|
|
77152ac577 | ||
|
|
f5bd99fa73 | ||
|
|
385c7e207c | ||
|
|
61c204366f | ||
|
|
570cad1c7f | ||
|
|
1d0dc60a2d | ||
|
|
fac0affa7b | ||
|
|
f57241abbd | ||
|
|
e9557b578e | ||
|
|
649f68288a | ||
|
|
37c50bae61 | ||
|
|
9ab31e37ea | ||
|
|
30707e2f19 | ||
|
|
1fb76ae56d | ||
|
|
4008191459 | ||
|
|
463bd0517c | ||
|
|
fb3a31ae43 | ||
|
|
f7e50e0950 | ||
|
|
552657fc58 | ||
|
|
d727046948 | ||
|
|
f6ca7d92e5 | ||
|
|
148e77b0e4 | ||
|
|
cc60ad1428 | ||
|
|
fecf3a556f | ||
|
|
39ef0ad88f | ||
|
|
f75826224b | ||
|
|
52f28a1cc3 | ||
|
|
61c3f8a5ba | ||
|
|
13da54b9bd | ||
|
|
680414d1c5 | ||
|
|
2c7d5c5964 | ||
|
|
3d69c929d9 | ||
|
|
8cbcfee346 | ||
|
|
43173c801f | ||
|
|
523faf71fb | ||
|
|
ad2bbb2c93 | ||
|
|
8756d25d78 | ||
|
|
8a27c2759b | ||
|
|
beddcd7138 | ||
|
|
2db90378a2 | ||
|
|
7684891285 | ||
|
|
821f1f1428 | ||
|
|
4538f081ee | ||
|
|
b4122be50c | ||
|
|
cd76514105 | ||
|
|
ba576d9f1b | ||
|
|
15d0c27e2a | ||
|
|
869cec1ccc | ||
|
|
d6054f1039 | ||
|
|
9fbe72a877 | ||
|
|
89165fc51d | ||
|
|
4758874d13 | ||
|
|
0153fd2a30 | ||
|
|
bb42c0ab36 | ||
|
|
95d291daac | ||
|
|
45b0966013 | ||
|
|
de07da3797 | ||
|
|
aebc1ea943 | ||
|
|
73cfd10218 | ||
|
|
d336ffea02 | ||
|
|
6da28e7365 | ||
|
|
d08a2d109f | ||
|
|
f57e047877 | ||
|
|
df5fe10a40 | ||
|
|
433ac8e96e | ||
|
|
ad4b03506a | ||
|
|
ace57dd205 | ||
|
|
bd4a031df8 | ||
|
|
6db94052c7 | ||
|
|
dd8797223a | ||
|
|
e54b0d7129 | ||
|
|
07ab8c75b8 | ||
|
|
5bcc666f34 | ||
|
|
6bef1d6b30 | ||
|
|
09cf788063 | ||
|
|
4d0b08d464 | ||
|
|
5447420832 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
.DS_Store
|
||||
tmp/
|
||||
output/
|
||||
|
||||
16
2bld.cmd
16
2bld.cmd
@@ -2,22 +2,13 @@
|
||||
|
||||
rem build TiddlyWiki 2.x
|
||||
|
||||
rem create a temporary directory if it doesn't already exist
|
||||
setlocal enableextensions
|
||||
mkdir tmp\tw2
|
||||
setlocal disableextensions
|
||||
|
||||
rem Delete any existing content
|
||||
|
||||
del /q /s tmp\tw2
|
||||
echo.
|
||||
|
||||
rem Prepare the readme file from the revelant content in the tw5.com wiki
|
||||
|
||||
node .\tiddlywiki.js ^
|
||||
editions\tw5.com ^
|
||||
--verbose ^
|
||||
--rendertiddler TiddlyWiki2ReadMe editions\tw2\readme.md text/html ^
|
||||
--output editions\tw2 ^
|
||||
--rendertiddler TiddlyWiki2ReadMe readme.md text/html ^
|
||||
|| exit 1
|
||||
|
||||
rem cook the TiddlyWiki 2.x.x index file
|
||||
@@ -25,8 +16,9 @@ rem cook the TiddlyWiki 2.x.x index file
|
||||
node .\tiddlywiki.js ^
|
||||
editions\tw2 ^
|
||||
--verbose ^
|
||||
--output tmp\tw2 ^
|
||||
--load editions\tw2\source\tiddlywiki.com\index.html.recipe ^
|
||||
--rendertiddler $:/core/templates/tiddlywiki2.template.html .\tmp\tw2\index.html text/plain ^
|
||||
--rendertiddler $:/core/templates/tiddlywiki2.template.html index.html text/plain ^
|
||||
|| exit 1
|
||||
|
||||
fc tmp\tw2\index.html editions\tw2\target\prebuilt.html
|
||||
|
||||
10
2bld.sh
10
2bld.sh
@@ -2,16 +2,13 @@
|
||||
|
||||
# build TiddlyWiki 2.x
|
||||
|
||||
# create a temporary directory if it doesn't already exist
|
||||
mkdir -p tmp
|
||||
mkdir -p tmp/tw2
|
||||
|
||||
# Prepare the readme file from the revelant content in the tw5.com wiki
|
||||
|
||||
node ./tiddlywiki.js \
|
||||
editions/tw5.com \
|
||||
--verbose \
|
||||
--rendertiddler TiddlyWiki2ReadMe editions/tw2/readme.md text/html \
|
||||
--output editions/tw2 \
|
||||
--rendertiddler TiddlyWiki2ReadMe readme.md text/html \
|
||||
|| exit 1
|
||||
|
||||
# cook the TiddlyWiki 2.x.x index file
|
||||
@@ -19,8 +16,9 @@ node ./tiddlywiki.js \
|
||||
node ./tiddlywiki.js \
|
||||
editions/tw2 \
|
||||
--verbose \
|
||||
--output tmp/tw2 \
|
||||
--load editions/tw2/source/tiddlywiki.com/index.html.recipe \
|
||||
--rendertiddler $:/core/templates/tiddlywiki2.template.html ./tmp/tw2/index.html text/plain \
|
||||
--rendertiddler $:/core/templates/tiddlywiki2.template.html index.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
diff -q tmp/tw2/index.html editions/tw2/target/prebuilt.html
|
||||
|
||||
@@ -25,28 +25,32 @@ echo "tiddlywiki.com" > $TW5_BUILD_OUTPUT/CNAME
|
||||
node ./tiddlywiki.js \
|
||||
./editions/de-AT-DE \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/save/all $TW5_BUILD_OUTPUT/de-AT-DE.html text/plain \
|
||||
--savetiddler $:/favicon.ico $TW5_BUILD_OUTPUT/favicon.ico \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all de-AT-DE.html text/plain \
|
||||
--savetiddler $:/favicon.ico favicon.ico \
|
||||
|| exit 1
|
||||
|
||||
node ./tiddlywiki.js \
|
||||
./editions/zh-Hant \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/save/all $TW5_BUILD_OUTPUT/zh-Hant.html text/plain \
|
||||
--savetiddler $:/favicon.ico $TW5_BUILD_OUTPUT/favicon.ico \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all zh-Hant.html text/plain \
|
||||
--savetiddler $:/favicon.ico favicon.ico \
|
||||
|| exit 1
|
||||
|
||||
node ./tiddlywiki.js \
|
||||
./editions/zh-Hans \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/save/all $TW5_BUILD_OUTPUT/zh-Hans.html text/plain \
|
||||
--savetiddler $:/favicon.ico $TW5_BUILD_OUTPUT/favicon.ico \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all zh-Hans.html text/plain \
|
||||
--savetiddler $:/favicon.ico favicon.ico \
|
||||
|| exit 1
|
||||
|
||||
node ./tiddlywiki.js \
|
||||
./editions/fr-FR \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/save/all $TW5_BUILD_OUTPUT/fr-FR.html text/plain \
|
||||
--savetiddler $:/favicon.ico $TW5_BUILD_OUTPUT/favicon.ico \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all fr-FR.html text/plain \
|
||||
--savetiddler $:/favicon.ico favicon.ico \
|
||||
|| exit 1
|
||||
|
||||
|
||||
35
bld.cmd
35
bld.cmd
@@ -34,18 +34,10 @@ rem static.html: the static version of the default tiddlers
|
||||
node .\tiddlywiki.js ^
|
||||
.\editions\tw5.com ^
|
||||
--verbose ^
|
||||
--rendertiddler $:/core/save/all %TW5_BUILD_OUTPUT%\index.html text/plain ^
|
||||
--savetiddler $:/favicon.ico %TW5_BUILD_OUTPUT%\favicon.ico ^
|
||||
--rendertiddler ReadMe .\readme.md text/html ^
|
||||
--rendertiddler ContributingTemplate .\contributing.md text/html ^
|
||||
--rendertiddler $:/core/copyright.txt .\licenses\copyright.md text/plain ^
|
||||
--rendertiddler $:/editions/tw5.com/download-empty %TW5_BUILD_OUTPUT%\empty.html text/plain ^
|
||||
--rendertiddler $:/editions/tw5.com/download-empty %TW5_BUILD_OUTPUT%\empty.hta text/plain ^
|
||||
--savetiddler $:/green_favicon.ico %TW5_BUILD_OUTPUT%/static/favicon.ico ^
|
||||
--rendertiddler $:/core/templates/static.template.html %TW5_BUILD_OUTPUT%\static.html text/plain ^
|
||||
--rendertiddler $:/core/templates/alltiddlers.template.html %TW5_BUILD_OUTPUT%\alltiddlers.html text/plain ^
|
||||
--rendertiddler $:/core/templates/static.template.css %TW5_BUILD_OUTPUT%\static\static.css text/plain ^
|
||||
--rendertiddlers [!is[system]] $:/core/templates/static.tiddler.html %TW5_BUILD_OUTPUT%\static text/plain ^
|
||||
--output . ^
|
||||
--build readmes ^
|
||||
--output %TW5_BUILD_OUTPUT% ^
|
||||
--build favicon empty static index ^
|
||||
|| exit 1
|
||||
|
||||
rem encrypted.html: a version of the main file encrypted with the password "password"
|
||||
@@ -53,8 +45,8 @@ rem encrypted.html: a version of the main file encrypted with the password "pass
|
||||
node .\tiddlywiki.js ^
|
||||
.\editions\tw5.com ^
|
||||
--verbose ^
|
||||
--password password ^
|
||||
--rendertiddler $:/core/save/all %TW5_BUILD_OUTPUT%\encrypted.html text/plain ^
|
||||
--output %TW5_BUILD_OUTPUT% ^
|
||||
--build encrypted ^
|
||||
|| exit 1
|
||||
|
||||
rem tahoelafs.html: empty wiki with plugin for Tahoe-LAFS
|
||||
@@ -62,7 +54,8 @@ rem tahoelafs.html: empty wiki with plugin for Tahoe-LAFS
|
||||
node .\tiddlywiki.js ^
|
||||
.\editions\tahoelafs ^
|
||||
--verbose ^
|
||||
--rendertiddler $:/core/save/all %TW5_BUILD_OUTPUT%\tahoelafs.html text/plain ^
|
||||
--output %TW5_BUILD_OUTPUT% ^
|
||||
--rendertiddler $:/core/save/all tahoelafs.html text/plain ^
|
||||
|| exit 1
|
||||
|
||||
rem d3demo.html: wiki to demo d3 plugin
|
||||
@@ -70,7 +63,8 @@ rem d3demo.html: wiki to demo d3 plugin
|
||||
node .\tiddlywiki.js ^
|
||||
.\editions\d3demo ^
|
||||
--verbose ^
|
||||
--rendertiddler $:/core/save/all %TW5_BUILD_OUTPUT%\d3demo.html text/plain ^
|
||||
--output %TW5_BUILD_OUTPUT% ^
|
||||
--rendertiddler $:/core/save/all d3demo.html text/plain ^
|
||||
|| exit 1
|
||||
|
||||
rem codemirrordemo.html: wiki to demo codemirror plugin
|
||||
@@ -78,7 +72,8 @@ rem codemirrordemo.html: wiki to demo codemirror plugin
|
||||
node .\tiddlywiki.js ^
|
||||
.\editions\codemirrordemo ^
|
||||
--verbose ^
|
||||
--rendertiddler $:/core/save/all %TW5_BUILD_OUTPUT%\codemirrordemo.html text/plain ^
|
||||
--output %TW5_BUILD_OUTPUT% ^
|
||||
--rendertiddler $:/core/save/all codemirrordemo.html text/plain ^
|
||||
|| exit 1
|
||||
|
||||
rem markdowndemo.html: wiki to demo markdown plugin
|
||||
@@ -86,7 +81,8 @@ rem markdowndemo.html: wiki to demo markdown plugin
|
||||
node .\tiddlywiki.js ^
|
||||
.\editions\markdowndemo ^
|
||||
--verbose ^
|
||||
--rendertiddler $:/core/save/all %TW5_BUILD_OUTPUT%\markdowndemo.html text/plain ^
|
||||
--output %TW5_BUILD_OUTPUT% ^
|
||||
--rendertiddler $:/core/save/all markdowndemo.html text/plain ^
|
||||
|| exit 1
|
||||
|
||||
|
||||
@@ -95,7 +91,8 @@ rem highlightdemo.html: wiki to demo highlight plugin
|
||||
node .\tiddlywiki.js ^
|
||||
.\editions\highlightdemo ^
|
||||
--verbose ^
|
||||
--rendertiddler $:/core/save/all %TW5_BUILD_OUTPUT%\highlightdemo.html text/plain ^
|
||||
--output %TW5_BUILD_OUTPUT% ^
|
||||
--rendertiddler $:/core/save/all highlightdemo.html text/plain ^
|
||||
|| exit 1
|
||||
|
||||
rem Make the CNAME file that GitHub Pages requires
|
||||
|
||||
35
bld.sh
35
bld.sh
@@ -35,18 +35,10 @@ rm $TW5_BUILD_OUTPUT/static/*
|
||||
node ./tiddlywiki.js \
|
||||
./editions/tw5.com \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/save/all $TW5_BUILD_OUTPUT/index.html text/plain \
|
||||
--savetiddler $:/favicon.ico $TW5_BUILD_OUTPUT/favicon.ico \
|
||||
--rendertiddler ReadMe ./readme.md text/html \
|
||||
--rendertiddler ContributingTemplate ./contributing.md text/html \
|
||||
--rendertiddler $:/core/copyright.txt ./licenses/copyright.md text/plain \
|
||||
--rendertiddler $:/editions/tw5.com/download-empty $TW5_BUILD_OUTPUT/empty.html text/plain \
|
||||
--rendertiddler $:/editions/tw5.com/download-empty $TW5_BUILD_OUTPUT/empty.hta text/plain \
|
||||
--savetiddler $:/green_favicon.ico $TW5_BUILD_OUTPUT/static/favicon.ico \
|
||||
--rendertiddler $:/core/templates/static.template.html $TW5_BUILD_OUTPUT/static.html text/plain \
|
||||
--rendertiddler $:/core/templates/alltiddlers.template.html $TW5_BUILD_OUTPUT/alltiddlers.html text/plain \
|
||||
--rendertiddler $:/core/templates/static.template.css $TW5_BUILD_OUTPUT/static/static.css text/plain \
|
||||
--rendertiddlers [!is[system]] $:/core/templates/static.tiddler.html $TW5_BUILD_OUTPUT/static text/plain \
|
||||
--output . \
|
||||
--build readmes \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--build favicon empty static index \
|
||||
|| exit 1
|
||||
|
||||
# encrypted.html: a version of the main file encrypted with the password "password"
|
||||
@@ -54,8 +46,8 @@ node ./tiddlywiki.js \
|
||||
node ./tiddlywiki.js \
|
||||
./editions/tw5.com \
|
||||
--verbose \
|
||||
--password password \
|
||||
--rendertiddler $:/core/save/all $TW5_BUILD_OUTPUT/encrypted.html text/plain \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--build encrypted \
|
||||
|| exit 1
|
||||
|
||||
# tahoelafs.html: empty wiki with plugin for Tahoe-LAFS
|
||||
@@ -63,7 +55,8 @@ node ./tiddlywiki.js \
|
||||
node ./tiddlywiki.js \
|
||||
./editions/tahoelafs \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/save/all $TW5_BUILD_OUTPUT/tahoelafs.html text/plain \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all tahoelafs.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# d3demo.html: wiki to demo d3 plugin
|
||||
@@ -71,7 +64,8 @@ node ./tiddlywiki.js \
|
||||
node ./tiddlywiki.js \
|
||||
./editions/d3demo \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/save/all $TW5_BUILD_OUTPUT/d3demo.html text/plain \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all d3demo.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# codemirrordemo.html: wiki to demo codemirror plugin
|
||||
@@ -79,7 +73,8 @@ node ./tiddlywiki.js \
|
||||
node ./tiddlywiki.js \
|
||||
./editions/codemirrordemo \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/save/all $TW5_BUILD_OUTPUT/codemirrordemo.html text/plain \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all codemirrordemo.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# markdowndemo.html: wiki to demo markdown plugin
|
||||
@@ -87,7 +82,8 @@ node ./tiddlywiki.js \
|
||||
node ./tiddlywiki.js \
|
||||
./editions/markdowndemo \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/save/all $TW5_BUILD_OUTPUT/markdowndemo.html text/plain \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all markdowndemo.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# highlightdemo.html: wiki to demo highlight plugin
|
||||
@@ -95,7 +91,8 @@ node ./tiddlywiki.js \
|
||||
node ./tiddlywiki.js \
|
||||
./editions/highlightdemo \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/save/all $TW5_BUILD_OUTPUT/highlightdemo.html text/plain \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all highlightdemo.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# Run the test edition to run the Node.js tests and to generate test.html for tests in the browser
|
||||
|
||||
454
boot/boot.js
454
boot/boot.js
@@ -33,7 +33,6 @@ if(!$tw) {
|
||||
}
|
||||
|
||||
$tw.utils = $tw.utils || Object.create(null);
|
||||
$tw.boot = $tw.boot || Object.create(null);
|
||||
|
||||
/////////////////////////// Standard node.js libraries
|
||||
|
||||
@@ -46,6 +45,11 @@ if($tw.node) {
|
||||
|
||||
/////////////////////////// Utility functions
|
||||
|
||||
$tw.boot.log = function(str) {
|
||||
$tw.boot.logMessages = $tw.boot.logMessages || [];
|
||||
$tw.boot.logMessages.push(str);
|
||||
}
|
||||
|
||||
/*
|
||||
Check if an object has a property
|
||||
*/
|
||||
@@ -131,7 +135,7 @@ $tw.utils.error = function(err) {
|
||||
promptMsg = "Well, this is embarrassing. It is recommended that you restart TiddlyWiki by refreshing your browser";
|
||||
// Log the error to the console
|
||||
console.error(err);
|
||||
if($tw.browser) {
|
||||
if($tw.browser && !$tw.node) {
|
||||
// Display an error message to the user
|
||||
var dm = $tw.utils.domMaker,
|
||||
heading = dm("h1",{text: errHeading}),
|
||||
@@ -146,7 +150,7 @@ $tw.utils.error = function(err) {
|
||||
return false;
|
||||
},true);
|
||||
return null;
|
||||
} else {
|
||||
} else if(!$tw.browser) {
|
||||
// Exit if we're under node.js
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -155,7 +159,7 @@ $tw.utils.error = function(err) {
|
||||
/*
|
||||
Use our custom error handler if we're in the browser
|
||||
*/
|
||||
if($tw.browser) {
|
||||
if($tw.boot.tasks.trapErrors) {
|
||||
window.onerror = function(errorMsg,url,lineNumber) {
|
||||
$tw.utils.error(errorMsg);
|
||||
return false;
|
||||
@@ -183,11 +187,11 @@ $tw.utils.deepDefaults = function(object /*, sourceObjectList */) {
|
||||
$tw.utils.each(Array.prototype.slice.call(arguments,1),function(source) {
|
||||
if(source) {
|
||||
for (var p in source) {
|
||||
if(object[p] == null) {
|
||||
if(object[p] === null || object[p] === undefined) {
|
||||
object[p] = source[p];
|
||||
}
|
||||
if(typeof object[p] === "object" && typeof source[p] === "object") {
|
||||
$tw.utils.deepDefaults(object[p],source[p]);
|
||||
$tw.utils.deepDefaults(object[p],source[p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,6 +206,14 @@ $tw.utils.htmlDecode = function(s) {
|
||||
return s.toString().replace(/</mg,"<").replace(/ /mg,"\xA0").replace(/>/mg,">").replace(/"/mg,"\"").replace(/&/mg,"&");
|
||||
};
|
||||
|
||||
/*
|
||||
Get the browser location.hash. We don't use location.hash because of the way that Firefox auto-urldecodes it (see http://stackoverflow.com/questions/1703552/encoding-of-window-location-hash)
|
||||
*/
|
||||
$tw.utils.getLocationHash = function() {
|
||||
var parts = window.location.href.split('#');
|
||||
return "#" + (parts.length > 1 ? parts[1] : "");
|
||||
};
|
||||
|
||||
/*
|
||||
Pad a string to a given length with "0"s. Length defaults to 2
|
||||
*/
|
||||
@@ -218,8 +230,8 @@ $tw.utils.pad = function(value,length) {
|
||||
$tw.utils.stringifyDate = function(value) {
|
||||
return value.getUTCFullYear() +
|
||||
$tw.utils.pad(value.getUTCMonth() + 1) +
|
||||
$tw.utils.pad(value.getUTCDate()) +
|
||||
$tw.utils.pad(value.getUTCHours()) +
|
||||
$tw.utils.pad(value.getUTCDate()) +
|
||||
$tw.utils.pad(value.getUTCHours()) +
|
||||
$tw.utils.pad(value.getUTCMinutes()) +
|
||||
$tw.utils.pad(value.getUTCSeconds()) +
|
||||
$tw.utils.pad(value.getUTCMilliseconds(),3);
|
||||
@@ -258,14 +270,14 @@ $tw.utils.stringifyList = function(value) {
|
||||
// Parse a string array from a bracketted list. For example "OneTiddler [[Another Tiddler]] LastOne"
|
||||
$tw.utils.parseStringArray = function(value) {
|
||||
if(typeof value === "string") {
|
||||
var memberRegExp = /(?:^|\s)(?:\[\[(.*?)\]\])(?=\s|$)|(\S+)/mg,
|
||||
var memberRegExp = /(?:^|[^\S\xA0])(?:\[\[(.*?)\]\])(?=[^\S\xA0]|$)|([\S\xA0]+)/mg,
|
||||
results = [],
|
||||
match;
|
||||
do {
|
||||
match = memberRegExp.exec(value);
|
||||
if(match) {
|
||||
var item = match[1] || match[2];
|
||||
if(results.indexOf(item) === -1) {
|
||||
if(item !== undefined && results.indexOf(item) === -1) {
|
||||
results.push(item);
|
||||
}
|
||||
}
|
||||
@@ -301,7 +313,6 @@ name `.` refers to the current directory
|
||||
*/
|
||||
$tw.utils.resolvePath = function(sourcepath,rootpath) {
|
||||
// If the source path starts with ./ or ../ then it is relative to the root
|
||||
|
||||
if(sourcepath.substr(0,2) === "./" || sourcepath.substr(0,3) === "../" ) {
|
||||
var src = sourcepath.split("/"),
|
||||
root = rootpath.split("/");
|
||||
@@ -352,7 +363,7 @@ $tw.utils.parseVersion = function(version) {
|
||||
};
|
||||
|
||||
/*
|
||||
Returns true if the version string A is greater than the version string B
|
||||
Returns true if the version string A is greater than the version string B. Returns true if the versions are the same
|
||||
*/
|
||||
$tw.utils.checkVersions = function(versionStringA,versionStringB) {
|
||||
var defaultVersion = {
|
||||
@@ -369,7 +380,8 @@ $tw.utils.checkVersions = function(versionStringA,versionStringB) {
|
||||
];
|
||||
return (diff[0] > 0) ||
|
||||
(diff[0] === 0 && diff[1] > 0) ||
|
||||
(diff[0] === 0 && diff[1] === 0 && diff[2] > 0);
|
||||
(diff[0] === 0 && diff[1] === 0 && diff[2] > 0) ||
|
||||
(diff[0] === 0 && diff[1] === 0 && diff[2] === 0);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -380,8 +392,8 @@ options: {flags: flags,deserializerType: deserializerType}
|
||||
*/
|
||||
$tw.utils.registerFileType = function(type,encoding,extension,options) {
|
||||
options = options || {};
|
||||
$tw.config.fileExtensionInfo[extension] = {type: type};
|
||||
$tw.config.contentTypeInfo[type] = {encoding: encoding, extension: extension, flags: options.flags || [], deserializerType: options.deserializerType || type};
|
||||
$tw.config.fileExtensionInfo[extension] = {type: type};
|
||||
$tw.config.contentTypeInfo[type] = {encoding: encoding, extension: extension, flags: options.flags || [], deserializerType: options.deserializerType || type};
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -413,7 +425,7 @@ $tw.utils.evalGlobal = function(code,context,filename) {
|
||||
if($tw.browser) {
|
||||
fn = window["eval"](code + "\n\n//# sourceURL=" + filename);
|
||||
} else {
|
||||
fn = vm.runInThisContext(code,filename);
|
||||
fn = vm.runInThisContext(code,filename);
|
||||
}
|
||||
// Call the function and return the exports
|
||||
return fn.apply(null,contextValues);
|
||||
@@ -553,7 +565,7 @@ Crypto helper object for encrypted content. It maintains the password text in a
|
||||
the password, and to encrypt/decrypt a block of text
|
||||
*/
|
||||
$tw.utils.Crypto = function() {
|
||||
var sjcl = $tw.browser ? window.sjcl : require("./sjcl.js"),
|
||||
var sjcl = $tw.node ? require("./sjcl.js") : window.sjcl,
|
||||
currentPassword = null,
|
||||
callSjcl = function(method,inputText,password) {
|
||||
password = password || currentPassword;
|
||||
@@ -564,7 +576,7 @@ $tw.utils.Crypto = function() {
|
||||
}
|
||||
} catch(ex) {
|
||||
console.log("Crypto error:" + ex);
|
||||
outputText = null;
|
||||
outputText = null;
|
||||
}
|
||||
return outputText;
|
||||
};
|
||||
@@ -652,7 +664,7 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
|
||||
return window.require(moduleName);
|
||||
} catch(e) {}
|
||||
}
|
||||
throw "Cannot find module named '" + moduleName + "' required by module '" + moduleRoot + "', resolved to " + name;
|
||||
throw "Cannot find module named '" + moduleName + "' required by module '" + moduleRoot + "', resolved to " + name;
|
||||
} else {
|
||||
// If we don't have a module with that name, let node.js try to find it
|
||||
return require(moduleName);
|
||||
@@ -668,6 +680,9 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
|
||||
} else if(typeof moduleInfo.definition === "string") { // String
|
||||
moduleInfo.exports = _exports;
|
||||
$tw.utils.evalSandboxed(moduleInfo.definition,sandbox,tiddler.fields.title);
|
||||
if(sandbox.module.exports) {
|
||||
moduleInfo.exports = sandbox.module.exports; //more codemirror workaround
|
||||
}
|
||||
} else { // Object
|
||||
moduleInfo.exports = moduleInfo.definition;
|
||||
}
|
||||
@@ -749,7 +764,7 @@ $tw.Tiddler = function(/* [fields,] fields */) {
|
||||
var arg = arguments[c],
|
||||
src = (arg instanceof $tw.Tiddler) ? arg.fields : arg;
|
||||
for(var t in src) {
|
||||
if(src[t] === undefined) {
|
||||
if(src[t] === undefined || src[t] === null) {
|
||||
if(t in this.fields) {
|
||||
delete this.fields[t]; // If we get a field that's undefined, delete any previous field value
|
||||
}
|
||||
@@ -764,7 +779,7 @@ $tw.Tiddler = function(/* [fields,] fields */) {
|
||||
}
|
||||
// Freeze the field to keep it immutable
|
||||
if(typeof value === "object") {
|
||||
Object.freeze(value);
|
||||
Object.freeze(value);
|
||||
}
|
||||
this.fields[t] = value;
|
||||
}
|
||||
@@ -834,7 +849,7 @@ $tw.Wiki = function(options) {
|
||||
tiddlers[title] = tiddler;
|
||||
this.clearCache(title);
|
||||
this.clearGlobalCache();
|
||||
this.enqueueTiddlerEvent(title);
|
||||
this.enqueueTiddlerEvent(title);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -884,6 +899,37 @@ $tw.Wiki = function(options) {
|
||||
}
|
||||
};
|
||||
|
||||
// Iterate through all tiddlers and then the shadows
|
||||
this.eachTiddlerPlusShadows = function(callback) {
|
||||
for(var title in tiddlers) {
|
||||
callback(tiddlers[title],title);
|
||||
}
|
||||
for(var title in shadowTiddlers) {
|
||||
if(!Object.prototype.hasOwnProperty.call(tiddlers,title)) {
|
||||
var shadowInfo = shadowTiddlers[title];
|
||||
callback(shadowInfo.tiddler,title);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Iterate through all the shadows and then the tiddlers
|
||||
this.eachShadowPlusTiddlers = function(callback) {
|
||||
for(var title in shadowTiddlers) {
|
||||
if(Object.prototype.hasOwnProperty.call(tiddlers,title)) {
|
||||
callback(tiddlers[title],title);
|
||||
} else {
|
||||
var shadowInfo = shadowTiddlers[title];
|
||||
callback(shadowInfo.tiddler,title);
|
||||
}
|
||||
}
|
||||
for(var title in tiddlers) {
|
||||
if(!Object.prototype.hasOwnProperty.call(shadowTiddlers,title)) {
|
||||
callback(tiddlers[title],title);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Test for the existence of a tiddler
|
||||
this.tiddlerExists = function(title) {
|
||||
return !!$tw.utils.hop(tiddlers,title);
|
||||
@@ -994,15 +1040,15 @@ $tw.Wiki = function(options) {
|
||||
};
|
||||
|
||||
// Dummy methods that will be filled in after boot
|
||||
$tw.Wiki.prototype.clearCache =
|
||||
$tw.Wiki.prototype.clearGlobalCache =
|
||||
$tw.Wiki.prototype.clearCache =
|
||||
$tw.Wiki.prototype.clearGlobalCache =
|
||||
$tw.Wiki.prototype.enqueueTiddlerEvent = function() {};
|
||||
|
||||
// Add an array of tiddlers
|
||||
$tw.Wiki.prototype.addTiddlers = function(tiddlers) {
|
||||
for(var t=0; t<tiddlers.length; t++) {
|
||||
this.addTiddler(tiddlers[t]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1043,6 +1089,37 @@ $tw.Wiki.prototype.defineShadowModules = function() {
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Enable safe mode by deleting any tiddlers that override a shadow tiddler
|
||||
*/
|
||||
$tw.Wiki.prototype.processSafeMode = function() {
|
||||
var self = this,
|
||||
overrides = [];
|
||||
// Find the overriding tiddlers
|
||||
this.each(function(tiddler,title) {
|
||||
if(self.isShadowTiddler(title)) {
|
||||
console.log(title);
|
||||
overrides.push(title);
|
||||
}
|
||||
});
|
||||
// Assemble a report tiddler
|
||||
var titleReportTiddler = "TiddlyWiki Safe Mode",
|
||||
report = [];
|
||||
report.push("TiddlyWiki has been started in [[safe mode|http://tiddlywiki.com/static/SafeMode.html]]. Most customisations have been disabled by renaming the following tiddlers:")
|
||||
// Delete the overrides
|
||||
overrides.forEach(function(title) {
|
||||
var tiddler = self.getTiddler(title),
|
||||
newTitle = "SAFE: " + title;
|
||||
self.deleteTiddler(title);
|
||||
self.addTiddler(new $tw.Tiddler(tiddler, {title: newTitle}));
|
||||
report.push("* [[" + title + "|" + newTitle + "]]");
|
||||
});
|
||||
report.push()
|
||||
this.addTiddler(new $tw.Tiddler({title: titleReportTiddler, text: report.join("\n\n")}));
|
||||
// Set $:/DefaultTiddlers to point to our report
|
||||
this.addTiddler(new $tw.Tiddler({title: "$:/DefaultTiddlers", text: "[[" + titleReportTiddler + "]]"}));
|
||||
};
|
||||
|
||||
/*
|
||||
Extracts tiddlers from a typed block of text, specifying default field values
|
||||
*/
|
||||
@@ -1098,8 +1175,6 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/tid","tiddlerdeserializer",{
|
||||
}
|
||||
if(split.length >= 2) {
|
||||
fields.text = split.slice(1).join("\n\n");
|
||||
} else {
|
||||
fields.text = "";
|
||||
}
|
||||
return [fields];
|
||||
}
|
||||
@@ -1155,7 +1230,7 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
|
||||
|
||||
/////////////////////////// Browser definitions
|
||||
|
||||
if($tw.browser) {
|
||||
if($tw.browser && !$tw.node) {
|
||||
|
||||
/*
|
||||
Decrypt any tiddlers stored within the element with the ID "encryptedArea". The function is asynchronous to allow the user to be prompted for a password
|
||||
@@ -1274,13 +1349,10 @@ $tw.loadTiddlersBrowser = function() {
|
||||
}
|
||||
};
|
||||
|
||||
// End of if($tw.browser)
|
||||
}
|
||||
} else {
|
||||
|
||||
/////////////////////////// Server definitions
|
||||
|
||||
if(!$tw.browser) {
|
||||
|
||||
/*
|
||||
Get any encrypted tiddlers
|
||||
*/
|
||||
@@ -1289,7 +1361,7 @@ $tw.boot.decryptEncryptedTiddlers = function(callback) {
|
||||
callback();
|
||||
};
|
||||
|
||||
}
|
||||
} // End of if($tw.browser && !$tw.node)
|
||||
|
||||
/////////////////////////// Node definitions
|
||||
|
||||
@@ -1353,7 +1425,7 @@ $tw.loadTiddlersFromPath = function(filepath,excludeRegExp) {
|
||||
} else {
|
||||
// If not, read all the files in the directory
|
||||
$tw.utils.each(files,function(file) {
|
||||
if(!excludeRegExp.test(file)) {
|
||||
if(!excludeRegExp.test(file) && file !== "plugin.info") {
|
||||
tiddlers.push.apply(tiddlers,$tw.loadTiddlersFromPath(filepath + path.sep + file,excludeRegExp));
|
||||
}
|
||||
});
|
||||
@@ -1370,53 +1442,102 @@ Load the tiddlers from a plugin folder, and package them up into a proper JSON p
|
||||
*/
|
||||
$tw.loadPluginFolder = function(filepath,excludeRegExp) {
|
||||
excludeRegExp = excludeRegExp || $tw.boot.excludeRegExp;
|
||||
var stat, files, pluginInfo, pluginTiddlers = [], f, file, titlePrefix, t;
|
||||
if(fs.existsSync(filepath)) {
|
||||
stat = fs.statSync(filepath);
|
||||
if(stat.isDirectory()) {
|
||||
// Read the plugin information
|
||||
pluginInfo = JSON.parse(fs.readFileSync(filepath + path.sep + "plugin.info","utf8"));
|
||||
// Read the plugin files
|
||||
files = fs.readdirSync(filepath);
|
||||
for(f=0; f<files.length; f++) {
|
||||
file = files[f];
|
||||
if(!excludeRegExp.test(file) && file !== "plugin.info" && file !== "tiddlywiki.files") {
|
||||
var tiddlerFiles = $tw.loadTiddlersFromPath(filepath + path.sep + file,excludeRegExp);
|
||||
$tw.utils.each(tiddlerFiles,function(tiddlerFile) {
|
||||
pluginTiddlers.push.apply(pluginTiddlers,tiddlerFile.tiddlers);
|
||||
});
|
||||
}
|
||||
}
|
||||
// Save the plugin tiddlers into the plugin info
|
||||
pluginInfo.tiddlers = pluginInfo.tiddlers || Object.create(null);
|
||||
for(t=0; t<pluginTiddlers.length; t++) {
|
||||
if(pluginTiddlers[t].title) {
|
||||
pluginInfo.tiddlers[pluginTiddlers[t].title] = pluginTiddlers[t];
|
||||
if(fs.existsSync(filepath) && fs.statSync(filepath).isDirectory()) {
|
||||
// Read the plugin information
|
||||
var pluginInfo = JSON.parse(fs.readFileSync(filepath + path.sep + "plugin.info","utf8"));
|
||||
// Read the plugin files
|
||||
var pluginFiles = $tw.loadTiddlersFromPath(filepath,excludeRegExp);
|
||||
// Save the plugin tiddlers into the plugin info
|
||||
pluginInfo.tiddlers = pluginInfo.tiddlers || Object.create(null);
|
||||
for(var f=0; f<pluginFiles.length; f++) {
|
||||
var tiddlers = pluginFiles[f].tiddlers;
|
||||
for(var t=0; t<tiddlers.length; t++) {
|
||||
var tiddler= tiddlers[t];
|
||||
if(tiddler.title) {
|
||||
pluginInfo.tiddlers[tiddler.title] = tiddler;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Give the plugin the same version number as the core if it doesn't have one
|
||||
if(pluginInfo && !("version" in pluginInfo)) {
|
||||
pluginInfo.version = $tw.packageInfo.version;
|
||||
}
|
||||
// Save the plugin tiddler
|
||||
if(pluginInfo) {
|
||||
var fields = {
|
||||
title: pluginInfo.title,
|
||||
type: "application/json",
|
||||
text: JSON.stringify({tiddlers: pluginInfo.tiddlers},null,4),
|
||||
"plugin-priority": pluginInfo["plugin-priority"],
|
||||
"name": pluginInfo["name"],
|
||||
"version": pluginInfo["version"],
|
||||
"thumbnail": pluginInfo["thumbnail"],
|
||||
"description": pluginInfo["description"],
|
||||
"plugin-type": pluginInfo["plugin-type"] || "plugin",
|
||||
"dependents": $tw.utils.stringifyList(pluginInfo["dependents"] || [])
|
||||
// Give the plugin the same version number as the core if it doesn't have one
|
||||
if(!("version" in pluginInfo)) {
|
||||
pluginInfo.version = $tw.packageInfo.version;
|
||||
}
|
||||
return fields;
|
||||
// Use "plugin" as the plugin-type if we don't have one
|
||||
if(!("plugin-type" in pluginInfo)) {
|
||||
pluginInfo["plugin-type"] = "plugin";
|
||||
}
|
||||
pluginInfo.dependents = pluginInfo.dependents || [];
|
||||
pluginInfo.type = "application/json";
|
||||
// Set plugin text
|
||||
pluginInfo.text = JSON.stringify({tiddlers: pluginInfo.tiddlers},null,4);
|
||||
delete pluginInfo.tiddlers;
|
||||
// Deserialise array fields (currently required for the dependents field)
|
||||
for(var field in pluginInfo) {
|
||||
if($tw.utils.isArray(pluginInfo[field])) {
|
||||
pluginInfo[field] = $tw.utils.stringifyList(pluginInfo[field]);
|
||||
}
|
||||
}
|
||||
return pluginInfo;
|
||||
} else {
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
name: Name of the plugin to find
|
||||
paths: array of file paths to search for it
|
||||
Returns the path of the plugin folder
|
||||
*/
|
||||
$tw.findLibraryItem = function(name,paths) {
|
||||
var pathIndex = 0;
|
||||
do {
|
||||
var pluginPath = path.resolve(paths[pathIndex],"./" + name)
|
||||
if(fs.existsSync(pluginPath) && fs.statSync(pluginPath).isDirectory()) {
|
||||
return pluginPath;
|
||||
}
|
||||
} while(++pathIndex < paths.length);
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
name: Name of the plugin to load
|
||||
paths: array of file paths to search for it
|
||||
*/
|
||||
$tw.loadPlugin = function(name,paths) {
|
||||
var pluginPath = $tw.findLibraryItem(name,paths);
|
||||
if(pluginPath) {
|
||||
var pluginFields = $tw.loadPluginFolder(pluginPath);
|
||||
if(pluginFields) {
|
||||
$tw.wiki.addTiddler(pluginFields);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
libraryPath: Path of library folder for these plugins (relative to core path)
|
||||
envVar: Environment variable name for these plugins
|
||||
Returns an array of search paths
|
||||
*/
|
||||
$tw.getLibraryItemSearchPaths = function(libraryPath,envVar) {
|
||||
var pluginPaths = [path.resolve($tw.boot.corePath,libraryPath)],
|
||||
env = process.env[envVar];
|
||||
if(env) {
|
||||
Array.prototype.push.apply(pluginPaths,env.split(":"));
|
||||
}
|
||||
return pluginPaths;
|
||||
};
|
||||
|
||||
/*
|
||||
plugins: Array of names of plugins (eg, "tiddlywiki/filesystemadaptor")
|
||||
libraryPath: Path of library folder for these plugins (relative to core path)
|
||||
envVar: Environment variable name for these plugins
|
||||
*/
|
||||
$tw.loadPlugins = function(plugins,libraryPath,envVar) {
|
||||
if(plugins) {
|
||||
var pluginPaths = $tw.getLibraryItemSearchPaths(libraryPath,envVar);
|
||||
for(var t=0; t<plugins.length; t++) {
|
||||
$tw.loadPlugin(plugins[t],pluginPaths);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1448,36 +1569,10 @@ $tw.loadWikiTiddlers = function(wikiPath,parentPaths) {
|
||||
}
|
||||
});
|
||||
}
|
||||
// Load any plugins listed in the wiki info file
|
||||
if(wikiInfo.plugins) {
|
||||
var pluginBasePath = path.resolve($tw.boot.corePath,$tw.config.pluginsPath);
|
||||
for(var t=0; t<wikiInfo.plugins.length; t++) {
|
||||
pluginFields = $tw.loadPluginFolder(path.resolve(pluginBasePath,"./" + wikiInfo.plugins[t]));
|
||||
if(pluginFields) {
|
||||
$tw.wiki.addTiddler(pluginFields);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Load any themes listed in the wiki info file
|
||||
if(wikiInfo.themes) {
|
||||
var themesBasePath = path.resolve($tw.boot.corePath,$tw.config.themesPath);
|
||||
for(var t=0; t<wikiInfo.themes.length; t++) {
|
||||
pluginFields = $tw.loadPluginFolder(path.resolve(themesBasePath,"./" + wikiInfo.themes[t]));
|
||||
if(pluginFields) {
|
||||
$tw.wiki.addTiddler(pluginFields);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Load any languages listed in the wiki info file
|
||||
if(wikiInfo.languages) {
|
||||
var languagesBasePath = path.resolve($tw.boot.corePath,$tw.config.languagesPath);
|
||||
for(var t=0; t<wikiInfo.languages.length; t++) {
|
||||
pluginFields = $tw.loadPluginFolder(path.resolve(languagesBasePath,"./" + wikiInfo.languages[t]));
|
||||
if(pluginFields) {
|
||||
$tw.wiki.addTiddler(pluginFields);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Load any plugins, themes and languages listed in the wiki info file
|
||||
$tw.loadPlugins(wikiInfo.plugins,$tw.config.pluginsPath,$tw.config.pluginsEnvVar);
|
||||
$tw.loadPlugins(wikiInfo.themes,$tw.config.themesPath,$tw.config.themesEnvVar);
|
||||
$tw.loadPlugins(wikiInfo.languages,$tw.config.languagesPath,$tw.config.languagesEnvVar);
|
||||
// Load the wiki files, registering them as writable
|
||||
var resolvedWikiPath = path.resolve(wikiPath,$tw.config.wikiTiddlersSubDir);
|
||||
$tw.utils.each($tw.loadTiddlersFromPath(resolvedWikiPath),function(tiddlerFile) {
|
||||
@@ -1506,7 +1601,7 @@ $tw.loadWikiTiddlers = function(wikiPath,parentPaths) {
|
||||
var wikiPluginsPath = path.resolve(wikiPath,$tw.config.wikiPluginsSubDir);
|
||||
if(fs.existsSync(wikiPluginsPath)) {
|
||||
var pluginFolders = fs.readdirSync(wikiPluginsPath);
|
||||
for(t=0; t<pluginFolders.length; t++) {
|
||||
for(var t=0; t<pluginFolders.length; t++) {
|
||||
pluginFields = $tw.loadPluginFolder(path.resolve(wikiPluginsPath,"./" + pluginFolders[t]));
|
||||
if(pluginFields) {
|
||||
$tw.wiki.addTiddler(pluginFields);
|
||||
@@ -1517,7 +1612,7 @@ $tw.loadWikiTiddlers = function(wikiPath,parentPaths) {
|
||||
var wikiThemesPath = path.resolve(wikiPath,$tw.config.wikiThemesSubDir);
|
||||
if(fs.existsSync(wikiThemesPath)) {
|
||||
var themeFolders = fs.readdirSync(wikiThemesPath);
|
||||
for(t=0; t<themeFolders.length; t++) {
|
||||
for(var t=0; t<themeFolders.length; t++) {
|
||||
pluginFields = $tw.loadPluginFolder(path.resolve(wikiThemesPath,"./" + themeFolders[t]));
|
||||
if(pluginFields) {
|
||||
$tw.wiki.addTiddler(pluginFields);
|
||||
@@ -1528,7 +1623,7 @@ $tw.loadWikiTiddlers = function(wikiPath,parentPaths) {
|
||||
var wikiLanguagesPath = path.resolve(wikiPath,$tw.config.wikiLanguagesSubDir);
|
||||
if(fs.existsSync(wikiLanguagesPath)) {
|
||||
var languageFolders = fs.readdirSync(wikiLanguagesPath);
|
||||
for(t=0; t<languageFolders.length; t++) {
|
||||
for(var t=0; t<languageFolders.length; t++) {
|
||||
pluginFields = $tw.loadPluginFolder(path.resolve(wikiLanguagesPath,"./" + languageFolders[t]));
|
||||
if(pluginFields) {
|
||||
$tw.wiki.addTiddler(pluginFields);
|
||||
@@ -1551,17 +1646,25 @@ $tw.loadTiddlersNode = function() {
|
||||
}
|
||||
};
|
||||
|
||||
// End of if($tw.node)
|
||||
// End of if($tw.node)
|
||||
}
|
||||
|
||||
/////////////////////////// Main startup function called once tiddlers have been decrypted
|
||||
|
||||
/*
|
||||
Startup TiddlyWiki. Options are:
|
||||
readBrowserTiddlers: whether to read tiddlers from the HTML file we're executing within; if not, tiddlers are read from the file system with Node.js APIs
|
||||
Startup TiddlyWiki
|
||||
*/
|
||||
$tw.boot.startup = function(options) {
|
||||
options = options || {};
|
||||
// Get the URL hash and check for safe mode
|
||||
$tw.locationHash = "#";
|
||||
if($tw.browser && !$tw.node) {
|
||||
if(location.hash === "#:safe") {
|
||||
$tw.safeMode = true;
|
||||
} else {
|
||||
$tw.locationHash = $tw.utils.getLocationHash();
|
||||
}
|
||||
}
|
||||
// Initialise some more $tw properties
|
||||
$tw.utils.deepDefaults($tw,{
|
||||
modules: { // Information about each module
|
||||
@@ -1578,12 +1681,17 @@ $tw.boot.startup = function(options) {
|
||||
wikiThemesSubDir: "./themes",
|
||||
wikiLanguagesSubDir: "./languages",
|
||||
wikiTiddlersSubDir: "./tiddlers",
|
||||
wikiOutputSubDir: "./output",
|
||||
jsModuleHeaderRegExpString: "^\\/\\*\\\\(?:\\r?\\n)((?:^[^\\r\\n]*(?:\\r?\\n))+?)(^\\\\\\*\\/$(?:\\r?\\n)?)",
|
||||
fileExtensionInfo: Object.create(null), // Map file extension to {type:}
|
||||
contentTypeInfo: Object.create(null) // Map type to {encoding:,extension:}
|
||||
contentTypeInfo: Object.create(null), // Map type to {encoding:,extension:}
|
||||
pluginsEnvVar: "TIDDLYWIKI_PLUGIN_PATH",
|
||||
themesEnvVar: "TIDDLYWIKI_THEME_PATH",
|
||||
languagesEnvVar: "TIDDLYWIKI_LANGUAGE_PATH",
|
||||
editionsEnvVar: "TIDDLYWIKI_EDITION_PATH"
|
||||
}
|
||||
});
|
||||
if(!options.readBrowserTiddlers) {
|
||||
if(!$tw.boot.tasks.readBrowserTiddlers) {
|
||||
// For writable tiddler files, a hashmap of title to {filepath:,type:,hasMetaFile:}
|
||||
$tw.boot.files = Object.create(null);
|
||||
// System paths and filenames
|
||||
@@ -1636,7 +1744,7 @@ $tw.boot.startup = function(options) {
|
||||
$tw.Wiki.tiddlerDeserializerModules = Object.create(null);
|
||||
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
|
||||
// Load tiddlers
|
||||
if(options.readBrowserTiddlers) {
|
||||
if($tw.boot.tasks.readBrowserTiddlers) {
|
||||
$tw.loadTiddlersBrowser();
|
||||
} else {
|
||||
$tw.loadTiddlersNode();
|
||||
@@ -1645,6 +1753,10 @@ $tw.boot.startup = function(options) {
|
||||
$tw.wiki.readPluginInfo();
|
||||
$tw.wiki.registerPluginTiddlers("plugin");
|
||||
$tw.wiki.unpackPluginTiddlers();
|
||||
// Process "safe mode"
|
||||
if($tw.safeMode) {
|
||||
$tw.wiki.processSafeMode();
|
||||
}
|
||||
// Register typed modules from the tiddlers we've just loaded
|
||||
$tw.wiki.defineTiddlerModules();
|
||||
// And any modules within plugins
|
||||
@@ -1653,12 +1765,114 @@ $tw.boot.startup = function(options) {
|
||||
if($tw.crypto) {
|
||||
$tw.crypto.updateCryptoStateTiddler();
|
||||
}
|
||||
// Run any startup modules
|
||||
// Gather up any startup modules
|
||||
$tw.boot.remainingStartupModules = []; // Array of startup modules
|
||||
$tw.modules.forEachModuleOfType("startup",function(title,module) {
|
||||
if(module.startup) {
|
||||
module.startup();
|
||||
$tw.boot.remainingStartupModules.push(module);
|
||||
}
|
||||
});
|
||||
// Keep track of the startup tasks that have been executed
|
||||
$tw.boot.executedStartupModules = Object.create(null);
|
||||
$tw.boot.disabledStartupModules = $tw.boot.disabledStartupModules || [];
|
||||
// Repeatedly execute the next eligible task
|
||||
$tw.boot.executeNextStartupTask();
|
||||
};
|
||||
|
||||
/*
|
||||
Execute the remaining eligible startup tasks
|
||||
*/
|
||||
$tw.boot.executeNextStartupTask = function() {
|
||||
// Find the next eligible task
|
||||
var taskIndex = 0, task,
|
||||
asyncTaskCallback = function() {
|
||||
if(task.name) {
|
||||
$tw.boot.executedStartupModules[task.name] = true;
|
||||
}
|
||||
return $tw.boot.executeNextStartupTask();
|
||||
};
|
||||
while(taskIndex < $tw.boot.remainingStartupModules.length) {
|
||||
task = $tw.boot.remainingStartupModules[taskIndex];
|
||||
if($tw.boot.isStartupTaskEligible(task)) {
|
||||
// Remove this task from the list
|
||||
$tw.boot.remainingStartupModules.splice(taskIndex,1);
|
||||
// Assemble log message
|
||||
var s = ["Startup task:",task.name];
|
||||
if(task.platforms) {
|
||||
s.push("platforms:",task.platforms.join(","));
|
||||
}
|
||||
if(task.after) {
|
||||
s.push("after:",task.after.join(","));
|
||||
}
|
||||
if(task.before) {
|
||||
s.push("before:",task.before.join(","));
|
||||
}
|
||||
$tw.boot.log(s.join(" "));
|
||||
// Execute task
|
||||
if(!$tw.utils.hop(task,"synchronous") || task.synchronous) {
|
||||
task.startup();
|
||||
if(task.name) {
|
||||
$tw.boot.executedStartupModules[task.name] = true;
|
||||
}
|
||||
return $tw.boot.executeNextStartupTask();
|
||||
} else {
|
||||
task.startup(asyncTaskCallback);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
taskIndex++;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/*
|
||||
Returns true if we are running on one platforms specified in a task modules `platforms` array
|
||||
*/
|
||||
$tw.boot.doesTaskMatchPlatform = function(taskModule) {
|
||||
var platforms = taskModule.platforms;
|
||||
if(platforms) {
|
||||
for(var t=0; t<platforms.length; t++) {
|
||||
if((platforms[t] === "browser" && !$tw.browser) || (platforms[t] === "node" && !$tw.node)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
$tw.boot.isStartupTaskEligible = function(taskModule) {
|
||||
var t;
|
||||
// Check that the platform is correct
|
||||
if(!$tw.boot.doesTaskMatchPlatform(taskModule)) {
|
||||
return false;
|
||||
}
|
||||
var name = taskModule.name,
|
||||
remaining = $tw.boot.remainingStartupModules;
|
||||
if(name) {
|
||||
// Fail if this module is disabled
|
||||
if($tw.boot.disabledStartupModules.indexOf(name) !== -1) {
|
||||
return false;
|
||||
}
|
||||
// Check that no other outstanding tasks must be executed before this one
|
||||
for(t=0; t<remaining.length; t++) {
|
||||
var task = remaining[t];
|
||||
if(task.before && task.before.indexOf(name) !== -1) {
|
||||
if($tw.boot.doesTaskMatchPlatform(task) || (task.name && $tw.boot.disabledStartupModules.indexOf(name) !== -1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check that all of the tasks that we must be performed after has been done
|
||||
var after = taskModule.after;
|
||||
if(after) {
|
||||
for(t=0; t<after.length; t++) {
|
||||
if(!$tw.boot.executedStartupModules[after[t]]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/////////////////////////// Main boot function to decrypt tiddlers and then startup
|
||||
@@ -1667,15 +1881,13 @@ $tw.boot.boot = function() {
|
||||
// Initialise crypto object
|
||||
$tw.crypto = new $tw.utils.Crypto();
|
||||
// Initialise password prompter
|
||||
if($tw.browser) {
|
||||
if($tw.browser && !$tw.node) {
|
||||
$tw.passwordPrompt = new $tw.utils.PasswordPrompt();
|
||||
}
|
||||
// Preload any encrypted tiddlers
|
||||
$tw.boot.decryptEncryptedTiddlers(function() {
|
||||
// Startup
|
||||
$tw.boot.startup({
|
||||
readBrowserTiddlers: !!$tw.browser
|
||||
});
|
||||
$tw.boot.startup();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -16,13 +16,20 @@ var _bootprefix = (function($tw) {
|
||||
|
||||
"use strict";
|
||||
|
||||
$tw = $tw || {};
|
||||
$tw = $tw || Object.create(null);
|
||||
$tw.boot = $tw.boot || Object.create(null);
|
||||
|
||||
// Detect platforms
|
||||
$tw.browser = typeof(window) !== "undefined" ? {} : null;
|
||||
$tw.node = typeof(process) === "object" ? {} : null;
|
||||
$tw.nodeWebKit = $tw.node && global.window && global.window.nwDispatcher ? {} : null;
|
||||
|
||||
// Set default boot tasks
|
||||
$tw.boot.tasks = {
|
||||
trapErrors: !!($tw.browser && !$tw.node),
|
||||
readBrowserTiddlers: !!($tw.browser && !$tw.node)
|
||||
};
|
||||
|
||||
/*
|
||||
Information about each module is kept in an object with these members:
|
||||
moduleType: type of module
|
||||
|
||||
File diff suppressed because one or more lines are too long
9
core/images/chevron-left.tid
Normal file
9
core/images/chevron-left.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: $:/core/images/chevron-left
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-chevron-left tw-image-button" width="22pt" height="22pt" viewBox="0 0 128 128" version="1.1">
|
||||
<g>
|
||||
<path d="M97.7982405,98.1688105 L152.184015,43.4979042 C155.938662,39.7236635 155.938662,33.6043964 152.184015,29.8301557 C148.429583,26.0559364 142.342116,26.0559364 138.587684,29.8301557 L91.0000107,77.667222 L43.4123803,29.8301557 C39.6578195,26.0559364 33.5704813,26.0559364 29.8159206,29.8301557 C26.0613598,33.6043964 26.0613598,39.7236635 29.8159206,43.4979042 L84.2017595,98.1688105 C87.9563202,101.943051 94.0436798,101.943051 97.7982405,98.1688126 L97.7982405,98.1688105 Z" transform="translate(91.000000, 63.999491) rotate(-270.000000) translate(-91.000000, -63.999491) "></path>
|
||||
<path d="M43.7982405,98.1688105 L98.1840153,43.4979042 C101.938662,39.7236635 101.938662,33.6043964 98.1840153,29.8301557 C94.4295828,26.0559364 88.3421164,26.0559364 84.5876838,29.8301557 L37.0000107,77.667222 L-10.5876197,29.8301557 C-14.3421805,26.0559364 -20.4295187,26.0559364 -24.1840794,29.8301557 C-27.9386402,33.6043964 -27.9386402,39.7236635 -24.1840794,43.4979042 L30.2017595,98.1688105 C33.9563202,101.943051 40.0436798,101.943051 43.7982405,98.1688126 L43.7982405,98.1688105 Z" transform="translate(37.000000, 63.999491) rotate(-270.000000) translate(-37.000000, -63.999491) "></path>
|
||||
</g>
|
||||
</svg>
|
||||
9
core/images/chevron-right.tid
Normal file
9
core/images/chevron-right.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: $:/core/images/chevron-right
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-chevron-right tw-image-button" width="22pt" height="22pt" viewBox="0 0 128 128">
|
||||
<g>
|
||||
<path d="M97.7982405,98.1688105 L152.184015,43.4979042 C155.938662,39.7236635 155.938662,33.6043964 152.184015,29.8301557 C148.429583,26.0559364 142.342116,26.0559364 138.587684,29.8301557 L91.0000107,77.667222 L43.4123803,29.8301557 C39.6578195,26.0559364 33.5704813,26.0559364 29.8159206,29.8301557 C26.0613598,33.6043964 26.0613598,39.7236635 29.8159206,43.4979042 L84.2017595,98.1688105 C87.9563202,101.943051 94.0436798,101.943051 97.7982405,98.1688126 L97.7982405,98.1688105 Z" transform="translate(91.000000, 63.999491) rotate(-90.000000) translate(-91.000000, -63.999491) "></path>
|
||||
<path d="M43.7982405,98.1688105 L98.1840153,43.4979042 C101.938662,39.7236635 101.938662,33.6043964 98.1840153,29.8301557 C94.4295828,26.0559364 88.3421164,26.0559364 84.5876838,29.8301557 L37.0000107,77.667222 L-10.5876197,29.8301557 C-14.3421805,26.0559364 -20.4295187,26.0559364 -24.1840794,29.8301557 C-27.9386402,33.6043964 -27.9386402,39.7236635 -24.1840794,43.4979042 L30.2017595,98.1688105 C33.9563202,101.943051 40.0436798,101.943051 43.7982405,98.1688126 L43.7982405,98.1688105 Z" transform="translate(37.000000, 63.999491) rotate(-90.000000) translate(-37.000000, -63.999491) "></path>
|
||||
</g>
|
||||
</svg>
|
||||
4
core/images/right-arrow.tid
Normal file
4
core/images/right-arrow.tid
Normal file
@@ -0,0 +1,4 @@
|
||||
title: $:/core/images/right-arrow
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-right-arrow tw-image-button" width="22pt" height="22pt" viewBox="0 0 128 128"><path d="M72.7982405,98.6541105 L127.184015,43.9832042 C130.938662,40.2089635 130.938662,34.0896964 127.184015,30.3154557 C123.429583,26.5412364 117.342116,26.5412364 113.587684,30.3154557 L66.0000107,78.152522 L18.4123803,30.3154557 C14.6578195,26.5412364 8.57048132,26.5412364 4.81592057,30.3154557 C1.06135981,34.0896964 1.06135981,40.2089635 4.81592057,43.9832042 L59.2017595,98.6541105 C62.9563202,102.428351 69.0436798,102.428351 72.7982405,98.6541126 L72.7982405,98.6541105 Z" transform="translate(66.000000, 64.484791) rotate(-90.000000) translate(-66.000000, -64.484791) "/></svg>
|
||||
26
core/language/en-GB/Buttons.multids
Normal file
26
core/language/en-GB/Buttons.multids
Normal file
@@ -0,0 +1,26 @@
|
||||
title: $:/language/Buttons/
|
||||
|
||||
AdvancedSearch/Caption: advanced search
|
||||
AdvancedSearch/Hint: Advanced search
|
||||
Cancel/Caption: cancel
|
||||
Cancel/Hint: Cancel editing this tiddler
|
||||
Close/Caption: close
|
||||
Close/Hint: Close this tiddler
|
||||
ControlPanel/Caption: control panel
|
||||
ControlPanel/Hint: Open control panel
|
||||
Delete/Caption: delete
|
||||
Delete/Hint: Delete this tiddler
|
||||
Edit/Caption: edit
|
||||
Edit/Hint: Edit this tiddler
|
||||
Info/Caption: info
|
||||
Info/Hint: Show information for this tiddler
|
||||
NewTiddler/Caption: new tiddler
|
||||
NewTiddler/Hint: Create a new tiddler
|
||||
Save/Caption: save
|
||||
Save/Hint: Save this tiddler
|
||||
SaveWiki/Caption: save changes
|
||||
SaveWiki/Hint: Save changes
|
||||
HideSideBar/Caption: hide sidebar
|
||||
HideSideBar/Hint: Hide sidebar
|
||||
ShowSideBar/Caption: show sidebar
|
||||
ShowSideBar/Hint: Show sidebar
|
||||
@@ -1,9 +1,24 @@
|
||||
title: $:/language/ControlPanel/
|
||||
|
||||
Advanced/Caption: Advanced
|
||||
Advanced/EditorTypes/Caption: Editor Types
|
||||
Advanced/EditorTypes/Editor/Caption: Editor
|
||||
Advanced/EditorTypes/Hint: These tiddlers determine which editor is used to edit specific tiddler types.
|
||||
Advanced/EditorTypes/Type/Caption: Type
|
||||
Advanced/Hint: Internal information about this TiddlyWiki
|
||||
Advanced/LoadedModules/Caption: Loaded Modules
|
||||
Advanced/LoadedModules/Hint: These are the currently loaded tiddler modules linked to their source tiddlers. Any italicised modules lack a source tiddler, typically because they were setup during the boot process.
|
||||
Advanced/Settings/Caption: Settings
|
||||
Advanced/Settings/Hint: These advanced settings let you customise the behaviour of TiddlyWiki.
|
||||
Advanced/Settings/NavigationAddressBar/Caption: Navigation Address Bar
|
||||
Advanced/Settings/NavigationAddressBar/Hint: Behaviour of the browser address bar when navigating to a tiddler:
|
||||
Advanced/Settings/NavigationAddressBar/No/Description: Do not update the address bar
|
||||
Advanced/Settings/NavigationAddressBar/Permalink/Description: Include the target tiddler
|
||||
Advanced/Settings/NavigationAddressBar/Permaview/Description: Include the target tiddler and the current story sequence
|
||||
Advanced/Settings/NavigationHistory/Caption: Navigation History
|
||||
Advanced/Settings/NavigationHistory/Hint: Update browser history when navigating to a tiddler:
|
||||
Advanced/Settings/NavigationHistory/No/Description: Do not update history
|
||||
Advanced/Settings/NavigationHistory/Yes/Description: Update history
|
||||
Advanced/TiddlerFields/Caption: Tiddler Fields
|
||||
Advanced/TiddlerFields/Hint: This is the full set of TiddlerFields in use in this wiki (including system tiddlers but excluding shadow tiddlers).
|
||||
Appearance/Caption: Appearance
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
title: $:/language/Docs/ModuleTypes/
|
||||
|
||||
animation: Animations that may be used with the RevealWidget.
|
||||
browser-startup: Startup functions that are only executed in the browser.
|
||||
command: Commands that can be executed under Node.js.
|
||||
config: Data to be inserted into `$tw.config`.
|
||||
filteroperator: Individual filter operator methods.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
title: $:/language/EditTemplate/
|
||||
|
||||
Body/External/Hint: This is an external tiddler stored outside of the main TiddlyWiki file. You can edit the tags and fields but cannot directly edit the content itself
|
||||
Body/Hint: Use [[wiki text|http://tiddlywiki.com/static/WikiText.html]] to add formatting, images, and dynamic features
|
||||
Body/Placeholder: Type the text for this tiddler
|
||||
Body/Preview/Button/Hide: hide preview
|
||||
@@ -8,6 +9,8 @@ Fields/Add/Button: add
|
||||
Fields/Add/Name/Placeholder: field name
|
||||
Fields/Add/Prompt: Add a new field:
|
||||
Fields/Add/Value/Placeholder: field value
|
||||
Shadow/Warning: This is a shadow tiddler. Any changes will override the default version
|
||||
Shadow/OverriddenWarning: This is a modified shadow tiddler. You can revert to the default version by deleting this tiddler
|
||||
Tags/Add/Button: add
|
||||
Tags/Add/Placeholder: tag name
|
||||
Type/Placeholder: content type
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
title: $:/language/Docs/Fields/
|
||||
|
||||
_canonical_uri: The full URI of an external image tiddler
|
||||
bag: The name of the bag from which a tiddler came
|
||||
caption: The text to be displayed on a tab or button
|
||||
color: The CSS color value associated with a tiddler
|
||||
|
||||
11
core/language/en-GB/Help/build.tid
Normal file
11
core/language/en-GB/Help/build.tid
Normal file
@@ -0,0 +1,11 @@
|
||||
title: $:/language/Help/build
|
||||
description: Automatically run configured commands
|
||||
|
||||
Build the specified build targets for the current wiki. If no build targets are specified then all available targets will be built.
|
||||
|
||||
```
|
||||
--build <target> [<target> ...]
|
||||
```
|
||||
|
||||
Build targets are defined in the `tiddlywiki.info` file of a wiki folder.
|
||||
|
||||
8
core/language/en-GB/Help/clearpassword.tid
Normal file
8
core/language/en-GB/Help/clearpassword.tid
Normal file
@@ -0,0 +1,8 @@
|
||||
title: $:/language/Help/clearpassword
|
||||
description: Clear a password for subsequent crypto operations
|
||||
|
||||
Clear the password for subsequent crypto operations
|
||||
|
||||
```
|
||||
--clearpassword
|
||||
```
|
||||
10
core/language/en-GB/Help/output.tid
Normal file
10
core/language/en-GB/Help/output.tid
Normal file
@@ -0,0 +1,10 @@
|
||||
title: $:/language/Help/output
|
||||
description: Set the base output directory for subsequent commands
|
||||
|
||||
Sets the base output directory for subsequent commands. The default output directory is the `output` subdirectory of the edition directory.
|
||||
|
||||
```
|
||||
--output <pathname>
|
||||
```
|
||||
|
||||
If the specified pathname is relative then it is resolved relative to the current working directory.
|
||||
@@ -6,3 +6,7 @@ Render an individual tiddler as a specified ContentType, defaults to `text/html`
|
||||
```
|
||||
--rendertiddler <title> <filename> [<type>]
|
||||
```
|
||||
|
||||
By default, the filename is resolved relative to the `output` subdirectory of the edition directory. The `--output` command can be used to direct output to a different directory.
|
||||
|
||||
Any missing directories in the path to the filename are automatically created.
|
||||
|
||||
@@ -12,3 +12,7 @@ For example:
|
||||
```
|
||||
--rendertiddlers [!is[system]] $:/core/templates/static.tiddler.html ./static text/plain
|
||||
```
|
||||
|
||||
By default, the pathname is resolved relative to the `output` subdirectory of the edition directory. The `--output` command can be used to direct output to a different directory.
|
||||
|
||||
Any files in the target directory are deleted. The target directory is recursively created if it is missing.
|
||||
|
||||
@@ -6,3 +6,7 @@ Saves an individual tiddler in its raw text or binary format to the specified fi
|
||||
```
|
||||
--savetiddler <title> <filename>
|
||||
```
|
||||
|
||||
By default, the filename is resolved relative to the `output` subdirectory of the edition directory. The `--output` command can be used to direct output to a different directory.
|
||||
|
||||
Any missing directories in the path to the filename are automatically created.
|
||||
|
||||
12
core/language/en-GB/Help/savetiddlers.tid
Normal file
12
core/language/en-GB/Help/savetiddlers.tid
Normal file
@@ -0,0 +1,12 @@
|
||||
title: $:/language/Help/savetiddlers
|
||||
description: Saves a group of raw tiddlers to a directory
|
||||
|
||||
Saves a group of tiddlers in their raw text or binary format to the specified directory.
|
||||
|
||||
```
|
||||
--savetiddlers <filter> <pathname>
|
||||
```
|
||||
|
||||
By default, the pathname is resolved relative to the `output` subdirectory of the edition directory. The `--output` command can be used to direct output to a different directory.
|
||||
|
||||
Any missing directories in the pathname are automatically created.
|
||||
@@ -6,7 +6,7 @@ The server built in to TiddlyWiki5 is very simple. Although compatible with Tidd
|
||||
At the root, it serves a rendering of a specified tiddler. Away from the root, it serves individual tiddlers encoded in JSON, and supports the basic HTTP operations for `GET`, `PUT` and `DELETE`.
|
||||
|
||||
```
|
||||
--server <port> <roottiddler> <rendertype> <servetype> <username> <password> <host>
|
||||
--server <port> <roottiddler> <rendertype> <servetype> <username> <password> <host> <pathprefix>
|
||||
```
|
||||
|
||||
The parameters are:
|
||||
@@ -18,6 +18,7 @@ The parameters are:
|
||||
* ''username'' - the default username for signing edits
|
||||
* ''password'' - optional password for basic authentication
|
||||
* ''host'' - optional hostname to serve from (defaults to "127.0.0.1" aka "localhost")
|
||||
* ''pathprefix'' - optional prefix for paths
|
||||
|
||||
If the password parameter is specified then the browser will prompt the user for the username and password. Note that the password is transmitted in plain text so this implementation isn't suitable for general use.
|
||||
|
||||
|
||||
18
core/language/en-GB/Help/setfield.tid
Normal file
18
core/language/en-GB/Help/setfield.tid
Normal file
@@ -0,0 +1,18 @@
|
||||
title: $:/language/Help/setfield
|
||||
description: Prepares external tiddlers for use
|
||||
|
||||
//Note that this command is experimental and may change or be replaced during the TiddlyWiki version 5 beta//
|
||||
|
||||
Sets the specified field of a group of tiddlers to the result of wikifying a template tiddler with the `currentTiddler` variable set to the tiddler.
|
||||
|
||||
```
|
||||
--setfield <filter> <fieldname> <templatetitle> <rendertype>
|
||||
```
|
||||
|
||||
The parameters are:
|
||||
|
||||
* ''filter'' - filter identifying the tiddlers to be affected
|
||||
* ''fieldname'' - the field to modify (defaults to "text")
|
||||
* ''templatetitle'' - the tiddler to wikify into the specified field. If blank or missing then the specified field is deleted
|
||||
* ''type'' - the text type to render (defaults to "text/plain"; "text/html" can be used to include HTML tags)
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
title: $:/language/
|
||||
|
||||
BinaryWarning/Prompt: This tiddler contains binary data
|
||||
ClassicWarning/Hint: This tiddler is written in TiddlyWiki Classic wiki text format, which is not fully compatible with TiddlyWiki version 5. See http://tiddlywiki.com/static/Upgrading.html for more details.
|
||||
ClassicWarning/Upgrade/Caption: upgrade
|
||||
CloseAll/Button: close all
|
||||
ConfirmCancelTiddler: Do you wish to discard changes to the tiddler "<$text text=<<title>>/>"?
|
||||
ConfirmDeleteTiddler: Do you wish to delete the tiddler "<$text text=<<title>>/>"?
|
||||
ConfirmOverwriteTiddler: Do you wish to overwrite the tiddler "<$text text=<<title>>/>"?
|
||||
InvalidFieldName: Illegal characters in field name "<$text text=<<fieldName>>/>". Fields can only contain lowercase letters and the characters underscore (`_`), hyphen (`-`) and period (`.`)
|
||||
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>>/>"?
|
||||
InvalidFieldName: Illegal characters in field name "<$text text=<<fieldName>>/>". Fields can only contain lowercase letters, digits and the characters underscore (`_`), hyphen (`-`) and period (`.`)
|
||||
MissingTiddler/Hint: Missing tiddler "<$text text=<<currentTiddler>>/>" - click {{$:/core/images/edit-button}} to create
|
||||
RecentChanges/DateFormat: DDth MMM YYYY
|
||||
RelativeDate/Future/Days: <<period>> days from now
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
title: $:/language/Search/
|
||||
|
||||
Advanced/Matches: //<small><$count filter={{$:/temp/advancedsearch}}/> matches</small>//
|
||||
Filter/Caption: Filter
|
||||
Filter/Hint: Search via a [[filter expression|http://tiddlywiki.com/static/TiddlerFilters.html]]
|
||||
Filter/Matches: //<small><$count filter={{$:/temp/advancedsearch}}/> matches</small>//
|
||||
Matches: //<small><$count filter="[!is[system]search{$:/temp/search}]"/> matches</small>//
|
||||
Shadows/Caption: Shadows
|
||||
Shadows/Hint: Search for shadow tiddlers
|
||||
Shadows/Matches: //<small><$count filter="[all[shadows]search{$:/temp/advancedsearch}]"/> matches</small>//
|
||||
Standard/Caption: Standard
|
||||
Standard/Hint: Search for standard tiddlers
|
||||
Standard/Matches: //<small><$count filter="[!is[system]search{$:/temp/advancedsearch}]"/> matches</small>//
|
||||
System/Caption: System
|
||||
System/Hint: Search for system tiddlers
|
||||
System/Matches: //<small><$count filter="[is[system]search{$:/temp/advancedsearch}]"/> matches</small>//
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
title: $:/language/SideBar/
|
||||
|
||||
All/Caption: All
|
||||
Contents/Caption: Contents
|
||||
Drafts/Caption: Drafts
|
||||
Missing/Caption: Missing
|
||||
More/Caption: More
|
||||
|
||||
4
core/language/en-GB/Types/application_javascript.tid
Normal file
4
core/language/en-GB/Types/application_javascript.tid
Normal file
@@ -0,0 +1,4 @@
|
||||
title: $:/language/Docs/Types/application/javascript
|
||||
description: JavaScript code
|
||||
name: application/javascript
|
||||
group: Developer
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/language/Docs/Types/application/json
|
||||
description: JSON data
|
||||
name: application/json
|
||||
group: Developer
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/language/Docs/Types/application/x-tiddler-dictionary
|
||||
description: Data dictionary
|
||||
name: application/x-tiddler-dictionary
|
||||
group: Developer
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/language/Docs/Types/image/gif
|
||||
description: GIF image
|
||||
name: image/gif
|
||||
group: Image
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/language/Docs/Types/image/jpeg
|
||||
description: JPEG image
|
||||
name: image/jpeg
|
||||
group: Image
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/language/Docs/Types/image/png
|
||||
description: PNG image
|
||||
name: image/png
|
||||
group: Image
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/language/Docs/Types/image/svg+xml
|
||||
description: Structured Vector Graphics image
|
||||
name: image/svg+xml
|
||||
group: Image
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/language/Docs/Types/image/x-icon
|
||||
description: ICO format icon file
|
||||
name: image/x-icon
|
||||
group: Image
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/language/Docs/Types/text/css
|
||||
description: Static stylesheet
|
||||
name: text/css
|
||||
group: Developer
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/language/Docs/Types/text/html
|
||||
description: HTML markup
|
||||
name: text/html
|
||||
group: Text
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/language/Docs/Types/text/plain
|
||||
description: Plain text
|
||||
name: text/plain
|
||||
group: Text
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/language/Docs/Types/text/vnd.tiddlywiki
|
||||
description: TiddlyWiki version 5 wikitext
|
||||
description: TiddlyWiki 5
|
||||
name: text/vnd.tiddlywiki
|
||||
group: Text
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/language/Docs/Types/text/x-tiddlywiki
|
||||
description: TiddlyWiki Classic wikitext
|
||||
description: TiddlyWiki Classic
|
||||
name: text/x-tiddlywiki
|
||||
group: Text
|
||||
|
||||
@@ -20,11 +20,20 @@ Parse a sequence of commands
|
||||
callback: a callback invoked as callback(err) where err is null if there was no error
|
||||
*/
|
||||
var Commander = function(commandTokens,callback,wiki,streams) {
|
||||
var path = require("path");
|
||||
this.commandTokens = commandTokens;
|
||||
this.nextToken = 0;
|
||||
this.callback = callback;
|
||||
this.wiki = wiki;
|
||||
this.streams = streams;
|
||||
this.outputPath = path.resolve($tw.boot.wikiPath,$tw.config.wikiOutputSubDir);
|
||||
};
|
||||
|
||||
/*
|
||||
Add a string of tokens to the command queue
|
||||
*/
|
||||
Commander.prototype.addCommandTokens = function(commandTokens) {
|
||||
Array.prototype.push.apply(this.commandTokens,commandTokens);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
52
core/modules/commands/build.js
Normal file
52
core/modules/commands/build.js
Normal file
@@ -0,0 +1,52 @@
|
||||
/*\
|
||||
title: $:/core/modules/commands/build.js
|
||||
type: application/javascript
|
||||
module-type: command
|
||||
|
||||
Command to build a build target
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.info = {
|
||||
name: "build",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
// Get the build targets defined in the wiki
|
||||
var buildTargets = $tw.boot.wikiInfo.build;
|
||||
if(!buildTargets) {
|
||||
return "No build targets defined"
|
||||
}
|
||||
// Loop through each of the specified targets
|
||||
var targets;
|
||||
if(this.params.length > 0) {
|
||||
targets = this.params;
|
||||
} else {
|
||||
targets = Object.keys(buildTargets);
|
||||
}
|
||||
for(var targetIndex=0; targetIndex<targets.length; targetIndex++) {
|
||||
var target = targets[targetIndex],
|
||||
commands = buildTargets[target];
|
||||
if(!commands) {
|
||||
return "Build target '" + target + "' not found";
|
||||
}
|
||||
// Add the commands to the queue
|
||||
this.commander.addCommandTokens(commands);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
33
core/modules/commands/clearpassword.js
Normal file
33
core/modules/commands/clearpassword.js
Normal file
@@ -0,0 +1,33 @@
|
||||
/*\
|
||||
title: $:/core/modules/commands/clearpassword.js
|
||||
type: application/javascript
|
||||
module-type: command
|
||||
|
||||
Clear password for crypto operations
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.info = {
|
||||
name: "clearpassword",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
$tw.crypto.setPassword(null);
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
@@ -34,7 +34,7 @@ Command.prototype.execute = function() {
|
||||
for(var editionIndex=0; editionIndex<editions.length; editionIndex++) {
|
||||
var editionName = editions[editionIndex];
|
||||
// Check the edition exists
|
||||
var editionPath = path.resolve($tw.boot.corePath,$tw.config.editionsPath) + path.sep + editionName;
|
||||
var editionPath = $tw.findLibraryItem(editionName,$tw.getLibraryItemSearchPaths($tw.config.editionsPath,$tw.config.editionsEnvVar));
|
||||
if(!$tw.utils.isDirectory(editionPath)) {
|
||||
return "Edition '" + editionName + "' not found";
|
||||
}
|
||||
|
||||
38
core/modules/commands/output.js
Normal file
38
core/modules/commands/output.js
Normal file
@@ -0,0 +1,38 @@
|
||||
/*\
|
||||
title: $:/core/modules/commands/output.js
|
||||
type: application/javascript
|
||||
module-type: command
|
||||
|
||||
Command to set the default output location (defaults to current working directory)
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.info = {
|
||||
name: "output",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
var fs = require("fs"),
|
||||
path = require("path");
|
||||
if(this.params.length < 1) {
|
||||
return "Missing output path";
|
||||
}
|
||||
this.commander.outputPath = path.resolve(process.cwd(),this.params[0]);
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
@@ -31,8 +31,9 @@ Command.prototype.execute = function() {
|
||||
fs = require("fs"),
|
||||
path = require("path"),
|
||||
title = this.params[0],
|
||||
filename = this.params[1],
|
||||
filename = path.resolve(this.commander.outputPath,this.params[1]),
|
||||
type = this.params[2] || "text/html";
|
||||
$tw.utils.createFileDirectories(filename);
|
||||
fs.writeFile(filename,this.commander.wiki.renderTiddler(type,title),"utf8",function(err) {
|
||||
self.callback(err);
|
||||
});
|
||||
|
||||
@@ -35,10 +35,12 @@ Command.prototype.execute = function() {
|
||||
wiki = this.commander.wiki,
|
||||
filter = this.params[0],
|
||||
template = this.params[1],
|
||||
pathname = this.params[2],
|
||||
pathname = path.resolve(this.commander.outputPath,this.params[2]),
|
||||
type = this.params[3] || "text/html",
|
||||
extension = this.params[4] || ".html",
|
||||
tiddlers = wiki.filterTiddlers(filter);
|
||||
$tw.utils.deleteDirectory(pathname);
|
||||
$tw.utils.createDirectory(pathname);
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
var parser = wiki.parseTiddler(template),
|
||||
widgetNode = wiki.makeWidget(parser,{variables: {currentTiddler: title}});
|
||||
|
||||
@@ -31,10 +31,11 @@ Command.prototype.execute = function() {
|
||||
fs = require("fs"),
|
||||
path = require("path"),
|
||||
title = this.params[0],
|
||||
filename = this.params[1],
|
||||
filename = path.resolve(this.commander.outputPath,this.params[1]),
|
||||
tiddler = this.commander.wiki.getTiddler(title),
|
||||
type = tiddler.fields.type || "text/vnd.tiddlywiki",
|
||||
contentTypeInfo = $tw.config.contentTypeInfo[type] || {encoding: "utf8"};
|
||||
$tw.utils.createFileDirectories(filename);
|
||||
fs.writeFile(filename,tiddler.fields.text,contentTypeInfo.encoding,function(err) {
|
||||
self.callback(err);
|
||||
});
|
||||
|
||||
53
core/modules/commands/savetiddlers.js
Normal file
53
core/modules/commands/savetiddlers.js
Normal file
@@ -0,0 +1,53 @@
|
||||
/*\
|
||||
title: $:/core/modules/commands/savetiddlers.js
|
||||
type: application/javascript
|
||||
module-type: command
|
||||
|
||||
Command to save several tiddlers to a folder of files
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
exports.info = {
|
||||
name: "savetiddlers",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing filename";
|
||||
}
|
||||
var self = this,
|
||||
fs = require("fs"),
|
||||
path = require("path"),
|
||||
wiki = this.commander.wiki,
|
||||
filter = this.params[0],
|
||||
pathname = path.resolve(this.commander.outputPath,this.params[1]),
|
||||
tiddlers = wiki.filterTiddlers(filter);
|
||||
$tw.utils.deleteDirectory(pathname);
|
||||
$tw.utils.createDirectory(pathname);
|
||||
$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"},
|
||||
filename = path.resolve(pathname,encodeURIComponent(title));
|
||||
fs.writeFileSync(filename,tiddler.fields.text,contentTypeInfo.encoding);
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
@@ -50,10 +50,22 @@ SimpleServer.prototype.addRoute = function(route) {
|
||||
};
|
||||
|
||||
SimpleServer.prototype.findMatchingRoute = function(request,state) {
|
||||
var pathprefix = this.get("pathprefix") || "";
|
||||
for(var t=0; t<this.routes.length; t++) {
|
||||
var potentialRoute = this.routes[t],
|
||||
pathRegExp = potentialRoute.path,
|
||||
match = potentialRoute.path.exec(state.urlInfo.pathname);
|
||||
pathname = state.urlInfo.pathname,
|
||||
match;
|
||||
if(pathprefix) {
|
||||
if(pathname.substr(0,pathprefix.length) === pathprefix) {
|
||||
pathname = pathname.substr(pathprefix.length);
|
||||
match = potentialRoute.path.exec(pathname);
|
||||
} else {
|
||||
match = false;
|
||||
}
|
||||
} else {
|
||||
match = potentialRoute.path.exec(pathname);
|
||||
}
|
||||
if(match && request.method === potentialRoute.method) {
|
||||
state.params = [];
|
||||
for(var p=1; p<match.length; p++) {
|
||||
@@ -161,7 +173,8 @@ var Command = function(params,commander,callback) {
|
||||
state.wiki.addTiddler(new $tw.Tiddler(state.wiki.getCreationFields(),fields,{title: title}));
|
||||
var changeCount = state.wiki.getChangeCount(title).toString();
|
||||
response.writeHead(204, "OK",{
|
||||
Etag: "\"default/" + encodeURIComponent(title) + "/" + changeCount + ":\""
|
||||
Etag: "\"default/" + encodeURIComponent(title) + "/" + changeCount + ":\"",
|
||||
"Content-Type": "text/plain"
|
||||
});
|
||||
response.end();
|
||||
}
|
||||
@@ -172,7 +185,9 @@ var Command = function(params,commander,callback) {
|
||||
handler: function(request,response,state) {
|
||||
var title = decodeURIComponent(state.params[0]);
|
||||
state.wiki.deleteTiddler(title);
|
||||
response.writeHead(204, "OK");
|
||||
response.writeHead(204, "OK", {
|
||||
"Content-Type": "text/plain"
|
||||
});
|
||||
response.end();
|
||||
}
|
||||
});
|
||||
@@ -269,13 +284,15 @@ Command.prototype.execute = function() {
|
||||
serveType = this.params[3] || "text/html",
|
||||
username = this.params[4],
|
||||
password = this.params[5],
|
||||
host = this.params[6] || "127.0.0.1";
|
||||
host = this.params[6] || "127.0.0.1",
|
||||
pathprefix = this.params[7];
|
||||
this.server.set({
|
||||
rootTiddler: rootTiddler,
|
||||
renderType: renderType,
|
||||
serveType: serveType,
|
||||
username: username,
|
||||
password: password
|
||||
password: password,
|
||||
pathprefix: pathprefix
|
||||
});
|
||||
this.server.listen(port,host);
|
||||
console.log("Serving on " + host + ":" + port);
|
||||
|
||||
58
core/modules/commands/setfield.js
Normal file
58
core/modules/commands/setfield.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/*\
|
||||
title: $:/core/modules/commands/setfield.js
|
||||
type: application/javascript
|
||||
module-type: command
|
||||
|
||||
Command to modify selected tiddlers to set a field to the text of a template tiddler that has been wikified with the selected tiddler as the current tiddler.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
exports.info = {
|
||||
name: "setfield",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 4) {
|
||||
return "Missing parameters";
|
||||
}
|
||||
var self = this,
|
||||
wiki = this.commander.wiki,
|
||||
filter = this.params[0],
|
||||
fieldname = this.params[1] || "text",
|
||||
templatetitle = this.params[2],
|
||||
rendertype = this.params[3] || "text/plain",
|
||||
tiddlers = wiki.filterTiddlers(filter);
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
var parser = wiki.parseTiddler(templatetitle),
|
||||
newFields = {},
|
||||
tiddler = wiki.getTiddler(title);
|
||||
if(parser) {
|
||||
var widgetNode = wiki.makeWidget(parser,{variables: {currentTiddler: title}});
|
||||
var container = $tw.fakeDocument.createElement("div");
|
||||
widgetNode.render(container,null);
|
||||
newFields[fieldname] = rendertype === "text/html" ? container.innerHTML : container.textContent;
|
||||
} else {
|
||||
newFields[fieldname] = undefined;
|
||||
}
|
||||
wiki.addTiddler(new $tw.Tiddler(tiddler,newFields));
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
@@ -24,6 +24,8 @@ var Command = function(params,commander) {
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
this.commander.verbose = true;
|
||||
// Output the boot message log
|
||||
this.commander.streams.output.write("Boot log:\n " + $tw.boot.logMessages.join("\n ") + "\n");
|
||||
return null; // No error
|
||||
};
|
||||
|
||||
|
||||
@@ -51,13 +51,13 @@ var parseTiddlerDiv = function(text /* [,fields] */) {
|
||||
// Extract the text
|
||||
result.text = text.substring(match.index + match[0].length,endMatch.index);
|
||||
// Process the attributes
|
||||
var attrRegExp = /\s*([^=\s]+)\s*=\s*"([^"]*)"/gi,
|
||||
var attrRegExp = /\s*([^=\s]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/gi,
|
||||
attrMatch;
|
||||
do {
|
||||
attrMatch = attrRegExp.exec(match[1]);
|
||||
if(attrMatch) {
|
||||
var name = attrMatch[1];
|
||||
var value = attrMatch[2];
|
||||
var value = attrMatch[2] !== undefined ? attrMatch[2] : attrMatch[3];
|
||||
result[name] = value;
|
||||
}
|
||||
} while(attrMatch);
|
||||
|
||||
@@ -149,22 +149,22 @@ exports.getFilterOperators = function() {
|
||||
return this.filterOperators;
|
||||
};
|
||||
|
||||
exports.filterTiddlers = function(filterString,currTiddlerTitle,source) {
|
||||
exports.filterTiddlers = function(filterString,widget,source) {
|
||||
var fn = this.compileFilter(filterString);
|
||||
return fn.call(this,source,currTiddlerTitle);
|
||||
return fn.call(this,source,widget);
|
||||
};
|
||||
|
||||
/*
|
||||
Compile a filter into a function with the signature fn(source,currTiddlerTitle) where:
|
||||
Compile a filter into a function with the signature fn(source,widget) where:
|
||||
source: an iterator function for the source tiddlers, called source(iterator), where iterator is called as iterator(tiddler,title)
|
||||
currTiddlerTitle: the optional name of the current tiddler
|
||||
widget: an optional widget node for retrieving the current tiddler etc.
|
||||
*/
|
||||
exports.compileFilter = function(filterString) {
|
||||
var filterParseTree;
|
||||
try {
|
||||
filterParseTree = this.parseFilter(filterString);
|
||||
} catch(e) {
|
||||
return function(source,currTiddlerTitle) {
|
||||
return function(source,widget) {
|
||||
return ["Filter error: " + e];
|
||||
};
|
||||
}
|
||||
@@ -176,9 +176,10 @@ exports.compileFilter = function(filterString) {
|
||||
var self = this;
|
||||
$tw.utils.each(filterParseTree,function(operation) {
|
||||
// Create a function for the chain of operators in the operation
|
||||
var operationSubFunction = function(source,currTiddlerTitle) {
|
||||
var operationSubFunction = function(source,widget) {
|
||||
var accumulator = source,
|
||||
results = [];
|
||||
results = [],
|
||||
currTiddlerTitle = widget && widget.getVariable("currentTiddler");
|
||||
$tw.utils.each(operation.operators,function(operator) {
|
||||
var operand = operator.operand,
|
||||
operatorFunction;
|
||||
@@ -200,35 +201,47 @@ exports.compileFilter = function(filterString) {
|
||||
regexp: operator.regexp
|
||||
},{
|
||||
wiki: self,
|
||||
currTiddlerTitle: currTiddlerTitle
|
||||
widget: widget
|
||||
});
|
||||
accumulator = self.makeTiddlerIterator(results);
|
||||
if($tw.utils.isArray(results)) {
|
||||
accumulator = self.makeTiddlerIterator(results);
|
||||
} else {
|
||||
accumulator = results;
|
||||
}
|
||||
});
|
||||
return results;
|
||||
if($tw.utils.isArray(results)) {
|
||||
return results;
|
||||
} else {
|
||||
var resultArray = [];
|
||||
results(function(tiddler,title) {
|
||||
resultArray.push(title);
|
||||
});
|
||||
return resultArray;
|
||||
}
|
||||
};
|
||||
// Wrap the operator functions in a wrapper function that depends on the prefix
|
||||
operationFunctions.push((function() {
|
||||
switch(operation.prefix || "") {
|
||||
case "": // No prefix means that the operation is unioned into the result
|
||||
return function(results,source,currTiddlerTitle) {
|
||||
$tw.utils.pushTop(results,operationSubFunction(source,currTiddlerTitle));
|
||||
return function(results,source,widget) {
|
||||
$tw.utils.pushTop(results,operationSubFunction(source,widget));
|
||||
};
|
||||
case "-": // The results of this operation are removed from the main result
|
||||
return function(results,source,currTiddlerTitle) {
|
||||
$tw.utils.removeArrayEntries(results,operationSubFunction(source,currTiddlerTitle));
|
||||
return function(results,source,widget) {
|
||||
$tw.utils.removeArrayEntries(results,operationSubFunction(source,widget));
|
||||
};
|
||||
case "+": // This operation is applied to the main results so far
|
||||
return function(results,source,currTiddlerTitle) {
|
||||
return function(results,source,widget) {
|
||||
// This replaces all the elements of the array, but keeps the actual array so that references to it are preserved
|
||||
source = self.makeTiddlerIterator(results);
|
||||
results.splice(0,results.length);
|
||||
$tw.utils.pushTop(results,operationSubFunction(source,currTiddlerTitle));
|
||||
$tw.utils.pushTop(results,operationSubFunction(source,widget));
|
||||
};
|
||||
}
|
||||
})());
|
||||
});
|
||||
// Return a function that applies the operations to a source iterator of tiddler titles
|
||||
return $tw.perf.measure("filter",function filterFunction(source,currTiddlerTitle) {
|
||||
return $tw.perf.measure("filter",function filterFunction(source,widget) {
|
||||
if(!source) {
|
||||
source = self.each;
|
||||
} else if(typeof source === "object") { // Array or hashmap
|
||||
@@ -236,7 +249,7 @@ exports.compileFilter = function(filterString) {
|
||||
}
|
||||
var results = [];
|
||||
$tw.utils.each(operationFunctions,function(operationFunction) {
|
||||
operationFunction(results,source,currTiddlerTitle);
|
||||
operationFunction(results,source,widget);
|
||||
});
|
||||
return results;
|
||||
});
|
||||
|
||||
31
core/modules/filters/after.js
Normal file
31
core/modules/filters/after.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/after.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator returning the tiddler from the current list that is after the tiddler named in the operand.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.after = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
var index = results.indexOf(operator.operand);
|
||||
if(index === -1 || index > (results.length - 2)) {
|
||||
return [];
|
||||
} else {
|
||||
return [results[index + 1]];
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -5,7 +5,7 @@ module-type: filteroperator
|
||||
|
||||
Filter operator for selecting tiddlers
|
||||
|
||||
[all[tiddlers+shadows]]
|
||||
[all[shadows+tiddlers]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
@@ -33,6 +33,17 @@ exports.all = function(source,operator,options) {
|
||||
// Cycle through the suboperators accumulating their results
|
||||
var results = [],
|
||||
subops = operator.operand.split("+");
|
||||
// Check for common optimisations
|
||||
if(subops.length === 1 && subops[0] === "tiddlers") {
|
||||
return options.wiki.each;
|
||||
} else if(subops.length === 1 && subops[0] === "shadows") {
|
||||
return options.wiki.eachShadow;
|
||||
} else if(subops.length === 2 && subops[0] === "tiddlers" && subops[1] === "shadows") {
|
||||
return options.wiki.eachTiddlerPlusShadows;
|
||||
} else if(subops.length === 2 && subops[0] === "shadows" && subops[1] === "tiddlers") {
|
||||
return options.wiki.eachShadowPlusTiddlers;
|
||||
}
|
||||
// Do it the hard way
|
||||
for(var t=0; t<subops.length; t++) {
|
||||
var subop = allFilterOperators[subops[t]];
|
||||
if(subop) {
|
||||
|
||||
@@ -16,8 +16,9 @@ Filter function for [all[current]]
|
||||
Export our filter function
|
||||
*/
|
||||
exports.current = function(source,prefix,options) {
|
||||
if(options.currTiddlerTitle) {
|
||||
return [options.currTiddlerTitle];
|
||||
var currTiddlerTitle = options.widget && options.widget.getVariable("currentTiddler");
|
||||
if(currTiddlerTitle) {
|
||||
return [currTiddlerTitle];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
||||
31
core/modules/filters/before.js
Normal file
31
core/modules/filters/before.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/before.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator returning the tiddler from the current list that is before the tiddler named in the operand.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.before = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
var index = results.indexOf(operator.operand);
|
||||
if(index <= 0) {
|
||||
return [];
|
||||
} else {
|
||||
return [results[index - 1]];
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
31
core/modules/filters/get.js
Normal file
31
core/modules/filters/get.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/get.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for replacing tiddler titles by the value of the field specified in the operand.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.get = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler) {
|
||||
var value = tiddler.getFieldString(operator.operand);
|
||||
if(value) {
|
||||
results.push(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -16,16 +16,17 @@ Filter function for [is[current]]
|
||||
Export our filter function
|
||||
*/
|
||||
exports.current = function(source,prefix,options) {
|
||||
var results = [];
|
||||
var results = [],
|
||||
currTiddlerTitle = options.widget && options.widget.getVariable("currentTiddler");
|
||||
if(prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(title !== options.currTiddlerTitle) {
|
||||
if(title !== currTiddlerTitle) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(title === options.currTiddlerTitle) {
|
||||
if(title === currTiddlerTitle) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
|
||||
37
core/modules/filters/is/tag.js
Normal file
37
core/modules/filters/is/tag.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/is/tag.js
|
||||
type: application/javascript
|
||||
module-type: isfilteroperator
|
||||
|
||||
Filter function for [is[tag]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.tag = function(source,prefix,options) {
|
||||
var results = [],
|
||||
tagMap = options.wiki.getTagMap();
|
||||
if(prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(!$tw.utils.hop(tagMap,title)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if($tw.utils.hop(tagMap,title)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -18,7 +18,8 @@ Export our filter function
|
||||
exports.list = function(source,operator,options) {
|
||||
var results = [],
|
||||
tr = $tw.utils.parseTextReference(operator.operand),
|
||||
list = options.wiki.getTiddlerList(tr.title || options.currTiddlerTitle,tr.field,tr.index);
|
||||
currTiddlerTitle = options.widget && options.widget.getVariable("currentTiddler"),
|
||||
list = options.wiki.getTiddlerList(tr.title || currTiddlerTitle,tr.field,tr.index);
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(list.indexOf(title) === -1) {
|
||||
|
||||
@@ -16,9 +16,10 @@ Filter operator returning all tiddlers that have the selected tiddlers in a list
|
||||
Export our filter function
|
||||
*/
|
||||
exports.listed = function(source,operator,options) {
|
||||
var results = [];
|
||||
var field = operator.operand || "list",
|
||||
results = [];
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.pushTop(results,options.wiki.findListingsOfTiddler(title));
|
||||
$tw.utils.pushTop(results,options.wiki.findListingsOfTiddler(title,field));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -25,10 +25,8 @@ exports.untagged = function(source,operator,options) {
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler) {
|
||||
if(!tiddler.hasField("tags") || ($tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length === 0)) {
|
||||
$tw.utils.pushTop(results,title);
|
||||
}
|
||||
if(!tiddler || !tiddler.hasField("tags") || ($tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length === 0)) {
|
||||
$tw.utils.pushTop(results,title);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ The CSV text parser processes CSV files into a table wrapped in a scrollable wid
|
||||
var CsvParser = function(type,text,options) {
|
||||
// Table framework
|
||||
this.tree = [{
|
||||
"type": "element", "tag": "$scrollable", "children": [{
|
||||
"type": "scrollable", "children": [{
|
||||
"type": "element", "tag": "table", "children": [{
|
||||
"type": "element", "tag": "tbody", "children": []
|
||||
}], "attributes": {
|
||||
|
||||
@@ -13,9 +13,18 @@ The HTML parser displays text as raw HTML
|
||||
"use strict";
|
||||
|
||||
var HtmlParser = function(type,text,options) {
|
||||
var src;
|
||||
if(options._canonical_uri) {
|
||||
src = options._canonical_uri;
|
||||
} else if(text) {
|
||||
src = "data:text/html," + encodeURIComponent(text);
|
||||
}
|
||||
this.tree = [{
|
||||
type: "raw",
|
||||
html: text
|
||||
type: "element",
|
||||
tag: "iframe",
|
||||
attributes: {
|
||||
src: {type: "string", value: src}
|
||||
}
|
||||
}];
|
||||
};
|
||||
|
||||
|
||||
@@ -19,7 +19,12 @@ var ImageParser = function(type,text,options) {
|
||||
attributes: {}
|
||||
},
|
||||
src;
|
||||
if(text) {
|
||||
if(options._canonical_uri) {
|
||||
element.attributes.src = {type: "string", value: options._canonical_uri};
|
||||
if(type === "application/pdf" || type === ".pdf") {
|
||||
element.tag = "embed";
|
||||
}
|
||||
} else if(text) {
|
||||
if(type === "application/pdf" || type === ".pdf") {
|
||||
element.attributes.src = {type: "string", value: "data:application/pdf;base64," + text};
|
||||
element.tag = "embed";
|
||||
|
||||
272
core/modules/parsers/parseutils.js
Normal file
272
core/modules/parsers/parseutils.js
Normal file
@@ -0,0 +1,272 @@
|
||||
/*\
|
||||
title: $:/core/modules/utils/parseutils.js
|
||||
type: application/javascript
|
||||
module-type: utils
|
||||
|
||||
Utility functions concerned with parsing text into tokens.
|
||||
|
||||
Most functions have the following pattern:
|
||||
|
||||
* The parameters are:
|
||||
** `source`: the source string being parsed
|
||||
** `pos`: the current parse position within the string
|
||||
** Any further parameters are used to identify the token that is being parsed
|
||||
* The return value is:
|
||||
** null if the token was not found at the specified position
|
||||
** an object representing the token with the following standard fields:
|
||||
*** `type`: string indicating the type of the token
|
||||
*** `start`: start position of the token in the source string
|
||||
*** `end`: end position of the token in the source string
|
||||
*** Any further fields required to describe the token
|
||||
|
||||
The exception is `skipWhiteSpace`, which just returns the position after the whitespace.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Look for a whitespace token. Returns null if not found, otherwise returns {type: "whitespace", start:, end:,}
|
||||
*/
|
||||
exports.parseWhiteSpace = function(source,pos) {
|
||||
var node = {
|
||||
type: "whitespace",
|
||||
start: pos
|
||||
};
|
||||
var re = /(\s)+/g;
|
||||
re.lastIndex = pos;
|
||||
var match = re.exec(source);
|
||||
if(match && match.index === pos) {
|
||||
node.end = pos + match[0].length;
|
||||
return node;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
Convenience wrapper for parseWhiteSpace. Returns the position after the whitespace
|
||||
*/
|
||||
exports.skipWhiteSpace = function(source,pos) {
|
||||
var whitespace = $tw.utils.parseWhiteSpace(source,pos);
|
||||
if(whitespace) {
|
||||
return whitespace.end;
|
||||
}
|
||||
return pos;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a given string token. Returns null if not found, otherwise returns {type: "token", value:, start:, end:,}
|
||||
*/
|
||||
exports.parseTokenString = function(source,pos,token) {
|
||||
var match = source.indexOf(token,pos) === pos;
|
||||
if(match) {
|
||||
return {
|
||||
type: "token",
|
||||
value: token,
|
||||
start: pos,
|
||||
end: pos + token.length
|
||||
};
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a token matching a regex. Returns null if not found, otherwise returns {type: "regexp", match:, start:, end:,}
|
||||
*/
|
||||
exports.parseTokenRegExp = function(source,pos,reToken) {
|
||||
var node = {
|
||||
type: "regexp",
|
||||
start: pos
|
||||
};
|
||||
reToken.lastIndex = pos;
|
||||
node.match = reToken.exec(source);
|
||||
if(node.match && node.match.index === pos) {
|
||||
node.end = pos + node.match[0].length;
|
||||
return node;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a string literal. Returns null if not found, otherwise returns {type: "string", value:, start:, end:,}
|
||||
*/
|
||||
exports.parseStringLiteral = function(source,pos) {
|
||||
var node = {
|
||||
type: "string",
|
||||
start: pos
|
||||
};
|
||||
var reString = /(?:"""([\s\S]*?)"""|"([^"]*)")|(?:'([^']*)')/g;
|
||||
reString.lastIndex = pos;
|
||||
var match = reString.exec(source);
|
||||
if(match && match.index === pos) {
|
||||
node.value = match[1] !== undefined ? match[1] :(
|
||||
match[2] !== undefined ? match[2] : match[3]
|
||||
);
|
||||
node.end = pos + match[0].length;
|
||||
return node;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a macro invocation parameter. Returns null if not found, or {type: "macro-parameter", name:, value:, start:, end:}
|
||||
*/
|
||||
exports.parseMacroParameter = function(source,pos) {
|
||||
var node = {
|
||||
type: "macro-parameter",
|
||||
start: pos
|
||||
};
|
||||
// Define our regexp
|
||||
var reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^\s>"'=]+)))/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for the parameter
|
||||
var token = $tw.utils.parseTokenRegExp(source,pos,reMacroParameter);
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Get the parameter details
|
||||
node.value = token.match[2] !== undefined ? token.match[2] : (
|
||||
token.match[3] !== undefined ? token.match[3] : (
|
||||
token.match[4] !== undefined ? token.match[4] : (
|
||||
token.match[5] !== undefined ? token.match[5] : (
|
||||
token.match[6] !== undefined ? token.match[6] : (
|
||||
""
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
if(token.match[1]) {
|
||||
node.name = token.match[1];
|
||||
}
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a macro invocation. Returns null if not found, or {type: "macrocall", name:, parameters:, start:, end:}
|
||||
*/
|
||||
exports.parseMacroInvocation = function(source,pos) {
|
||||
var node = {
|
||||
type: "macrocall",
|
||||
start: pos,
|
||||
params: []
|
||||
};
|
||||
// Define our regexps
|
||||
var reMacroName = /([^\s>"'=]+)/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a double less than sign
|
||||
var token = $tw.utils.parseTokenString(source,pos,"<<");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Get the macro name
|
||||
var name = $tw.utils.parseTokenRegExp(source,pos,reMacroName);
|
||||
if(!name) {
|
||||
return null;
|
||||
}
|
||||
node.name = name.match[1];
|
||||
pos = name.end;
|
||||
// Process parameters
|
||||
var parameter = $tw.utils.parseMacroParameter(source,pos);
|
||||
while(parameter) {
|
||||
node.params.push(parameter);
|
||||
pos = parameter.end;
|
||||
// Get the next parameter
|
||||
parameter = $tw.utils.parseMacroParameter(source,pos);
|
||||
}
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a double greater than sign
|
||||
token = $tw.utils.parseTokenString(source,pos,">>");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for an HTML attribute definition. Returns null if not found, otherwise returns {type: "attribute", name:, valueType: "string|indirect|macro", value:, start:, end:,}
|
||||
*/
|
||||
exports.parseAttribute = function(source,pos) {
|
||||
var node = {
|
||||
start: pos
|
||||
};
|
||||
// Define our regexps
|
||||
var reAttributeName = /([^\/\s>"'=]+)/g,
|
||||
reUnquotedAttribute = /([^\/\s<>"'=]+)/g,
|
||||
reIndirectValue = /\{\{([^\}]+)\}\}/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Get the attribute name
|
||||
var name = $tw.utils.parseTokenRegExp(source,pos,reAttributeName);
|
||||
if(!name) {
|
||||
return null;
|
||||
}
|
||||
node.name = name.match[1];
|
||||
pos = name.end;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for an equals sign
|
||||
var token = $tw.utils.parseTokenString(source,pos,"=");
|
||||
if(token) {
|
||||
pos = token.end;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a string literal
|
||||
var stringLiteral = $tw.utils.parseStringLiteral(source,pos);
|
||||
if(stringLiteral) {
|
||||
pos = stringLiteral.end;
|
||||
node.type = "string";
|
||||
node.value = stringLiteral.value;
|
||||
} else {
|
||||
// Look for an indirect value
|
||||
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
|
||||
if(indirectValue) {
|
||||
pos = indirectValue.end;
|
||||
node.type = "indirect";
|
||||
node.textReference = indirectValue.match[1];
|
||||
} else {
|
||||
// Look for a unquoted value
|
||||
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
|
||||
if(unquotedValue) {
|
||||
pos = unquotedValue.end;
|
||||
node.type = "string";
|
||||
node.value = unquotedValue.match[1];
|
||||
} else {
|
||||
// Look for a macro invocation value
|
||||
var macroInvocation = $tw.utils.parseMacroInvocation(source,pos);
|
||||
if(macroInvocation) {
|
||||
pos = macroInvocation.end;
|
||||
node.type = "macro";
|
||||
node.value = macroInvocation;
|
||||
} else {
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
}
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -14,12 +14,11 @@ The plain text parser processes blocks of source text into a degenerate parse tr
|
||||
|
||||
var TextParser = function(type,text,options) {
|
||||
this.tree = [{
|
||||
type: "element",
|
||||
tag: "pre",
|
||||
children: [{
|
||||
type: "text",
|
||||
text: text
|
||||
}]
|
||||
type: "codeblock",
|
||||
attributes: {
|
||||
code: {type: "string", value: text},
|
||||
language: {type: "string", value: type}
|
||||
}
|
||||
}];
|
||||
};
|
||||
|
||||
|
||||
@@ -46,8 +46,7 @@ exports.parse = function() {
|
||||
}
|
||||
// Return the $codeblock widget
|
||||
return [{
|
||||
type: "element",
|
||||
tag: "$codeblock",
|
||||
type: "codeblock",
|
||||
attributes: {
|
||||
code: {type: "string", value: text},
|
||||
language: {type: "string", value: this.match[1]}
|
||||
|
||||
@@ -40,8 +40,7 @@ exports.parse = function() {
|
||||
classes = this.match[5];
|
||||
// Return the list widget
|
||||
var node = {
|
||||
type: "element",
|
||||
tag: "$list",
|
||||
type: "list",
|
||||
attributes: {
|
||||
filter: {type: "string", value: filter}
|
||||
},
|
||||
|
||||
@@ -40,8 +40,7 @@ exports.parse = function() {
|
||||
classes = this.match[5];
|
||||
// Return the list widget
|
||||
var node = {
|
||||
type: "element",
|
||||
tag: "$list",
|
||||
type: "list",
|
||||
attributes: {
|
||||
filter: {type: "string", value: filter}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ exports.parse = function() {
|
||||
// Advance the parser position to past the tag
|
||||
this.parser.pos = tag.end;
|
||||
// Check for an immediately following double linebreak
|
||||
var hasLineBreak = !tag.isSelfClosing && !!this.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n]*\r?\n(?:[^\S\n]*\r?\n|$))/g);
|
||||
var hasLineBreak = !tag.isSelfClosing && !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n]*\r?\n(?:[^\S\n]*\r?\n|$))/g);
|
||||
// Set whether we're in block mode
|
||||
tag.isBlock = this.is.block || hasLineBreak;
|
||||
// Parse the body if we need to
|
||||
@@ -71,244 +71,7 @@ exports.parse = function() {
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a whitespace token. Returns null if not found, otherwise returns {type: "whitespace", start:, end:,}
|
||||
*/
|
||||
exports.parseWhiteSpace = function(source,pos) {
|
||||
var node = {
|
||||
type: "whitespace",
|
||||
start: pos
|
||||
};
|
||||
var re = /(\s)+/g;
|
||||
re.lastIndex = pos;
|
||||
var match = re.exec(source);
|
||||
if(match && match.index === pos) {
|
||||
node.end = pos + match[0].length;
|
||||
return node;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
Convenience wrapper for parseWhiteSpace
|
||||
*/
|
||||
exports.skipWhiteSpace = function(source,pos) {
|
||||
var whitespace = this.parseWhiteSpace(source,pos);
|
||||
if(whitespace) {
|
||||
return whitespace.end;
|
||||
}
|
||||
return pos;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a given string token. Returns null if not found, otherwise returns {type: "token", value:, start:, end:,}
|
||||
*/
|
||||
exports.parseTokenString = function(source,pos,token) {
|
||||
var match = source.indexOf(token,pos) === pos;
|
||||
if(match) {
|
||||
return {
|
||||
type: "token",
|
||||
value: token,
|
||||
start: pos,
|
||||
end: pos + token.length
|
||||
};
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a token matching a regex. Returns null if not found, otherwise returns {type: "regexp", match:, start:, end:,}
|
||||
*/
|
||||
exports.parseTokenRegExp = function(source,pos,reToken) {
|
||||
var node = {
|
||||
type: "regexp",
|
||||
start: pos
|
||||
};
|
||||
reToken.lastIndex = pos;
|
||||
node.match = reToken.exec(source);
|
||||
if(node.match && node.match.index === pos) {
|
||||
node.end = pos + node.match[0].length;
|
||||
return node;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a string literal. Returns null if not found, otherwise returns {type: "string", value:, start:, end:,}
|
||||
*/
|
||||
exports.parseStringLiteral = function(source,pos) {
|
||||
var node = {
|
||||
type: "string",
|
||||
start: pos
|
||||
};
|
||||
var reString = /(?:"([^"]*)")|(?:'([^']*)')/g;
|
||||
reString.lastIndex = pos;
|
||||
var match = reString.exec(source);
|
||||
if(match && match.index === pos) {
|
||||
node.value = match[1] === undefined ? match[2] : match[1];
|
||||
node.end = pos + match[0].length;
|
||||
return node;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a macro invocation parameter. Returns null if not found, or {type: "macro-parameter", name:, value:, start:, end:}
|
||||
*/
|
||||
exports.parseMacroParameter = function(source,pos) {
|
||||
var node = {
|
||||
type: "macro-parameter",
|
||||
start: pos
|
||||
};
|
||||
// Define our regexp
|
||||
var reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^\s>"'=]+)))/g;
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
// Look for the parameter
|
||||
var token = this.parseTokenRegExp(source,pos,reMacroParameter);
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Get the parameter details
|
||||
node.value = token.match[2] !== undefined ? token.match[2] : (
|
||||
token.match[3] !== undefined ? token.match[3] : (
|
||||
token.match[4] !== undefined ? token.match[4] : (
|
||||
token.match[5] !== undefined ? token.match[5] : (
|
||||
""
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
if(token.match[1]) {
|
||||
node.name = token.match[1];
|
||||
}
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a macro invocation. Returns null if not found, or {type: "macrocall", name:, parameters:, start:, end:}
|
||||
*/
|
||||
exports.parseMacroInvocation = function(source,pos) {
|
||||
var node = {
|
||||
type: "macrocall",
|
||||
start: pos,
|
||||
params: []
|
||||
};
|
||||
// Define our regexps
|
||||
var reMacroName = /([^\s>"'=]+)/g;
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
// Look for a double less than sign
|
||||
var token = this.parseTokenString(source,pos,"<<");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Get the macro name
|
||||
var name = this.parseTokenRegExp(source,pos,reMacroName);
|
||||
if(!name) {
|
||||
return null;
|
||||
}
|
||||
node.name = name.match[1];
|
||||
pos = name.end;
|
||||
// Process parameters
|
||||
var parameter = this.parseMacroParameter(source,pos);
|
||||
while(parameter) {
|
||||
node.params.push(parameter);
|
||||
pos = parameter.end;
|
||||
// Get the next parameter
|
||||
parameter = this.parseMacroParameter(source,pos);
|
||||
}
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
// Look for a double greater than sign
|
||||
token = this.parseTokenString(source,pos,">>");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for an HTML attribute definition. Returns null if not found, otherwise returns {type: "attribute", name:, valueType: "string|indirect|macro", value:, start:, end:,}
|
||||
*/
|
||||
exports.parseAttribute = function(source,pos) {
|
||||
var node = {
|
||||
start: pos
|
||||
};
|
||||
// Define our regexps
|
||||
var reAttributeName = /([^\/\s>"'=]+)/g,
|
||||
reUnquotedAttribute = /([^\/\s<>"'=]+)/g,
|
||||
reIndirectValue = /\{\{([^\}]+)\}\}/g;
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
// Get the attribute name
|
||||
var name = this.parseTokenRegExp(source,pos,reAttributeName);
|
||||
if(!name) {
|
||||
return null;
|
||||
}
|
||||
node.name = name.match[1];
|
||||
pos = name.end;
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
// Look for an equals sign
|
||||
var token = this.parseTokenString(source,pos,"=");
|
||||
if(token) {
|
||||
pos = token.end;
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
// Look for a string literal
|
||||
var stringLiteral = this.parseStringLiteral(source,pos);
|
||||
if(stringLiteral) {
|
||||
pos = stringLiteral.end;
|
||||
node.type = "string";
|
||||
node.value = stringLiteral.value;
|
||||
} else {
|
||||
// Look for an indirect value
|
||||
var indirectValue = this.parseTokenRegExp(source,pos,reIndirectValue);
|
||||
if(indirectValue) {
|
||||
pos = indirectValue.end;
|
||||
node.type = "indirect";
|
||||
node.textReference = indirectValue.match[1];
|
||||
} else {
|
||||
// Look for a unquoted value
|
||||
var unquotedValue = this.parseTokenRegExp(source,pos,reUnquotedAttribute);
|
||||
if(unquotedValue) {
|
||||
pos = unquotedValue.end;
|
||||
node.type = "string";
|
||||
node.value = unquotedValue.match[1];
|
||||
} else {
|
||||
// Look for a macro invocation value
|
||||
var macroInvocation = this.parseMacroInvocation(source,pos);
|
||||
if(macroInvocation) {
|
||||
pos = macroInvocation.end;
|
||||
node.type = "macro";
|
||||
node.value = macroInvocation;
|
||||
} else {
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
}
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for an HTML tag. Returns null if not found, otherwise returns {type: "tag", name:, attributes: [], isSelfClosing:, start:, end:,}
|
||||
Look for an HTML tag. Returns null if not found, otherwise returns {type: "element", name:, attributes: [], isSelfClosing:, start:, end:,}
|
||||
*/
|
||||
exports.parseTag = function(source,pos,options) {
|
||||
options = options || {};
|
||||
@@ -321,45 +84,48 @@ exports.parseTag = function(source,pos,options) {
|
||||
// Define our regexps
|
||||
var reTagName = /([a-zA-Z0-9\-\$]+)/g;
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a less than sign
|
||||
token = this.parseTokenString(source,pos,"<");
|
||||
token = $tw.utils.parseTokenString(source,pos,"<");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Get the tag name
|
||||
token = this.parseTokenRegExp(source,pos,reTagName);
|
||||
token = $tw.utils.parseTokenRegExp(source,pos,reTagName);
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
node.tag = token.match[1];
|
||||
if(node.tag.charAt(0) === "$") {
|
||||
node.type = node.tag.substr(1);
|
||||
}
|
||||
pos = token.end;
|
||||
// Process attributes
|
||||
var attribute = this.parseAttribute(source,pos);
|
||||
var attribute = $tw.utils.parseAttribute(source,pos);
|
||||
while(attribute) {
|
||||
node.attributes[attribute.name] = attribute;
|
||||
pos = attribute.end;
|
||||
// Get the next attribute
|
||||
attribute = this.parseAttribute(source,pos);
|
||||
attribute = $tw.utils.parseAttribute(source,pos);
|
||||
}
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a closing slash
|
||||
token = this.parseTokenString(source,pos,"/");
|
||||
token = $tw.utils.parseTokenString(source,pos,"/");
|
||||
if(token) {
|
||||
pos = token.end;
|
||||
node.isSelfClosing = true;
|
||||
}
|
||||
// Look for a greater than sign
|
||||
token = this.parseTokenString(source,pos,">");
|
||||
token = $tw.utils.parseTokenString(source,pos,">");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Check for a required line break
|
||||
if(options.requireLineBreak) {
|
||||
token = this.parseTokenRegExp(source,pos,/([^\S\n]*\r?\n(?:[^\S\n]*\r?\n|$))/g);
|
||||
token = $tw.utils.parseTokenRegExp(source,pos,/([^\S\n]*\r?\n(?:[^\S\n]*\r?\n|$))/g);
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
@@ -379,7 +145,7 @@ exports.findNextTag = function(source,pos,options) {
|
||||
// Try to parse the candidate as a tag
|
||||
var tag = this.parseTag(source,match.index,options);
|
||||
// Return success
|
||||
if(tag && this.isLegalTag(tag.tag)) {
|
||||
if(tag && this.isLegalTag(tag)) {
|
||||
return tag;
|
||||
}
|
||||
// Look for the next match
|
||||
@@ -391,11 +157,11 @@ exports.findNextTag = function(source,pos,options) {
|
||||
};
|
||||
|
||||
exports.isLegalTag = function(tag) {
|
||||
// If it starts with a $ then we'll let anything go
|
||||
if(tag.charAt(0) === "$") {
|
||||
// Widgets are always OK
|
||||
if(tag.type !== "element") {
|
||||
return true;
|
||||
// If it starts with a dash then it's not legal
|
||||
} else if(tag.charAt(0) === "-") {
|
||||
// If it's an HTML tag that starts with a dash then it's not legal
|
||||
} else if(tag.tag.charAt(0) === "-") {
|
||||
return false;
|
||||
} else {
|
||||
// Otherwise it's OK
|
||||
|
||||
133
core/modules/parsers/wikiparser/rules/image.js
Normal file
133
core/modules/parsers/wikiparser/rules/image.js
Normal file
@@ -0,0 +1,133 @@
|
||||
/*\
|
||||
title: $:/core/modules/parsers/wikiparser/rules/image.js
|
||||
type: application/javascript
|
||||
module-type: wikirule
|
||||
|
||||
Wiki text inline rule for embedding images. For example:
|
||||
|
||||
```
|
||||
[img[http://tiddlywiki.com/fractalveg.jpg]]
|
||||
[img width=23 height=24 [http://tiddlywiki.com/fractalveg.jpg]]
|
||||
[img width={{!!width}} height={{!!height}} [http://tiddlywiki.com/fractalveg.jpg]]
|
||||
[img[Description of image|http://tiddlywiki.com/fractalveg.jpg]]
|
||||
[img[TiddlerTitle]]
|
||||
[img[Description of image|TiddlerTitle]]
|
||||
```
|
||||
|
||||
Generates the `<$image>` widget.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.name = "image";
|
||||
exports.types = {inline: true};
|
||||
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
};
|
||||
|
||||
exports.findNextMatch = function(startPos) {
|
||||
// Find the next tag
|
||||
this.nextImage = this.findNextImage(this.parser.source,startPos);
|
||||
return this.nextImage ? this.nextImage.start : undefined;
|
||||
};
|
||||
|
||||
exports.parse = function() {
|
||||
// Move past the match
|
||||
this.parser.pos = this.nextImage.end;
|
||||
var node = {
|
||||
type: "image",
|
||||
attributes: this.nextImage.attributes
|
||||
};
|
||||
return [node];
|
||||
};
|
||||
|
||||
/*
|
||||
Find the next image from the current position
|
||||
*/
|
||||
exports.findNextImage = function(source,pos) {
|
||||
// A regexp for finding candidate HTML tags
|
||||
var reLookahead = /(\[img)/g;
|
||||
// Find the next candidate
|
||||
reLookahead.lastIndex = pos;
|
||||
var match = reLookahead.exec(source);
|
||||
while(match) {
|
||||
// Try to parse the candidate as a tag
|
||||
var tag = this.parseImage(source,match.index);
|
||||
// Return success
|
||||
if(tag) {
|
||||
return tag;
|
||||
}
|
||||
// Look for the next match
|
||||
reLookahead.lastIndex = match.index + 1;
|
||||
match = reLookahead.exec(source);
|
||||
}
|
||||
// Failed
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for an image at the specified position. Returns null if not found, otherwise returns {type: "image", attributes: [], isSelfClosing:, start:, end:,}
|
||||
*/
|
||||
exports.parseImage = function(source,pos) {
|
||||
var token,
|
||||
node = {
|
||||
type: "image",
|
||||
start: pos,
|
||||
attributes: {}
|
||||
};
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for the `[img`
|
||||
token = $tw.utils.parseTokenString(source,pos,"[img");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Process attributes
|
||||
if(source.charAt(pos) !== "[") {
|
||||
var attribute = $tw.utils.parseAttribute(source,pos);
|
||||
while(attribute) {
|
||||
node.attributes[attribute.name] = attribute;
|
||||
pos = attribute.end;
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
if(source.charAt(pos) !== "[") {
|
||||
// Get the next attribute
|
||||
attribute = $tw.utils.parseAttribute(source,pos);
|
||||
} else {
|
||||
attribute = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for the `[` after the attributes
|
||||
token = $tw.utils.parseTokenString(source,pos,"[");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Get the source up to the terminating `]]`
|
||||
token = $tw.utils.parseTokenRegExp(source,pos,/(?:([^|\]]*?)\|)?([^\]]+?)\]\]/g);
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
if(token.match[1]) {
|
||||
node.attributes.tooltip = {type: "string", value: token.match[1].trim()};
|
||||
}
|
||||
node.attributes.source = {type: "string", value: (token.match[2] || "").trim()};
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -35,12 +35,12 @@ exports.parse = function() {
|
||||
// Move past the macro call
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
var params = [],
|
||||
reParam = /\s*(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^"'\s]+)))/mg,
|
||||
reParam = /\s*(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^"'\s]+)))/mg,
|
||||
paramMatch = reParam.exec(paramString);
|
||||
while(paramMatch) {
|
||||
// Process this parameter
|
||||
var paramInfo = {
|
||||
value: paramMatch[2] || paramMatch[3] || paramMatch[4] || paramMatch[5]
|
||||
value: paramMatch[2] || paramMatch[3] || paramMatch[4] || paramMatch[5] || paramMatch[6]
|
||||
};
|
||||
if(paramMatch[1]) {
|
||||
paramInfo.name = paramMatch[1];
|
||||
|
||||
@@ -35,12 +35,12 @@ exports.parse = function() {
|
||||
// Move past the macro call
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
var params = [],
|
||||
reParam = /\s*(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^"'\s]+)))/mg,
|
||||
reParam = /\s*(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^"'\s]+)))/mg,
|
||||
paramMatch = reParam.exec(paramString);
|
||||
while(paramMatch) {
|
||||
// Process this parameter
|
||||
var paramInfo = {
|
||||
value: paramMatch[2] || paramMatch[3] || paramMatch[4] || paramMatch[5]
|
||||
value: paramMatch[2] || paramMatch[3] || paramMatch[4] || paramMatch[5]|| paramMatch[6]
|
||||
};
|
||||
if(paramMatch[1]) {
|
||||
paramInfo.name = paramMatch[1];
|
||||
|
||||
@@ -40,12 +40,12 @@ exports.parse = function() {
|
||||
var paramString = this.match[2],
|
||||
params = [];
|
||||
if(paramString !== "") {
|
||||
var reParam = /\s*([A-Za-z0-9\-_]+)(?:\s*:\s*(?:"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^"'\s]+)))?/mg,
|
||||
var reParam = /\s*([A-Za-z0-9\-_]+)(?:\s*:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^"'\s]+)))?/mg,
|
||||
paramMatch = reParam.exec(paramString);
|
||||
while(paramMatch) {
|
||||
// Save the parameter details
|
||||
var paramInfo = {name: paramMatch[1]},
|
||||
defaultValue = paramMatch[2] || paramMatch[3] || paramMatch[4] || paramMatch[5];
|
||||
defaultValue = paramMatch[2] || paramMatch[3] || paramMatch[4] || paramMatch[5] || paramMatch[6];
|
||||
if(defaultValue) {
|
||||
paramInfo["default"] = defaultValue;
|
||||
}
|
||||
|
||||
114
core/modules/parsers/wikiparser/rules/prettyextlink.js
Normal file
114
core/modules/parsers/wikiparser/rules/prettyextlink.js
Normal file
@@ -0,0 +1,114 @@
|
||||
/*\
|
||||
title: $:/core/modules/parsers/wikiparser/rules/prettyextlink.js
|
||||
type: application/javascript
|
||||
module-type: wikirule
|
||||
|
||||
Wiki text inline rule for external links. For example:
|
||||
|
||||
```
|
||||
[ext[http://tiddlywiki.com/fractalveg.jpg]]
|
||||
[ext[Tooltip|http://tiddlywiki.com/fractalveg.jpg]]
|
||||
```
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.name = "prettyextlink";
|
||||
exports.types = {inline: true};
|
||||
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
};
|
||||
|
||||
exports.findNextMatch = function(startPos) {
|
||||
// Find the next tag
|
||||
this.nextLink = this.findNextLink(this.parser.source,startPos);
|
||||
return this.nextLink ? this.nextLink.start : undefined;
|
||||
};
|
||||
|
||||
exports.parse = function() {
|
||||
// Move past the match
|
||||
this.parser.pos = this.nextLink.end;
|
||||
return [this.nextLink];
|
||||
};
|
||||
|
||||
/*
|
||||
Find the next link from the current position
|
||||
*/
|
||||
exports.findNextLink = function(source,pos) {
|
||||
// A regexp for finding candidate links
|
||||
var reLookahead = /(\[ext\[)/g;
|
||||
// Find the next candidate
|
||||
reLookahead.lastIndex = pos;
|
||||
var match = reLookahead.exec(source);
|
||||
while(match) {
|
||||
// Try to parse the candidate as a link
|
||||
var link = this.parseLink(source,match.index);
|
||||
// Return success
|
||||
if(link) {
|
||||
return link;
|
||||
}
|
||||
// Look for the next match
|
||||
reLookahead.lastIndex = match.index + 1;
|
||||
match = reLookahead.exec(source);
|
||||
}
|
||||
// Failed
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for an link at the specified position. Returns null if not found, otherwise returns {type: "element", tag: "a", attributes: [], isSelfClosing:, start:, end:,}
|
||||
*/
|
||||
exports.parseLink = function(source,pos) {
|
||||
var token,
|
||||
textNode = {
|
||||
type: "text"
|
||||
},
|
||||
node = {
|
||||
type: "element",
|
||||
tag: "a",
|
||||
start: pos,
|
||||
attributes: {
|
||||
"class": {type: "string", value: "tw-tiddlylink-external"},
|
||||
},
|
||||
children: [textNode]
|
||||
};
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for the `[ext[`
|
||||
token = $tw.utils.parseTokenString(source,pos,"[ext[");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Look ahead for the terminating `]]`
|
||||
var closePos = source.indexOf("]]",pos);
|
||||
if(closePos === -1) {
|
||||
return null;
|
||||
}
|
||||
// Look for a `|` separating the tooltip
|
||||
var splitPos = source.indexOf("|",pos);
|
||||
if(splitPos === -1 || splitPos > closePos) {
|
||||
splitPos = null;
|
||||
}
|
||||
// Pull out the tooltip and URL
|
||||
var tooltip, URL;
|
||||
if(splitPos) {
|
||||
URL = source.substring(splitPos + 1,closePos).trim();
|
||||
textNode.text = source.substring(pos,splitPos).trim();
|
||||
} else {
|
||||
URL = source.substring(pos,closePos).trim();
|
||||
textNode.text = URL;
|
||||
}
|
||||
node.attributes.href = {type: "string", value: URL};
|
||||
node.attributes.target = {type: "string", value: "_blank"};
|
||||
// Update the end position
|
||||
node.end = closePos + 2;
|
||||
return node;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -53,8 +53,7 @@ exports.parse = function() {
|
||||
}];
|
||||
} else {
|
||||
return [{
|
||||
type: "element",
|
||||
tag: "$link",
|
||||
type: "link",
|
||||
attributes: {
|
||||
to: {type: "string", value: link}
|
||||
},
|
||||
|
||||
@@ -36,8 +36,7 @@ exports.parse = function() {
|
||||
textRef = $tw.utils.trim(this.match[1]);
|
||||
// Prepare the transclude widget
|
||||
var transcludeNode = {
|
||||
type: "element",
|
||||
tag: "$transclude",
|
||||
type: "transclude",
|
||||
attributes: {},
|
||||
isBlock: true
|
||||
};
|
||||
@@ -48,8 +47,7 @@ exports.parse = function() {
|
||||
targetField = tr.field,
|
||||
targetIndex = tr.index,
|
||||
tiddlerNode = {
|
||||
type: "element",
|
||||
tag: "$tiddler",
|
||||
type: "tiddler",
|
||||
attributes: {
|
||||
tiddler: {type: "string", value: targetTitle}
|
||||
},
|
||||
|
||||
@@ -34,8 +34,7 @@ exports.parse = function() {
|
||||
textRef = $tw.utils.trim(this.match[1]);
|
||||
// Prepare the transclude widget
|
||||
var transcludeNode = {
|
||||
type: "element",
|
||||
tag: "$transclude",
|
||||
type: "transclude",
|
||||
attributes: {}
|
||||
};
|
||||
// Prepare the tiddler widget
|
||||
@@ -45,8 +44,7 @@ exports.parse = function() {
|
||||
targetField = tr.field,
|
||||
targetIndex = tr.index,
|
||||
tiddlerNode = {
|
||||
type: "element",
|
||||
tag: "$tiddler",
|
||||
type: "tiddler",
|
||||
attributes: {
|
||||
tiddler: {type: "string", value: targetTitle}
|
||||
},
|
||||
|
||||
@@ -64,8 +64,7 @@ exports.parse = function() {
|
||||
}
|
||||
}
|
||||
return [{
|
||||
type: "element",
|
||||
tag: "$link",
|
||||
type: "link",
|
||||
attributes: {
|
||||
to: {type: "string", value: linkText}
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@ var AndTidWiki = function(wiki) {
|
||||
|
||||
AndTidWiki.prototype.save = function(text,method,callback) {
|
||||
// Get the pathname of this document
|
||||
var pathname = decodeURIComponent(document.location.toString());
|
||||
var pathname = decodeURIComponent(document.location.toString().split("#")[0]);
|
||||
// Strip the file://
|
||||
if(pathname.indexOf("file://") === 0) {
|
||||
pathname = pathname.substr(7);
|
||||
|
||||
@@ -19,16 +19,31 @@ TiddlyFoxSaver.prototype.save = function(text,method,callback) {
|
||||
var messageBox = document.getElementById("tiddlyfox-message-box");
|
||||
if(messageBox) {
|
||||
// Get the pathname of this document
|
||||
var pathname = document.location.pathname;
|
||||
// Test for a Windows path of the form /x:/blah/blah
|
||||
if(/^\/[A-Z]\:\//i.test(pathname)) {
|
||||
// Remove the leading slash
|
||||
pathname = pathname.substr(1);
|
||||
// Convert slashes to backslashes
|
||||
pathname = pathname.replace(/\//g,"\\");
|
||||
var pathname = document.location.toString().split("#")[0];
|
||||
// Replace file://localhost/ with file:///
|
||||
if(pathname.indexOf("file://localhost/") == 0) {
|
||||
pathname = "file://" + pathname.substr(16);
|
||||
}
|
||||
// Windows path file:///x:/blah/blah --> x:\blah\blah
|
||||
if(/^file\:\/\/\/[A-Z]\:\//i.test(pathname)) {
|
||||
// Remove the leading slash and convert slashes to backslashes
|
||||
pathname = pathname.substr(8).replace(/\//g,"\\");
|
||||
// Firefox Windows network path file://///server/share/blah/blah --> //server/share/blah/blah
|
||||
} else if(pathname.indexOf("file://///") === 0) {
|
||||
pathname = "\\\\" + unescape(pathname.substr(10)).replace(/\//g,"\\");
|
||||
// Mac/Unix local path file:///path/path --> /path/path
|
||||
} else if(pathname.indexOf("file:///") == 0) {
|
||||
pathname = unescape(pathname.substr(7));
|
||||
// Mac/Unix local path file:/path/path --> /path/path
|
||||
} else if(pathname.indexOf("file:/") == 0) {
|
||||
pathname = unescape(pathname.substr(5));
|
||||
// Otherwise Windows networth path file://server/share/path/path --> \\server\share\path\path
|
||||
} else {
|
||||
pathname = "\\\\" + unescape(pathname.substr(7)).replace(new RegExp("/","g"),"\\");
|
||||
}
|
||||
// Create the message element and put it in the message box
|
||||
var message = document.createElement("div");
|
||||
console.log("Pathname",pathname);
|
||||
message.setAttribute("data-tiddlyfox-path",decodeURIComponent(pathname));
|
||||
message.setAttribute("data-tiddlyfox-content",text);
|
||||
messageBox.appendChild(message);
|
||||
|
||||
@@ -12,38 +12,22 @@ This is the main application logic for both the client and server
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
// Export name and synchronous status
|
||||
exports.name = "startup";
|
||||
exports.after = ["load-modules"];
|
||||
exports.synchronous = true;
|
||||
|
||||
// Set to `true` to enable performance instrumentation
|
||||
var PERFORMANCE_INSTRUMENTATION = false;
|
||||
|
||||
// Time (in ms) that we defer refreshing changes to draft tiddlers
|
||||
var DRAFT_TIDDLER_TIMEOUT = 400;
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
exports.startup = function() {
|
||||
var modules,n,m,f,commander;
|
||||
// Load modules
|
||||
$tw.modules.applyMethods("utils",$tw.utils);
|
||||
if($tw.node) {
|
||||
$tw.modules.applyMethods("utils-node",$tw.utils);
|
||||
}
|
||||
$tw.modules.applyMethods("global",$tw);
|
||||
$tw.modules.applyMethods("config",$tw.config);
|
||||
var modules,n,m,f;
|
||||
if($tw.browser) {
|
||||
$tw.utils.getBrowserInfo($tw.browser);
|
||||
$tw.browser.isIE = (/msie|trident/i.test(navigator.userAgent));
|
||||
}
|
||||
$tw.version = $tw.utils.extractVersionInfo();
|
||||
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
|
||||
$tw.modules.applyMethods("tiddlermethod",$tw.Tiddler.prototype);
|
||||
$tw.modules.applyMethods("wikimethod",$tw.Wiki.prototype);
|
||||
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
|
||||
$tw.macros = $tw.modules.getModulesByTypeAsHashmap("macro");
|
||||
// Set up the performance framework
|
||||
$tw.perf = new $tw.Performance(PERFORMANCE_INSTRUMENTATION);
|
||||
// Set up the parsers
|
||||
$tw.wiki.initParsers();
|
||||
// Set up the command modules
|
||||
$tw.Commander.initCommands();
|
||||
// Kick off the language manager and switcher
|
||||
$tw.language = new $tw.Language();
|
||||
$tw.languageSwitcher = new $tw.PluginSwitcher({
|
||||
@@ -64,24 +48,8 @@ exports.startup = function() {
|
||||
"$:/themes/tiddlywiki/vanilla"
|
||||
]
|
||||
});
|
||||
// Display the default tiddlers
|
||||
var displayDefaultTiddlers = function() {
|
||||
// Get the default tiddlers
|
||||
var defaultTiddlersTitle = "$:/DefaultTiddlers",
|
||||
defaultTiddlersTiddler = $tw.wiki.getTiddler(defaultTiddlersTitle),
|
||||
defaultTiddlers = [];
|
||||
if(defaultTiddlersTiddler) {
|
||||
defaultTiddlers = $tw.wiki.filterTiddlers(defaultTiddlersTiddler.fields.text);
|
||||
}
|
||||
// Initialise the story
|
||||
var storyTitle = "$:/StoryList",
|
||||
story = [];
|
||||
for(var t=0; t<defaultTiddlers.length; t++) {
|
||||
story[t] = defaultTiddlers[t];
|
||||
}
|
||||
$tw.wiki.addTiddler({title: storyTitle, text: "", list: story},$tw.wiki.getModificationFields());
|
||||
};
|
||||
displayDefaultTiddlers();
|
||||
// Clear outstanding tiddler store change events to avoid an unnecessary refresh cycle at startup
|
||||
$tw.wiki.clearTiddlerEventQueue();
|
||||
// Set up the syncer object
|
||||
$tw.syncer = new $tw.Syncer({wiki: $tw.wiki});
|
||||
// Host-specific startup
|
||||
@@ -101,196 +69,7 @@ exports.startup = function() {
|
||||
});
|
||||
// Install the animator
|
||||
$tw.anim = new $tw.utils.Animator();
|
||||
// Create a root widget for attaching event handlers. By using it as the parentWidget for another widget tree, one can reuse the event handlers
|
||||
$tw.rootWidget = new widget.widget({
|
||||
type: "widget",
|
||||
children: []
|
||||
},{
|
||||
wiki: $tw.wiki,
|
||||
document: document
|
||||
});
|
||||
// Install the modal message mechanism
|
||||
$tw.modal = new $tw.utils.Modal($tw.wiki);
|
||||
$tw.rootWidget.addEventListener("tw-modal",function(event) {
|
||||
$tw.modal.display(event.param);
|
||||
});
|
||||
// Install the notification mechanism
|
||||
$tw.notifier = new $tw.utils.Notifier($tw.wiki);
|
||||
$tw.rootWidget.addEventListener("tw-notify",function(event) {
|
||||
$tw.notifier.display(event.param);
|
||||
});
|
||||
// Install the scroller
|
||||
$tw.pageScroller = new $tw.utils.PageScroller();
|
||||
$tw.rootWidget.addEventListener("tw-scroll",function(event) {
|
||||
$tw.pageScroller.handleEvent(event);
|
||||
});
|
||||
// Listen for the tw-home message
|
||||
$tw.rootWidget.addEventListener("tw-home",function(event) {
|
||||
displayDefaultTiddlers();
|
||||
});
|
||||
// Install the save action handlers
|
||||
$tw.rootWidget.addEventListener("tw-save-wiki",function(event) {
|
||||
$tw.syncer.saveWiki({
|
||||
template: event.param,
|
||||
downloadType: "text/plain"
|
||||
});
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tw-auto-save-wiki",function(event) {
|
||||
$tw.syncer.saveWiki({
|
||||
method: "autosave",
|
||||
template: event.param,
|
||||
downloadType: "text/plain"
|
||||
});
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tw-download-file",function(event) {
|
||||
$tw.syncer.saveWiki({
|
||||
method: "download",
|
||||
template: event.param,
|
||||
downloadType: "text/plain"
|
||||
});
|
||||
});
|
||||
// Listen out for login/logout/refresh events in the browser
|
||||
$tw.rootWidget.addEventListener("tw-login",function() {
|
||||
$tw.syncer.handleLoginEvent();
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tw-logout",function() {
|
||||
$tw.syncer.handleLogoutEvent();
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tw-server-refresh",function() {
|
||||
$tw.syncer.handleRefreshEvent();
|
||||
});
|
||||
// Install the crypto event handlers
|
||||
$tw.rootWidget.addEventListener("tw-set-password",function(event) {
|
||||
$tw.passwordPrompt.createPrompt({
|
||||
serviceName: "Set a new password for this TiddlyWiki",
|
||||
noUserName: true,
|
||||
submitText: "Set password",
|
||||
canCancel: true,
|
||||
callback: function(data) {
|
||||
if(data) {
|
||||
$tw.crypto.setPassword(data.password);
|
||||
}
|
||||
return true; // Get rid of the password prompt
|
||||
}
|
||||
});
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tw-clear-password",function(event) {
|
||||
$tw.crypto.setPassword(null);
|
||||
});
|
||||
// Ensure that $:/isEncrypted is maintained properly
|
||||
$tw.wiki.addEventListener("change",function(changes) {
|
||||
if($tw.utils.hop(changes,"$:/isEncrypted")) {
|
||||
$tw.crypto.updateCryptoStateTiddler();
|
||||
}
|
||||
});
|
||||
// Set up the favicon
|
||||
var faviconTitle = "$:/favicon.ico",
|
||||
faviconLink = document.getElementById("faviconLink"),
|
||||
setFavicon = function() {
|
||||
var tiddler = $tw.wiki.getTiddler(faviconTitle);
|
||||
if(tiddler) {
|
||||
faviconLink.setAttribute("href","data:" + tiddler.fields.type + ";base64," + tiddler.fields.text);
|
||||
}
|
||||
};
|
||||
setFavicon();
|
||||
$tw.wiki.addEventListener("change",function(changes) {
|
||||
if($tw.utils.hop(changes,faviconTitle)) {
|
||||
setFavicon();
|
||||
}
|
||||
});
|
||||
// Set up the styles
|
||||
var styleTemplateTitle = "$:/core/ui/PageStylesheet",
|
||||
styleParser = $tw.wiki.parseTiddler(styleTemplateTitle);
|
||||
$tw.styleWidgetNode = $tw.wiki.makeWidget(styleParser,{document: $tw.fakeDocument});
|
||||
$tw.styleContainer = $tw.fakeDocument.createElement("style");
|
||||
$tw.styleWidgetNode.render($tw.styleContainer,null);
|
||||
$tw.styleElement = document.createElement("style");
|
||||
$tw.styleElement.innerHTML = $tw.styleContainer.textContent;
|
||||
document.head.insertBefore($tw.styleElement,document.head.firstChild);
|
||||
$tw.wiki.addEventListener("change",$tw.perf.report("styleRefresh",function(changes) {
|
||||
if($tw.styleWidgetNode.refresh(changes,$tw.styleContainer,null)) {
|
||||
$tw.styleElement.innerHTML = $tw.styleContainer.textContent;
|
||||
}
|
||||
}));
|
||||
// Display the $:/PageMacros tiddler to kick off the display
|
||||
renderPage();
|
||||
// Fix up the link between the root widget and the page container
|
||||
$tw.rootWidget.domNodes = [$tw.pageContainer];
|
||||
$tw.rootWidget.children = [$tw.pageWidgetNode];
|
||||
// If we're being viewed on a data: URI then give instructions for how to save
|
||||
if(document.location.protocol === "data:") {
|
||||
$tw.utils.dispatchCustomEvent(document,"tw-modal",{
|
||||
param: "$:/language/Modals/SaveInstructions"
|
||||
});
|
||||
}
|
||||
// Call browser startup modules
|
||||
$tw.modules.forEachModuleOfType("browser-startup",function(title,module) {
|
||||
if(module.startup) {
|
||||
module.startup();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// On the server, start a commander with the command line arguments
|
||||
commander = new $tw.Commander(
|
||||
$tw.boot.argv,
|
||||
function(err) {
|
||||
if(err) {
|
||||
console.log("Error: " + err);
|
||||
}
|
||||
},
|
||||
$tw.wiki,
|
||||
{output: process.stdout, error: process.stderr}
|
||||
);
|
||||
commander.execute();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Main render function for PageMacros, which includes the PageTemplate
|
||||
*/
|
||||
function renderPage() {
|
||||
// Parse and render the template
|
||||
var templateTitle = "$:/core/ui/PageMacros",
|
||||
parser = $tw.wiki.parseTiddler(templateTitle);
|
||||
$tw.perf.report("mainRender",function() {
|
||||
$tw.pageWidgetNode = $tw.wiki.makeWidget(parser,{document: document, parentWidget: $tw.rootWidget});
|
||||
$tw.pageContainer = document.createElement("div");
|
||||
$tw.utils.addClass($tw.pageContainer,"tw-page-container-wrapper");
|
||||
document.body.insertBefore($tw.pageContainer,document.body.firstChild);
|
||||
$tw.pageWidgetNode.render($tw.pageContainer,null);
|
||||
})();
|
||||
// Prepare refresh mechanism
|
||||
var deferredChanges = Object.create(null),
|
||||
timerId;
|
||||
function refresh() {
|
||||
// Process the refresh
|
||||
$tw.pageWidgetNode.refresh(deferredChanges,$tw.pageContainer,null);
|
||||
deferredChanges = Object.create(null);
|
||||
}
|
||||
// Add the change event handler
|
||||
$tw.wiki.addEventListener("change",$tw.perf.report("mainRefresh",function(changes) {
|
||||
// Check if only drafts have changed
|
||||
var onlyDraftsHaveChanged = true;
|
||||
for(var title in changes) {
|
||||
var tiddler = $tw.wiki.getTiddler(title);
|
||||
if(!tiddler || !tiddler.hasField("draft.of")) {
|
||||
onlyDraftsHaveChanged = false;
|
||||
}
|
||||
}
|
||||
// Defer the change if only drafts have changed
|
||||
if(timerId) {
|
||||
clearTimeout(timerId);
|
||||
}
|
||||
timerId = null;
|
||||
if(onlyDraftsHaveChanged) {
|
||||
timerId = setTimeout(refresh,DRAFT_TIDDLER_TIMEOUT);
|
||||
$tw.utils.extend(deferredChanges,changes);
|
||||
} else {
|
||||
$tw.utils.extend(deferredChanges,changes);
|
||||
refresh();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
37
core/modules/startup/commands.js
Normal file
37
core/modules/startup/commands.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/*\
|
||||
title: $:/core/modules/startup/commands.js
|
||||
type: application/javascript
|
||||
module-type: startup
|
||||
|
||||
Command processing
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
// Export name and synchronous status
|
||||
exports.name = "commands";
|
||||
exports.platforms = ["node"];
|
||||
exports.after = ["story"];
|
||||
exports.synchronous = false;
|
||||
|
||||
exports.startup = function(callback) {
|
||||
// On the server, start a commander with the command line arguments
|
||||
var commander = new $tw.Commander(
|
||||
$tw.boot.argv,
|
||||
function(err) {
|
||||
if(err) {
|
||||
console.log("Error: " + err);
|
||||
}
|
||||
callback();
|
||||
},
|
||||
$tw.wiki,
|
||||
{output: process.stdout, error: process.stderr}
|
||||
);
|
||||
commander.execute();
|
||||
};
|
||||
|
||||
})();
|
||||
43
core/modules/startup/favicon.js
Normal file
43
core/modules/startup/favicon.js
Normal file
@@ -0,0 +1,43 @@
|
||||
/*\
|
||||
title: $:/core/modules/startup/favicon.js
|
||||
type: application/javascript
|
||||
module-type: startup
|
||||
|
||||
Favicon handling
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
// Export name and synchronous status
|
||||
exports.name = "favicon";
|
||||
exports.platforms = ["browser"];
|
||||
exports.after = ["startup"];
|
||||
exports.synchronous = true;
|
||||
|
||||
// Favicon tiddler
|
||||
var FAVICON_TITLE = "$:/favicon.ico";
|
||||
|
||||
exports.startup = function() {
|
||||
// Set up the favicon
|
||||
setFavicon();
|
||||
// Reset the favicon when the tiddler changes
|
||||
$tw.wiki.addEventListener("change",function(changes) {
|
||||
if($tw.utils.hop(changes,FAVICON_TITLE)) {
|
||||
setFavicon();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function setFavicon() {
|
||||
var tiddler = $tw.wiki.getTiddler(FAVICON_TITLE);
|
||||
if(tiddler) {
|
||||
var faviconLink = document.getElementById("faviconLink");
|
||||
faviconLink.setAttribute("href","data:" + tiddler.fields.type + ";base64," + tiddler.fields.text);
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
36
core/modules/startup/load-modules.js
Normal file
36
core/modules/startup/load-modules.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/*\
|
||||
title: $:/core/modules/startup/load-modules.js
|
||||
type: application/javascript
|
||||
module-type: startup
|
||||
|
||||
Load core modules
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
// Export name and synchronous status
|
||||
exports.name = "load-modules";
|
||||
exports.synchronous = true;
|
||||
|
||||
exports.startup = function() {
|
||||
// Load modules
|
||||
$tw.modules.applyMethods("utils",$tw.utils);
|
||||
if($tw.node && !$tw.browser) {
|
||||
$tw.modules.applyMethods("utils-node",$tw.utils);
|
||||
}
|
||||
$tw.modules.applyMethods("global",$tw);
|
||||
$tw.modules.applyMethods("config",$tw.config);
|
||||
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
|
||||
$tw.modules.applyMethods("tiddlermethod",$tw.Tiddler.prototype);
|
||||
$tw.modules.applyMethods("wikimethod",$tw.Wiki.prototype);
|
||||
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
|
||||
$tw.macros = $tw.modules.getModulesByTypeAsHashmap("macro");
|
||||
$tw.wiki.initParsers();
|
||||
$tw.Commander.initCommands();
|
||||
};
|
||||
|
||||
})();
|
||||
47
core/modules/startup/password.js
Normal file
47
core/modules/startup/password.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/*\
|
||||
title: $:/core/modules/startup/password.js
|
||||
type: application/javascript
|
||||
module-type: startup
|
||||
|
||||
Password handling
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
// Export name and synchronous status
|
||||
exports.name = "password";
|
||||
exports.platforms = ["browser"];
|
||||
exports.after = ["rootwidget"];
|
||||
exports.synchronous = true;
|
||||
|
||||
exports.startup = function() {
|
||||
$tw.rootWidget.addEventListener("tw-set-password",function(event) {
|
||||
$tw.passwordPrompt.createPrompt({
|
||||
serviceName: "Set a new password for this TiddlyWiki",
|
||||
noUserName: true,
|
||||
submitText: "Set password",
|
||||
canCancel: true,
|
||||
callback: function(data) {
|
||||
if(data) {
|
||||
$tw.crypto.setPassword(data.password);
|
||||
}
|
||||
return true; // Get rid of the password prompt
|
||||
}
|
||||
});
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tw-clear-password",function(event) {
|
||||
$tw.crypto.setPassword(null);
|
||||
});
|
||||
// Ensure that $:/isEncrypted is maintained properly
|
||||
$tw.wiki.addEventListener("change",function(changes) {
|
||||
if($tw.utils.hop(changes,"$:/isEncrypted")) {
|
||||
$tw.crypto.updateCryptoStateTiddler();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
})();
|
||||
96
core/modules/startup/render.js
Normal file
96
core/modules/startup/render.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/*\
|
||||
title: $:/core/modules/startup/render.js
|
||||
type: application/javascript
|
||||
module-type: startup
|
||||
|
||||
Title, stylesheet and page rendering
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
// Export name and synchronous status
|
||||
exports.name = "render";
|
||||
exports.platforms = ["browser"];
|
||||
exports.after = ["story"];
|
||||
exports.synchronous = true;
|
||||
|
||||
// Default story and history lists
|
||||
var PAGE_TITLE_TITLE = "$:/core/wiki/title"
|
||||
var PAGE_STYLESHEET_TITLE = "$:/core/ui/PageStylesheet";
|
||||
var PAGE_TEMPLATE_TITLE = "$:/core/ui/PageTemplate";
|
||||
|
||||
// Time (in ms) that we defer refreshing changes to draft tiddlers
|
||||
var DRAFT_TIDDLER_TIMEOUT = 400;
|
||||
|
||||
exports.startup = function() {
|
||||
// Set up the title
|
||||
$tw.titleWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_TITLE_TITLE,{document: $tw.fakeDocument, parseAsInline: true});
|
||||
$tw.titleContainer = $tw.fakeDocument.createElement("div");
|
||||
$tw.titleWidgetNode.render($tw.titleContainer,null);
|
||||
document.title = $tw.titleContainer.textContent;
|
||||
$tw.wiki.addEventListener("change",function(changes) {
|
||||
if($tw.titleWidgetNode.refresh(changes,$tw.titleContainer,null)) {
|
||||
document.title = $tw.titleContainer.textContent;
|
||||
}
|
||||
});
|
||||
// Set up the styles
|
||||
$tw.styleWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_STYLESHEET_TITLE,{document: $tw.fakeDocument});
|
||||
$tw.styleContainer = $tw.fakeDocument.createElement("style");
|
||||
$tw.styleWidgetNode.render($tw.styleContainer,null);
|
||||
$tw.styleElement = document.createElement("style");
|
||||
$tw.styleElement.innerHTML = $tw.styleContainer.textContent;
|
||||
document.head.insertBefore($tw.styleElement,document.head.firstChild);
|
||||
$tw.wiki.addEventListener("change",$tw.perf.report("styleRefresh",function(changes) {
|
||||
if($tw.styleWidgetNode.refresh(changes,$tw.styleContainer,null)) {
|
||||
$tw.styleElement.innerHTML = $tw.styleContainer.textContent;
|
||||
}
|
||||
}));
|
||||
// Display the $:/core/ui/PageTemplate tiddler to kick off the display
|
||||
$tw.perf.report("mainRender",function() {
|
||||
$tw.pageWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_TEMPLATE_TITLE,{document: document, parentWidget: $tw.rootWidget});
|
||||
$tw.pageContainer = document.createElement("div");
|
||||
$tw.utils.addClass($tw.pageContainer,"tw-page-container-wrapper");
|
||||
document.body.insertBefore($tw.pageContainer,document.body.firstChild);
|
||||
$tw.pageWidgetNode.render($tw.pageContainer,null);
|
||||
})();
|
||||
// Prepare refresh mechanism
|
||||
var deferredChanges = Object.create(null),
|
||||
timerId;
|
||||
function refresh() {
|
||||
// Process the refresh
|
||||
$tw.pageWidgetNode.refresh(deferredChanges,$tw.pageContainer,null);
|
||||
deferredChanges = Object.create(null);
|
||||
}
|
||||
// Add the change event handler
|
||||
$tw.wiki.addEventListener("change",$tw.perf.report("mainRefresh",function(changes) {
|
||||
// Check if only drafts have changed
|
||||
var onlyDraftsHaveChanged = true;
|
||||
for(var title in changes) {
|
||||
var tiddler = $tw.wiki.getTiddler(title);
|
||||
if(!tiddler || !tiddler.hasField("draft.of")) {
|
||||
onlyDraftsHaveChanged = false;
|
||||
}
|
||||
}
|
||||
// Defer the change if only drafts have changed
|
||||
if(timerId) {
|
||||
clearTimeout(timerId);
|
||||
}
|
||||
timerId = null;
|
||||
if(onlyDraftsHaveChanged) {
|
||||
timerId = setTimeout(refresh,DRAFT_TIDDLER_TIMEOUT);
|
||||
$tw.utils.extend(deferredChanges,changes);
|
||||
} else {
|
||||
$tw.utils.extend(deferredChanges,changes);
|
||||
refresh();
|
||||
}
|
||||
}));
|
||||
// Fix up the link between the root widget and the page container
|
||||
$tw.rootWidget.domNodes = [$tw.pageContainer];
|
||||
$tw.rootWidget.children = [$tw.pageWidgetNode];
|
||||
};
|
||||
|
||||
})();
|
||||
78
core/modules/startup/rootwidget.js
Normal file
78
core/modules/startup/rootwidget.js
Normal file
@@ -0,0 +1,78 @@
|
||||
/*\
|
||||
title: $:/core/modules/startup/rootwidget.js
|
||||
type: application/javascript
|
||||
module-type: startup
|
||||
|
||||
Setup the root widget and the core root widget handlers
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
// Export name and synchronous status
|
||||
exports.name = "rootwidget";
|
||||
exports.platforms = ["browser"];
|
||||
exports.after = ["load-modules"];
|
||||
exports.before = ["story"];
|
||||
exports.synchronous = true;
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
exports.startup = function() {
|
||||
// Create a root widget for attaching event handlers. By using it as the parentWidget for another widget tree, one can reuse the event handlers
|
||||
$tw.rootWidget = new widget.widget({
|
||||
type: "widget",
|
||||
children: []
|
||||
},{
|
||||
wiki: $tw.wiki,
|
||||
document: document
|
||||
});
|
||||
// Install the modal message mechanism
|
||||
$tw.modal = new $tw.utils.Modal($tw.wiki);
|
||||
$tw.rootWidget.addEventListener("tw-modal",function(event) {
|
||||
$tw.modal.display(event.param);
|
||||
});
|
||||
// Install the notification mechanism
|
||||
$tw.notifier = new $tw.utils.Notifier($tw.wiki);
|
||||
$tw.rootWidget.addEventListener("tw-notify",function(event) {
|
||||
$tw.notifier.display(event.param);
|
||||
});
|
||||
// Install the scroller
|
||||
$tw.pageScroller = new $tw.utils.PageScroller();
|
||||
$tw.rootWidget.addEventListener("tw-scroll",function(event) {
|
||||
$tw.pageScroller.handleEvent(event);
|
||||
});
|
||||
// Install the save action handlers
|
||||
$tw.rootWidget.addEventListener("tw-save-wiki",function(event) {
|
||||
$tw.syncer.saveWiki({
|
||||
template: event.param,
|
||||
downloadType: "text/plain"
|
||||
});
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tw-auto-save-wiki",function(event) {
|
||||
$tw.syncer.saveWiki({
|
||||
method: "autosave",
|
||||
template: event.param,
|
||||
downloadType: "text/plain"
|
||||
});
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tw-download-file",function(event) {
|
||||
$tw.syncer.saveWiki({
|
||||
method: "download",
|
||||
template: event.param,
|
||||
downloadType: "text/plain"
|
||||
});
|
||||
});
|
||||
// If we're being viewed on a data: URI then give instructions for how to save
|
||||
if(document.location.protocol === "data:") {
|
||||
$tw.rootWidget.dispatchEvent({
|
||||
type: "tw-modal",
|
||||
param: "$:/language/Modals/SaveInstructions"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
144
core/modules/startup/story.js
Normal file
144
core/modules/startup/story.js
Normal file
@@ -0,0 +1,144 @@
|
||||
/*\
|
||||
title: $:/core/modules/startup/story.js
|
||||
type: application/javascript
|
||||
module-type: startup
|
||||
|
||||
Load core modules
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
// Export name and synchronous status
|
||||
exports.name = "story";
|
||||
exports.after = ["startup"];
|
||||
exports.synchronous = true;
|
||||
|
||||
// Default story and history lists
|
||||
var DEFAULT_STORY_TITLE = "$:/StoryList";
|
||||
var DEFAULT_HISTORY_TITLE = "$:/HistoryList";
|
||||
|
||||
// Default tiddlers
|
||||
var DEFAULT_TIDDLERS_TITLE = "$:/DefaultTiddlers";
|
||||
|
||||
// Config
|
||||
var CONFIG_UPDATE_ADDRESS_BAR = "$:/config/Navigation/UpdateAddressBar"; // Can be "no", "permalink", "permaview"
|
||||
var CONFIG_UPDATE_HISTORY = "$:/config/Navigation/UpdateHistory"; // Can be "yes" or "no"
|
||||
|
||||
exports.startup = function() {
|
||||
// Open startup tiddlers
|
||||
openStartupTiddlers();
|
||||
if($tw.browser) {
|
||||
// Set up location hash update
|
||||
$tw.wiki.addEventListener("change",function(changes) {
|
||||
if($tw.utils.hop(changes,DEFAULT_STORY_TITLE) || $tw.utils.hop(changes,DEFAULT_HISTORY_TITLE)) {
|
||||
updateLocationHash();
|
||||
}
|
||||
});
|
||||
// Listen for changes to the browser location hash
|
||||
window.addEventListener("hashchange",function() {
|
||||
var hash = $tw.utils.getLocationHash();
|
||||
if(hash !== $tw.locationHash) {
|
||||
$tw.locationHash = hash;
|
||||
openStartupTiddlers({defaultToCurrentStory: true});
|
||||
}
|
||||
},false)
|
||||
// Listen for the tw-home message
|
||||
$tw.rootWidget.addEventListener("tw-home",function(event) {
|
||||
var storyFilter = $tw.wiki.getTiddlerText(DEFAULT_TIDDLERS_TITLE),
|
||||
storyList = $tw.wiki.filterTiddlers(storyFilter);
|
||||
$tw.wiki.addTiddler({title: DEFAULT_STORY_TITLE, text: "", list: storyList},$tw.wiki.getModificationFields());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Process the location hash to open the specified tiddlers. Options:
|
||||
defaultToCurrentStory: If true, the current story is retained as the default, instead of opening the default tiddlers
|
||||
*/
|
||||
function openStartupTiddlers(options) {
|
||||
options = options || {};
|
||||
// Work out the target tiddler and the story filter. "null" means "unspecified"
|
||||
var target = null,
|
||||
storyFilter = null;
|
||||
if($tw.locationHash.length > 1) {
|
||||
var hash = $tw.locationHash.substr(1),
|
||||
split = hash.indexOf(":");
|
||||
if(split === -1) {
|
||||
target = decodeURIComponent(hash.trim());
|
||||
} else {
|
||||
target = decodeURIComponent(hash.substr(0,split).trim());
|
||||
storyFilter = decodeURIComponent(hash.substr(split + 1).trim());
|
||||
}
|
||||
}
|
||||
// If the story wasn't specified use the current tiddlers or a blank story
|
||||
if(storyFilter === null) {
|
||||
if(options.defaultToCurrentStory) {
|
||||
var currStoryList = $tw.wiki.getTiddlerList(DEFAULT_STORY_TITLE);
|
||||
storyFilter = $tw.utils.stringifyList(currStoryList);
|
||||
} else {
|
||||
if(target && target !== "") {
|
||||
storyFilter = "";
|
||||
} else {
|
||||
storyFilter = $tw.wiki.getTiddlerText(DEFAULT_TIDDLERS_TITLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Process the story filter to get the story list
|
||||
var storyList = $tw.wiki.filterTiddlers(storyFilter);
|
||||
// If the target tiddler isn't included then splice it in at the top
|
||||
if(target && storyList.indexOf(target) === -1) {
|
||||
storyList.unshift(target);
|
||||
}
|
||||
// Save the story list
|
||||
$tw.wiki.addTiddler({title: DEFAULT_STORY_TITLE, text: "", list: storyList},$tw.wiki.getModificationFields());
|
||||
// If a target tiddler was specified add it to the history stack
|
||||
if(target && target !== "") {
|
||||
// The target tiddler doesn't need double square brackets, but we'll silently remove them if they're present
|
||||
if(target.indexOf("[[") === 0 && target.substr(-2) === "]]") {
|
||||
target = target.substr(2,target.length - 4);
|
||||
}
|
||||
$tw.wiki.addToHistory(target);
|
||||
} else if(storyList.length > 0) {
|
||||
$tw.wiki.addToHistory(storyList[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function updateLocationHash() {
|
||||
var updateAddressBar = $tw.wiki.getTiddlerText(CONFIG_UPDATE_ADDRESS_BAR,"permaview").trim();
|
||||
if(updateAddressBar !== "no") {
|
||||
// Get the story and the history stack
|
||||
var storyList = $tw.wiki.getTiddlerList(DEFAULT_STORY_TITLE),
|
||||
historyList = $tw.wiki.getTiddlerData(DEFAULT_HISTORY_TITLE,[]);
|
||||
var targetTiddler = "";
|
||||
// The target tiddler is the one at the top of the stack
|
||||
if(historyList.length > 0) {
|
||||
targetTiddler = historyList[historyList.length-1].title;
|
||||
}
|
||||
// Blank the target tiddler if it isn't present in the story
|
||||
if(storyList.indexOf(targetTiddler) === -1) {
|
||||
targetTiddler = "";
|
||||
}
|
||||
// Assemble the location hash
|
||||
if(updateAddressBar === "permalink") {
|
||||
$tw.locationHash = "#" + encodeURIComponent(targetTiddler)
|
||||
} else {
|
||||
$tw.locationHash = "#" + encodeURIComponent(targetTiddler) + ":" + encodeURIComponent($tw.utils.stringifyList(storyList));
|
||||
}
|
||||
// Only change the location hash if we must, thus avoiding unnecessary onhashchange events
|
||||
if($tw.utils.getLocationHash() !== $tw.locationHash) {
|
||||
if($tw.wiki.getTiddlerText(CONFIG_UPDATE_HISTORY,"no").trim() === "yes") {
|
||||
// Assign the location hash so that history is updated
|
||||
window.location.hash = $tw.locationHash;
|
||||
} else {
|
||||
// We use replace so that browser history isn't affected
|
||||
window.location.replace(window.location.toString().split("#")[0] + $tw.locationHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
34
core/modules/startup/syncer-browser.js
Normal file
34
core/modules/startup/syncer-browser.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/*\
|
||||
title: $:/core/modules/startup/syncer-browser.js
|
||||
type: application/javascript
|
||||
module-type: startup
|
||||
|
||||
Startup handling
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
// Export name and synchronous status
|
||||
exports.name = "syncer-browser";
|
||||
exports.platforms = ["browser"];
|
||||
exports.after = ["rootwidget"];
|
||||
exports.synchronous = true;
|
||||
|
||||
exports.startup = function() {
|
||||
// Listen out for login/logout/refresh events in the browser
|
||||
$tw.rootWidget.addEventListener("tw-login",function() {
|
||||
$tw.syncer.handleLoginEvent();
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tw-logout",function() {
|
||||
$tw.syncer.handleLogoutEvent();
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tw-server-refresh",function() {
|
||||
$tw.syncer.handleRefreshEvent();
|
||||
});
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -15,10 +15,16 @@ Zooms between individual tiddlers
|
||||
var ZoominListView = function(listWidget) {
|
||||
var self = this;
|
||||
this.listWidget = listWidget;
|
||||
// Make all the tiddlers position absolute, and hide all but the first one
|
||||
// Get the index of the tiddler that is at the top of the history
|
||||
var history = this.listWidget.wiki.getTiddlerData(this.listWidget.historyTitle,[]),
|
||||
targetTiddler;
|
||||
if(history.length > 0) {
|
||||
targetTiddler = history[history.length-1].title;
|
||||
}
|
||||
// Make all the tiddlers position absolute, and hide all but the top (or first) one
|
||||
$tw.utils.each(this.listWidget.children,function(itemWidget,index) {
|
||||
var domNode = itemWidget.findFirstDomNode();
|
||||
if(index) {
|
||||
if(targetTiddler !== itemWidget.parseTreeNode.itemTitle || (!targetTiddler && index)) {
|
||||
domNode.style.display = "none";
|
||||
} else {
|
||||
self.currentTiddlerDomNode = domNode;
|
||||
|
||||
@@ -18,7 +18,11 @@ exports.hasTag = function(tag) {
|
||||
|
||||
exports.isPlugin = function() {
|
||||
return this.fields.type === "application/json" && this.hasField("plugin-type");
|
||||
}
|
||||
};
|
||||
|
||||
exports.isDraft = function() {
|
||||
return this.hasField("draft.of");
|
||||
};
|
||||
|
||||
exports.getFieldString = function(field) {
|
||||
var value = this.fields[field];
|
||||
@@ -53,4 +57,52 @@ exports.getFieldStringBlock = function(options) {
|
||||
return fields.join("\n");
|
||||
};
|
||||
|
||||
/*
|
||||
Compare two tiddlers for equality
|
||||
tiddler: the tiddler to compare
|
||||
excludeFields: array of field names to exclude from the comparison
|
||||
*/
|
||||
exports.isEqual = function(tiddler,excludeFields) {
|
||||
excludeFields = excludeFields || [];
|
||||
var self = this,
|
||||
differences = []; // Fields that have differences
|
||||
// Add to the differences array
|
||||
function addDifference(fieldName) {
|
||||
// Check for this field being excluded
|
||||
if(excludeFields.indexOf(fieldName) === -1) {
|
||||
// Save the field as a difference
|
||||
$tw.utils.pushTop(differences,fieldName);
|
||||
}
|
||||
}
|
||||
// Returns true if the two values of this field are equal
|
||||
function isFieldValueEqual(fieldName) {
|
||||
var valueA = self.fields[fieldName],
|
||||
valueB = tiddler.fields[fieldName];
|
||||
// Check for identical string values
|
||||
if(typeof(valueA) === "string" && typeof(valueB) === "string" && valueA === valueB) {
|
||||
return true;
|
||||
}
|
||||
// Check for identical array values
|
||||
if($tw.utils.isArray(valueA) && $tw.utils.isArray(valueB) && $tw.utils.isArrayEqual(valueA,valueB)) {
|
||||
return true;
|
||||
}
|
||||
// Otherwise the fields must be different
|
||||
return false;
|
||||
}
|
||||
// Compare our fields
|
||||
for(var fieldName in this.fields) {
|
||||
if(!isFieldValueEqual(fieldName)) {
|
||||
addDifference(fieldName);
|
||||
}
|
||||
}
|
||||
// There's a difference for every field in the other tiddler that we don't have
|
||||
for(fieldName in tiddler.fields) {
|
||||
if(!(fieldName in this.fields)) {
|
||||
addDifference(fieldName);
|
||||
}
|
||||
}
|
||||
// Return whether there were any differences
|
||||
return differences.length === 0;
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -130,9 +130,4 @@ exports.convertEventName = function(eventName) {
|
||||
return newEventName;
|
||||
};
|
||||
|
||||
// Setup constants for the current browser
|
||||
exports.getBrowserInfo = function(info) {
|
||||
info.isIE = (/msie|trident/i.test(navigator.userAgent));
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -157,17 +157,5 @@ exports.addEventListeners = function(domNode,events) {
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Construct and dispatch a custom event
|
||||
*/
|
||||
exports.dispatchCustomEvent = function(target,name,members) {
|
||||
var event = document.createEvent("Event");
|
||||
event.initEvent(name,true,true);
|
||||
$tw.utils.each(members,function(member,name) {
|
||||
event[name] = member;
|
||||
});
|
||||
target.dispatchEvent(event);
|
||||
};
|
||||
|
||||
|
||||
})();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user