mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-24 03:44:41 +00:00
Compare commits
484 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
165538180e | ||
|
|
42060acb43 | ||
|
|
978d52f3e8 | ||
|
|
b8129b6e36 | ||
|
|
b5e4cc0cc8 | ||
|
|
3732c83ad4 | ||
|
|
ff6070f033 | ||
|
|
fb12807a33 | ||
|
|
953038f0b2 | ||
|
|
f74e4c520d | ||
|
|
85da202cca | ||
|
|
00fb4190f2 | ||
|
|
19d2aab6b9 | ||
|
|
fff97e7326 | ||
|
|
996ee52cf9 | ||
|
|
bb036ced93 | ||
|
|
ef5c53bf9a | ||
|
|
6899be59e2 | ||
|
|
9e67be5b6c | ||
|
|
7f5a5dbe09 | ||
|
|
6fb2a33847 | ||
|
|
9305881efb | ||
|
|
6496107a32 | ||
|
|
0610a7b1eb | ||
|
|
16652f926f | ||
|
|
dd09266b46 | ||
|
|
27858625df | ||
|
|
ab24d58b11 | ||
|
|
ba7e7fd649 | ||
|
|
1873785ef6 | ||
|
|
2008a617b5 | ||
|
|
8053cf1806 | ||
|
|
c81bf49704 | ||
|
|
1c5b3e3d8d | ||
|
|
82d18ad1fa | ||
|
|
4ef9ccbab9 | ||
|
|
83386f34b5 | ||
|
|
b88812233c | ||
|
|
471b73158a | ||
|
|
990619b634 | ||
|
|
8d3dfdebe3 | ||
|
|
654eda02c6 | ||
|
|
a170210069 | ||
|
|
67066fe86e | ||
|
|
fada96651e | ||
|
|
0402dbd48d | ||
|
|
bab1bca485 | ||
|
|
a986e4f7d6 | ||
|
|
f49c55fe3c | ||
|
|
ad175e222b | ||
|
|
2a3ea14437 | ||
|
|
762810361f | ||
|
|
9244a2f4fd | ||
|
|
067e8a9f94 | ||
|
|
a91ae1a877 | ||
|
|
2be09f23eb | ||
|
|
59264bbf2a | ||
|
|
803c2c749f | ||
|
|
c3df892321 | ||
|
|
68e6298e7d | ||
|
|
9df64c1ecf | ||
|
|
b8ac2d7a06 | ||
|
|
41d30bebc8 | ||
|
|
6df7b617fb | ||
|
|
31e7dbf020 | ||
|
|
f49ab78ebd | ||
|
|
41d3e80397 | ||
|
|
e1bb532d98 | ||
|
|
8159c4a865 | ||
|
|
0903fd2fec | ||
|
|
62a7fa4203 | ||
|
|
776ce0f65f | ||
|
|
4952be6518 | ||
|
|
427fbfd623 | ||
|
|
17711657b6 | ||
|
|
394725f00c | ||
|
|
9a2de11db1 | ||
|
|
fab67a463b | ||
|
|
64fe260f4d | ||
|
|
8db893b9c9 | ||
|
|
2d4831f920 | ||
|
|
0a6870656f | ||
|
|
b5653babdf | ||
|
|
3afaa9de9a | ||
|
|
dbaccf792d | ||
|
|
5faae2547d | ||
|
|
7f78065992 | ||
|
|
cb1d35e230 | ||
|
|
0a2d532a7b | ||
|
|
e669ec098f | ||
|
|
269fa5313f | ||
|
|
b30746813b | ||
|
|
32c5490a20 | ||
|
|
e86d4d29d5 | ||
|
|
cbd07465f3 | ||
|
|
27b75f3922 | ||
|
|
8a53cca00d | ||
|
|
5d36b484c6 | ||
|
|
e2bad34e89 | ||
|
|
b67e088e55 | ||
|
|
cb77f3f503 | ||
|
|
8226efa154 | ||
|
|
ac49b4d20c | ||
|
|
78cc80db13 | ||
|
|
2bcb36f151 | ||
|
|
8e7c0907f8 | ||
|
|
66dc7df745 | ||
|
|
fd88be4173 | ||
|
|
880a2aa153 | ||
|
|
173e9c6c3a | ||
|
|
a87a299aa9 | ||
|
|
f5b2599432 | ||
|
|
ba2f4822dd | ||
|
|
a3a25f2453 | ||
|
|
ecbbe87a0d | ||
|
|
217670cdf3 | ||
|
|
345a6a0f90 | ||
|
|
c647b42574 | ||
|
|
7811614d53 | ||
|
|
8aa6427d67 | ||
|
|
86286c6fce | ||
|
|
f7da4bafae | ||
|
|
08c900786e | ||
|
|
efa593bb50 | ||
|
|
19f2280803 | ||
|
|
6721d70de5 | ||
|
|
7b3d190974 | ||
|
|
3997600137 | ||
|
|
9f31867731 | ||
|
|
a06acc4eb8 | ||
|
|
6f3db0118e | ||
|
|
f5acf3adaa | ||
|
|
5ac2064d18 | ||
|
|
2a4c60b23d | ||
|
|
3edaa652ee | ||
|
|
77fedf9582 | ||
|
|
cf4c4532c3 | ||
|
|
ea0e1357bf | ||
|
|
ef7210adf4 | ||
|
|
e91fb29253 | ||
|
|
f978355ea4 | ||
|
|
1e1b2e28b6 | ||
|
|
d489f61f2a | ||
|
|
727d660715 | ||
|
|
6e5566b907 | ||
|
|
958b3e7b7c | ||
|
|
c578566dea | ||
|
|
8a0aef4dcb | ||
|
|
35a71ad577 | ||
|
|
c202ef4201 | ||
|
|
f42351e235 | ||
|
|
da61917797 | ||
|
|
16a53ae394 | ||
|
|
d1948621d3 | ||
|
|
de04755a0a | ||
|
|
02b141f97f | ||
|
|
15b576618f | ||
|
|
91db09bd1e | ||
|
|
d2f1debf92 | ||
|
|
f6c9150d32 | ||
|
|
2f723dd85a | ||
|
|
42bde75de2 | ||
|
|
112443c054 | ||
|
|
7781cb1f8b | ||
|
|
bf51ae0019 | ||
|
|
ed67f4a88b | ||
|
|
274dffe750 | ||
|
|
14003b0e88 | ||
|
|
36c7e82cc0 | ||
|
|
31b141097d | ||
|
|
448d108d69 | ||
|
|
69d3a47073 | ||
|
|
e313b0b7ca | ||
|
|
dc9f4e2de7 | ||
|
|
cb2bf25563 | ||
|
|
e09ac2ab37 | ||
|
|
b580baf5ee | ||
|
|
a6500ba711 | ||
|
|
fd8ede07bf | ||
|
|
c8d6f3b681 | ||
|
|
6582b106ee | ||
|
|
90684f9f52 | ||
|
|
ceb2d9f119 | ||
|
|
9b27f82a80 | ||
|
|
d8b79723cd | ||
|
|
2e2ed7902c | ||
|
|
6fd70f9c11 | ||
|
|
6099ec576c | ||
|
|
47dc59cd54 | ||
|
|
c963680f9c | ||
|
|
e6ac709840 | ||
|
|
32a2bea7f5 | ||
|
|
62829dc9d3 | ||
|
|
58cb300a0a | ||
|
|
a4dcc20797 | ||
|
|
2002ff72b7 | ||
|
|
250a1e5356 | ||
|
|
630a0ecf9e | ||
|
|
fef2ea97a1 | ||
|
|
73eb7fbd4e | ||
|
|
fc09f8e331 | ||
|
|
1a08430a0c | ||
|
|
23dd8da22c | ||
|
|
e5e5b1d739 | ||
|
|
7fcdc83bae | ||
|
|
86387a9185 | ||
|
|
dd7837d164 | ||
|
|
4a66ecbf6f | ||
|
|
f02352f6a1 | ||
|
|
cd412d8ccb | ||
|
|
18fe112da7 | ||
|
|
37bb75f0cf | ||
|
|
ac1d5b828d | ||
|
|
55bc6e086f | ||
|
|
6fdc5c8cb2 | ||
|
|
7590977dd5 | ||
|
|
1e8a56768f | ||
|
|
8012a3508f | ||
|
|
abb3c01505 | ||
|
|
28c732d2be | ||
|
|
72c64013c7 | ||
|
|
9c2726c530 | ||
|
|
427b56039b | ||
|
|
736ac9052d | ||
|
|
6c08fec2ee | ||
|
|
147d758931 | ||
|
|
5f6abad3c5 | ||
|
|
5b09881679 | ||
|
|
496610aa49 | ||
|
|
c80fcf19c0 | ||
|
|
698733a4ad | ||
|
|
a8f70b08a8 | ||
|
|
b992b79adb | ||
|
|
feab75a6d1 | ||
|
|
2f8053265e | ||
|
|
409a297a63 | ||
|
|
ba0da99b17 | ||
|
|
634ac92ba2 | ||
|
|
184fd9dda8 | ||
|
|
94d18a2f18 | ||
|
|
ff85fcfe93 | ||
|
|
e8d1fbba6c | ||
|
|
7869546fef | ||
|
|
dddfb7ce67 | ||
|
|
5ae14a16ec | ||
|
|
fddc5d4ee6 | ||
|
|
091864ddaf | ||
|
|
07198b9cda | ||
|
|
4401e71498 | ||
|
|
df416814b1 | ||
|
|
b7e0930122 | ||
|
|
0a5c826816 | ||
|
|
25c0ebb523 | ||
|
|
b32a5aa9af | ||
|
|
232eba2f7d | ||
|
|
04a4a0f92e | ||
|
|
0513837228 | ||
|
|
58cdbbf865 | ||
|
|
373afd72c8 | ||
|
|
7fcd2f132e | ||
|
|
edd3156430 | ||
|
|
8c72a28f0c | ||
|
|
61db047870 | ||
|
|
9b72eabd1a | ||
|
|
12b08b7abf | ||
|
|
53124e1d82 | ||
|
|
4ecc99c9d5 | ||
|
|
61d87875ff | ||
|
|
73703da2e7 | ||
|
|
aa5eaa98fc | ||
|
|
662ae91067 | ||
|
|
d5fa68b46a | ||
|
|
6e81122fa3 | ||
|
|
6575db07c7 | ||
|
|
f4d8c90191 | ||
|
|
37ea659bf0 | ||
|
|
754c1251a9 | ||
|
|
1c436cbbf3 | ||
|
|
94607aa9cd | ||
|
|
62477c9fbb | ||
|
|
b1edcdb757 | ||
|
|
d51a89135d | ||
|
|
d38b42f7c7 | ||
|
|
fffd0ee9e1 | ||
|
|
9f0d726f7d | ||
|
|
7709192cc8 | ||
|
|
02ae8969b2 | ||
|
|
a01dc6cb3d | ||
|
|
f99fb4f9f5 | ||
|
|
e52a616891 | ||
|
|
05243a6c48 | ||
|
|
a89991cc46 | ||
|
|
f4fe254038 | ||
|
|
9f630b5829 | ||
|
|
c904aeb05f | ||
|
|
efd7aa3a53 | ||
|
|
a4b24670f6 | ||
|
|
2e0b2c8045 | ||
|
|
d068cb3625 | ||
|
|
0d8c749f37 | ||
|
|
0303b7871b | ||
|
|
44d1a00bb0 | ||
|
|
784db30614 | ||
|
|
26c6d6035e | ||
|
|
b82cf3d070 | ||
|
|
f07ffb2b41 | ||
|
|
c9b16d88f3 | ||
|
|
256321cd42 | ||
|
|
71aed78e2e | ||
|
|
0ab29e2c09 | ||
|
|
648c7ccd1f | ||
|
|
2dc70682cd | ||
|
|
441011885c | ||
|
|
449fd02cda | ||
|
|
a7dc8b5583 | ||
|
|
7478ba9165 | ||
|
|
12630d4a91 | ||
|
|
07635d7b3e | ||
|
|
e61c71961b | ||
|
|
f047e7cbf5 | ||
|
|
2c2d03f7a7 | ||
|
|
c036c22826 | ||
|
|
6de13e2f60 | ||
|
|
0c2689dd78 | ||
|
|
a9e595c3f6 | ||
|
|
348a0bc8bc | ||
|
|
477c41f843 | ||
|
|
0b1ce30a04 | ||
|
|
e8b50df4a6 | ||
|
|
2104017249 | ||
|
|
148c1a0355 | ||
|
|
dd4305d520 | ||
|
|
638eb53429 | ||
|
|
b6e2985ac6 | ||
|
|
87eab62b7e | ||
|
|
fb0713ae78 | ||
|
|
16bb474fef | ||
|
|
77e6f5c0e3 | ||
|
|
41e338dc41 | ||
|
|
a6875df7ef | ||
|
|
655fc31cee | ||
|
|
18c00c2ef0 | ||
|
|
b862348b06 | ||
|
|
36e76429b1 | ||
|
|
181897514f | ||
|
|
810033bd71 | ||
|
|
6aab4d5524 | ||
|
|
72f2a94251 | ||
|
|
6dedcd958d | ||
|
|
f97d18bb6e | ||
|
|
9d7d3fefa0 | ||
|
|
6ff7a7d261 | ||
|
|
2710fae71d | ||
|
|
0e6855eba8 | ||
|
|
8b04cfd4d5 | ||
|
|
2c37c25c28 | ||
|
|
adb07ccba0 | ||
|
|
b64216cfa7 | ||
|
|
9601e570af | ||
|
|
5c5628e10b | ||
|
|
cdeabbaf56 | ||
|
|
5577f7a4fe | ||
|
|
51b4f63c5c | ||
|
|
7df58a6813 | ||
|
|
158f96a207 | ||
|
|
dc29acd656 | ||
|
|
af40485e37 | ||
|
|
9b2d52716a | ||
|
|
64b665e706 | ||
|
|
f709641967 | ||
|
|
94f143bf64 | ||
|
|
22fe4451c8 | ||
|
|
1c982fba2d | ||
|
|
0ea00b59b0 | ||
|
|
5e9fc661a9 | ||
|
|
e5f3301c1c | ||
|
|
b08a7e3f04 | ||
|
|
44c66b98a9 | ||
|
|
ce256102a7 | ||
|
|
6f5f9ca2fb | ||
|
|
e31c5563ff | ||
|
|
70f5dff81e | ||
|
|
689e172e79 | ||
|
|
5ffcd7e5da | ||
|
|
5a37a84a54 | ||
|
|
4228c3f9cc | ||
|
|
a4eb139f99 | ||
|
|
7bc1458749 | ||
|
|
92b8368115 | ||
|
|
c4bb2110e3 | ||
|
|
f7d938e4bc | ||
|
|
8defe41458 | ||
|
|
6753a1485a | ||
|
|
7f97e3080c | ||
|
|
b6d901f888 | ||
|
|
90b7961629 | ||
|
|
c5aa855ce6 | ||
|
|
036ea400c5 | ||
|
|
049244e8a8 | ||
|
|
95aca11719 | ||
|
|
02fbae4200 | ||
|
|
fc3227831f | ||
|
|
72ec4d05e4 | ||
|
|
07aeaaa1a4 | ||
|
|
790d606885 | ||
|
|
c6f1fb7627 | ||
|
|
44816ea0da | ||
|
|
ca7b62a5f6 | ||
|
|
353821f442 | ||
|
|
4c1e3aa8d6 | ||
|
|
952826e0fa | ||
|
|
e6aaafbc8d | ||
|
|
79eb6a5ec1 | ||
|
|
7c0528340d | ||
|
|
273768da1d | ||
|
|
52a30be7c6 | ||
|
|
479726c46e | ||
|
|
3afb251b3a | ||
|
|
1f829dd5a8 | ||
|
|
95dbdff08a | ||
|
|
bfd09133de | ||
|
|
dc74fc4306 | ||
|
|
557053ab35 | ||
|
|
317d75171c | ||
|
|
0e568fe69a | ||
|
|
e2fe40a282 | ||
|
|
193fb32423 | ||
|
|
e14e69bedc | ||
|
|
af9f90e8cd | ||
|
|
b899563971 | ||
|
|
d0afbe50a1 | ||
|
|
0aac98f361 | ||
|
|
fa638b8b5b | ||
|
|
4d5a79acb8 | ||
|
|
fcfdb0632b | ||
|
|
d14d7f0168 | ||
|
|
83bea2a270 | ||
|
|
2b8efdc3ea | ||
|
|
27d0b2b491 | ||
|
|
824930682a | ||
|
|
d8104e2c41 | ||
|
|
06f1f1a532 | ||
|
|
6121c0b5a7 | ||
|
|
2c5b1c4a8c | ||
|
|
3d687a7935 | ||
|
|
5d20a54713 | ||
|
|
14623d33d2 | ||
|
|
37b335a136 | ||
|
|
d5a25c9a96 | ||
|
|
6c48c24332 | ||
|
|
86e27d64f2 | ||
|
|
decbe33f1f | ||
|
|
8205893af9 | ||
|
|
75158c0366 | ||
|
|
a2d4239db0 | ||
|
|
1d9c932e16 | ||
|
|
58f7e7bd85 | ||
|
|
8f54231d62 | ||
|
|
97f7f8f111 | ||
|
|
4e0b03b19f | ||
|
|
097b0e2d4a | ||
|
|
87f077314b | ||
|
|
7a07c84eac | ||
|
|
512d5662cc | ||
|
|
32974eebdb | ||
|
|
eca5df9f01 | ||
|
|
c42eba3308 | ||
|
|
77d286213f | ||
|
|
da864e23d6 | ||
|
|
d58bc33df4 | ||
|
|
c97c3cea74 | ||
|
|
e9f2a24f30 | ||
|
|
0b7f72ce5c | ||
|
|
52d328ee1b | ||
|
|
ddf22ec2a4 | ||
|
|
6b4294923f | ||
|
|
2dd76007d3 | ||
|
|
31470f676c | ||
|
|
d6bffad8ab | ||
|
|
6195069c5e | ||
|
|
8e3f9d6aba | ||
|
|
1793dc5e34 | ||
|
|
18ed2faf82 | ||
|
|
38b088eabf |
34
.travis.yml
Normal file
34
.travis.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
language: node_js
|
||||
- "node"
|
||||
|
||||
stages:
|
||||
- name: test
|
||||
- name: build-prerelease
|
||||
if: branch = "master"
|
||||
- name: build-tiddlywiki-com
|
||||
if: branch = "tiddlywiki-com"
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: test
|
||||
script: ./bin/test.sh
|
||||
- stage: build-prerelease
|
||||
script:
|
||||
- ./bin/travis-pre-build.sh
|
||||
- export TW5_BUILD_TIDDLYWIKI='./tiddlywiki.js'
|
||||
- export TW5_BUILD_VERSION=$(./bin/get-plugin-library-version-number)
|
||||
- export TW5_BUILD_DETAILS="Prerelease built from branch '$TRAVIS_BRANCH' at commit $(git rev-parse HEAD) of $(git remote get-url origin) at $(date +'%F %T %Z')"
|
||||
- export TW5_BUILD_MAIN_EDITION='./editions/prerelease'
|
||||
- export TW5_BUILD_OUTPUT='./output/prerelease'
|
||||
- ./bin/build-site.sh
|
||||
- ./bin/travis-push.sh
|
||||
- stage: build-tiddlywiki-com
|
||||
script:
|
||||
- ./bin/travis-pre-build.sh
|
||||
- export TW5_BUILD_TIDDLYWIKI='./node_modules/tiddlywiki/tiddlywiki.js'
|
||||
- export TW5_BUILD_VERSION=$(./bin/get-plugin-library-version-number)
|
||||
- export TW5_BUILD_DETAILS="Built from branch '$TRAVIS_BRANCH' at commit $(git rev-parse HEAD) of $(git remote get-url origin) at $(date +'%F %T %Z')"
|
||||
- export TW5_BUILD_MAIN_EDITION='./editions/tw5.com'
|
||||
- export TW5_BUILD_OUTPUT='./output'
|
||||
- ./bin/build-site.sh
|
||||
- ./bin/travis-push.sh
|
||||
15
bin/2bld.cmd
15
bin/2bld.cmd
@@ -1,15 +0,0 @@
|
||||
@echo off
|
||||
|
||||
rem build TiddlyWiki 2.x
|
||||
|
||||
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 index.html text/plain ^
|
||||
|| exit 1
|
||||
|
||||
fc tmp\tw2\index.html editions\tw2\target\prebuilt.html
|
||||
15
bin/2bld.sh
15
bin/2bld.sh
@@ -1,15 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# build TiddlyWiki 2.x
|
||||
|
||||
# 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 index.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
diff -q tmp/tw2/index.html editions/tw2/target/prebuilt.html
|
||||
449
bin/build-site.sh
Executable file
449
bin/build-site.sh
Executable file
@@ -0,0 +1,449 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Build all tiddlywiki.com assets.
|
||||
|
||||
# Default to the current version number for building the plugin library
|
||||
|
||||
if [ -z "$TW5_BUILD_VERSION" ]; then
|
||||
TW5_BUILD_VERSION=v5.1.20
|
||||
fi
|
||||
|
||||
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
||||
|
||||
# Default to using tw5.com as the main edition for /index.html
|
||||
|
||||
if [ -z "$TW5_BUILD_MAIN_EDITION" ]; then
|
||||
TW5_BUILD_MAIN_EDITION=./editions/tw5.com
|
||||
fi
|
||||
|
||||
echo "Using TW5_BUILD_MAIN_EDITION as [$TW5_BUILD_MAIN_EDITION]"
|
||||
|
||||
# Default to the version of TiddlyWiki installed in this repo
|
||||
|
||||
if [ -z "$TW5_BUILD_TIDDLYWIKI" ]; then
|
||||
TW5_BUILD_TIDDLYWIKI=./tiddlywiki.js
|
||||
fi
|
||||
|
||||
echo "Using TW5_BUILD_TIDDLYWIKI as [$TW5_BUILD_TIDDLYWIKI]"
|
||||
|
||||
# Set up the build details
|
||||
|
||||
if [ -z "$TW5_BUILD_DETAILS" ]; then
|
||||
TW5_BUILD_DETAILS="$(git symbolic-ref --short HEAD)-$(git rev-parse HEAD) from $(git remote get-url origin)"
|
||||
fi
|
||||
|
||||
echo "Using TW5_BUILD_DETAILS as [$TW5_BUILD_DETAILS]"
|
||||
|
||||
if [ -z "$TW5_BUILD_COMMIT" ]; then
|
||||
TW5_BUILD_COMMIT="$(git rev-parse HEAD)"
|
||||
fi
|
||||
|
||||
echo "Using TW5_BUILD_COMMIT as [$TW5_BUILD_COMMIT]"
|
||||
|
||||
# Set up the build output directory
|
||||
|
||||
if [ -z "$TW5_BUILD_OUTPUT" ]; then
|
||||
TW5_BUILD_OUTPUT=./output
|
||||
fi
|
||||
|
||||
mkdir -p $TW5_BUILD_OUTPUT
|
||||
|
||||
if [ ! -d "$TW5_BUILD_OUTPUT" ]; then
|
||||
echo 'A valid TW5_BUILD_OUTPUT environment variable must be set'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Using TW5_BUILD_OUTPUT as [$TW5_BUILD_OUTPUT]"
|
||||
|
||||
echo "Build details: $TW5_BUILD_DETAILS"
|
||||
|
||||
# Make the CNAME file that GitHub Pages requires
|
||||
|
||||
echo "tiddlywiki.com" > $TW5_BUILD_OUTPUT/CNAME
|
||||
|
||||
# Delete any existing static content
|
||||
|
||||
mkdir -p $TW5_BUILD_OUTPUT/static
|
||||
mkdir -p $TW5_BUILD_OUTPUT/dev
|
||||
mkdir -p $TW5_BUILD_OUTPUT/dev/static
|
||||
rm $TW5_BUILD_OUTPUT/static/*
|
||||
rm $TW5_BUILD_OUTPUT/dev/static/*
|
||||
|
||||
# Redirects
|
||||
|
||||
echo "<a href='./plugins/tiddlywiki/tw2parser/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tw2parser/index.html</a>" > $TW5_BUILD_OUTPUT/classicparserdemo.html
|
||||
echo "<a href='./plugins/tiddlywiki/codemirror/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/codemirror/index.html</a>" > $TW5_BUILD_OUTPUT/codemirrordemo.html
|
||||
echo "<a href='./plugins/tiddlywiki/d3/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/d3/index.html</a>" > $TW5_BUILD_OUTPUT/d3demo.html
|
||||
echo "<a href='./plugins/tiddlywiki/highlight/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/highlight/index.html</a>" > $TW5_BUILD_OUTPUT/highlightdemo.html
|
||||
echo "<a href='./plugins/tiddlywiki/markdown/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/markdown/index.html</a>" > $TW5_BUILD_OUTPUT/markdowndemo.html
|
||||
echo "<a href='./plugins/tiddlywiki/tahoelafs/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tahoelafs/index.html</a>" > $TW5_BUILD_OUTPUT/tahoelafs.html
|
||||
|
||||
# Put the build details into a .tid file so that it can be included in each build (deleted at the end of this script)
|
||||
|
||||
echo -e -n "title: $:/build\ncommit: $TW5_BUILD_COMMIT\n\n$TW5_BUILD_DETAILS\n" > $TW5_BUILD_OUTPUT/build.tid
|
||||
|
||||
######################################################
|
||||
#
|
||||
# Core distribution
|
||||
#
|
||||
######################################################
|
||||
|
||||
# /index.html Main site
|
||||
# /favicon.ico Favicon for main site
|
||||
# /static.html Static rendering of default tiddlers
|
||||
# /alltiddlers.html Static rendering of all tiddlers
|
||||
# /static/* Static single tiddlers
|
||||
# /static/static.css Static stylesheet
|
||||
# /static/favicon.ico Favicon for static pages
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
$TW5_BUILD_MAIN_EDITION \
|
||||
--verbose \
|
||||
--version \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--build favicon static index \
|
||||
|| exit 1
|
||||
|
||||
# /empty.html Empty
|
||||
# /empty.hta For Internet Explorer
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/empty \
|
||||
--verbose \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--build empty \
|
||||
|| exit 1
|
||||
|
||||
|
||||
# /test.html Test edition
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/test \
|
||||
--verbose \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all test.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /dev/index.html Developer docs
|
||||
# /dev/favicon.ico Favicon for dev site
|
||||
# /dev/static.html Static rendering of default tiddlers
|
||||
# /dev/alltiddlers.html Static rendering of all tiddlers
|
||||
# /dev/static/* Static single tiddlers
|
||||
# /dev/static/static.css Static stylesheet
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/dev \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/dev \
|
||||
--build index favicon static \
|
||||
|| exit 1
|
||||
|
||||
# /upgrade.html Custom edition for performing upgrades
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/upgrade \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--build upgrade \
|
||||
|| exit 1
|
||||
|
||||
# /encrypted.html Copy of the main file encrypted with the password "password"
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
$TW5_BUILD_MAIN_EDITION \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--build encrypted \
|
||||
|| exit 1
|
||||
|
||||
|
||||
######################################################
|
||||
#
|
||||
# Editions
|
||||
#
|
||||
######################################################
|
||||
|
||||
# /editions/xlsx-utils/index.html xlsx-utils edition
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/xlsx-utils \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/editions/xlsx-utils/ \
|
||||
--build index \
|
||||
|| exit 1
|
||||
|
||||
# /editions/resumebuilder/index.html Resume builder edition
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/resumebuilder \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/editions/resumebuilder/ \
|
||||
--build index \
|
||||
|| exit 1
|
||||
|
||||
# /editions/text-slicer/index.html Text slicer edition
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/text-slicer \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/editions/text-slicer/ \
|
||||
--build index \
|
||||
|| exit 1
|
||||
|
||||
# /editions/translators/index.html Translators edition
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/translators \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/editions/translators/ \
|
||||
--build index \
|
||||
|| exit 1
|
||||
|
||||
# /editions/introduction/index.html Introduction edition
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/introduction \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/editions/introduction/ \
|
||||
--build index \
|
||||
|| exit 1
|
||||
|
||||
# /editions/full/index.html Full edition
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/full \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/editions/full/ \
|
||||
--build index \
|
||||
|| exit 1
|
||||
|
||||
# /editions/tw5.com-docs/index.html tiddlywiki.com docs edition
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/tw5.com-docs \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/editions/tw5.com-docs/ \
|
||||
--build index \
|
||||
|| exit 1
|
||||
|
||||
######################################################
|
||||
#
|
||||
# Plugin demos
|
||||
#
|
||||
######################################################
|
||||
|
||||
# /plugins/tiddlywiki/innerwiki/index.html Demo wiki with Innerwiki plugin
|
||||
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/innerwikidemo \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/innerwiki/index.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/dynaview/index.html Demo wiki with DynaView plugin
|
||||
# /plugins/tiddlywiki/dynaview/empty.html Empty wiki with DynaView plugin
|
||||
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/dynaviewdemo \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/dynaview/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/dynaview/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/katex/index.html Demo wiki with KaTeX plugin
|
||||
# /plugins/tiddlywiki/katex/empty.html Empty wiki with KaTeX plugin
|
||||
|
||||
# TODO: Build the static file with the release of 5.1.3
|
||||
# --rendertiddler $:/core/templates/static.template.html plugins/tiddlywiki/katex/static.html text/plain \
|
||||
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/katexdemo \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/katex/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/katex/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/tahoelafs/index.html Demo wiki with Tahoe-LAFS plugin
|
||||
# /plugins/tiddlywiki/tahoelafs/empty.html Empty wiki with Tahoe-LAFS plugin
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/tahoelafs \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/tahoelafs/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/tahoelafs/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/d3/index.html Demo wiki with D3 plugin
|
||||
# /plugins/tiddlywiki/d3/empty.html Empty wiki with D3 plugin
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/d3demo \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/d3/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/d3/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/codemirror/index.html Demo wiki with codemirror plugin
|
||||
# /plugins/tiddlywiki/codemirror/empty.html Empty wiki with codemirror plugin
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/codemirrordemo \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/codemirror/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/codemirror/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/markdown/index.html Demo wiki with Markdown plugin
|
||||
# /plugins/tiddlywiki/markdown/empty.html Empty wiki with Markdown plugin
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/markdowndemo \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/markdown/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/markdown/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/tw2parser/index.html Demo wiki with tw2parser plugin
|
||||
# /plugins/tiddlywiki/tw2parser/empty.html Empty wiki with tw2parser plugin
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/classicparserdemo \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/tw2parser/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/tw2parser/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/highlight/index.html Demo wiki with highlight plugin
|
||||
# /plugins/tiddlywiki/highlight/empty.html Empty wiki with highlight plugin
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/highlightdemo \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/highlight/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/highlight/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
######################################################
|
||||
#
|
||||
# Language editions
|
||||
#
|
||||
######################################################
|
||||
|
||||
# Delete any existing static content
|
||||
|
||||
rm $TW5_BUILD_OUTPUT/languages/de-AT/static/*
|
||||
rm $TW5_BUILD_OUTPUT/languages/de-DE/static/*
|
||||
rm $TW5_BUILD_OUTPUT/languages/es-ES/static/*
|
||||
rm $TW5_BUILD_OUTPUT/languages/fr-FR/static/*
|
||||
rm $TW5_BUILD_OUTPUT/languages/ja-JP/static/*
|
||||
rm $TW5_BUILD_OUTPUT/languages/ko-KR/static/*
|
||||
rm $TW5_BUILD_OUTPUT/languages/zh-Hans/static/*
|
||||
rm $TW5_BUILD_OUTPUT/languages/zh-Hant/static/*
|
||||
|
||||
# /languages/de-AT/index.html Demo wiki with de-AT language
|
||||
# /languages/de-AT/empty.html Empty wiki with de-AT language
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/de-AT \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/languages/de-AT \
|
||||
--build favicon empty static index \
|
||||
|| exit 1
|
||||
|
||||
# /languages/de-DE/index.html Demo wiki with de-DE language
|
||||
# /languages/de-DE/empty.html Empty wiki with de-DE language
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/de-DE \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/languages/de-DE \
|
||||
--build favicon empty static index \
|
||||
|| exit 1
|
||||
|
||||
# /languages/es-ES/index.html Demo wiki with es-ES language
|
||||
# /languages/es-ES/empty.html Empty wiki with es-ES language
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/es-ES \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/languages/es-ES \
|
||||
--build favicon empty static index \
|
||||
|| exit 1
|
||||
|
||||
# /languages/fr-FR/index.html Demo wiki with fr-FR language
|
||||
# /languages/fr-FR/empty.html Empty wiki with fr-FR language
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/fr-FR \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/languages/fr-FR \
|
||||
--build favicon empty static index \
|
||||
|| exit 1
|
||||
|
||||
# /languages/ja-JP/index.html Demo wiki with ja-JP language
|
||||
# /languages/ja-JP/empty.html Empty wiki with ja-JP language
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/ja-JP \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/languages/ja-JP \
|
||||
--build empty index \
|
||||
|| exit 1
|
||||
|
||||
# /languages/ko-KR/index.html Demo wiki with ko-KR language
|
||||
# /languages/ko-KR/empty.html Empty wiki with ko-KR language
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/ko-KR \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/languages/ko-KR \
|
||||
--build favicon empty static index \
|
||||
|| exit 1
|
||||
|
||||
# /languages/zh-Hans/index.html Demo wiki with zh-Hans language
|
||||
# /languages/zh-Hans/empty.html Empty wiki with zh-Hans language
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/zh-Hans \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/languages/zh-Hans \
|
||||
--build empty index \
|
||||
|| exit 1
|
||||
|
||||
# /languages/zh-Hant/index.html Demo wiki with zh-Hant language
|
||||
# /languages/zh-Hant/empty.html Empty wiki with zh-Hant language
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/zh-Hant \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/languages/zh-Hant \
|
||||
--build empty index \
|
||||
|| exit 1
|
||||
|
||||
######################################################
|
||||
#
|
||||
# Plugin library
|
||||
#
|
||||
######################################################
|
||||
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/pluginlibrary \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/library/$TW5_BUILD_VERSION \
|
||||
--build \
|
||||
|| exit 1
|
||||
|
||||
# Delete the temporary build tiddler
|
||||
|
||||
rm $TW5_BUILD_OUTPUT/build.tid || exit 1
|
||||
19
bin/get-plugin-library-version-number
Executable file
19
bin/get-plugin-library-version-number
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Extract raw version number from package.json (without the optional "-prerelease" suffix)
|
||||
|
||||
if(!process.env["TW5_BUILD_TIDDLYWIKI"]) {
|
||||
throw "TW5_BUILD_TIDDLYWIKI environment variable not set";
|
||||
}
|
||||
|
||||
var fs = require("fs"),
|
||||
path = require("path");
|
||||
|
||||
var filename = path.resolve(path.dirname(process.env["TW5_BUILD_TIDDLYWIKI"]),"./package.json"),
|
||||
json = JSON.parse(fs.readFileSync(filename,"utf8"));
|
||||
|
||||
if(!json.version) {
|
||||
throw "Missing version number in package.json";
|
||||
}
|
||||
|
||||
process.stdout.write("v" + json.version.split("-")[0]);
|
||||
7
bin/npm-publish.sh
Executable file
7
bin/npm-publish.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# publish to npm
|
||||
|
||||
./bin/clean.sh
|
||||
|
||||
npm publish || exit 1
|
||||
8
bin/quick-bld.sh
Executable file
8
bin/quick-bld.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Abbreviated build script for building prerelease
|
||||
|
||||
tiddlywiki editions/prerelease \
|
||||
--verbose \
|
||||
--build favicon index \
|
||||
|| exit 1
|
||||
17
bin/readme-bld.sh
Executable file
17
bin/readme-bld.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Build readmes from corresponding tiddlers
|
||||
|
||||
# Default to the version of TiddlyWiki installed in this repo
|
||||
|
||||
if [ -z "$TW5_BUILD_TIDDLYWIKI" ]; then
|
||||
TW5_BUILD_TIDDLYWIKI=./tiddlywiki.js
|
||||
fi
|
||||
|
||||
# tw5.com readmes
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
editions/tw5.com \
|
||||
--verbose \
|
||||
--output . \
|
||||
--build readmes \
|
||||
|| exit 1
|
||||
@@ -1,3 +1,4 @@
|
||||
<h1 class="">Script Files</h1><p>The <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a> repository contains several scripts in the <code>bin</code> folder that you can use to automate common tasks, or as a useful starting point for your own scripts. See <a class="tc-tiddlylink tc-tiddlylink-missing" href="https://tiddlywiki.com/static/Scripts%2520for%2520building%2520tiddlywiki.com.html">Scripts for building tiddlywiki.com</a> for details of the scripts used to build and release <a class="tc-tiddlylink-external" href="https://tiddlywiki.com/" rel="noopener noreferrer" target="_blank">https://tiddlywiki.com/</a>.</p><p>All the scripts expect to be run from the root folder of the repository.</p><h2 class=""><code>serve</code>: serves tw5.com</h2><pre><code>./bin/serve.sh -h
|
||||
./bin/serve.sh [edition dir] [username] [password] [host] [port]</code></pre><p>Or:</p><pre><code>./bin/serve.cmd -h
|
||||
./bin/serve.cmd [edition dir] [username] [password] [host] [port]</code></pre><p>This script starts <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a> running as an HTTP server, defaulting to the content from the <code>tw5.com-server</code> edition. By default, the Node.js serves on port 8080. If the optional <code>username</code> parameter is provided, it is used for signing edits. If the <code>password</code> is provided then HTTP basic authentication is used. Run the script with the <code>-h</code> parameter to see online help.</p><p>To experiment with this configuration, run the script and then visit <code>http://127.0.0.1:8080</code> in a browser.</p><p>Changes made in the browser propagate to the server over HTTP (use the browser developer console to see these requests). The server then syncs changes to the file system (and logs each change to the screen).</p><h2 class=""><code>test</code>: build and run tests</h2><p>This script runs the <code>test</code> edition of <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> on the server to perform the server-side tests and to build <code>test.html</code> for running the tests in the browser.</p><h2 class=""><code>lazy</code>: serves tw5.com with lazily loaded images</h2><pre><code>./bin/lazy.sh <username> [<password>]</code></pre><p>Or:</p><pre><code>./bin/lazy.cmd <username> [<password>]</code></pre><p>This script serves the <code>tw5.com-server</code> edition content with <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/LazyLoading.html">LazyLoading</a> applied to images.</p><h2 class=""><code>2bld</code>: builds <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> 2.6.5</h2><p>This script builds <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> 2.6.5 from the original source and then displays the differences between them (<code>diff</code> is used for *nix, <code>fc</code> for Windows).</p>
|
||||
./bin/serve.cmd [edition dir] [username] [password] [host] [port]</code></pre><p>This script starts <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a> running as an HTTP server, defaulting to the content from the <code>tw5.com-server</code> edition. By default, the Node.js serves on port 8080. If the optional <code>username</code> parameter is provided, it is used for signing edits. If the <code>password</code> is provided then HTTP basic authentication is used. Run the script with the <code>-h</code> parameter to see online help.</p><p>To experiment with this configuration, run the script and then visit <code>http://127.0.0.1:8080</code> in a browser.</p><p>Changes made in the browser propagate to the server over HTTP (use the browser developer console to see these requests). The server then syncs changes to the file system (and logs each change to the screen).</p><h2 class=""><code>test</code>: build and run tests</h2><p>This script runs the <code>test</code> edition of <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> on the server to perform the server-side tests and to build <code>test.html</code> for running the tests in the browser.</p><h2 class=""><code>lazy</code>: serves tw5.com with lazily loaded images</h2><pre><code>./bin/lazy.sh <username> [<password>]</code></pre><p>Or:</p><pre><code>./bin/lazy.cmd <username> [<password>]</code></pre><p>This script serves the <code>tw5.com-server</code> edition content with <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/LazyLoading.html">LazyLoading</a> applied to images.
|
||||
</p>
|
||||
@@ -7,6 +7,7 @@
|
||||
node ./tiddlywiki.js \
|
||||
./editions/test \
|
||||
--verbose \
|
||||
--version \
|
||||
--rendertiddler $:/core/save/all test.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
|
||||
10
bin/travis-pre-build.sh
Executable file
10
bin/travis-pre-build.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Install latest current release from npm
|
||||
# (we need to force because otherwise npm will refuse to install a module of the same name)
|
||||
|
||||
npm --force install tiddlywiki || exit 1
|
||||
|
||||
# Pull existing GitHub pages content
|
||||
|
||||
git clone --depth=1 --branch=master "https://github.com/Jermolene/jermolene.github.io.git" output
|
||||
20
bin/travis-push.sh
Executable file
20
bin/travis-push.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Push output back to GitHub
|
||||
|
||||
|
||||
cd output || exit 1
|
||||
|
||||
git config --global user.email "travis@travis-ci.org" || exit 1
|
||||
|
||||
git config --global user.name "Travis CI" || exit 1
|
||||
|
||||
git add -A . || exit 1
|
||||
|
||||
git commit --message "Travis build: $TRAVIS_BUILD_NUMBER of $TRAVIS_BRANCH ($(date +'%F %T %Z'))" || exit 1
|
||||
|
||||
git remote add deploy "https://$GH_TOKEN@github.com/Jermolene/jermolene.github.io.git" &>/dev/null || exit 1
|
||||
|
||||
git push deploy master &>/dev/null || exit 1
|
||||
|
||||
cd .. || exit 1
|
||||
17
bin/verbump.sh
Executable file
17
bin/verbump.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Bump to a new version number
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Missing version (eg '5.1.38-prerelease')"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set the new version number (will also commit and tag the release)
|
||||
|
||||
npm version $1 -m "Version number update for $1" || exit 1
|
||||
|
||||
# Make sure our tags are pushed to the origin server
|
||||
|
||||
git push origin --tags || exit 1
|
||||
268
boot/boot.js
268
boot/boot.js
@@ -51,6 +51,63 @@ $tw.utils.isArray = function(value) {
|
||||
return Object.prototype.toString.call(value) == "[object Array]";
|
||||
};
|
||||
|
||||
/*
|
||||
Check if an array is equal by value and by reference.
|
||||
*/
|
||||
$tw.utils.isArrayEqual = function(array1,array2) {
|
||||
if(array1 === array2) {
|
||||
return true;
|
||||
}
|
||||
array1 = array1 || [];
|
||||
array2 = array2 || [];
|
||||
if(array1.length !== array2.length) {
|
||||
return false;
|
||||
}
|
||||
return array1.every(function(value,index) {
|
||||
return value === array2[index];
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Push entries onto an array, removing them first if they already exist in the array
|
||||
array: array to modify (assumed to be free of duplicates)
|
||||
value: a single value to push or an array of values to push
|
||||
*/
|
||||
$tw.utils.pushTop = function(array,value) {
|
||||
var t,p;
|
||||
if($tw.utils.isArray(value)) {
|
||||
// Remove any array entries that are duplicated in the new values
|
||||
if(value.length !== 0) {
|
||||
if(array.length !== 0) {
|
||||
if(value.length < array.length) {
|
||||
for(t=0; t<value.length; t++) {
|
||||
p = array.indexOf(value[t]);
|
||||
if(p !== -1) {
|
||||
array.splice(p,1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(t=array.length-1; t>=0; t--) {
|
||||
p = value.indexOf(array[t]);
|
||||
if(p !== -1) {
|
||||
array.splice(t,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Push the values on top of the main array
|
||||
array.push.apply(array,value);
|
||||
}
|
||||
} else {
|
||||
p = array.indexOf(value);
|
||||
if(p !== -1) {
|
||||
array.splice(p,1);
|
||||
}
|
||||
array.push(value);
|
||||
}
|
||||
return array;
|
||||
};
|
||||
|
||||
/*
|
||||
Determine if a value is a date
|
||||
*/
|
||||
@@ -89,7 +146,9 @@ Helper for making DOM elements
|
||||
tag: tag name
|
||||
options: see below
|
||||
Options include:
|
||||
namespace: defaults to http://www.w3.org/1999/xhtml
|
||||
attributes: hashmap of attribute values
|
||||
style: hashmap of styles
|
||||
text: text to add as a child node
|
||||
children: array of further child nodes
|
||||
innerHTML: optional HTML for element
|
||||
@@ -99,7 +158,7 @@ eventListeners: array of event listeners (this option won't work until $tw.utils
|
||||
*/
|
||||
$tw.utils.domMaker = function(tag,options) {
|
||||
var doc = options.document || document;
|
||||
var element = doc.createElement(tag);
|
||||
var element = doc.createElementNS(options.namespace || "http://www.w3.org/1999/xhtml",tag);
|
||||
if(options["class"]) {
|
||||
element.className = options["class"];
|
||||
}
|
||||
@@ -115,6 +174,9 @@ $tw.utils.domMaker = function(tag,options) {
|
||||
$tw.utils.each(options.attributes,function(attribute,name) {
|
||||
element.setAttribute(name,attribute);
|
||||
});
|
||||
$tw.utils.each(options.style,function(value,name) {
|
||||
element.style[name] = value;
|
||||
});
|
||||
if(options.eventListeners) {
|
||||
$tw.utils.addEventListeners(element,options.eventListeners);
|
||||
}
|
||||
@@ -252,13 +314,13 @@ $tw.utils.parseDate = function(value) {
|
||||
// Stringify an array of tiddler titles into a list string
|
||||
$tw.utils.stringifyList = function(value) {
|
||||
if($tw.utils.isArray(value)) {
|
||||
var result = [];
|
||||
for(var t=0; t<value.length; t++) {
|
||||
var result = new Array(value.length);
|
||||
for(var t=0, l=value.length; t<l; t++) {
|
||||
var entry = value[t] || "";
|
||||
if(entry.indexOf(" ") !== -1) {
|
||||
result.push("[[" + entry + "]]");
|
||||
result[t] = "[[" + entry + "]]";
|
||||
} else {
|
||||
result.push(entry);
|
||||
result[t] = entry;
|
||||
}
|
||||
}
|
||||
return result.join(" ");
|
||||
@@ -862,6 +924,61 @@ $tw.Tiddler.prototype.hasField = function(field) {
|
||||
return $tw.utils.hop(this.fields,field);
|
||||
};
|
||||
|
||||
/*
|
||||
Compare two tiddlers for equality
|
||||
tiddler: the tiddler to compare
|
||||
excludeFields: array of field names to exclude from the comparison
|
||||
*/
|
||||
$tw.Tiddler.prototype.isEqual = function(tiddler,excludeFields) {
|
||||
if(!(tiddler instanceof $tw.Tiddler)) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
// Check for identical date values
|
||||
if($tw.utils.isDate(valueA) && $tw.utils.isDate(valueB) && valueA.getTime() === valueB.getTime()) {
|
||||
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;
|
||||
};
|
||||
|
||||
/*
|
||||
Register and install the built in tiddler field modules
|
||||
*/
|
||||
@@ -896,7 +1013,7 @@ $tw.modules.define("$:/boot/tiddlerfields/list","tiddlerfield",{
|
||||
/*
|
||||
Wiki constructor. State is stored in private members that only a small number of privileged accessor methods have direct access. Methods added via the prototype have to use these accessors and cannot access the state data directly.
|
||||
options include:
|
||||
shadowTiddlers: Array of shadow tiddlers to be added
|
||||
enableIndexers - Array of indexer names to enable, or null to use all available indexers
|
||||
*/
|
||||
$tw.Wiki = function(options) {
|
||||
options = options || {};
|
||||
@@ -911,14 +1028,31 @@ $tw.Wiki = function(options) {
|
||||
},
|
||||
pluginTiddlers = [], // Array of tiddlers containing registered plugins, ordered by priority
|
||||
pluginInfo = Object.create(null), // Hashmap of parsed plugin content
|
||||
shadowTiddlers = options.shadowTiddlers || Object.create(null), // Hashmap by title of {source:, tiddler:}
|
||||
shadowTiddlers = Object.create(null), // Hashmap by title of {source:, tiddler:}
|
||||
shadowTiddlerTitles = null,
|
||||
getShadowTiddlerTitles = function() {
|
||||
if(!shadowTiddlerTitles) {
|
||||
shadowTiddlerTitles = Object.keys(shadowTiddlers);
|
||||
}
|
||||
return shadowTiddlerTitles;
|
||||
};
|
||||
},
|
||||
enableIndexers = options.enableIndexers || null,
|
||||
indexers = [],
|
||||
indexersByName = Object.create(null);
|
||||
|
||||
this.addIndexer = function(indexer,name) {
|
||||
// Bail if this indexer is not enabled
|
||||
if(enableIndexers && enableIndexers.indexOf(name) === -1) {
|
||||
return;
|
||||
}
|
||||
indexers.push(indexer);
|
||||
indexersByName[name] = indexer;
|
||||
indexer.init();
|
||||
};
|
||||
|
||||
this.getIndexer = function(name) {
|
||||
return indexersByName[name] || null;
|
||||
};
|
||||
|
||||
// Add a tiddler to the store
|
||||
this.addTiddler = function(tiddler) {
|
||||
@@ -931,12 +1065,33 @@ $tw.Wiki = function(options) {
|
||||
if(title) {
|
||||
// Uncomment the following line for detailed logs of all tiddler writes
|
||||
// console.log("Adding",title,tiddler)
|
||||
// Record the old tiddler state
|
||||
var updateDescriptor = {
|
||||
old: {
|
||||
tiddler: this.getTiddler(title),
|
||||
shadow: this.isShadowTiddler(title),
|
||||
exists: this.tiddlerExists(title)
|
||||
}
|
||||
}
|
||||
// Save the new tiddler
|
||||
tiddlers[title] = tiddler;
|
||||
// Check we've got it's title
|
||||
if(tiddlerTitles && tiddlerTitles.indexOf(title) === -1) {
|
||||
tiddlerTitles.push(title);
|
||||
}
|
||||
// Record the new tiddler state
|
||||
updateDescriptor["new"] = {
|
||||
tiddler: tiddler,
|
||||
shadow: this.isShadowTiddler(title),
|
||||
exists: this.tiddlerExists(title)
|
||||
}
|
||||
// Update indexes
|
||||
this.clearCache(title);
|
||||
this.clearGlobalCache();
|
||||
$tw.utils.each(indexers,function(indexer) {
|
||||
indexer.update(updateDescriptor);
|
||||
});
|
||||
// Queue a change event
|
||||
this.enqueueTiddlerEvent(title);
|
||||
}
|
||||
}
|
||||
@@ -947,15 +1102,36 @@ $tw.Wiki = function(options) {
|
||||
// Uncomment the following line for detailed logs of all tiddler deletions
|
||||
// console.log("Deleting",title)
|
||||
if($tw.utils.hop(tiddlers,title)) {
|
||||
// Record the old tiddler state
|
||||
var updateDescriptor = {
|
||||
old: {
|
||||
tiddler: this.getTiddler(title),
|
||||
shadow: this.isShadowTiddler(title),
|
||||
exists: this.tiddlerExists(title)
|
||||
}
|
||||
}
|
||||
// Delete the tiddler
|
||||
delete tiddlers[title];
|
||||
// Delete it from the list of titles
|
||||
if(tiddlerTitles) {
|
||||
var index = tiddlerTitles.indexOf(title);
|
||||
if(index !== -1) {
|
||||
tiddlerTitles.splice(index,1);
|
||||
}
|
||||
}
|
||||
// Record the new tiddler state
|
||||
updateDescriptor["new"] = {
|
||||
tiddler: this.getTiddler(title),
|
||||
shadow: this.isShadowTiddler(title),
|
||||
exists: this.tiddlerExists(title)
|
||||
}
|
||||
// Update indexes
|
||||
this.clearCache(title);
|
||||
this.clearGlobalCache();
|
||||
$tw.utils.each(indexers,function(indexer) {
|
||||
indexer.update(updateDescriptor);
|
||||
});
|
||||
// Queue a change event
|
||||
this.enqueueTiddlerEvent(title,true);
|
||||
}
|
||||
};
|
||||
@@ -1042,7 +1218,6 @@ $tw.Wiki = function(options) {
|
||||
callback(tiddlers[title],title);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Test for the existence of a tiddler (excludes shadow tiddlers)
|
||||
@@ -1156,8 +1331,14 @@ $tw.Wiki = function(options) {
|
||||
shadowTiddlerTitles = null;
|
||||
this.clearCache(null);
|
||||
this.clearGlobalCache();
|
||||
$tw.utils.each(indexers,function(indexer) {
|
||||
indexer.rebuild();
|
||||
});
|
||||
};
|
||||
|
||||
if(this.addIndexersToWiki) {
|
||||
this.addIndexersToWiki();
|
||||
}
|
||||
};
|
||||
|
||||
// Dummy methods that will be filled in after boot
|
||||
@@ -1352,8 +1533,40 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/html","tiddlerdeserializer",{
|
||||
});
|
||||
$tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
|
||||
"application/json": function(text,fields) {
|
||||
var data = JSON.parse(text);
|
||||
return $tw.utils.isArray(data) ? data : [data];
|
||||
var isTiddlerValid = function(data) {
|
||||
// Not valid if it's not an object with a title property
|
||||
if(typeof(data) !== "object" || !$tw.utils.hop(data,"title")) {
|
||||
return false;
|
||||
}
|
||||
for(var f in data) {
|
||||
if($tw.utils.hop(data,f)) {
|
||||
// Check field name doesn't contain whitespace or control characters
|
||||
if(typeof(data[f]) !== "string" || /[\x00-\x1F\s]/.test(f)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
isTiddlerArrayValid = function(data) {
|
||||
for(var t=0; t<data.length; t++) {
|
||||
if(!isTiddlerValid(data[t])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
data = JSON.parse(text);
|
||||
if($tw.utils.isArray(data) && isTiddlerArrayValid(data)) {
|
||||
return data;
|
||||
} else if(isTiddlerValid(data)) {
|
||||
return [data];
|
||||
} else {
|
||||
// Plain JSON file
|
||||
fields.text = text;
|
||||
fields.type = "application/json";
|
||||
return [fields];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1506,9 +1719,11 @@ $tw.loadTiddlersFromFile = function(filepath,fields) {
|
||||
typeInfo = type ? $tw.config.contentTypeInfo[type] : null,
|
||||
data = fs.readFileSync(filepath,typeInfo ? typeInfo.encoding : "utf8"),
|
||||
tiddlers = $tw.wiki.deserializeTiddlers(ext,data,fields),
|
||||
metadata;
|
||||
if(ext !== ".json" && tiddlers.length === 1) {
|
||||
metadata = $tw.loadMetadataForFile(filepath);
|
||||
if(metadata) {
|
||||
if(type === "application/json") {
|
||||
tiddlers = [{text: data, type: "application/json"}];
|
||||
}
|
||||
tiddlers = [$tw.utils.extend({},tiddlers[0],metadata)];
|
||||
}
|
||||
return {filepath: filepath, type: type, tiddlers: tiddlers, hasMetaFile: !!metadata};
|
||||
@@ -1738,8 +1953,10 @@ $tw.loadPlugin = function(name,paths) {
|
||||
var pluginFields = $tw.loadPluginFolder(pluginPath);
|
||||
if(pluginFields) {
|
||||
$tw.wiki.addTiddler(pluginFields);
|
||||
return;
|
||||
}
|
||||
}
|
||||
console.log("Warning: Cannot find plugin '" + name + "'");
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1753,7 +1970,7 @@ $tw.getLibraryItemSearchPaths = function(libraryPath,envVar) {
|
||||
if(env) {
|
||||
env.split(path.delimiter).map(function(item) {
|
||||
if(item) {
|
||||
pluginPaths.push(item)
|
||||
pluginPaths.push(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1889,6 +2106,21 @@ $tw.loadTiddlersNode = function() {
|
||||
});
|
||||
// Load the core tiddlers
|
||||
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.corePath));
|
||||
// Load any extra plugins
|
||||
$tw.utils.each($tw.boot.extraPlugins,function(name) {
|
||||
if(name.charAt(0) === "+") { // Relative path to plugin
|
||||
var pluginFields = $tw.loadPluginFolder(name.substring(1));;
|
||||
if(pluginFields) {
|
||||
$tw.wiki.addTiddler(pluginFields);
|
||||
}
|
||||
} else {
|
||||
var parts = name.split("/"),
|
||||
type = parts[0];
|
||||
if(parts.length === 3 && ["plugins","themes","languages"].indexOf(type) !== -1) {
|
||||
$tw.loadPlugins([parts[1] + "/" + parts[2]],$tw.config[type + "Path"],$tw.config[type + "EnvVar"]);
|
||||
}
|
||||
}
|
||||
});
|
||||
// Load the tiddlers from the wiki directory
|
||||
if($tw.boot.wikiPath) {
|
||||
$tw.boot.wikiInfo = $tw.loadWikiTiddlers($tw.boot.wikiPath);
|
||||
@@ -1952,6 +2184,12 @@ $tw.boot.startup = function(options) {
|
||||
if($tw.boot.argv.length === 0) {
|
||||
$tw.boot.argv = ["--help"];
|
||||
}
|
||||
// Parse any extra plugin references
|
||||
$tw.boot.extraPlugins = $tw.boot.extraPlugins || [];
|
||||
while($tw.boot.argv[0] && $tw.boot.argv[0].indexOf("+") === 0) {
|
||||
$tw.boot.extraPlugins.push($tw.boot.argv[0].substring(1));
|
||||
$tw.boot.argv.splice(0,1);
|
||||
}
|
||||
// If the first command line argument doesn't start with `--` then we
|
||||
// interpret it as the path to the wiki folder, which will otherwise default
|
||||
// to the current folder
|
||||
@@ -2037,6 +2275,8 @@ $tw.boot.startup = function(options) {
|
||||
if($tw.preloadTiddlers) {
|
||||
$tw.wiki.addTiddlers($tw.preloadTiddlers);
|
||||
}
|
||||
// Give hooks a chance to modify the store
|
||||
$tw.hooks.invokeHook("th-boot-tiddlers-loaded");
|
||||
// Unpack plugin tiddlers
|
||||
$tw.wiki.readPluginInfo();
|
||||
$tw.wiki.registerPluginTiddlers("plugin",$tw.safeMode ? ["$:/core"] : undefined);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
<h1 class="">Contributing to <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a></h1><p>We welcome contributions to the code and documentation of <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> in several ways:</p><ul><li><a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/ReportingBugs.html">ReportingBugs</a></li><li>Helping to <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/Improving%2520TiddlyWiki%2520Documentation.html">improve our documentation</a></li><li>Contributing to the code via <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5" rel="noopener noreferrer" target="_blank">GitHub</a><ul><li>See <a class="tc-tiddlylink-external" href="https://tiddlywiki.com/dev" rel="noopener noreferrer" target="_blank">https://tiddlywiki.com/dev</a> for more details</li></ul></li></ul><p>There are other ways to <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/HelpingTiddlyWiki.html">help TiddlyWiki</a> too.</p><h1 class="">Contributor License Agreement</h1><p>Like other <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/OpenSource.html">OpenSource</a> projects, <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a> needs a signed contributor license agreement from individual contributors. This is a legal agreement that allows contributors to assert that they own the copyright of their contribution, and that they agree to license it to the <a class="tc-tiddlylink tc-tiddlylink-missing" href="https://tiddlywiki.com/static/UnaMesa.html">UnaMesa</a> Association (the legal entity that owns <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> on behalf of the community).</p><ul><li>For individuals use: <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-individual.md" rel="noopener noreferrer" target="_blank">licenses/CLA-individual</a></li><li>For entities use: <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-entity.md" rel="noopener noreferrer" target="_blank">licenses/CLA-entity</a></li></ul><h1 class="">How to sign the CLA</h1><p>Create a <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/GitHub.html">GitHub</a> pull request to add your name to <code>cla-individual.md</code> or <code>cla-entity.md</code>, with the date in the format (YYYY/MM/DD).</p><p><strong>step by step</strong></p><ol><li>Navigate to <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-individual.md" rel="noopener noreferrer" target="_blank">licenses/CLA-individual</a> or <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-entity.md" rel="noopener noreferrer" target="_blank">licenses/CLA-entity</a> according to whether you are signing as an individual or representative of an organisation</li><li>Click the "edit" button at the top-right corner (clicking this button will fork the project so you can edit the file)</li><li>Add your name at the bottom<ul><li>eg: <code>Jeremy Ruston, @Jermolene, 2011/11/22</code></li></ul></li><li>Below the edit box for the CLA text you should see a box labelled <strong>Propose file change</strong></li><li>Enter a brief title to explain the change (eg, "Signing the CLA")</li><li>Click the green button labelled <strong>Propose file change</strong></li><li>On the following screen, click the green button labelled <strong>Create pull request</strong></li></ol><hr><p><em>The CLA documents used for this project were created using <a class="tc-tiddlylink-external" href="http://www.harmonyagreements.org" rel="noopener noreferrer" target="_blank">Harmony Project Templates</a>. "HA-CLA-I-LIST Version 1.0" for "CLA-individual" and "HA-CLA-E-LIST Version 1.0" for "CLA-entity".</em></p><p>Remarks
|
||||
----—</p><ul><li><ul><li>When not owning the copyright in the entire work of authorship**</li></ul></li></ul><p>In this case, please clearly state so, since otherwise we assume that you are the legal copyright holder of the contributed work! Please provide links and additional information that clarify under which license the rest of the code is distributed.
|
||||
<h1 class="">Contributing to <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a></h1><p>We welcome contributions to the code and documentation of <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> in several ways:</p><ul><li><a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/ReportingBugs.html">ReportingBugs</a></li><li>Helping to <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/Improving%2520TiddlyWiki%2520Documentation.html">improve our documentation</a></li><li>Contributing to the code via <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5" rel="noopener noreferrer" target="_blank">GitHub</a><ul><li>See <a class="tc-tiddlylink-external" href="https://tiddlywiki.com/dev" rel="noopener noreferrer" target="_blank">https://tiddlywiki.com/dev</a> for more details</li></ul></li></ul><p>There are other ways to <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/HelpingTiddlyWiki.html">help TiddlyWiki</a> too.</p><h1 class="">Contributor License Agreement</h1><p>Like other <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/OpenSource.html">OpenSource</a> projects, <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a> needs a signed contributor license agreement from individual contributors. This is a legal agreement that allows contributors to assert that they own the copyright of their contribution, and that they agree to license it to the <a class="tc-tiddlylink tc-tiddlylink-missing" href="https://tiddlywiki.com/static/UnaMesa.html">UnaMesa</a> Association (the legal entity that owns <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> on behalf of the community).</p><ul><li>For individuals use: <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-individual.md" rel="noopener noreferrer" target="_blank">licenses/CLA-individual</a></li><li>For entities use: <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-entity.md" rel="noopener noreferrer" target="_blank">licenses/CLA-entity</a></li></ul><h1 class="">How to sign the CLA</h1><p>Create a <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/GitHub.html">GitHub</a> pull request to add your name to <code>cla-individual.md</code> or <code>cla-entity.md</code>, with the date in the format (YYYY/MM/DD).</p><p><strong>step by step</strong></p><ol><li>Navigate to <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-individual.md" rel="noopener noreferrer" target="_blank">licenses/CLA-individual</a> or <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-entity.md" rel="noopener noreferrer" target="_blank">licenses/CLA-entity</a> according to whether you are signing as an individual or representative of an organisation</li><li>Ensure that the "branch" dropdown at the top left is set to <code>tiddlywiki-com</code></li><li>Click the "edit" button at the top-right corner (clicking this button will fork the project so you can edit the file)</li><li>Add your name at the bottom<ul><li>eg: <code>Jeremy Ruston, @Jermolene, 2011/11/22</code></li></ul></li><li>Below the edit box for the CLA text you should see a box labelled <strong>Propose file change</strong></li><li>Enter a brief title to explain the change (eg, "Signing the CLA")</li><li>Click the green button labelled <strong>Propose file change</strong></li><li>On the following screen, click the green button labelled <strong>Create pull request</strong></li></ol><hr><p><em>The CLA documents used for this project were created using <a class="tc-tiddlylink-external" href="http://www.harmonyagreements.org" rel="noopener noreferrer" target="_blank">Harmony Project Templates</a>. "HA-CLA-I-LIST Version 1.0" for "CLA-individual" and "HA-CLA-E-LIST Version 1.0" for "CLA-entity".</em></p><h2 class="">Remarks</h2><p><strong>If you do not own the copyright in the entire work of authorship</strong>:</p><p>In this case, please clearly state so and provide links and any additional information that clarify under which license the rest of the code is distributed.
|
||||
</p><p><em>This file was automatically generated by <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a></em>
|
||||
</p>
|
||||
@@ -32,6 +32,7 @@ ExportTiddler/Caption: export tiddler
|
||||
ExportTiddler/Hint: Export tiddler
|
||||
ExportTiddlers/Caption: export tiddlers
|
||||
ExportTiddlers/Hint: Export tiddlers
|
||||
SidebarSearch/Hint: Select the sidebar search field
|
||||
Fold/Caption: fold tiddler
|
||||
Fold/Hint: Fold the body of this tiddler
|
||||
Fold/FoldBar/Caption: fold-bar
|
||||
@@ -181,6 +182,7 @@ Subscript/Caption: subscript
|
||||
Subscript/Hint: Apply subscript formatting to selection
|
||||
Superscript/Caption: superscript
|
||||
Superscript/Hint: Apply superscript formatting to selection
|
||||
ToggleSidebar/Hint: Toggle the sidebar visibility
|
||||
Transcludify/Caption: transclusion
|
||||
Transcludify/Hint: Wrap selection in curly brackets
|
||||
Underline/Caption: underline
|
||||
|
||||
@@ -47,6 +47,8 @@ LoadedModules/Hint: These are the currently loaded tiddler modules linked to the
|
||||
Palette/Caption: Palette
|
||||
Palette/Editor/Clone/Caption: clone
|
||||
Palette/Editor/Clone/Prompt: It is recommended that you clone this shadow palette before editing it
|
||||
Palette/Editor/Delete/Hint: delete this entry from the current palette
|
||||
Palette/Editor/Names/External/Show: Show color names that are not part of the current palette
|
||||
Palette/Editor/Prompt/Modified: This shadow palette has been modified
|
||||
Palette/Editor/Prompt: Editing
|
||||
Palette/Editor/Reset/Caption: reset
|
||||
@@ -89,6 +91,18 @@ Saving/DownloadSaver/Hint: These settings apply to the HTML5-compatible download
|
||||
Saving/General/Caption: General
|
||||
Saving/General/Hint: These settings apply to all the loaded savers
|
||||
Saving/Hint: Settings used for saving the entire TiddlyWiki as a single file via a saver module
|
||||
Saving/GitService/Branch: Target branch for saving
|
||||
Saving/GitService/CommitMessage: Saved by TiddlyWiki
|
||||
Saving/GitService/Description: These settings are only used when saving to <<service-name>>
|
||||
Saving/GitService/Filename: Filename of target file (e.g. `index.html`)
|
||||
Saving/GitService/Path: Path to target file (e.g. `/wiki/`)
|
||||
Saving/GitService/Repo: Target repository (e.g. `Jermolene/TiddlyWiki5`)
|
||||
Saving/GitService/ServerURL: Server API URL
|
||||
Saving/GitService/UserName: Username
|
||||
Saving/GitService/GitHub/Caption: ~GitHub Saver
|
||||
Saving/GitService/GitHub/Password: Password, OAUTH token, or personal access token (see [[GitHub help page|https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line]] for details)
|
||||
Saving/GitService/GitLab/Caption: ~GitLab Saver
|
||||
Saving/GitService/GitLab/Password: Personal access token for API (see [[GitLab help page|https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html]] for details)
|
||||
Saving/TiddlySpot/Advanced/Heading: Advanced Settings
|
||||
Saving/TiddlySpot/BackupDir: Backup Directory
|
||||
Saving/TiddlySpot/Backups: Backups
|
||||
|
||||
@@ -14,8 +14,9 @@ draft.of: For draft tiddlers, contains the title of the tiddler of which this is
|
||||
draft.title: For draft tiddlers, contains the proposed new title of the tiddler
|
||||
footer: The footer text for a wizard
|
||||
hack-to-give-us-something-to-compare-against: A temporary storage field used in [[$:/core/templates/static.content]]
|
||||
hide-body: The view template will hide bodies of tiddlers if set to: ''yes''
|
||||
icon: The title of the tiddler containing the icon associated with a tiddler
|
||||
library: If set to "yes" indicates that a tiddler should be saved as a JavaScript library
|
||||
library: Indicates that a tiddler should be saved as a JavaScript library if set to: ''yes''
|
||||
list: An ordered list of tiddler titles associated with a tiddler
|
||||
list-before: If set, the title of a tiddler before which this tiddler should be added to the ordered list of tiddler titles, or at the start of the list if this field is present but empty
|
||||
list-after: If set, the title of the tiddler after which this tiddler should be added to the ordered list of tiddler titles, or at the end of the list if this field is present but empty
|
||||
@@ -31,5 +32,6 @@ subtitle: The subtitle text for a wizard
|
||||
tags: A list of tags associated with a tiddler
|
||||
text: The body text of a tiddler
|
||||
title: The unique name of a tiddler
|
||||
toc-link: Suppresses the tiddler's link in a Table of Contents tree if set to: ''no''
|
||||
type: The content type of a tiddler
|
||||
version: Version information for a plugin
|
||||
|
||||
@@ -10,6 +10,7 @@ Orphans: Orphan tiddlers
|
||||
SystemTiddlers: System tiddlers
|
||||
ShadowTiddlers: Shadow tiddlers
|
||||
OverriddenShadowTiddlers: Overridden shadow tiddlers
|
||||
SessionTiddlers: Tiddlers modified since the wiki was loaded
|
||||
SystemTags: System tags
|
||||
StoryList: Tiddlers in the story river, excluding <$text text="$:/AdvancedSearch"/>
|
||||
TypedTiddlers: Non wiki-text tiddlers
|
||||
8
core/language/en-GB/Help/deletetiddlers.tid
Normal file
8
core/language/en-GB/Help/deletetiddlers.tid
Normal file
@@ -0,0 +1,8 @@
|
||||
title: $:/language/Help/deletetiddlers
|
||||
description: Deletes a group of tiddlers
|
||||
|
||||
<<.from-version "5.1.20">> Deletes a group of tiddlers identified by a filter.
|
||||
|
||||
```
|
||||
--deletetiddlers <filter>
|
||||
```
|
||||
@@ -28,6 +28,7 @@ All parameters are optional with safe defaults, and can be specified in any orde
|
||||
* ''tls-cert'' - pathname of TLS certificate file (relative to wiki folder)
|
||||
* ''tls-key'' - pathname of TLS key file (relative to wiki folder)
|
||||
* ''debug-level'' - optional debug level; set to "debug" to view request details (defaults to "none")
|
||||
* ''gzip'' - set to "yes" to enable gzip compression for some http endpoints (defaults to "no")
|
||||
|
||||
For information on opening up your instance to the entire local network, and possible security concerns, see the WebServer tiddler at TiddlyWiki.com.
|
||||
|
||||
|
||||
@@ -4,10 +4,12 @@ description: Load tiddlers from a file
|
||||
Load tiddlers from TiddlyWiki (`.html`), `.tiddler`, `.tid`, `.json` or other local files. The processing applied to incoming files is determined by the file extension. Use the alternative `import` command if you need to specify the deserializer and encoding explicitly.
|
||||
|
||||
```
|
||||
--load <filepath>
|
||||
--load <dirpath>
|
||||
--load <filepath> [noerror]
|
||||
--load <dirpath> [noerror]
|
||||
```
|
||||
|
||||
By default, the load command raises an error if no tiddlers are found. The error can be suppressed by providing the optional "noerror" parameter.
|
||||
|
||||
To load tiddlers from an encrypted TiddlyWiki file you should first specify the password with the PasswordCommand. For example:
|
||||
|
||||
```
|
||||
|
||||
@@ -13,8 +13,8 @@ A name and value for an additional variable may optionally also be specified.
|
||||
|
||||
* ''tiddler-filter'': A filter identifying the tiddler(s) to be rendered
|
||||
* ''filename-filter'': Optional filter transforming tiddler titles into pathnames. If omitted, defaults to `[is[tiddler]addsuffix[.html]]`, which uses the unchanged tiddler title as the filename
|
||||
* ''template'': Optional template through which each tiddler is rendered
|
||||
* ''render-type'': Optional render type: `text/html` (the default) returns the full HTML text and `text/plain` just returns the text content (ie it ignores HTML tags and other unprintable material)
|
||||
* ''template'': Optional template through which each tiddler is rendered
|
||||
* ''name'': Name of optional variable
|
||||
* ''value'': Value of optional variable
|
||||
|
||||
|
||||
19
core/language/en-GB/Help/savewikifolder.tid
Normal file
19
core/language/en-GB/Help/savewikifolder.tid
Normal file
@@ -0,0 +1,19 @@
|
||||
title: $:/language/Help/savewikifolder
|
||||
description: Saves a wiki to a new wiki folder
|
||||
|
||||
<<.from-version "5.1.20">> Saves the current wiki as a wiki folder, including tiddlers, plugins and configuration:
|
||||
|
||||
```
|
||||
--savewikifolder <wikifolderpath> [<filter>]
|
||||
```
|
||||
|
||||
* The target wiki folder must be empty or non-existent
|
||||
* The filter specifies which tiddlers should be included. It is optional, defaulting to `[all[tiddlers]]`
|
||||
* Plugins from the official plugin library are replaced with references to those plugins in the `tiddlywiki.info` file
|
||||
* Custom plugins are unpacked into their own folder
|
||||
|
||||
A common usage is to convert a TiddlyWiki HTML file into a wiki folder:
|
||||
|
||||
```
|
||||
tiddlywiki --load ./mywiki.html --savewikifolder ./mywikifolder
|
||||
```
|
||||
@@ -18,4 +18,6 @@ Upgrader/Plugins/Suppressed/Version: Blocked plugin (due to incoming <<incoming>
|
||||
Upgrader/Plugins/Upgraded: Upgraded plugin from <<incoming>> to <<upgraded>>
|
||||
Upgrader/State/Suppressed: Blocked temporary state tiddler
|
||||
Upgrader/System/Suppressed: Blocked system tiddler
|
||||
Upgrader/System/Warning: Core module tiddler
|
||||
Upgrader/System/Alert: You are about to import a tiddler that will overwrite a core module tiddler. This is not recommended as it may make the system unstable
|
||||
Upgrader/ThemeTweaks/Created: Migrated theme tweak from <$text text=<<from>>/>
|
||||
|
||||
42
core/modules/commands/deletetiddlers.js
Normal file
42
core/modules/commands/deletetiddlers.js
Normal file
@@ -0,0 +1,42 @@
|
||||
/*\
|
||||
title: $:/core/modules/commands/deletetiddlers.js
|
||||
type: application/javascript
|
||||
module-type: command
|
||||
|
||||
Command to delete tiddlers
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.info = {
|
||||
name: "deletetiddlers",
|
||||
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 filter";
|
||||
}
|
||||
var self = this,
|
||||
wiki = this.commander.wiki,
|
||||
filter = this.params[0],
|
||||
tiddlers = wiki.filterTiddlers(filter);
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
wiki.deleteTiddler(title);
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
@@ -38,7 +38,7 @@ Command.prototype.execute = function() {
|
||||
count++;
|
||||
});
|
||||
});
|
||||
if(!count) {
|
||||
if(!count && self.params[1] !== "noerror") {
|
||||
self.callback("No tiddlers found in file \"" + self.params[0] + "\"");
|
||||
} else {
|
||||
self.callback(null);
|
||||
|
||||
184
core/modules/commands/savewikifolder.js
Normal file
184
core/modules/commands/savewikifolder.js
Normal file
@@ -0,0 +1,184 @@
|
||||
/*\
|
||||
title: $:/core/modules/commands/savewikifolder.js
|
||||
type: application/javascript
|
||||
module-type: command
|
||||
|
||||
Command to save the current wiki as a wiki folder
|
||||
|
||||
--savewikifolder <wikifolderpath> [<filter>]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.info = {
|
||||
name: "savewikifolder",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var fs,path;
|
||||
if($tw.node) {
|
||||
fs = require("fs");
|
||||
path = require("path");
|
||||
}
|
||||
|
||||
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 wiki folder path";
|
||||
}
|
||||
var wikifoldermaker = new WikiFolderMaker(this.params[0],this.params[1],this.commander);
|
||||
return wikifoldermaker.save();
|
||||
};
|
||||
|
||||
function WikiFolderMaker(wikiFolderPath,wikiFilter,commander) {
|
||||
this.wikiFolderPath = wikiFolderPath;
|
||||
this.wikiFilter = wikiFilter || "[all[tiddlers]]";
|
||||
this.commander = commander;
|
||||
this.wiki = commander.wiki;
|
||||
this.savedPaths = []; // So that we can detect filename clashes
|
||||
}
|
||||
|
||||
WikiFolderMaker.prototype.log = function(str) {
|
||||
if(this.commander.verbose) {
|
||||
console.log(str);
|
||||
}
|
||||
};
|
||||
|
||||
WikiFolderMaker.prototype.tiddlersToIgnore = [
|
||||
"$:/boot/boot.css",
|
||||
"$:/boot/boot.js",
|
||||
"$:/boot/bootprefix.js",
|
||||
"$:/core",
|
||||
"$:/library/sjcl.js",
|
||||
"$:/temp/info-plugin"
|
||||
];
|
||||
|
||||
/*
|
||||
Returns null if successful, or an error string if there was an error
|
||||
*/
|
||||
WikiFolderMaker.prototype.save = function() {
|
||||
var self = this;
|
||||
// Check that the output directory doesn't exist
|
||||
if(fs.existsSync(this.wikiFolderPath) && !$tw.utils.isDirectoryEmpty(this.wikiFolderPath)) {
|
||||
return "The unpackwiki command requires that the output wiki folder be empty";
|
||||
}
|
||||
// Get the tiddlers from the source wiki
|
||||
var tiddlerTitles = this.wiki.filterTiddlers(this.wikiFilter);
|
||||
// Initialise a new tiddlwiki.info file
|
||||
var newWikiInfo = {};
|
||||
// Process each incoming tiddler in turn
|
||||
$tw.utils.each(tiddlerTitles,function(title) {
|
||||
var tiddler = self.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
if(self.tiddlersToIgnore.indexOf(title) !== -1) {
|
||||
// Ignore the core plugin and the ephemeral info plugin
|
||||
self.log("Ignoring tiddler: " + title);
|
||||
} else {
|
||||
var type = tiddler.fields.type,
|
||||
pluginType = tiddler.fields["plugin-type"];
|
||||
if(type === "application/json" && pluginType) {
|
||||
// Plugin tiddler
|
||||
var libraryDetails = self.findPluginInLibrary(title);
|
||||
if(libraryDetails) {
|
||||
// A plugin from the core library
|
||||
self.log("Adding built-in plugin: " + libraryDetails.name);
|
||||
newWikiInfo[libraryDetails.type] = newWikiInfo[libraryDetails.type] || [];
|
||||
$tw.utils.pushTop(newWikiInfo[libraryDetails.type],libraryDetails.name);
|
||||
} else {
|
||||
// A custom plugin
|
||||
self.log("Processing custom plugin: " + title);
|
||||
self.saveCustomPlugin(tiddler);
|
||||
}
|
||||
} else {
|
||||
// Ordinary tiddler
|
||||
self.saveTiddler("tiddlers",tiddler);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// Save the tiddlywiki.info file
|
||||
this.saveJSONFile("tiddlywiki.info",newWikiInfo);
|
||||
self.log("Writing tiddlywiki.info: " + JSON.stringify(newWikiInfo,null,$tw.config.preferences.jsonSpaces));
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
Test whether the specified tiddler is a plugin in the plugin library
|
||||
*/
|
||||
WikiFolderMaker.prototype.findPluginInLibrary = function(title) {
|
||||
var parts = title.split("/"),
|
||||
pluginPath, type, name;
|
||||
if(parts[0] === "$:") {
|
||||
if(parts[1] === "languages" && parts.length === 3) {
|
||||
pluginPath = "languages" + path.sep + parts[2];
|
||||
type = parts[1];
|
||||
name = parts[2];
|
||||
} else if(parts[1] === "plugins" || parts[1] === "themes" && parts.length === 4) {
|
||||
pluginPath = parts[1] + path.sep + parts[2] + path.sep + parts[3];
|
||||
type = parts[1];
|
||||
name = parts[2] + "/" + parts[3];
|
||||
}
|
||||
}
|
||||
if(pluginPath && type && name) {
|
||||
pluginPath = path.resolve($tw.boot.bootPath,"..",pluginPath);
|
||||
if(fs.existsSync(pluginPath)) {
|
||||
return {
|
||||
pluginPath: pluginPath,
|
||||
type: type,
|
||||
name: name
|
||||
};
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
WikiFolderMaker.prototype.saveCustomPlugin = function(pluginTiddler) {
|
||||
var self = this,
|
||||
pluginTitle = pluginTiddler.fields.title,
|
||||
titleParts = pluginTitle.split("/"),
|
||||
directory = $tw.utils.generateTiddlerFilepath(titleParts[titleParts.length - 1],{
|
||||
directory: path.resolve(this.wikiFolderPath,pluginTiddler.fields["plugin-type"] + "s")
|
||||
}),
|
||||
pluginInfo = pluginTiddler.getFieldStrings({exclude: ["text","type"]});
|
||||
this.saveJSONFile(directory + path.sep + "plugin.info",pluginInfo);
|
||||
self.log("Writing " + directory + path.sep + "plugin.info: " + JSON.stringify(pluginInfo,null,$tw.config.preferences.jsonSpaces));
|
||||
var pluginTiddlers = JSON.parse(pluginTiddler.fields.text).tiddlers; // A hashmap of tiddlers in the plugin
|
||||
$tw.utils.each(pluginTiddlers,function(tiddler) {
|
||||
self.saveTiddler(directory,new $tw.Tiddler(tiddler));
|
||||
});
|
||||
};
|
||||
|
||||
WikiFolderMaker.prototype.saveTiddler = function(directory,tiddler) {
|
||||
var fileInfo = $tw.utils.generateTiddlerFileInfo(tiddler,{
|
||||
directory: path.resolve(this.wikiFolderPath,directory),
|
||||
wiki: this.wiki
|
||||
});
|
||||
$tw.utils.saveTiddlerToFileSync(tiddler,fileInfo);
|
||||
};
|
||||
|
||||
WikiFolderMaker.prototype.saveJSONFile = function(filename,json) {
|
||||
this.saveTextFile(filename,JSON.stringify(json,null,$tw.config.preferences.jsonSpaces));
|
||||
};
|
||||
|
||||
WikiFolderMaker.prototype.saveTextFile = function(filename,data) {
|
||||
this.saveFile(filename,"utf8",data);
|
||||
};
|
||||
|
||||
WikiFolderMaker.prototype.saveFile = function(filename,encoding,data) {
|
||||
var filepath = path.resolve(this.wikiFolderPath,filename);
|
||||
$tw.utils.createFileDirectories(filepath);
|
||||
fs.writeFileSync(filepath,data,encoding);
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
@@ -42,6 +42,7 @@ function FramedEngine(options) {
|
||||
this.iframeNode.style.border = "none";
|
||||
this.iframeNode.style.padding = "0";
|
||||
this.iframeNode.style.resize = "none";
|
||||
this.iframeNode.style["background-color"] = this.widget.wiki.extractTiddlerDataItem(this.widget.wiki.getTiddlerText("$:/palette"),"tiddler-editor-background");
|
||||
this.iframeDoc.body.style.margin = "0";
|
||||
this.iframeDoc.body.style.padding = "0";
|
||||
this.widget.domNodes.push(this.iframeNode);
|
||||
@@ -70,11 +71,15 @@ function FramedEngine(options) {
|
||||
if(this.widget.editRows) {
|
||||
this.domNode.setAttribute("rows",this.widget.editRows);
|
||||
}
|
||||
if(this.widget.editTabIndex) {
|
||||
this.iframeNode.setAttribute("tabindex",this.widget.editTabIndex);
|
||||
}
|
||||
// Copy the styles from the dummy textarea
|
||||
this.copyStyles();
|
||||
// Add event listeners
|
||||
$tw.utils.addEventListeners(this.domNode,[
|
||||
{name: "click",handlerObject: this,handlerMethod: "handleClickEvent"},
|
||||
{name: "focus",handlerObject: this,handlerMethod: "handleFocusEvent"},
|
||||
{name: "input",handlerObject: this,handlerMethod: "handleInputEvent"},
|
||||
{name: "keydown",handlerObject: this.widget,handlerMethod: "handleKeydownEvent"}
|
||||
]);
|
||||
@@ -92,6 +97,7 @@ FramedEngine.prototype.copyStyles = function() {
|
||||
this.domNode.style.display = "block";
|
||||
this.domNode.style.width = "100%";
|
||||
this.domNode.style.margin = "0";
|
||||
this.domNode.style["background-color"] = this.widget.wiki.extractTiddlerDataItem(this.widget.wiki.getTiddlerText("$:/palette"),"tiddler-editor-background");
|
||||
// In Chrome setting -webkit-text-fill-color overrides the placeholder text colour
|
||||
this.domNode.style["-webkit-text-fill-color"] = "currentcolor";
|
||||
};
|
||||
@@ -147,6 +153,14 @@ FramedEngine.prototype.focus = function() {
|
||||
this.domNode.select();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Handle the focus event
|
||||
*/
|
||||
FramedEngine.prototype.handleFocusEvent = function(event) {
|
||||
this.widget.cancelPopups();
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a click
|
||||
|
||||
@@ -49,6 +49,9 @@ function SimpleEngine(options) {
|
||||
if(this.widget.editClass) {
|
||||
this.domNode.className = this.widget.editClass;
|
||||
}
|
||||
if(this.widget.editTabIndex) {
|
||||
this.domNode.setAttribute("tabindex",this.widget.editTabIndex);
|
||||
}
|
||||
// Add an input event handler
|
||||
$tw.utils.addEventListeners(this.domNode,[
|
||||
{name: "focus", handlerObject: this, handlerMethod: "handleFocusEvent"},
|
||||
@@ -119,6 +122,7 @@ SimpleEngine.prototype.handleInputEvent = function(event) {
|
||||
Handle a dom "focus" event
|
||||
*/
|
||||
SimpleEngine.prototype.handleFocusEvent = function(event) {
|
||||
this.widget.cancelPopups();
|
||||
if(this.widget.editFocusPopup) {
|
||||
$tw.popup.triggerPopup({
|
||||
domNode: this.domNode,
|
||||
|
||||
@@ -176,6 +176,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
this.editMinHeight = this.getAttribute("minHeight",DEFAULT_MIN_TEXT_AREA_HEIGHT);
|
||||
this.editFocusPopup = this.getAttribute("focusPopup");
|
||||
this.editFocus = this.getAttribute("focus");
|
||||
this.editTabIndex = this.getAttribute("tabindex");
|
||||
// Get the default editor element tag and type
|
||||
var tag,type;
|
||||
if(this.editField === "text") {
|
||||
@@ -192,7 +193,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
type = type || "text";
|
||||
}
|
||||
// Get the rest of our parameters
|
||||
this.editTag = this.getAttribute("tag",tag);
|
||||
this.editTag = this.getAttribute("tag",tag) || "input";
|
||||
this.editType = this.getAttribute("type",type);
|
||||
// Make the child widgets
|
||||
this.makeChildWidgets();
|
||||
@@ -207,7 +208,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
EditTextWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
// Completely rerender if any of our attributes have changed
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE]) {
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE]) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else if(changedTiddlers[this.editTitle]) {
|
||||
@@ -216,7 +217,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
}
|
||||
this.engine.fixHeight();
|
||||
if(this.editShowToolbar) {
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -247,6 +248,13 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Cancel Popups
|
||||
*/
|
||||
EditTextWidget.prototype.cancelPopups = function() {
|
||||
$tw.popup.cancel(0,this.engine.domNode);
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a dom "keydown" event, which we'll bubble up to our container for the keyboard widgets benefit
|
||||
*/
|
||||
@@ -266,7 +274,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
el.dispatchEvent(clickEvent);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,12 @@ exports["wrap-selection"] = function(event,operation) {
|
||||
if(operation.selStart === operation.selEnd) {
|
||||
// No selection; check if we're within the prefix/suffix
|
||||
if(operation.text.substring(operation.selStart - event.paramObject.prefix.length,operation.selStart + event.paramObject.suffix.length) === event.paramObject.prefix + event.paramObject.suffix) {
|
||||
// Remove the prefix and suffix unless they comprise the entire text
|
||||
if(operation.selStart > event.paramObject.prefix.length || (operation.selEnd + event.paramObject.suffix.length) < operation.text.length ) {
|
||||
operation.cutStart = operation.selStart - event.paramObject.prefix.length;
|
||||
operation.cutEnd = operation.selEnd + event.paramObject.suffix.length;
|
||||
operation.replacement = "";
|
||||
operation.newSelStart = operation.cutStart;
|
||||
operation.newSelEnd = operation.newSelStart;
|
||||
}
|
||||
// Remove the prefix and suffix
|
||||
operation.cutStart = operation.selStart - event.paramObject.prefix.length;
|
||||
operation.cutEnd = operation.selEnd + event.paramObject.suffix.length;
|
||||
operation.replacement = "";
|
||||
operation.newSelStart = operation.cutStart;
|
||||
operation.newSelEnd = operation.newSelStart;
|
||||
} else {
|
||||
// Wrap the cursor instead
|
||||
operation.cutStart = operation.selStart;
|
||||
|
||||
@@ -119,7 +119,7 @@ exports.parseFilter = function(filterString) {
|
||||
p = 0, // Current position in the filter string
|
||||
match;
|
||||
var whitespaceRegExp = /(\s+)/mg,
|
||||
operandRegExp = /((?:\+|\-|~)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||
operandRegExp = /((?:\+|\-|~|=)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||
while(p < filterString.length) {
|
||||
// Skip any whitespace
|
||||
whitespaceRegExp.lastIndex = p;
|
||||
@@ -248,6 +248,10 @@ exports.compileFilter = function(filterString) {
|
||||
return function(results,source,widget) {
|
||||
$tw.utils.pushTop(results,operationSubFunction(source,widget));
|
||||
};
|
||||
case "=": // The results of the operation are pushed into the result without deduplication
|
||||
return function(results,source,widget) {
|
||||
Array.prototype.push.apply(results,operationSubFunction(source,widget));
|
||||
};
|
||||
case "-": // The results of this operation are removed from the main result
|
||||
return function(results,source,widget) {
|
||||
$tw.utils.removeArrayEntries(results,operationSubFunction(source,widget));
|
||||
@@ -270,7 +274,7 @@ exports.compileFilter = function(filterString) {
|
||||
})());
|
||||
});
|
||||
// Return a function that applies the operations to a source iterator of tiddler titles
|
||||
return $tw.perf.measure("filter",function filterFunction(source,widget) {
|
||||
return $tw.perf.measure("filter: " + filterString,function filterFunction(source,widget) {
|
||||
if(!source) {
|
||||
source = self.each;
|
||||
} else if(typeof source === "object") { // Array or hashmap
|
||||
|
||||
30
core/modules/filters/else.js
Normal file
30
core/modules/filters/else.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/else.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for replacing an empty input list with a constant, passing a non-empty input list straight through
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.else = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
if(results.length === 0) {
|
||||
return [operator.operand];
|
||||
} else {
|
||||
return results;
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -98,4 +98,13 @@ exports.escaperegexp = function(source,operator,options) {
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.escapecss = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
// escape any character with a special meaning in CSS using CSS.escape()
|
||||
results.push(CSS.escape(title));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -16,7 +16,16 @@ Filter operator returning its operand parsed as a list
|
||||
Export our filter function
|
||||
*/
|
||||
exports.enlist = function(source,operator,options) {
|
||||
var list = $tw.utils.parseStringArray(operator.operand);
|
||||
var allowDuplicates = false;
|
||||
switch(operator.suffix) {
|
||||
case "raw":
|
||||
allowDuplicates = true;
|
||||
break;
|
||||
case "dedupe":
|
||||
allowDuplicates = false;
|
||||
break;
|
||||
}
|
||||
var list = $tw.utils.parseStringArray(operator.operand,allowDuplicates);
|
||||
if(operator.prefix === "!") {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -16,7 +16,7 @@ Filter operator for comparing fields for equality
|
||||
Export our filter function
|
||||
*/
|
||||
exports.field = function(source,operator,options) {
|
||||
var results = [],
|
||||
var results = [],indexedResults,
|
||||
fieldname = (operator.suffix || operator.operator || "title").toLowerCase();
|
||||
if(operator.prefix === "!") {
|
||||
if(operator.regexp) {
|
||||
@@ -53,6 +53,12 @@ exports.field = function(source,operator,options) {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if(source.byField && operator.operand) {
|
||||
indexedResults = source.byField(fieldname,operator.operand);
|
||||
if(indexedResults) {
|
||||
return indexedResults
|
||||
}
|
||||
}
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler) {
|
||||
var text = tiddler.getFieldString(fieldname);
|
||||
|
||||
26
core/modules/filters/getvariable.js
Normal file
26
core/modules/filters/getvariable.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/getvariable.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for replacing input values by the value of the variable with the same name, or blank if the variable is missing
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.getvariable = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(options.widget.getVariable(title) || "");
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -45,7 +45,7 @@ exports.has = function(source,operator,options) {
|
||||
if(tiddler && $tw.utils.hop(tiddler.fields,operator.operand) && !(tiddler.fields[operator.operand] === "" || tiddler.fields[operator.operand].length === 0)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
return results;
|
||||
|
||||
36
core/modules/filters/is/blank.js
Normal file
36
core/modules/filters/is/blank.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/is/blank.js
|
||||
type: application/javascript
|
||||
module-type: isfilteroperator
|
||||
|
||||
Filter function for [is[blank]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.blank = function(source,prefix,options) {
|
||||
var results = [];
|
||||
if(prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(title) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(!title) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
36
core/modules/filters/is/variable.js
Normal file
36
core/modules/filters/is/variable.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/is/variable.js
|
||||
type: application/javascript
|
||||
module-type: isfilteroperator
|
||||
|
||||
Filter function for [is[variable]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.variable = function(source,prefix,options) {
|
||||
var results = [];
|
||||
if(prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(!(title in options.widget.variables)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(title in options.widget.variables) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
53
core/modules/filters/match.js
Normal file
53
core/modules/filters/match.js
Normal file
@@ -0,0 +1,53 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/match.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for checking if a title matches a string
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.match = function(source,operator,options) {
|
||||
var results = [],
|
||||
suffixes = (operator.suffixes || [])[0] || [];
|
||||
if(suffixes.indexOf("caseinsensitive") !== -1) {
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(title.toLowerCase() !== (operator.operand || "").toLowerCase()) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(title.toLowerCase() === (operator.operand || "").toLowerCase()) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(title !== operator.operand) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(title === operator.operand) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
146
core/modules/filters/math.js
Normal file
146
core/modules/filters/math.js
Normal file
@@ -0,0 +1,146 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/math.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operators for math. Unary/binary operators work on each item in turn, and return a new item list.
|
||||
|
||||
Sum/product/maxall/minall operate on the entire list, returning a single item.
|
||||
|
||||
Note that strings are converted to numbers automatically. Trailing non-digits are ignored.
|
||||
|
||||
* "" converts to 0
|
||||
* "12kk" converts to 12
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.negate = makeNumericBinaryOperator(
|
||||
function(a) {return -a}
|
||||
);
|
||||
|
||||
exports.abs = makeNumericBinaryOperator(
|
||||
function(a) {return Math.abs(a)}
|
||||
);
|
||||
|
||||
exports.ceil = makeNumericBinaryOperator(
|
||||
function(a) {return Math.ceil(a)}
|
||||
);
|
||||
|
||||
exports.floor = makeNumericBinaryOperator(
|
||||
function(a) {return Math.floor(a)}
|
||||
);
|
||||
|
||||
exports.round = makeNumericBinaryOperator(
|
||||
function(a) {return Math.round(a)}
|
||||
);
|
||||
|
||||
exports.trunc = makeNumericBinaryOperator(
|
||||
function(a) {return Math.trunc(a)}
|
||||
);
|
||||
|
||||
exports.untrunc = makeNumericBinaryOperator(
|
||||
function(a) {return Math.ceil(Math.abs(a)) * Math.sign(a)}
|
||||
);
|
||||
|
||||
exports.sign = makeNumericBinaryOperator(
|
||||
function(a) {return Math.sign(a)}
|
||||
);
|
||||
|
||||
exports.add = makeNumericBinaryOperator(
|
||||
function(a,b) {return a + b;}
|
||||
);
|
||||
|
||||
exports.subtract = makeNumericBinaryOperator(
|
||||
function(a,b) {return a - b;}
|
||||
);
|
||||
|
||||
exports.multiply = makeNumericBinaryOperator(
|
||||
function(a,b) {return a * b;}
|
||||
);
|
||||
|
||||
exports.divide = makeNumericBinaryOperator(
|
||||
function(a,b) {return a / b;}
|
||||
);
|
||||
|
||||
exports.remainder = makeNumericBinaryOperator(
|
||||
function(a,b) {return a % b;}
|
||||
);
|
||||
|
||||
exports.max = makeNumericBinaryOperator(
|
||||
function(a,b) {return Math.max(a,b);}
|
||||
);
|
||||
|
||||
exports.min = makeNumericBinaryOperator(
|
||||
function(a,b) {return Math.min(a,b);}
|
||||
);
|
||||
|
||||
exports.fixed = makeNumericBinaryOperator(
|
||||
function(a,b) {return Number.prototype.toFixed.call(a,Math.min(Math.max(b,0),100));}
|
||||
);
|
||||
|
||||
exports.precision = makeNumericBinaryOperator(
|
||||
function(a,b) {return Number.prototype.toPrecision.call(a,Math.min(Math.max(b,1),100));}
|
||||
);
|
||||
|
||||
exports.exponential = makeNumericBinaryOperator(
|
||||
function(a,b) {return Number.prototype.toExponential.call(a,Math.min(Math.max(b,0),100));}
|
||||
);
|
||||
|
||||
exports.sum = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return accumulator + value},
|
||||
0 // Initial value
|
||||
);
|
||||
|
||||
exports.product = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return accumulator * value},
|
||||
1 // Initial value
|
||||
);
|
||||
|
||||
exports.maxall = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return Math.max(accumulator,value)},
|
||||
-Infinity // Initial value
|
||||
);
|
||||
|
||||
exports.minall = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return Math.min(accumulator,value)},
|
||||
Infinity // Initial value
|
||||
);
|
||||
|
||||
function makeNumericBinaryOperator(fnCalc) {
|
||||
return function(source,operator,options) {
|
||||
var result = [],
|
||||
numOperand = parseNumber(operator.operand);
|
||||
source(function(tiddler,title) {
|
||||
result.push(stringifyNumber(fnCalc(parseNumber(title),numOperand)));
|
||||
});
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
function makeNumericReducingOperator(fnCalc,initialValue) {
|
||||
initialValue = initialValue || 0;
|
||||
return function(source,operator,options) {
|
||||
var result = [];
|
||||
source(function(tiddler,title) {
|
||||
result.push(title);
|
||||
});
|
||||
return [stringifyNumber(result.reduce(function(accumulator,currentValue) {
|
||||
return fnCalc(accumulator,parseNumber(currentValue));
|
||||
},initialValue))];
|
||||
};
|
||||
}
|
||||
|
||||
function parseNumber(str) {
|
||||
return parseFloat(str) || 0;
|
||||
}
|
||||
|
||||
function stringifyNumber(num) {
|
||||
return num + "";
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -18,7 +18,7 @@ Export our filter function
|
||||
exports.removesuffix = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
if(title.substr(-operator.operand.length) === operator.operand) {
|
||||
if(title && title.substr(-operator.operand.length) === operator.operand) {
|
||||
results.push(title.substr(0,title.length - operator.operand.length));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -43,6 +43,7 @@ exports.search = function(source,operator,options) {
|
||||
caseSensitive: hasFlag("casesensitive"),
|
||||
literal: hasFlag("literal"),
|
||||
whitespace: hasFlag("whitespace"),
|
||||
anchored: hasFlag("anchored"),
|
||||
regexp: hasFlag("regexp"),
|
||||
words: hasFlag("words")
|
||||
});
|
||||
|
||||
93
core/modules/filters/strings.js
Normal file
93
core/modules/filters/strings.js
Normal file
@@ -0,0 +1,93 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/strings.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operators for strings. Unary/binary operators work on each item in turn, and return a new item list.
|
||||
|
||||
Sum/product/maxall/minall operate on the entire list, returning a single item.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.length = makeStringBinaryOperator(
|
||||
function(a) {return ["" + ("" + a).length];}
|
||||
);
|
||||
|
||||
exports.uppercase = makeStringBinaryOperator(
|
||||
function(a) {return [("" + a).toUpperCase()];}
|
||||
);
|
||||
|
||||
exports.lowercase = makeStringBinaryOperator(
|
||||
function(a) {return [("" + a).toLowerCase()];}
|
||||
);
|
||||
|
||||
exports.sentencecase = makeStringBinaryOperator(
|
||||
function(a) {return [$tw.utils.toSentenceCase(a)];}
|
||||
);
|
||||
|
||||
exports.titlecase = makeStringBinaryOperator(
|
||||
function(a) {return [$tw.utils.toTitleCase(a)];}
|
||||
);
|
||||
|
||||
exports.trim = makeStringBinaryOperator(
|
||||
function(a) {return [$tw.utils.trim(a)];}
|
||||
);
|
||||
|
||||
exports.split = makeStringBinaryOperator(
|
||||
function(a,b) {return ("" + a).split(b);}
|
||||
);
|
||||
|
||||
exports.join = makeStringReducingOperator(
|
||||
function(accumulator,value,operand) {
|
||||
if(accumulator === null) {
|
||||
return value;
|
||||
} else {
|
||||
return accumulator + operand + value;
|
||||
}
|
||||
},null
|
||||
);
|
||||
|
||||
function makeStringBinaryOperator(fnCalc) {
|
||||
return function(source,operator,options) {
|
||||
var result = [];
|
||||
source(function(tiddler,title) {
|
||||
Array.prototype.push.apply(result,fnCalc(title,operator.operand || ""));
|
||||
});
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
function makeStringReducingOperator(fnCalc,initialValue) {
|
||||
return function(source,operator,options) {
|
||||
var result = [];
|
||||
source(function(tiddler,title) {
|
||||
result.push(title);
|
||||
});
|
||||
return [result.reduce(function(accumulator,currentValue) {
|
||||
return fnCalc(accumulator,currentValue,operator.operand || "");
|
||||
},initialValue)];
|
||||
};
|
||||
}
|
||||
|
||||
exports.splitregexp = function(source,operator,options) {
|
||||
var result = [],
|
||||
suffix = operator.suffix || "",
|
||||
flags = (suffix.indexOf("m") !== -1 ? "m" : "") + (suffix.indexOf("i") !== -1 ? "i" : ""),
|
||||
regExp;
|
||||
try {
|
||||
regExp = new RegExp(operator.operand || "",flags);
|
||||
} catch(ex) {
|
||||
return ["RegExp error: " + ex];
|
||||
}
|
||||
source(function(tiddler,title) {
|
||||
Array.prototype.push.apply(result,title.split(regExp));
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -16,7 +16,7 @@ Filter operator for checking for the presence of a tag
|
||||
Export our filter function
|
||||
*/
|
||||
exports.tag = function(source,operator,options) {
|
||||
var results = [];
|
||||
var results = [],indexedResults;
|
||||
if((operator.suffix || "").toLowerCase() === "strict" && !operator.operand) {
|
||||
// New semantics:
|
||||
// Always return copy of input if operator.operand is missing
|
||||
@@ -25,9 +25,10 @@ exports.tag = function(source,operator,options) {
|
||||
});
|
||||
} else {
|
||||
// Old semantics:
|
||||
var tiddlers = options.wiki.getTiddlersWithTag(operator.operand);
|
||||
var tiddlers;
|
||||
if(operator.prefix === "!") {
|
||||
// Returns a copy of the input if operator.operand is missing
|
||||
tiddlers = options.wiki.getTiddlersWithTag(operator.operand);
|
||||
source(function(tiddler,title) {
|
||||
if(tiddlers.indexOf(title) === -1) {
|
||||
results.push(title);
|
||||
@@ -35,12 +36,20 @@ exports.tag = function(source,operator,options) {
|
||||
});
|
||||
} else {
|
||||
// Returns empty results if operator.operand is missing
|
||||
source(function(tiddler,title) {
|
||||
if(tiddlers.indexOf(title) !== -1) {
|
||||
results.push(title);
|
||||
if(source.byTag) {
|
||||
indexedResults = source.byTag(operator.operand);
|
||||
if(indexedResults) {
|
||||
return indexedResults;
|
||||
}
|
||||
});
|
||||
results = options.wiki.sortByList(results,operator.operand);
|
||||
} else {
|
||||
tiddlers = options.wiki.getTiddlersWithTag(operator.operand);
|
||||
source(function(tiddler,title) {
|
||||
if(tiddlers.indexOf(title) !== -1) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
results = options.wiki.sortByList(results,operator.operand);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
|
||||
26
core/modules/filters/then.js
Normal file
26
core/modules/filters/then.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/then.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for replacing any titles with a constant
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.then = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(operator.operand);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
26
core/modules/filters/variables.js
Normal file
26
core/modules/filters/variables.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/variables.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for returning the names of the active variables
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.variables = function(source,operator,options) {
|
||||
var names = [];
|
||||
for(var variable in options.widget.variables) {
|
||||
names.push(variable);
|
||||
}
|
||||
return names.sort();
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -95,7 +95,7 @@ Extended filter operators to manipulate the current list.
|
||||
exports.allafter = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand);
|
||||
return (index === -1 || index > (results.length - 2)) ? [] :
|
||||
return (index === -1) ? [] :
|
||||
(operator.suffix) ? results.slice(index) :
|
||||
results.slice(index + 1);
|
||||
};
|
||||
@@ -106,7 +106,7 @@ Extended filter operators to manipulate the current list.
|
||||
exports.allbefore = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand);
|
||||
return (index < 0) ? [] :
|
||||
return (index === -1) ? [] :
|
||||
(operator.suffix) ? results.slice(0, index + 1) :
|
||||
results.slice(0, index);
|
||||
};
|
||||
|
||||
143
core/modules/indexers/field-indexer.js
Normal file
143
core/modules/indexers/field-indexer.js
Normal file
@@ -0,0 +1,143 @@
|
||||
/*\
|
||||
title: $:/core/modules/indexers/field-indexer.js
|
||||
type: application/javascript
|
||||
module-type: indexer
|
||||
|
||||
Indexes the tiddlers with each field value
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global modules: false */
|
||||
"use strict";
|
||||
|
||||
var DEFAULT_MAXIMUM_INDEXED_VALUE_LENGTH = 128;
|
||||
|
||||
function FieldIndexer(wiki) {
|
||||
this.wiki = wiki;
|
||||
}
|
||||
|
||||
FieldIndexer.prototype.init = function() {
|
||||
this.index = null;
|
||||
this.maxIndexedValueLength = DEFAULT_MAXIMUM_INDEXED_VALUE_LENGTH;
|
||||
this.addIndexMethods();
|
||||
}
|
||||
|
||||
// Provided for testing
|
||||
FieldIndexer.prototype.setMaxIndexedValueLength = function(length) {
|
||||
this.index = null;
|
||||
this.maxIndexedValueLength = length;
|
||||
};
|
||||
|
||||
FieldIndexer.prototype.addIndexMethods = function() {
|
||||
var self = this;
|
||||
this.wiki.each.byField = function(name,value) {
|
||||
var titles = self.wiki.allTitles(),
|
||||
lookup = self.lookup(name,value);
|
||||
return lookup && lookup.filter(function(title) {
|
||||
return titles.indexOf(title) !== -1;
|
||||
});
|
||||
};
|
||||
this.wiki.eachShadow.byField = function(name,value) {
|
||||
var titles = self.wiki.allShadowTitles(),
|
||||
lookup = self.lookup(name,value);
|
||||
return lookup && lookup.filter(function(title) {
|
||||
return titles.indexOf(title) !== -1;
|
||||
});
|
||||
};
|
||||
this.wiki.eachTiddlerPlusShadows.byField = function(name,value) {
|
||||
var lookup = self.lookup(name,value);
|
||||
return lookup ? lookup.slice(0) : null;
|
||||
};
|
||||
this.wiki.eachShadowPlusTiddlers.byField = function(name,value) {
|
||||
var lookup = self.lookup(name,value);
|
||||
return lookup ? lookup.slice(0) : null;
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
Tear down and then rebuild the index as if all tiddlers have changed
|
||||
*/
|
||||
FieldIndexer.prototype.rebuild = function() {
|
||||
// Invalidate the index so that it will be rebuilt when it is next used
|
||||
this.index = null;
|
||||
};
|
||||
|
||||
/*
|
||||
Build the index for a particular field
|
||||
*/
|
||||
FieldIndexer.prototype.buildIndexForField = function(name) {
|
||||
var self = this;
|
||||
// Hashmap by field name of hashmap by field value of array of tiddler titles
|
||||
this.index = this.index || Object.create(null);
|
||||
this.index[name] = Object.create(null);
|
||||
var baseIndex = this.index[name];
|
||||
// Update the index for each tiddler
|
||||
this.wiki.eachTiddlerPlusShadows(function(tiddler,title) {
|
||||
if(name in tiddler.fields) {
|
||||
var value = tiddler.getFieldString(name);
|
||||
// Skip any values above the maximum length
|
||||
if(value.length < self.maxIndexedValueLength) {
|
||||
baseIndex[value] = baseIndex[value] || [];
|
||||
baseIndex[value].push(title);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Update the index in the light of a tiddler value changing; note that the title must be identical. (Renames are handled as a separate delete and create)
|
||||
updateDescriptor: {old: {tiddler: <tiddler>, shadow: <boolean>, exists: <boolean>},new: {tiddler: <tiddler>, shadow: <boolean>, exists: <boolean>}}
|
||||
*/
|
||||
FieldIndexer.prototype.update = function(updateDescriptor) {
|
||||
var self = this;
|
||||
// Don't do anything if the index hasn't been built yet
|
||||
if(this.index === null) {
|
||||
return;
|
||||
}
|
||||
// Remove the old tiddler from the index
|
||||
if(updateDescriptor.old.tiddler) {
|
||||
$tw.utils.each(this.index,function(indexEntry,name) {
|
||||
if(name in updateDescriptor.old.tiddler.fields) {
|
||||
var value = updateDescriptor.old.tiddler.getFieldString(name),
|
||||
tiddlerList = indexEntry[value];
|
||||
if(tiddlerList) {
|
||||
var index = tiddlerList.indexOf(updateDescriptor.old.tiddler.fields.title);
|
||||
if(index !== -1) {
|
||||
tiddlerList.splice(index,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// Add the new tiddler to the index
|
||||
if(updateDescriptor["new"].tiddler) {
|
||||
$tw.utils.each(this.index,function(indexEntry,name) {
|
||||
if(name in updateDescriptor["new"].tiddler.fields) {
|
||||
var value = updateDescriptor["new"].tiddler.getFieldString(name);
|
||||
if(value.length < self.maxIndexedValueLength) {
|
||||
indexEntry[value] = indexEntry[value] || [];
|
||||
indexEntry[value].push(updateDescriptor["new"].tiddler.fields.title);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Lookup the given field returning a list of tiddler titles
|
||||
FieldIndexer.prototype.lookup = function(name,value) {
|
||||
// Fail the lookup if the value is too long
|
||||
if(value.length >= this.maxIndexedValueLength) {
|
||||
return null;
|
||||
}
|
||||
// Update the index if it has yet to be built
|
||||
if(this.index === null || !this.index[name]) {
|
||||
this.buildIndexForField(name);
|
||||
}
|
||||
return this.index[name][value] || [];
|
||||
};
|
||||
|
||||
exports.FieldIndexer = FieldIndexer;
|
||||
|
||||
})();
|
||||
98
core/modules/indexers/tag-indexer.js
Normal file
98
core/modules/indexers/tag-indexer.js
Normal file
@@ -0,0 +1,98 @@
|
||||
/*\
|
||||
title: $:/core/modules/indexers/tag-indexer.js
|
||||
type: application/javascript
|
||||
module-type: indexer
|
||||
|
||||
Indexes the tiddlers with each tag
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global modules: false */
|
||||
"use strict";
|
||||
|
||||
function TagIndexer(wiki) {
|
||||
this.wiki = wiki;
|
||||
}
|
||||
|
||||
TagIndexer.prototype.init = function() {
|
||||
this.subIndexers = [
|
||||
new TagSubIndexer(this,"each"),
|
||||
new TagSubIndexer(this,"eachShadow"),
|
||||
new TagSubIndexer(this,"eachTiddlerPlusShadows"),
|
||||
new TagSubIndexer(this,"eachShadowPlusTiddlers")
|
||||
];
|
||||
$tw.utils.each(this.subIndexers,function(subIndexer) {
|
||||
subIndexer.addIndexMethod();
|
||||
});
|
||||
};
|
||||
|
||||
TagIndexer.prototype.rebuild = function() {
|
||||
$tw.utils.each(this.subIndexers,function(subIndexer) {
|
||||
subIndexer.rebuild();
|
||||
});
|
||||
};
|
||||
|
||||
TagIndexer.prototype.update = function(updateDescriptor) {
|
||||
$tw.utils.each(this.subIndexers,function(subIndexer) {
|
||||
subIndexer.update(updateDescriptor);
|
||||
});
|
||||
};
|
||||
|
||||
function TagSubIndexer(indexer,iteratorMethod) {
|
||||
this.indexer = indexer;
|
||||
this.iteratorMethod = iteratorMethod;
|
||||
this.index = null; // Hashmap of tag title to {isSorted: bool, titles: [array]} or null if not yet initialised
|
||||
}
|
||||
|
||||
TagSubIndexer.prototype.addIndexMethod = function() {
|
||||
var self = this;
|
||||
this.indexer.wiki[this.iteratorMethod].byTag = function(tag) {
|
||||
return self.lookup(tag).slice(0);
|
||||
};
|
||||
};
|
||||
|
||||
TagSubIndexer.prototype.rebuild = function() {
|
||||
var self = this;
|
||||
// Hashmap by tag of array of {isSorted:, titles:[]}
|
||||
this.index = Object.create(null);
|
||||
// Add all the tags
|
||||
this.indexer.wiki[this.iteratorMethod](function(tiddler,title) {
|
||||
$tw.utils.each(tiddler.fields.tags,function(tag) {
|
||||
if(!self.index[tag]) {
|
||||
self.index[tag] = {isSorted: false, titles: [title]};
|
||||
} else {
|
||||
self.index[tag].titles.push(title);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
TagSubIndexer.prototype.update = function(updateDescriptor) {
|
||||
this.index = null;
|
||||
};
|
||||
|
||||
TagSubIndexer.prototype.lookup = function(tag) {
|
||||
// Update the index if it has yet to be built
|
||||
if(this.index === null) {
|
||||
this.rebuild();
|
||||
}
|
||||
var indexRecord = this.index[tag];
|
||||
if(indexRecord) {
|
||||
if(!indexRecord.isSorted) {
|
||||
if(this.indexer.wiki.sortByList) {
|
||||
indexRecord.titles = this.indexer.wiki.sortByList(indexRecord.titles,tag);
|
||||
}
|
||||
indexRecord.isSorted = true;
|
||||
}
|
||||
return indexRecord.titles;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.TagIndexer = TagIndexer;
|
||||
|
||||
})();
|
||||
@@ -35,6 +35,8 @@ exports.getInfoTiddlerFields = function() {
|
||||
// Screen size
|
||||
infoTiddlerFields.push({title: "$:/info/browser/screen/width", text: window.screen.width.toString()});
|
||||
infoTiddlerFields.push({title: "$:/info/browser/screen/height", text: window.screen.height.toString()});
|
||||
// Language
|
||||
infoTiddlerFields.push({title: "$:/info/browser/language", text: navigator.language || ""});
|
||||
}
|
||||
return infoTiddlerFields;
|
||||
};
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/macros/dumpvariables.js
|
||||
type: application/javascript
|
||||
module-type: macro
|
||||
|
||||
Macro to dump all active variable values
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Information about this macro
|
||||
*/
|
||||
|
||||
exports.name = "dumpvariables";
|
||||
|
||||
exports.params = [
|
||||
];
|
||||
|
||||
/*
|
||||
Run the macro
|
||||
*/
|
||||
exports.run = function() {
|
||||
var output = ["|!Variable |!Value |"],
|
||||
variables = [], variable;
|
||||
for(variable in this.variables) {
|
||||
variables.push(variable);
|
||||
}
|
||||
variables.sort();
|
||||
for(var index=0; index<variables.length; index++) {
|
||||
var variable = variables[index];
|
||||
output.push("|" + variable + " |<input size=50 value=<<" + variable + ">>/> |")
|
||||
}
|
||||
return output.join("\n");
|
||||
};
|
||||
|
||||
})();
|
||||
34
core/modules/macros/uniquetitle.js
Normal file
34
core/modules/macros/uniquetitle.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/*\
|
||||
title: $:/core/modules/macros/unusedtitle.js
|
||||
type: application/javascript
|
||||
module-type: macro
|
||||
Macro to return a new title that is unused in the wiki. It can be given a name as a base.
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Information about this macro
|
||||
*/
|
||||
|
||||
exports.name = "unusedtitle";
|
||||
|
||||
exports.params = [
|
||||
{name: "baseName"},
|
||||
{name: "options"}
|
||||
];
|
||||
|
||||
/*
|
||||
Run the macro
|
||||
*/
|
||||
exports.run = function(baseName, options) {
|
||||
if(!baseName) {
|
||||
baseName = $tw.language.getString("DefaultNewTiddlerTitle");
|
||||
}
|
||||
return this.wiki.generateNewTitle(baseName, options);
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -27,8 +27,6 @@ exports.init = function(parser) {
|
||||
};
|
||||
|
||||
exports.parse = function() {
|
||||
// Move past the match
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
// Move past the match
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
// Get the match details
|
||||
|
||||
@@ -21,6 +21,7 @@ function SaverHandler(options) {
|
||||
var self = this;
|
||||
this.wiki = options.wiki;
|
||||
this.dirtyTracking = options.dirtyTracking;
|
||||
this.preloadDirty = options.preloadDirty || [];
|
||||
this.pendingAutoSave = false;
|
||||
// Make a logger
|
||||
this.logger = new $tw.utils.Logger("saver-handler");
|
||||
@@ -33,7 +34,13 @@ function SaverHandler(options) {
|
||||
// Compile the dirty tiddler filter
|
||||
this.filterFn = this.wiki.compileFilter(this.wiki.getTiddlerText(this.titleSyncFilter));
|
||||
// Count of changes that have not yet been saved
|
||||
this.numChanges = 0;
|
||||
var filteredChanges = self.filterFn.call(self.wiki,function(iterator) {
|
||||
$tw.utils.each(self.preloadDirty,function(title) {
|
||||
var tiddler = self.wiki.getTiddler(title);
|
||||
iterator(tiddler,title);
|
||||
});
|
||||
});
|
||||
this.numChanges = filteredChanges.length;
|
||||
// Listen out for changes to tiddlers
|
||||
this.wiki.addEventListener("change",function(changes) {
|
||||
// Filter the changes so that we only count changes to tiddlers that we care about
|
||||
@@ -144,8 +151,12 @@ Save the wiki contents. Options are:
|
||||
SaverHandler.prototype.saveWiki = function(options) {
|
||||
options = options || {};
|
||||
var self = this,
|
||||
method = options.method || "save",
|
||||
variables = options.variables || {},
|
||||
method = options.method || "save";
|
||||
// Ignore autosave if disabled
|
||||
if(method === "autosave" && this.wiki.getTiddlerText(this.titleAutoSave,"yes") !== "yes") {
|
||||
return false;
|
||||
}
|
||||
var variables = options.variables || {},
|
||||
template = options.template || "$:/core/save/all",
|
||||
downloadType = options.downloadType || "text/plain",
|
||||
text = this.wiki.renderTiddler(downloadType,template,options),
|
||||
@@ -164,10 +175,6 @@ SaverHandler.prototype.saveWiki = function(options) {
|
||||
}
|
||||
}
|
||||
};
|
||||
// Ignore autosave if disabled
|
||||
if(method === "autosave" && this.wiki.getTiddlerText(this.titleAutoSave,"yes") !== "yes") {
|
||||
return false;
|
||||
}
|
||||
// Call the highest priority saver that supports this method
|
||||
for(var t=this.savers.length-1; t>=0; t--) {
|
||||
var saver = this.savers[t];
|
||||
|
||||
118
core/modules/savers/github.js
Normal file
118
core/modules/savers/github.js
Normal file
@@ -0,0 +1,118 @@
|
||||
/*\
|
||||
title: $:/core/modules/savers/github.js
|
||||
type: application/javascript
|
||||
module-type: saver
|
||||
|
||||
Saves wiki by pushing a commit to the GitHub v3 REST API
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Select the appropriate saver module and set it up
|
||||
*/
|
||||
var GitHubSaver = function(wiki) {
|
||||
this.wiki = wiki;
|
||||
};
|
||||
|
||||
GitHubSaver.prototype.save = function(text,method,callback) {
|
||||
var self = this,
|
||||
username = this.wiki.getTiddlerText("$:/GitHub/Username"),
|
||||
password = $tw.utils.getPassword("github"),
|
||||
repo = this.wiki.getTiddlerText("$:/GitHub/Repo"),
|
||||
path = this.wiki.getTiddlerText("$:/GitHub/Path"),
|
||||
filename = this.wiki.getTiddlerText("$:/GitHub/Filename"),
|
||||
branch = this.wiki.getTiddlerText("$:/GitHub/Branch") || "master",
|
||||
endpoint = this.wiki.getTiddlerText("$:/GitHub/ServerURL") || "https://api.github.com",
|
||||
headers = {
|
||||
"Accept": "application/vnd.github.v3+json",
|
||||
"Content-Type": "application/json;charset=UTF-8",
|
||||
"Authorization": "Basic " + window.btoa(username + ":" + password)
|
||||
};
|
||||
// Bail if we don't have everything we need
|
||||
if(!username || !password || !repo || !path || !filename) {
|
||||
return false;
|
||||
}
|
||||
// Make sure the path start and ends with a slash
|
||||
if(path.substring(0,1) !== "/") {
|
||||
path = "/" + path;
|
||||
}
|
||||
if(path.substring(path.length - 1) !== "/") {
|
||||
path = path + "/";
|
||||
}
|
||||
// Compose the base URI
|
||||
var uri = endpoint + "/repos/" + repo + "/contents" + path;
|
||||
// Perform a get request to get the details (inc shas) of files in the same path as our file
|
||||
$tw.utils.httpRequest({
|
||||
url: uri,
|
||||
type: "GET",
|
||||
headers: headers,
|
||||
data: {
|
||||
ref: branch
|
||||
},
|
||||
callback: function(err,getResponseDataJson,xhr) {
|
||||
var getResponseData,sha = "";
|
||||
if(err && xhr.status !== 404) {
|
||||
return callback(err);
|
||||
}
|
||||
if(xhr.status !== 404) {
|
||||
getResponseData = JSON.parse(getResponseDataJson);
|
||||
$tw.utils.each(getResponseData,function(details) {
|
||||
if(details.name === filename) {
|
||||
sha = details.sha;
|
||||
}
|
||||
});
|
||||
}
|
||||
var data = {
|
||||
message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
content: $tw.utils.base64Encode(text),
|
||||
branch: branch,
|
||||
sha: sha
|
||||
};
|
||||
// Perform a PUT request to save the file
|
||||
$tw.utils.httpRequest({
|
||||
url: uri + filename,
|
||||
type: "PUT",
|
||||
headers: headers,
|
||||
data: JSON.stringify(data),
|
||||
callback: function(err,putResponseDataJson,xhr) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
var putResponseData = JSON.parse(putResponseDataJson);
|
||||
callback(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
Information about this saver
|
||||
*/
|
||||
GitHubSaver.prototype.info = {
|
||||
name: "github",
|
||||
priority: 2000,
|
||||
capabilities: ["save", "autosave"]
|
||||
};
|
||||
|
||||
/*
|
||||
Static method that returns true if this saver is capable of working
|
||||
*/
|
||||
exports.canSave = function(wiki) {
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
Create an instance of this saver
|
||||
*/
|
||||
exports.create = function(wiki) {
|
||||
return new GitHubSaver(wiki);
|
||||
};
|
||||
|
||||
})();
|
||||
120
core/modules/savers/gitlab.js
Normal file
120
core/modules/savers/gitlab.js
Normal file
@@ -0,0 +1,120 @@
|
||||
/*\
|
||||
title: $:/core/modules/savers/gitlab.js
|
||||
type: application/javascript
|
||||
module-type: saver
|
||||
|
||||
Saves wiki by pushing a commit to the GitLab REST API
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: true */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Select the appropriate saver module and set it up
|
||||
*/
|
||||
var GitLabSaver = function(wiki) {
|
||||
this.wiki = wiki;
|
||||
};
|
||||
|
||||
GitLabSaver.prototype.save = function(text,method,callback) {
|
||||
/* See https://docs.gitlab.com/ee/api/repository_files.html */
|
||||
var self = this,
|
||||
username = this.wiki.getTiddlerText("$:/GitLab/Username"),
|
||||
password = $tw.utils.getPassword("gitlab"),
|
||||
repo = this.wiki.getTiddlerText("$:/GitLab/Repo"),
|
||||
path = this.wiki.getTiddlerText("$:/GitLab/Path"),
|
||||
filename = this.wiki.getTiddlerText("$:/GitLab/Filename"),
|
||||
branch = this.wiki.getTiddlerText("$:/GitLab/Branch") || "master",
|
||||
endpoint = this.wiki.getTiddlerText("$:/GitLab/ServerURL") || "https://gitlab.com/api/v4",
|
||||
headers = {
|
||||
"Content-Type": "application/json;charset=UTF-8",
|
||||
"Private-Token": password
|
||||
};
|
||||
// Bail if we don't have everything we need
|
||||
if(!username || !password || !repo || !path || !filename) {
|
||||
return false;
|
||||
}
|
||||
// Make sure the path start and ends with a slash
|
||||
if(path.substring(0,1) !== "/") {
|
||||
path = "/" + path;
|
||||
}
|
||||
if(path.substring(path.length - 1) !== "/") {
|
||||
path = path + "/";
|
||||
}
|
||||
// Compose the base URI
|
||||
var uri = endpoint + "/projects/" + encodeURIComponent(repo) + "/repository/";
|
||||
// Perform a get request to get the details (inc shas) of files in the same path as our file
|
||||
$tw.utils.httpRequest({
|
||||
url: uri + "tree/" + encodeURIComponent(path.replace(/^\/+|\/$/g, '')),
|
||||
type: "GET",
|
||||
headers: headers,
|
||||
data: {
|
||||
ref: branch
|
||||
},
|
||||
callback: function(err,getResponseDataJson,xhr) {
|
||||
var getResponseData,sha = "";
|
||||
if(err && xhr.status !== 404) {
|
||||
return callback(err);
|
||||
}
|
||||
var requestType = "POST";
|
||||
if(xhr.status !== 404) {
|
||||
getResponseData = JSON.parse(getResponseDataJson);
|
||||
$tw.utils.each(getResponseData,function(details) {
|
||||
if(details.name === filename) {
|
||||
requestType = "PUT";
|
||||
sha = details.sha;
|
||||
}
|
||||
});
|
||||
}
|
||||
var data = {
|
||||
commit_message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
content: text,
|
||||
branch: branch,
|
||||
sha: sha
|
||||
};
|
||||
// Perform a request to save the file
|
||||
$tw.utils.httpRequest({
|
||||
url: uri + "files/" + encodeURIComponent(path.replace(/^\/+/, '') + filename),
|
||||
type: requestType,
|
||||
headers: headers,
|
||||
data: JSON.stringify(data),
|
||||
callback: function(err,putResponseDataJson,xhr) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
var putResponseData = JSON.parse(putResponseDataJson);
|
||||
callback(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
Information about this saver
|
||||
*/
|
||||
GitLabSaver.prototype.info = {
|
||||
name: "gitlab",
|
||||
priority: 2000,
|
||||
capabilities: ["save", "autosave"]
|
||||
};
|
||||
|
||||
/*
|
||||
Static method that returns true if this saver is capable of working
|
||||
*/
|
||||
exports.canSave = function(wiki) {
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
Create an instance of this saver
|
||||
*/
|
||||
exports.create = function(wiki) {
|
||||
return new GitLabSaver(wiki);
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -41,7 +41,7 @@ BasicAuthenticator.prototype.init = function() {
|
||||
this.credentialsData = credentialsData;
|
||||
}
|
||||
} else {
|
||||
return "Error: Unable to load user credentials from '" + credentialsFilepath + "'";
|
||||
return "Error: Unable to load user credentials from '" + resolveCredentialsFilepath + "'";
|
||||
}
|
||||
}
|
||||
// Add the hardcoded username and password if specified
|
||||
|
||||
@@ -12,14 +12,38 @@ GET /
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var zlib = require("zlib");
|
||||
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
response.writeHead(200, {"Content-Type": state.server.get("root-serve-type")});
|
||||
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler"));
|
||||
response.end(text,"utf8");
|
||||
var acceptEncoding = request.headers["accept-encoding"];
|
||||
if(!acceptEncoding) {
|
||||
acceptEncoding = "";
|
||||
}
|
||||
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
|
||||
responseHeaders = {
|
||||
"Content-Type": state.server.get("root-serve-type")
|
||||
};
|
||||
/*
|
||||
If the gzip=yes flag for `listen` is set, check if the user agent permits
|
||||
compression. If so, compress our response. Note that we use the synchronous
|
||||
functions from zlib to stay in the imperative style. The current `Server`
|
||||
doesn't depend on this, and we may just as well use the async versions.
|
||||
*/
|
||||
if(state.server.enableGzip) {
|
||||
if (/\bdeflate\b/.test(acceptEncoding)) {
|
||||
responseHeaders["Content-Encoding"] = "deflate";
|
||||
text = zlib.deflateSync(text);
|
||||
} else if (/\bgzip\b/.test(acceptEncoding)) {
|
||||
responseHeaders["Content-Encoding"] = "gzip";
|
||||
text = zlib.gzipSync(text);
|
||||
}
|
||||
}
|
||||
response.writeHead(200,responseHeaders);
|
||||
response.end(text);
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
@@ -43,6 +43,8 @@ function Server(options) {
|
||||
$tw.utils.extend({},this.defaultVariables,options.variables);
|
||||
// Initialise CSRF
|
||||
this.csrfDisable = this.get("csrf-disable") === "yes";
|
||||
// Initialize Gzip compression
|
||||
this.enableGzip = this.get("gzip") === "yes";
|
||||
// Initialise authorization
|
||||
var authorizedUserName = (this.get("username") && this.get("password")) ? this.get("username") : "(anon)";
|
||||
this.authorizationPrincipals = {
|
||||
@@ -84,7 +86,8 @@ Server.prototype.defaultVariables = {
|
||||
"tiddler-render-template": "$:/core/templates/server/static.tiddler.html",
|
||||
"system-tiddler-render-type": "text/plain",
|
||||
"system-tiddler-render-template": "$:/core/templates/wikified-tiddler",
|
||||
"debug-level": "none"
|
||||
"debug-level": "none",
|
||||
"gzip": "no"
|
||||
};
|
||||
|
||||
Server.prototype.get = function(name) {
|
||||
@@ -229,17 +232,19 @@ Server.prototype.requestHandler = function(request,response) {
|
||||
/*
|
||||
Listen for requests
|
||||
port: optional port number (falls back to value of "port" variable)
|
||||
host: optional host address (falls back to value of "hist" variable)
|
||||
host: optional host address (falls back to value of "host" variable)
|
||||
prefix: optional prefix (falls back to value of "path-prefix" variable)
|
||||
*/
|
||||
Server.prototype.listen = function(port,host) {
|
||||
Server.prototype.listen = function(port,host,prefix) {
|
||||
// Handle defaults for port and host
|
||||
port = port || this.get("port");
|
||||
host = host || this.get("host");
|
||||
prefix = prefix || this.get("path-prefix") || "";
|
||||
// Check for the port being a string and look it up as an environment variable
|
||||
if(parseInt(port,10).toString() !== port) {
|
||||
port = process.env[port] || 8080;
|
||||
}
|
||||
$tw.utils.log("Serving on " + this.protocol + "://" + host + ":" + port,"brown/orange");
|
||||
$tw.utils.log("Serving on " + this.protocol + "://" + host + ":" + port + prefix,"brown/orange");
|
||||
$tw.utils.log("(press ctrl-C to exit)","red");
|
||||
// Warn if required plugins are missing
|
||||
if(!$tw.wiki.getTiddler("$:/plugins/tiddlywiki/tiddlyweb") || !$tw.wiki.getTiddler("$:/plugins/tiddlywiki/filesystem")) {
|
||||
|
||||
@@ -144,9 +144,9 @@ exports.startup = function() {
|
||||
});
|
||||
// Listen for window messages from other windows
|
||||
window.addEventListener("message",function listener(event){
|
||||
console.log("browser-messaging: ",document.location.toString())
|
||||
console.log("browser-messaging: Received message from",event.origin);
|
||||
console.log("browser-messaging: Message content",event.data);
|
||||
// console.log("browser-messaging: ",document.location.toString())
|
||||
// console.log("browser-messaging: Received message from",event.origin);
|
||||
// console.log("browser-messaging: Message content",event.data);
|
||||
switch(event.data.verb) {
|
||||
case "GET-RESPONSE":
|
||||
if(event.data.status.charAt(0) === "2") {
|
||||
|
||||
114
core/modules/startup/css-escape-polyfill.js
Normal file
114
core/modules/startup/css-escape-polyfill.js
Normal file
@@ -0,0 +1,114 @@
|
||||
/*\
|
||||
title: $:/core/modules/startup/CSSescape.js
|
||||
type: application/javascript
|
||||
module-type: startup
|
||||
|
||||
Polyfill for CSS.escape()
|
||||
|
||||
\*/
|
||||
(function(root,factory){
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
// Export name and synchronous status
|
||||
exports.name = "css-escape";
|
||||
exports.platforms = ["browser"];
|
||||
exports.after = ["startup"];
|
||||
exports.synchronous = true;
|
||||
|
||||
/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */
|
||||
// https://github.com/umdjs/umd/blob/master/returnExports.js
|
||||
exports.startup = factory(root);
|
||||
}(typeof global != 'undefined' ? global : this, function(root) {
|
||||
|
||||
if (root.CSS && root.CSS.escape) {
|
||||
return;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom/#serialize-an-identifier
|
||||
var cssEscape = function(value) {
|
||||
if (arguments.length == 0) {
|
||||
throw new TypeError('`CSS.escape` requires an argument.');
|
||||
}
|
||||
var string = String(value);
|
||||
var length = string.length;
|
||||
var index = -1;
|
||||
var codeUnit;
|
||||
var result = '';
|
||||
var firstCodeUnit = string.charCodeAt(0);
|
||||
while (++index < length) {
|
||||
codeUnit = string.charCodeAt(index);
|
||||
// Note: there’s no need to special-case astral symbols, surrogate
|
||||
// pairs, or lone surrogates.
|
||||
|
||||
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER
|
||||
// (U+FFFD).
|
||||
if (codeUnit == 0x0000) {
|
||||
result += '\uFFFD';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
|
||||
// U+007F, […]
|
||||
(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
|
||||
// If the character is the first character and is in the range [0-9]
|
||||
// (U+0030 to U+0039), […]
|
||||
(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
|
||||
// If the character is the second character and is in the range [0-9]
|
||||
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
|
||||
(
|
||||
index == 1 &&
|
||||
codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
|
||||
firstCodeUnit == 0x002D
|
||||
)
|
||||
) {
|
||||
// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
|
||||
result += '\\' + codeUnit.toString(16) + ' ';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
// If the character is the first character and is a `-` (U+002D), and
|
||||
// there is no second character, […]
|
||||
index == 0 &&
|
||||
length == 1 &&
|
||||
codeUnit == 0x002D
|
||||
) {
|
||||
result += '\\' + string.charAt(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the character is not handled by one of the above rules and is
|
||||
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
|
||||
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
|
||||
// U+005A), or [a-z] (U+0061 to U+007A), […]
|
||||
if (
|
||||
codeUnit >= 0x0080 ||
|
||||
codeUnit == 0x002D ||
|
||||
codeUnit == 0x005F ||
|
||||
codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
|
||||
codeUnit >= 0x0041 && codeUnit <= 0x005A ||
|
||||
codeUnit >= 0x0061 && codeUnit <= 0x007A
|
||||
) {
|
||||
// the character itself
|
||||
result += string.charAt(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, the escaped character.
|
||||
// https://drafts.csswg.org/cssom/#escape-a-character
|
||||
result += '\\' + string.charAt(index);
|
||||
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
if (!root.CSS) {
|
||||
root.CSS = {};
|
||||
}
|
||||
|
||||
root.CSS.escape = cssEscape;
|
||||
|
||||
}));
|
||||
@@ -27,6 +27,7 @@ exports.startup = function() {
|
||||
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
|
||||
$tw.modules.applyMethods("tiddlermethod",$tw.Tiddler.prototype);
|
||||
$tw.modules.applyMethods("wikimethod",$tw.Wiki.prototype);
|
||||
$tw.wiki.addIndexersToWiki();
|
||||
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
|
||||
$tw.macros = $tw.modules.getModulesByTypeAsHashmap("macro");
|
||||
$tw.wiki.initParsers();
|
||||
|
||||
@@ -71,9 +71,10 @@ exports.startup = function() {
|
||||
timerId;
|
||||
function refresh() {
|
||||
// Process the refresh
|
||||
$tw.hooks.invokeHook("th-page-refreshing");
|
||||
$tw.pageWidgetNode.refresh(deferredChanges);
|
||||
deferredChanges = Object.create(null);
|
||||
$tw.hooks.invokeHook("th-page-refreshed");
|
||||
$tw.hooks.invokeHook("th-page-refreshed");
|
||||
}
|
||||
// Add the change event handler
|
||||
$tw.wiki.addEventListener("change",$tw.perf.report("mainRefresh",function(changes) {
|
||||
|
||||
@@ -34,6 +34,19 @@ exports.startup = function() {
|
||||
$tw.rootWidget.addEventListener("tm-copy-to-clipboard",function(event) {
|
||||
$tw.utils.copyToClipboard(event.param);
|
||||
});
|
||||
// Install the tm-focus-selector message
|
||||
$tw.rootWidget.addEventListener("tm-focus-selector",function(event) {
|
||||
var selector = event.param || "",
|
||||
element;
|
||||
try {
|
||||
element = document.querySelector(selector);
|
||||
} catch(e) {
|
||||
console.log("Error in selector: ",selector)
|
||||
}
|
||||
if(element && element.focus) {
|
||||
element.focus(event.paramObject);
|
||||
}
|
||||
});
|
||||
// Install the scroller
|
||||
$tw.pageScroller = new $tw.utils.PageScroller();
|
||||
$tw.rootWidget.addEventListener("tm-scroll",function(event) {
|
||||
@@ -42,15 +55,16 @@ exports.startup = function() {
|
||||
var fullscreen = $tw.utils.getFullScreenApis();
|
||||
if(fullscreen) {
|
||||
$tw.rootWidget.addEventListener("tm-full-screen",function(event) {
|
||||
var fullScreenDocument = event.event ? event.event.target.ownerDocument : document;
|
||||
if(event.param === "enter") {
|
||||
event.event.target.ownerDocument.documentElement[fullscreen._requestFullscreen](Element.ALLOW_KEYBOARD_INPUT);
|
||||
fullScreenDocument.documentElement[fullscreen._requestFullscreen](Element.ALLOW_KEYBOARD_INPUT);
|
||||
} else if(event.param === "exit") {
|
||||
event.event.target.ownerDocument[fullscreen._exitFullscreen]();
|
||||
fullScreenDocument[fullscreen._exitFullscreen]();
|
||||
} else {
|
||||
if(event.event.target.ownerDocument[fullscreen._fullscreenElement]) {
|
||||
event.event.target.ownerDocument[fullscreen._exitFullscreen]();
|
||||
if(fullScreenDocument[fullscreen._fullscreenElement]) {
|
||||
fullScreenDocument[fullscreen._exitFullscreen]();
|
||||
} else {
|
||||
event.event.target.ownerDocument.documentElement[fullscreen._requestFullscreen](Element.ALLOW_KEYBOARD_INPUT);
|
||||
fullScreenDocument.documentElement[fullscreen._requestFullscreen](Element.ALLOW_KEYBOARD_INPUT);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -55,6 +55,27 @@ exports.startup = function() {
|
||||
$tw.version = $tw.utils.extractVersionInfo();
|
||||
// Set up the performance framework
|
||||
$tw.perf = new $tw.Performance($tw.wiki.getTiddlerText(PERFORMANCE_INSTRUMENTATION_CONFIG_TITLE,"no") === "yes");
|
||||
// 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: $tw.browser ? document : $tw.fakeDocument
|
||||
});
|
||||
// Execute any startup actions
|
||||
var executeStartupTiddlers = function(tag) {
|
||||
$tw.utils.each($tw.wiki.filterTiddlers("[all[shadows+tiddlers]tag[" + tag + "]!has[draft.of]]"),function(title) {
|
||||
$tw.rootWidget.invokeActionString($tw.wiki.getTiddlerText(title),$tw.rootWidget);
|
||||
});
|
||||
};
|
||||
executeStartupTiddlers("$:/tags/StartupAction");
|
||||
if($tw.browser) {
|
||||
executeStartupTiddlers("$:/tags/StartupAction/Browser");
|
||||
}
|
||||
if($tw.node) {
|
||||
executeStartupTiddlers("$:/tags/StartupAction/Node");
|
||||
}
|
||||
// Kick off the language manager and switcher
|
||||
$tw.language = new $tw.Language();
|
||||
$tw.languageSwitcher = new $tw.PluginSwitcher({
|
||||
@@ -62,7 +83,7 @@ exports.startup = function() {
|
||||
pluginType: "language",
|
||||
controllerTitle: "$:/language",
|
||||
defaultPlugins: [
|
||||
"$:/languages/en-US"
|
||||
"$:/languages/en-GB"
|
||||
],
|
||||
onSwitch: function(plugins) {
|
||||
if($tw.browser) {
|
||||
@@ -95,27 +116,6 @@ exports.startup = function() {
|
||||
handlerMethod: "handleKeydownEvent"
|
||||
}]);
|
||||
}
|
||||
// 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: $tw.browser ? document : $tw.fakeDocument
|
||||
});
|
||||
// Execute any startup actions
|
||||
var executeStartupTiddlers = function(tag) {
|
||||
$tw.utils.each($tw.wiki.filterTiddlers("[all[shadows+tiddlers]tag[" + tag + "]!has[draft.of]]"),function(title) {
|
||||
$tw.rootWidget.invokeActionString($tw.wiki.getTiddlerText(title),$tw.rootWidget);
|
||||
});
|
||||
};
|
||||
executeStartupTiddlers("$:/tags/StartupAction");
|
||||
if($tw.browser) {
|
||||
executeStartupTiddlers("$:/tags/StartupAction/Browser");
|
||||
}
|
||||
if($tw.node) {
|
||||
executeStartupTiddlers("$:/tags/StartupAction/Node");
|
||||
}
|
||||
// Clear outstanding tiddler store change events to avoid an unnecessary refresh cycle at startup
|
||||
$tw.wiki.clearTiddlerEventQueue();
|
||||
// Find a working syncadaptor
|
||||
@@ -130,7 +130,11 @@ exports.startup = function() {
|
||||
$tw.syncer = new $tw.Syncer({wiki: $tw.wiki, syncadaptor: $tw.syncadaptor});
|
||||
}
|
||||
// Setup the saver handler
|
||||
$tw.saverHandler = new $tw.SaverHandler({wiki: $tw.wiki, dirtyTracking: !$tw.syncadaptor});
|
||||
$tw.saverHandler = new $tw.SaverHandler({
|
||||
wiki: $tw.wiki,
|
||||
dirtyTracking: !$tw.syncadaptor,
|
||||
preloadDirty: $tw.boot.preloadDirty || []
|
||||
});
|
||||
// Host-specific startup
|
||||
if($tw.browser) {
|
||||
// Install the popup manager
|
||||
|
||||
@@ -36,7 +36,9 @@ var HELP_OPEN_EXTERNAL_WINDOW = "http://tiddlywiki.com/#WidgetMessage%3A%20tm-op
|
||||
|
||||
exports.startup = function() {
|
||||
// Open startup tiddlers
|
||||
openStartupTiddlers();
|
||||
openStartupTiddlers({
|
||||
disableHistory: $tw.boot.disableStartupNavigation
|
||||
});
|
||||
if($tw.browser) {
|
||||
// Set up location hash update
|
||||
$tw.wiki.addEventListener("change",function(changes) {
|
||||
@@ -106,6 +108,7 @@ exports.startup = function() {
|
||||
|
||||
/*
|
||||
Process the location hash to open the specified tiddlers. Options:
|
||||
disableHistory: if true $:/History is NOT updated
|
||||
defaultToCurrentStory: If true, the current story is retained as the default, instead of opening the default tiddlers
|
||||
*/
|
||||
function openStartupTiddlers(options) {
|
||||
@@ -146,15 +149,18 @@ function openStartupTiddlers(options) {
|
||||
}
|
||||
// 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]);
|
||||
// Update history
|
||||
if(!options.disableHistory) {
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ exports.startup = function() {
|
||||
var refreshHandler,
|
||||
title = event.param || event.tiddlerTitle,
|
||||
paramObject = event.paramObject || {},
|
||||
windowTitle = paramObject.windowTitle || title,
|
||||
template = paramObject.template || "$:/core/templates/single.tiddler.window",
|
||||
width = paramObject.width || "700",
|
||||
height = paramObject.height || "600",
|
||||
@@ -51,7 +52,7 @@ exports.startup = function() {
|
||||
// Initialise the document
|
||||
srcDocument.write("<html><head></head><body class='tc-body tc-single-tiddler-window'></body></html>");
|
||||
srcDocument.close();
|
||||
srcDocument.title = title;
|
||||
srcDocument.title = windowTitle;
|
||||
srcWindow.addEventListener("beforeunload",function(event) {
|
||||
delete windows[title];
|
||||
$tw.wiki.removeEventListener("change",refreshHandler);
|
||||
|
||||
@@ -19,6 +19,7 @@ var ClassicStoryView = function(listWidget) {
|
||||
};
|
||||
|
||||
ClassicStoryView.prototype.navigateTo = function(historyInfo) {
|
||||
var duration = $tw.utils.getAnimationDuration()
|
||||
var listElementIndex = this.listWidget.findListItem(0,historyInfo.title);
|
||||
if(listElementIndex === undefined) {
|
||||
return;
|
||||
@@ -29,80 +30,90 @@ ClassicStoryView.prototype.navigateTo = function(historyInfo) {
|
||||
if(!(targetElement instanceof Element)) {
|
||||
return;
|
||||
}
|
||||
// Scroll the node into view
|
||||
this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement});
|
||||
if(duration) {
|
||||
// Scroll the node into view
|
||||
this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement});
|
||||
} else {
|
||||
targetElement.scrollIntoView();
|
||||
}
|
||||
};
|
||||
|
||||
ClassicStoryView.prototype.insert = function(widget) {
|
||||
var targetElement = widget.findFirstDomNode(),
|
||||
duration = $tw.utils.getAnimationDuration();
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
return;
|
||||
}
|
||||
// Get the current height of the tiddler
|
||||
var computedStyle = window.getComputedStyle(targetElement),
|
||||
currMarginBottom = parseInt(computedStyle.marginBottom,10),
|
||||
currMarginTop = parseInt(computedStyle.marginTop,10),
|
||||
currHeight = targetElement.offsetHeight + currMarginTop;
|
||||
// Reset the margin once the transition is over
|
||||
setTimeout(function() {
|
||||
var duration = $tw.utils.getAnimationDuration();
|
||||
if(duration) {
|
||||
var targetElement = widget.findFirstDomNode();
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
return;
|
||||
}
|
||||
// Get the current height of the tiddler
|
||||
var computedStyle = window.getComputedStyle(targetElement),
|
||||
currMarginBottom = parseInt(computedStyle.marginBottom,10),
|
||||
currMarginTop = parseInt(computedStyle.marginTop,10),
|
||||
currHeight = targetElement.offsetHeight + currMarginTop;
|
||||
// Reset the margin once the transition is over
|
||||
setTimeout(function() {
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "none"},
|
||||
{marginBottom: ""}
|
||||
]);
|
||||
},duration);
|
||||
// Set up the initial position of the element
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "none"},
|
||||
{marginBottom: ""}
|
||||
{marginBottom: (-currHeight) + "px"},
|
||||
{opacity: "0.0"}
|
||||
]);
|
||||
},duration);
|
||||
// Set up the initial position of the element
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "none"},
|
||||
{marginBottom: (-currHeight) + "px"},
|
||||
{opacity: "0.0"}
|
||||
]);
|
||||
$tw.utils.forceLayout(targetElement);
|
||||
// Transition to the final position
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "opacity " + duration + "ms " + easing + ", " +
|
||||
"margin-bottom " + duration + "ms " + easing},
|
||||
{marginBottom: currMarginBottom + "px"},
|
||||
{opacity: "1.0"}
|
||||
$tw.utils.forceLayout(targetElement);
|
||||
// Transition to the final position
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "opacity " + duration + "ms " + easing + ", " +
|
||||
"margin-bottom " + duration + "ms " + easing},
|
||||
{marginBottom: currMarginBottom + "px"},
|
||||
{opacity: "1.0"}
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
ClassicStoryView.prototype.remove = function(widget) {
|
||||
var targetElement = widget.findFirstDomNode(),
|
||||
duration = $tw.utils.getAnimationDuration(),
|
||||
removeElement = function() {
|
||||
widget.removeChildDomNodes();
|
||||
};
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
removeElement();
|
||||
return;
|
||||
var duration = $tw.utils.getAnimationDuration();
|
||||
if(duration) {
|
||||
var targetElement = widget.findFirstDomNode(),
|
||||
removeElement = function() {
|
||||
widget.removeChildDomNodes();
|
||||
};
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!(targetElement instanceof Element)) {
|
||||
removeElement();
|
||||
return;
|
||||
}
|
||||
// Get the current height of the tiddler
|
||||
var currWidth = targetElement.offsetWidth,
|
||||
computedStyle = window.getComputedStyle(targetElement),
|
||||
currMarginBottom = parseInt(computedStyle.marginBottom,10),
|
||||
currMarginTop = parseInt(computedStyle.marginTop,10),
|
||||
currHeight = targetElement.offsetHeight + currMarginTop;
|
||||
// Remove the dom nodes of the widget at the end of the transition
|
||||
setTimeout(removeElement,duration);
|
||||
// Animate the closure
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "none"},
|
||||
{transform: "translateX(0px)"},
|
||||
{marginBottom: currMarginBottom + "px"},
|
||||
{opacity: "1.0"}
|
||||
]);
|
||||
$tw.utils.forceLayout(targetElement);
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms " + easing + ", " +
|
||||
"opacity " + duration + "ms " + easing + ", " +
|
||||
"margin-bottom " + duration + "ms " + easing},
|
||||
{transform: "translateX(-" + currWidth + "px)"},
|
||||
{marginBottom: (-currHeight) + "px"},
|
||||
{opacity: "0.0"}
|
||||
]);
|
||||
} else {
|
||||
widget.removeChildDomNodes();
|
||||
}
|
||||
// Get the current height of the tiddler
|
||||
var currWidth = targetElement.offsetWidth,
|
||||
computedStyle = window.getComputedStyle(targetElement),
|
||||
currMarginBottom = parseInt(computedStyle.marginBottom,10),
|
||||
currMarginTop = parseInt(computedStyle.marginTop,10),
|
||||
currHeight = targetElement.offsetHeight + currMarginTop;
|
||||
// Remove the dom nodes of the widget at the end of the transition
|
||||
setTimeout(removeElement,duration);
|
||||
// Animate the closure
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "none"},
|
||||
{transform: "translateX(0px)"},
|
||||
{marginBottom: currMarginBottom + "px"},
|
||||
{opacity: "1.0"}
|
||||
]);
|
||||
$tw.utils.forceLayout(targetElement);
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms " + easing + ", " +
|
||||
"opacity " + duration + "ms " + easing + ", " +
|
||||
"margin-bottom " + duration + "ms " + easing},
|
||||
{transform: "translateX(-" + currWidth + "px)"},
|
||||
{marginBottom: (-currHeight) + "px"},
|
||||
{opacity: "0.0"}
|
||||
]);
|
||||
};
|
||||
|
||||
exports.classic = ClassicStoryView;
|
||||
|
||||
@@ -44,7 +44,14 @@ PopStoryView.prototype.insert = function(widget) {
|
||||
{transition: "none"},
|
||||
{transform: "none"}
|
||||
]);
|
||||
$tw.utils.setStyle(widget.document.body,[
|
||||
{"overflow-x": ""}
|
||||
]);
|
||||
},duration);
|
||||
// Prevent the page from overscrolling due to the zoom factor
|
||||
$tw.utils.setStyle(widget.document.body,[
|
||||
{"overflow-x": "hidden"}
|
||||
]);
|
||||
// Set up the initial position of the element
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "none"},
|
||||
@@ -65,7 +72,7 @@ PopStoryView.prototype.remove = function(widget) {
|
||||
var targetElement = widget.findFirstDomNode(),
|
||||
duration = $tw.utils.getAnimationDuration(),
|
||||
removeElement = function() {
|
||||
if(targetElement.parentNode) {
|
||||
if(targetElement && targetElement.parentNode) {
|
||||
widget.removeChildDomNodes();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -75,67 +75,16 @@ Get all the fields as a name:value block. Options:
|
||||
*/
|
||||
exports.getFieldStringBlock = function(options) {
|
||||
options = options || {};
|
||||
var exclude = options.exclude || [];
|
||||
var fields = [];
|
||||
for(var field in this.fields) {
|
||||
if($tw.utils.hop(this.fields,field)) {
|
||||
if(exclude.indexOf(field) === -1) {
|
||||
fields.push(field + ": " + this.getFieldString(field));
|
||||
}
|
||||
var exclude = options.exclude || [],
|
||||
fields = Object.keys(this.fields).sort(),
|
||||
result = [];
|
||||
for(var t=0; t<fields.length; t++) {
|
||||
var field = fields[t];
|
||||
if(exclude.indexOf(field) === -1) {
|
||||
result.push(field + ": " + this.getFieldString(field));
|
||||
}
|
||||
}
|
||||
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) {
|
||||
if(!(tiddler instanceof $tw.Tiddler)) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
return result.join("\n");
|
||||
};
|
||||
|
||||
exports.getFieldDay = function(field) {
|
||||
|
||||
@@ -13,11 +13,13 @@ Upgrader module that suppresses certain system tiddlers that shouldn't be import
|
||||
"use strict";
|
||||
|
||||
var DONT_IMPORT_LIST = ["$:/StoryList","$:/HistoryList"],
|
||||
DONT_IMPORT_PREFIX_LIST = ["$:/temp/","$:/state/"];
|
||||
DONT_IMPORT_PREFIX_LIST = ["$:/temp/","$:/state/","$:/Import"],
|
||||
WARN_IMPORT_PREFIX_LIST = ["$:/core/modules/"];
|
||||
|
||||
exports.upgrade = function(wiki,titles,tiddlers) {
|
||||
var self = this,
|
||||
messages = {};
|
||||
messages = {},
|
||||
showAlert = false;
|
||||
// Check for tiddlers on our list
|
||||
$tw.utils.each(titles,function(title) {
|
||||
if(DONT_IMPORT_LIST.indexOf(title) !== -1) {
|
||||
@@ -31,8 +33,19 @@ exports.upgrade = function(wiki,titles,tiddlers) {
|
||||
messages[title] = $tw.language.getString("Import/Upgrader/State/Suppressed");
|
||||
}
|
||||
}
|
||||
for(var t=0; t<WARN_IMPORT_PREFIX_LIST.length; t++) {
|
||||
var prefix = WARN_IMPORT_PREFIX_LIST[t];
|
||||
if(title.substr(0,prefix.length) === prefix && wiki.isShadowTiddler(title)) {
|
||||
showAlert = true;
|
||||
messages[title] = $tw.language.getString("Import/Upgrader/System/Warning");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if(showAlert) {
|
||||
var logger = new $tw.utils.Logger("import");
|
||||
logger.alert($tw.language.getString("Import/Upgrader/System/Alert"));
|
||||
}
|
||||
return messages;
|
||||
};
|
||||
|
||||
|
||||
124
core/modules/utils/base64-utf8/base64-utf8.module.js
Normal file
124
core/modules/utils/base64-utf8/base64-utf8.module.js
Normal file
@@ -0,0 +1,124 @@
|
||||
// From https://gist.github.com/Nijikokun/5192472
|
||||
//
|
||||
// UTF8 Module
|
||||
//
|
||||
// Cleaner and modularized utf-8 encoding and decoding library for javascript.
|
||||
//
|
||||
// copyright: MIT
|
||||
// author: Nijiko Yonskai, @nijikokun, nijikokun@gmail.com
|
||||
(function (name, definition, context, dependencies) {
|
||||
if (typeof context['module'] !== 'undefined' && context['module']['exports']) { if (dependencies && context['require']) { for (var i = 0; i < dependencies.length; i++) context[dependencies[i]] = context['require'](dependencies[i]); } context['module']['exports'] = definition.apply(context); }
|
||||
else if (typeof context['define'] !== 'undefined' && context['define'] === 'function' && context['define']['amd']) { define(name, (dependencies || []), definition); }
|
||||
else { context[name] = definition.apply(context); }
|
||||
})('utf8', function () {
|
||||
return {
|
||||
encode: function (string) {
|
||||
if (typeof string !== 'string') return string;
|
||||
else string = string.replace(/\r\n/g, "\n");
|
||||
var output = "", i = 0, charCode;
|
||||
|
||||
for (i; i < string.length; i++) {
|
||||
charCode = string.charCodeAt(i);
|
||||
|
||||
if (charCode < 128)
|
||||
output += String.fromCharCode(charCode);
|
||||
else if ((charCode > 127) && (charCode < 2048))
|
||||
output += String.fromCharCode((charCode >> 6) | 192),
|
||||
output += String.fromCharCode((charCode & 63) | 128);
|
||||
else
|
||||
output += String.fromCharCode((charCode >> 12) | 224),
|
||||
output += String.fromCharCode(((charCode >> 6) & 63) | 128),
|
||||
output += String.fromCharCode((charCode & 63) | 128);
|
||||
}
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
decode: function (string) {
|
||||
if (typeof string !== 'string') return string;
|
||||
var output = "", i = 0, charCode = 0;
|
||||
|
||||
while (i < string.length) {
|
||||
charCode = string.charCodeAt(i);
|
||||
|
||||
if (charCode < 128)
|
||||
output += String.fromCharCode(charCode),
|
||||
i++;
|
||||
else if ((charCode > 191) && (charCode < 224))
|
||||
output += String.fromCharCode(((charCode & 31) << 6) | (string.charCodeAt(i + 1) & 63)),
|
||||
i += 2;
|
||||
else
|
||||
output += String.fromCharCode(((charCode & 15) << 12) | ((string.charCodeAt(i + 1) & 63) << 6) | (string.charCodeAt(i + 2) & 63)),
|
||||
i += 3;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
};
|
||||
}, this);
|
||||
|
||||
// Base64 Module
|
||||
//
|
||||
// Cleaner, modularized and properly scoped base64 encoding and decoding module for strings.
|
||||
//
|
||||
// copyright: MIT
|
||||
// author: Nijiko Yonskai, @nijikokun, nijikokun@gmail.com
|
||||
(function (name, definition, context, dependencies) {
|
||||
if (typeof context['module'] !== 'undefined' && context['module']['exports']) { if (dependencies && context['require']) { for (var i = 0; i < dependencies.length; i++) context[dependencies[i]] = context['require'](dependencies[i]); } context['module']['exports'] = definition.apply(context); }
|
||||
else if (typeof context['define'] !== 'undefined' && context['define'] === 'function' && context['define']['amd']) { define(name, (dependencies || []), definition); }
|
||||
else { context[name] = definition.apply(context); }
|
||||
})('base64', function (utf8) {
|
||||
var $this = this;
|
||||
var $utf8 = utf8 || this.utf8;
|
||||
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
|
||||
return {
|
||||
encode: function (input) {
|
||||
if (typeof $utf8 === 'undefined') throw { error: "MissingMethod", message: "UTF8 Module is missing." };
|
||||
if (typeof input !== 'string') return input;
|
||||
else input = $utf8.encode(input);
|
||||
var output = "", a, b, c, d, e, f, g, i = 0;
|
||||
|
||||
while (i < input.length) {
|
||||
a = input.charCodeAt(i++);
|
||||
b = input.charCodeAt(i++);
|
||||
c = input.charCodeAt(i++);
|
||||
d = a >> 2;
|
||||
e = ((a & 3) << 4) | (b >> 4);
|
||||
f = ((b & 15) << 2) | (c >> 6);
|
||||
g = c & 63;
|
||||
|
||||
if (isNaN(b)) f = g = 64;
|
||||
else if (isNaN(c)) g = 64;
|
||||
|
||||
output += map.charAt(d) + map.charAt(e) + map.charAt(f) + map.charAt(g);
|
||||
}
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
decode: function (input) {
|
||||
if (typeof $utf8 === 'undefined') throw { error: "MissingMethod", message: "UTF8 Module is missing." };
|
||||
if (typeof input !== 'string') return input;
|
||||
else input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
|
||||
var output = "", a, b, c, d, e, f, g, i = 0;
|
||||
|
||||
while (i < input.length) {
|
||||
d = map.indexOf(input.charAt(i++));
|
||||
e = map.indexOf(input.charAt(i++));
|
||||
f = map.indexOf(input.charAt(i++));
|
||||
g = map.indexOf(input.charAt(i++));
|
||||
|
||||
a = (d << 2) | (e >> 4);
|
||||
b = ((e & 15) << 4) | (f >> 2);
|
||||
c = ((f & 3) << 6) | g;
|
||||
|
||||
output += String.fromCharCode(a);
|
||||
if (f != 64) output += String.fromCharCode(b);
|
||||
if (g != 64) output += String.fromCharCode(c);
|
||||
}
|
||||
|
||||
return $utf8.decode(output);
|
||||
}
|
||||
}
|
||||
}, this, [ "utf8" ]);
|
||||
9
core/modules/utils/base64-utf8/base64-utf8.module.min.js
vendored
Normal file
9
core/modules/utils/base64-utf8/base64-utf8.module.min.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// From https://gist.github.com/Nijikokun/5192472
|
||||
//
|
||||
// UTF8 Module
|
||||
//
|
||||
// Cleaner and modularized utf-8 encoding and decoding library for javascript.
|
||||
//
|
||||
// copyright: MIT
|
||||
// author: Nijiko Yonskai, @nijikokun, nijikokun@gmail.com
|
||||
!function(r,e,o,t){void 0!==o.module&&o.module.exports?o.module.exports=e.apply(o):void 0!==o.define&&"function"===o.define&&o.define.amd?define("utf8",[],e):o.utf8=e.apply(o)}(0,function(){return{encode:function(r){if("string"!=typeof r)return r;r=r.replace(/\r\n/g,"\n");for(var e,o="",t=0;t<r.length;t++)(e=r.charCodeAt(t))<128?o+=String.fromCharCode(e):e>127&&e<2048?(o+=String.fromCharCode(e>>6|192),o+=String.fromCharCode(63&e|128)):(o+=String.fromCharCode(e>>12|224),o+=String.fromCharCode(e>>6&63|128),o+=String.fromCharCode(63&e|128));return o},decode:function(r){if("string"!=typeof r)return r;for(var e="",o=0,t=0;o<r.length;)(t=r.charCodeAt(o))<128?(e+=String.fromCharCode(t),o++):t>191&&t<224?(e+=String.fromCharCode((31&t)<<6|63&r.charCodeAt(o+1)),o+=2):(e+=String.fromCharCode((15&t)<<12|(63&r.charCodeAt(o+1))<<6|63&r.charCodeAt(o+2)),o+=3);return e}}},this),function(r,e,o,t){if(void 0!==o.module&&o.module.exports){if(t&&o.require)for(var n=0;n<t.length;n++)o[t[n]]=o.require(t[n]);o.module.exports=e.apply(o)}else void 0!==o.define&&"function"===o.define&&o.define.amd?define("base64",t||[],e):o.base64=e.apply(o)}(0,function(r){var e=r||this.utf8,o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";return{encode:function(r){if(void 0===e)throw{error:"MissingMethod",message:"UTF8 Module is missing."};if("string"!=typeof r)return r;r=e.encode(r);for(var t,n,i,d,f,a,h,c="",u=0;u<r.length;)d=(t=r.charCodeAt(u++))>>2,f=(3&t)<<4|(n=r.charCodeAt(u++))>>4,a=(15&n)<<2|(i=r.charCodeAt(u++))>>6,h=63&i,isNaN(n)?a=h=64:isNaN(i)&&(h=64),c+=o.charAt(d)+o.charAt(f)+o.charAt(a)+o.charAt(h);return c},decode:function(r){if(void 0===e)throw{error:"MissingMethod",message:"UTF8 Module is missing."};if("string"!=typeof r)return r;r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");for(var t,n,i,d,f,a,h="",c=0;c<r.length;)t=o.indexOf(r.charAt(c++))<<2|(d=o.indexOf(r.charAt(c++)))>>4,n=(15&d)<<4|(f=o.indexOf(r.charAt(c++)))>>2,i=(3&f)<<6|(a=o.indexOf(r.charAt(c++))),h+=String.fromCharCode(t),64!=f&&(h+=String.fromCharCode(n)),64!=a&&(h+=String.fromCharCode(i));return e.decode(h)}}},this,["utf8"]);
|
||||
14
core/modules/utils/base64-utf8/tiddlywiki.files
Normal file
14
core/modules/utils/base64-utf8/tiddlywiki.files
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"tiddlers": [
|
||||
{
|
||||
"file": "base64-utf8.module.min.js",
|
||||
"fields": {
|
||||
"type": "application/javascript",
|
||||
"title": "$:/core/modules/utils/base64-utf8/base64-utf8.module.js",
|
||||
"module-type": "library"
|
||||
},
|
||||
"prefix": "(function(){",
|
||||
"suffix": "}).call(exports);"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -136,22 +136,31 @@ exports.getBoundingPageRect = function(element) {
|
||||
Saves a named password in the browser
|
||||
*/
|
||||
exports.savePassword = function(name,password) {
|
||||
var done = false;
|
||||
try {
|
||||
if(window.localStorage) {
|
||||
localStorage.setItem("tw5-password-" + name,password);
|
||||
}
|
||||
window.localStorage.setItem("tw5-password-" + name,password);
|
||||
done = true;
|
||||
} catch(e) {
|
||||
}
|
||||
if(!done) {
|
||||
$tw.savedPasswords = $tw.savedPasswords || Object.create(null);
|
||||
$tw.savedPasswords[name] = password;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Retrieve a named password from the browser
|
||||
*/
|
||||
exports.getPassword = function(name) {
|
||||
var value;
|
||||
try {
|
||||
return window.localStorage ? localStorage.getItem("tw5-password-" + name) : "";
|
||||
value = window.localStorage.getItem("tw5-password-" + name);
|
||||
} catch(e) {
|
||||
return "";
|
||||
}
|
||||
if(value !== undefined) {
|
||||
return value;
|
||||
} else {
|
||||
return ($tw.savedPasswords || Object.create(null))[name] || "";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ A quick and dirty HTTP function; to be refactored later. Options are:
|
||||
url: URL to retrieve
|
||||
headers: hashmap of headers to send
|
||||
type: GET, PUT, POST etc
|
||||
callback: function invoked with (err,data)
|
||||
callback: function invoked with (err,data,xhr)
|
||||
returnProp: string name of the property to return as first argument of callback
|
||||
*/
|
||||
exports.httpRequest = function(options) {
|
||||
@@ -48,7 +48,7 @@ exports.httpRequest = function(options) {
|
||||
return;
|
||||
}
|
||||
// Something went wrong
|
||||
options.callback($tw.language.getString("Error/XMLHttpRequest") + ": " + this.status);
|
||||
options.callback($tw.language.getString("Error/XMLHttpRequest") + ": " + this.status,null,this);
|
||||
}
|
||||
};
|
||||
// Make the request
|
||||
@@ -67,7 +67,7 @@ exports.httpRequest = function(options) {
|
||||
try {
|
||||
request.send(data);
|
||||
} catch(e) {
|
||||
options.callback(e);
|
||||
options.callback(e,null,this);
|
||||
}
|
||||
return request;
|
||||
};
|
||||
|
||||
@@ -30,7 +30,7 @@ Modal.prototype.display = function(title,options) {
|
||||
options = options || {};
|
||||
this.srcDocument = options.variables && (options.variables.rootwindow === "true" ||
|
||||
options.variables.rootwindow === "yes") ? document :
|
||||
(options.event.event ? options.event.event.target.ownerDocument : document);
|
||||
(options.event.event && options.event.event.target ? options.event.event.target.ownerDocument : document);
|
||||
this.srcWindow = this.srcDocument.defaultView;
|
||||
var self = this,
|
||||
refreshHandler,
|
||||
|
||||
@@ -120,7 +120,8 @@ Popup.prototype.show = function(options) {
|
||||
this.popups.push({
|
||||
title: options.title,
|
||||
wiki: options.wiki,
|
||||
domNode: options.domNode
|
||||
domNode: options.domNode,
|
||||
noStateReference: options.noStateReference
|
||||
});
|
||||
}
|
||||
// Set the state tiddler
|
||||
@@ -148,17 +149,46 @@ Popup.prototype.show = function(options) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Detect if a Popup contains an input field that has focus
|
||||
Returns true or false
|
||||
*/
|
||||
Popup.prototype.detectInputWithinPopup = function(node) {
|
||||
var withinPopup = false,
|
||||
currNode = node;
|
||||
for(var i=0; i<this.popups.length; i++) {
|
||||
var popup = (this.popups[i] && this.popups[i].domNode) ? this.popups[i].domNode : null;
|
||||
while(node && popup) {
|
||||
if(node === popup || (node.classList && (node.classList.contains("tc-popup-keep") || (node !== currNode && node.classList.contains("tc-popup-handle"))))) {
|
||||
withinPopup = true;
|
||||
}
|
||||
node = node.parentNode;
|
||||
}
|
||||
}
|
||||
return withinPopup;
|
||||
};
|
||||
|
||||
/*
|
||||
Cancel all popups at or above a specified level or DOM node
|
||||
level: popup level to cancel (0 cancels all popups)
|
||||
*/
|
||||
Popup.prototype.cancel = function(level) {
|
||||
Popup.prototype.cancel = function(level,focusedInputNode) {
|
||||
var numPopups = this.popups.length;
|
||||
level = Math.max(0,Math.min(level,numPopups));
|
||||
for(var t=level; t<numPopups; t++) {
|
||||
var popup = this.popups.pop();
|
||||
if(popup.title) {
|
||||
popup.wiki.deleteTiddler(popup.title);
|
||||
var inputWithinPopup;
|
||||
if(focusedInputNode) {
|
||||
inputWithinPopup = this.detectInputWithinPopup(focusedInputNode);
|
||||
}
|
||||
if(!inputWithinPopup) {
|
||||
var popup = this.popups.pop();
|
||||
if(popup.title) {
|
||||
if(popup.noStateReference) {
|
||||
popup.wiki.deleteTiddler(popup.title);
|
||||
} else {
|
||||
popup.wiki.deleteTiddler($tw.utils.parseTextReference(popup.title).title);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(this.popups.length === 0) {
|
||||
|
||||
@@ -33,6 +33,10 @@ var PageScroller = function() {
|
||||
};
|
||||
};
|
||||
|
||||
PageScroller.prototype.isScrolling = function() {
|
||||
return this.idRequestFrame !== null;
|
||||
}
|
||||
|
||||
PageScroller.prototype.cancelScroll = function(srcWindow) {
|
||||
if(this.idRequestFrame) {
|
||||
this.cancelAnimationFrame.call(srcWindow,this.idRequestFrame);
|
||||
|
||||
@@ -45,10 +45,28 @@ var TW_Element = function(tag,namespace) {
|
||||
this.attributes = {};
|
||||
this.isRaw = false;
|
||||
this.children = [];
|
||||
this.style = {};
|
||||
this._style = {};
|
||||
this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml";
|
||||
};
|
||||
|
||||
Object.defineProperty(TW_Element.prototype, "style", {
|
||||
get: function() {
|
||||
return this._style;
|
||||
},
|
||||
set: function(str) {
|
||||
var self = this;
|
||||
str = str || "";
|
||||
$tw.utils.each(str.split(";"),function(declaration) {
|
||||
var parts = declaration.split(":"),
|
||||
name = $tw.utils.trim(parts[0]),
|
||||
value = $tw.utils.trim(parts[1]);
|
||||
if(name && value) {
|
||||
self._style[$tw.utils.convertStyleNameToPropertyName(name)] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(TW_Element.prototype, "nodeType", {
|
||||
get: function() {
|
||||
return 1;
|
||||
@@ -169,13 +187,13 @@ Object.defineProperty(TW_Element.prototype, "outerHTML", {
|
||||
}
|
||||
}
|
||||
}
|
||||
if(this.style) {
|
||||
if(this._style) {
|
||||
var style = [];
|
||||
for(var s in this.style) {
|
||||
style.push(s + ":" + this.style[s] + ";");
|
||||
for(var s in this._style) {
|
||||
style.push($tw.utils.convertPropertyNameToStyleName(s) + ":" + this._style[s] + ";");
|
||||
}
|
||||
if(style.length > 0) {
|
||||
output.push(" style=\"",style.join(""),"\"")
|
||||
output.push(" style=\"",style.join(""),"\"");
|
||||
}
|
||||
}
|
||||
output.push(">");
|
||||
|
||||
@@ -181,4 +181,169 @@ exports.deleteEmptyDirs = function(dirpath,callback) {
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Create a fileInfo object for saving a tiddler:
|
||||
filepath: the absolute path to the file containing the tiddler
|
||||
type: the type of the tiddler file (NOT the type of the tiddler)
|
||||
hasMetaFile: true if the file also has a companion .meta file
|
||||
Options include:
|
||||
directory: absolute path of root directory to which we are saving
|
||||
pathFilters: optional array of filters to be used to generate the base path
|
||||
wiki: optional wiki for evaluating the pathFilters
|
||||
*/
|
||||
exports.generateTiddlerFileInfo = function(tiddler,options) {
|
||||
var fileInfo = {};
|
||||
// Check if the tiddler has any unsafe fields that can't be expressed in a .tid or .meta file: containing control characters, or leading/trailing whitespace
|
||||
var hasUnsafeFields = false;
|
||||
$tw.utils.each(tiddler.getFieldStrings(),function(value,fieldName) {
|
||||
if(fieldName !== "text") {
|
||||
hasUnsafeFields = hasUnsafeFields || /[\x00-\x1F]/mg.test(value);
|
||||
hasUnsafeFields = hasUnsafeFields || ($tw.utils.trim(value) !== value);
|
||||
}
|
||||
});
|
||||
// Check for field values
|
||||
if(hasUnsafeFields) {
|
||||
// Save as a JSON file
|
||||
fileInfo.type = "application/json";
|
||||
fileInfo.hasMetaFile = false;
|
||||
} else {
|
||||
// Save as a .tid or a text/binary file plus a .meta file
|
||||
var tiddlerType = tiddler.fields.type || "text/vnd.tiddlywiki";
|
||||
if(tiddlerType === "text/vnd.tiddlywiki") {
|
||||
// Save as a .tid file
|
||||
fileInfo.type = "application/x-tiddler";
|
||||
fileInfo.hasMetaFile = false;
|
||||
} else {
|
||||
// Save as a text/binary file and a .meta file
|
||||
fileInfo.type = tiddlerType;
|
||||
fileInfo.hasMetaFile = true;
|
||||
}
|
||||
}
|
||||
// Take the file extension from the tiddler content type
|
||||
var contentTypeInfo = $tw.config.contentTypeInfo[fileInfo.type] || {extension: ""};
|
||||
// Generate the filepath
|
||||
fileInfo.filepath = $tw.utils.generateTiddlerFilepath(tiddler.fields.title,{
|
||||
extension: contentTypeInfo.extension,
|
||||
directory: options.directory,
|
||||
pathFilters: options.pathFilters,
|
||||
wiki: options.wiki
|
||||
});
|
||||
return fileInfo;
|
||||
};
|
||||
|
||||
/*
|
||||
Generate the filepath for saving a tiddler
|
||||
Options include:
|
||||
extension: file extension to be added the finished filepath
|
||||
directory: absolute path of root directory to which we are saving
|
||||
pathFilters: optional array of filters to be used to generate the base path
|
||||
wiki: optional wiki for evaluating the pathFilters
|
||||
*/
|
||||
exports.generateTiddlerFilepath = function(title,options) {
|
||||
var self = this,
|
||||
directory = options.directory || "",
|
||||
extension = options.extension || "",
|
||||
filepath;
|
||||
// Check if any of the pathFilters applies
|
||||
if(options.pathFilters && options.wiki) {
|
||||
$tw.utils.each(options.pathFilters,function(filter) {
|
||||
if(!filepath) {
|
||||
var source = options.wiki.makeTiddlerIterator([title]),
|
||||
result = options.wiki.filterTiddlers(filter,null,source);
|
||||
if(result.length > 0) {
|
||||
filepath = result[0];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// If not, generate a base pathname
|
||||
if(!filepath) {
|
||||
filepath = title;
|
||||
// If the filepath already ends in the extension then remove it
|
||||
if(filepath.substring(filepath.length - extension.length) === extension) {
|
||||
filepath = filepath.substring(0,filepath.length - extension.length);
|
||||
}
|
||||
// Remove any forward or backward slashes so we don't create directories
|
||||
filepath = filepath.replace(/\/|\\/g,"_");
|
||||
}
|
||||
// Don't let the filename start with a dot because such files are invisible on *nix
|
||||
filepath = filepath.replace(/^\./g,"_");
|
||||
// Remove any characters that can't be used in cross-platform filenames
|
||||
filepath = $tw.utils.transliterate(filepath.replace(/<|>|\:|\"|\||\?|\*|\^/g,"_"));
|
||||
// Truncate the filename if it is too long
|
||||
if(filepath.length > 200) {
|
||||
filepath = filepath.substr(0,200);
|
||||
}
|
||||
// If the resulting filename is blank (eg because the title is just punctuation characters)
|
||||
if(!filepath) {
|
||||
// ...then just use the character codes of the title
|
||||
filepath = "";
|
||||
$tw.utils.each(title.split(""),function(char) {
|
||||
if(filepath) {
|
||||
filepath += "-";
|
||||
}
|
||||
filepath += char.charCodeAt(0).toString();
|
||||
});
|
||||
}
|
||||
// Add a uniquifier if the file already exists
|
||||
var fullPath,
|
||||
count = 0;
|
||||
do {
|
||||
fullPath = path.resolve(directory,filepath + (count ? "_" + count : "") + extension);
|
||||
count++;
|
||||
} while(fs.existsSync(fullPath));
|
||||
// Return the full path to the file
|
||||
return fullPath;
|
||||
};
|
||||
|
||||
/*
|
||||
Save a tiddler to a file described by the fileInfo:
|
||||
filepath: the absolute path to the file containing the tiddler
|
||||
type: the type of the tiddler file (NOT the type of the tiddler)
|
||||
hasMetaFile: true if the file also has a companion .meta file
|
||||
*/
|
||||
exports.saveTiddlerToFile = function(tiddler,fileInfo,callback) {
|
||||
$tw.utils.createDirectory(path.dirname(fileInfo.filepath));
|
||||
if(fileInfo.hasMetaFile) {
|
||||
// Save the tiddler as a separate body and meta file
|
||||
var typeInfo = $tw.config.contentTypeInfo[tiddler.fields.type || "text/plain"] || {encoding: "utf8"};
|
||||
fs.writeFile(fileInfo.filepath,tiddler.fields.text,typeInfo.encoding,function(err) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
fs.writeFile(fileInfo.filepath + ".meta",tiddler.getFieldStringBlock({exclude: ["text","bag"]}),"utf8",callback);
|
||||
});
|
||||
} else {
|
||||
// Save the tiddler as a self contained templated file
|
||||
if(fileInfo.type === "application/x-tiddler") {
|
||||
fs.writeFile(fileInfo.filepath,tiddler.getFieldStringBlock({exclude: ["text","bag"]}) + (!!tiddler.fields.text ? "\n\n" + tiddler.fields.text : ""),"utf8",callback);
|
||||
} else {
|
||||
fs.writeFile(fileInfo.filepath,JSON.stringify([tiddler.getFieldStrings({exclude: ["bag"]})],null,$tw.config.preferences.jsonSpaces),"utf8",callback);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Save a tiddler to a file described by the fileInfo:
|
||||
filepath: the absolute path to the file containing the tiddler
|
||||
type: the type of the tiddler file (NOT the type of the tiddler)
|
||||
hasMetaFile: true if the file also has a companion .meta file
|
||||
*/
|
||||
exports.saveTiddlerToFileSync = function(tiddler,fileInfo) {
|
||||
$tw.utils.createDirectory(path.dirname(fileInfo.filepath));
|
||||
if(fileInfo.hasMetaFile) {
|
||||
// Save the tiddler as a separate body and meta file
|
||||
var typeInfo = $tw.config.contentTypeInfo[tiddler.fields.type || "text/plain"] || {encoding: "utf8"};
|
||||
fs.writeFileSync(fileInfo.filepath,tiddler.fields.text,typeInfo.encoding);
|
||||
fs.writeFileSync(fileInfo.filepath + ".meta",tiddler.getFieldStringBlock({exclude: ["text","bag"]}),"utf8");
|
||||
} else {
|
||||
// Save the tiddler as a self contained templated file
|
||||
if(fileInfo.type === "application/x-tiddler") {
|
||||
fs.writeFileSync(fileInfo.filepath,tiddler.getFieldStringBlock({exclude: ["text","bag"]}) + (!!tiddler.fields.text ? "\n\n" + tiddler.fields.text : ""),"utf8");
|
||||
} else {
|
||||
fs.writeFileSync(fileInfo.filepath,JSON.stringify([tiddler.getFieldStrings({exclude: ["bag"]})],null,$tw.config.preferences.jsonSpaces),"utf8");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -33,6 +33,13 @@ Logger.prototype.log = function(/* args */) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Log a structure as a table
|
||||
*/
|
||||
Logger.prototype.table = function(value) {
|
||||
(console.table || console.log)(value);
|
||||
};
|
||||
|
||||
/*
|
||||
Alert a message
|
||||
*/
|
||||
|
||||
@@ -14,10 +14,17 @@ Performance measurement.
|
||||
|
||||
function Performance(enabled) {
|
||||
this.enabled = !!enabled;
|
||||
this.measures = {}; // Hashmap of current values of measurements
|
||||
this.measures = {}; // Hashmap by measurement name of {time:, invocations:}
|
||||
this.logger = new $tw.utils.Logger("performance");
|
||||
this.showGreeting();
|
||||
}
|
||||
|
||||
Performance.prototype.showGreeting = function() {
|
||||
if($tw.browser) {
|
||||
this.logger.log("Execute $tw.perf.log(); to see filter execution timings");
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Wrap performance reporting around a top level function
|
||||
*/
|
||||
@@ -25,13 +32,9 @@ Performance.prototype.report = function(name,fn) {
|
||||
var self = this;
|
||||
if(this.enabled) {
|
||||
return function() {
|
||||
self.measures = {};
|
||||
var startTime = $tw.utils.timer(),
|
||||
result = fn.apply(this,arguments);
|
||||
self.logger.log(name + ": " + $tw.utils.timer(startTime).toFixed(2) + "ms");
|
||||
for(var m in self.measures) {
|
||||
self.logger.log("+" + m + ": " + self.measures[m].toFixed(2) + "ms");
|
||||
}
|
||||
return result;
|
||||
};
|
||||
} else {
|
||||
@@ -39,6 +42,29 @@ Performance.prototype.report = function(name,fn) {
|
||||
}
|
||||
};
|
||||
|
||||
Performance.prototype.log = function() {
|
||||
var self = this,
|
||||
totalTime = 0,
|
||||
orderedMeasures = Object.keys(this.measures).sort(function(a,b) {
|
||||
if(self.measures[a].time > self.measures[b].time) {
|
||||
return -1;
|
||||
} else if (self.measures[a].time < self.measures[b].time) {
|
||||
return + 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
$tw.utils.each(orderedMeasures,function(name) {
|
||||
totalTime += self.measures[name].time;
|
||||
});
|
||||
var results = []
|
||||
$tw.utils.each(orderedMeasures,function(name) {
|
||||
var measure = self.measures[name];
|
||||
results.push({name: name,invocations: measure.invocations, avgTime: measure.time / measure.invocations, totalTime: measure.time, percentTime: (measure.time / totalTime) * 100})
|
||||
});
|
||||
self.logger.table(results);
|
||||
};
|
||||
|
||||
/*
|
||||
Wrap performance measurements around a subfunction
|
||||
*/
|
||||
@@ -47,9 +73,12 @@ Performance.prototype.measure = function(name,fn) {
|
||||
if(this.enabled) {
|
||||
return function() {
|
||||
var startTime = $tw.utils.timer(),
|
||||
result = fn.apply(this,arguments),
|
||||
value = self.measures[name] || 0;
|
||||
self.measures[name] = value + $tw.utils.timer(startTime);
|
||||
result = fn.apply(this,arguments);
|
||||
if(!(name in self.measures)) {
|
||||
self.measures[name] = {time: 0, invocations: 0};
|
||||
}
|
||||
self.measures[name].time += $tw.utils.timer(startTime);
|
||||
self.measures[name].invocations++;
|
||||
return result;
|
||||
};
|
||||
} else {
|
||||
|
||||
@@ -12,6 +12,8 @@ Various static utility functions.
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var base64utf8 = require("$:/core/modules/utils/base64-utf8/base64-utf8.module.js");
|
||||
|
||||
/*
|
||||
Display a message, in colour if we're on a terminal
|
||||
*/
|
||||
@@ -92,6 +94,20 @@ exports.trim = function(str) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Convert a string to sentence case (ie capitalise first letter)
|
||||
*/
|
||||
exports.toSentenceCase = function(str) {
|
||||
return (str || "").replace(/^\S/, function(c) {return c.toUpperCase();});
|
||||
}
|
||||
|
||||
/*
|
||||
Convert a string to title case (ie capitalise each initial letter)
|
||||
*/
|
||||
exports.toTitleCase = function(str) {
|
||||
return (str || "").replace(/(^|\s)\S/g, function(c) {return c.toUpperCase();});
|
||||
}
|
||||
|
||||
/*
|
||||
Find the line break preceding a given position in a string
|
||||
Returns position immediately after that line break, or the start of the string
|
||||
@@ -132,23 +148,6 @@ exports.count = function(object) {
|
||||
return Object.keys(object || {}).length;
|
||||
};
|
||||
|
||||
/*
|
||||
Check if an array is equal by value and by reference.
|
||||
*/
|
||||
exports.isArrayEqual = function(array1,array2) {
|
||||
if(array1 === array2) {
|
||||
return true;
|
||||
}
|
||||
array1 = array1 || [];
|
||||
array2 = array2 || [];
|
||||
if(array1.length !== array2.length) {
|
||||
return false;
|
||||
}
|
||||
return array1.every(function(value,index) {
|
||||
return value === array2[index];
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Determine whether an array-item is an object-property
|
||||
*/
|
||||
@@ -161,46 +160,6 @@ exports.hopArray = function(object,array) {
|
||||
return false;
|
||||
};
|
||||
|
||||
/*
|
||||
Push entries onto an array, removing them first if they already exist in the array
|
||||
array: array to modify (assumed to be free of duplicates)
|
||||
value: a single value to push or an array of values to push
|
||||
*/
|
||||
exports.pushTop = function(array,value) {
|
||||
var t,p;
|
||||
if($tw.utils.isArray(value)) {
|
||||
// Remove any array entries that are duplicated in the new values
|
||||
if(value.length !== 0) {
|
||||
if(array.length !== 0) {
|
||||
if(value.length < array.length) {
|
||||
for(t=0; t<value.length; t++) {
|
||||
p = array.indexOf(value[t]);
|
||||
if(p !== -1) {
|
||||
array.splice(p,1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(t=array.length-1; t>=0; t--) {
|
||||
p = value.indexOf(array[t]);
|
||||
if(p !== -1) {
|
||||
array.splice(t,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Push the values on top of the main array
|
||||
array.push.apply(array,value);
|
||||
}
|
||||
} else {
|
||||
p = array.indexOf(value);
|
||||
if(p !== -1) {
|
||||
array.splice(p,1);
|
||||
}
|
||||
array.push(value);
|
||||
}
|
||||
return array;
|
||||
};
|
||||
|
||||
/*
|
||||
Remove entries from an array
|
||||
array: array to modify
|
||||
@@ -708,7 +667,7 @@ exports.extractVersionInfo = function() {
|
||||
Get the animation duration in ms
|
||||
*/
|
||||
exports.getAnimationDuration = function() {
|
||||
return parseInt($tw.wiki.getTiddlerText("$:/config/AnimationDuration","400"),10);
|
||||
return parseInt($tw.wiki.getTiddlerText("$:/config/AnimationDuration","400"),10) || 0;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -726,12 +685,14 @@ exports.hashString = function(str) {
|
||||
Decode a base64 string
|
||||
*/
|
||||
exports.base64Decode = function(string64) {
|
||||
if($tw.browser) {
|
||||
// TODO
|
||||
throw "$tw.utils.base64Decode() doesn't work in the browser";
|
||||
} else {
|
||||
return Buffer.from(string64,"base64").toString();
|
||||
}
|
||||
return base64utf8.base64.decode.call(base64utf8,string64);
|
||||
};
|
||||
|
||||
/*
|
||||
Encode a string to base64
|
||||
*/
|
||||
exports.base64Encode = function(string64) {
|
||||
return base64utf8.base64.encode.call(base64utf8,string64);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -37,6 +37,7 @@ Compute the internal state of the widget
|
||||
CreateTiddlerWidget.prototype.execute = function() {
|
||||
this.actionBaseTitle = this.getAttribute("$basetitle");
|
||||
this.actionSaveTitle = this.getAttribute("$savetitle");
|
||||
this.actionSaveDraftTitle = this.getAttribute("$savedrafttitle");
|
||||
this.actionTimestamp = this.getAttribute("$timestamp","yes") === "yes";
|
||||
};
|
||||
|
||||
@@ -73,6 +74,9 @@ CreateTiddlerWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
if(this.actionSaveTitle) {
|
||||
this.wiki.setTextReference(this.actionSaveTitle,title,this.getVariable("currentTiddler"));
|
||||
}
|
||||
if(this.actionSaveDraftTitle) {
|
||||
this.wiki.setTextReference(this.actionSaveDraftTitle,this.wiki.generateDraftTitle(title),this.getVariable("currentTiddler"));
|
||||
}
|
||||
return true; // Action was invoked
|
||||
};
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ DeleteFieldWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
tiddler = this.wiki.getTiddler(self.actionTiddler),
|
||||
removeFields = {},
|
||||
hasChanged = false;
|
||||
if(this.actionField) {
|
||||
if(this.actionField && tiddler) {
|
||||
removeFields[this.actionField] = undefined;
|
||||
if(this.actionField in tiddler.fields) {
|
||||
hasChanged = true;
|
||||
|
||||
@@ -156,6 +156,9 @@ CheckboxWidget.prototype.handleChangeEvent = function(event) {
|
||||
if(this.checkboxActions) {
|
||||
this.invokeActionString(this.checkboxActions,this,event);
|
||||
}
|
||||
if(this.checkboxCheckActions && checked) {
|
||||
this.invokeActionString(this.checkboxCheckActions,this,event);
|
||||
}
|
||||
if(this.checkboxUncheckActions && !checked) {
|
||||
this.invokeActionString(this.checkboxUncheckActions,this,event);
|
||||
}
|
||||
@@ -167,6 +170,7 @@ Compute the internal state of the widget
|
||||
CheckboxWidget.prototype.execute = function() {
|
||||
// Get the parameters from the attributes
|
||||
this.checkboxActions = this.getAttribute("actions");
|
||||
this.checkboxCheckActions = this.getAttribute("checkactions");
|
||||
this.checkboxUncheckActions = this.getAttribute("uncheckactions");
|
||||
this.checkboxTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
|
||||
this.checkboxTag = this.getAttribute("tag");
|
||||
|
||||
@@ -42,7 +42,8 @@ DropZoneWidget.prototype.render = function(parent,nextSibling) {
|
||||
{name: "dragover", handlerObject: this, handlerMethod: "handleDragOverEvent"},
|
||||
{name: "dragleave", handlerObject: this, handlerMethod: "handleDragLeaveEvent"},
|
||||
{name: "drop", handlerObject: this, handlerMethod: "handleDropEvent"},
|
||||
{name: "paste", handlerObject: this, handlerMethod: "handlePasteEvent"}
|
||||
{name: "paste", handlerObject: this, handlerMethod: "handlePasteEvent"},
|
||||
{name: "dragend", handlerObject: this, handlerMethod: "handleDragEndEvent"}
|
||||
]);
|
||||
domNode.addEventListener("click",function (event) {
|
||||
},false);
|
||||
@@ -103,6 +104,10 @@ DropZoneWidget.prototype.handleDragLeaveEvent = function(event) {
|
||||
this.leaveDrag(event);
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.handleDragEndEvent = function(event) {
|
||||
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.handleDropEvent = function(event) {
|
||||
var self = this,
|
||||
readFileCallback = function(tiddlerFieldsArray) {
|
||||
|
||||
@@ -14,7 +14,8 @@ Edit-bitmap widget
|
||||
|
||||
// Default image sizes
|
||||
var DEFAULT_IMAGE_WIDTH = 600,
|
||||
DEFAULT_IMAGE_HEIGHT = 370;
|
||||
DEFAULT_IMAGE_HEIGHT = 370,
|
||||
DEFAULT_IMAGE_TYPE = "image/png";
|
||||
|
||||
// Configuration tiddlers
|
||||
var LINE_WIDTH_TITLE = "$:/config/BitmapEditor/LineWidth",
|
||||
@@ -154,7 +155,13 @@ EditBitmapWidget.prototype.loadCanvas = function() {
|
||||
self.refreshToolbar();
|
||||
};
|
||||
// Get the current bitmap into an image object
|
||||
currImage.src = "data:" + tiddler.fields.type + ";base64," + tiddler.fields.text;
|
||||
if(tiddler && tiddler.fields.type && tiddler.fields.text) {
|
||||
currImage.src = "data:" + tiddler.fields.type + ";base64," + tiddler.fields.text;
|
||||
} else {
|
||||
currImage.width = DEFAULT_IMAGE_WIDTH;
|
||||
currImage.height = DEFAULT_IMAGE_HEIGHT;
|
||||
currImage.onerror();
|
||||
}
|
||||
};
|
||||
|
||||
EditBitmapWidget.prototype.initCanvas = function(canvas,width,height,image) {
|
||||
@@ -319,18 +326,16 @@ EditBitmapWidget.prototype.strokeEnd = function() {
|
||||
};
|
||||
|
||||
EditBitmapWidget.prototype.saveChanges = function() {
|
||||
var tiddler = this.wiki.getTiddler(this.editTitle);
|
||||
if(tiddler) {
|
||||
// data URIs look like "data:<type>;base64,<text>"
|
||||
var dataURL = this.canvasDomNode.toDataURL(tiddler.fields.type),
|
||||
posColon = dataURL.indexOf(":"),
|
||||
posSemiColon = dataURL.indexOf(";"),
|
||||
posComma = dataURL.indexOf(","),
|
||||
type = dataURL.substring(posColon+1,posSemiColon),
|
||||
text = dataURL.substring(posComma+1);
|
||||
var update = {type: type, text: text};
|
||||
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getModificationFields(),tiddler,update,this.wiki.getCreationFields()));
|
||||
}
|
||||
var tiddler = this.wiki.getTiddler(this.editTitle) || new $tw.Tiddler({title: this.editTitle,type: DEFAULT_IMAGE_TYPE});
|
||||
// data URIs look like "data:<type>;base64,<text>"
|
||||
var dataURL = this.canvasDomNode.toDataURL(tiddler.fields.type),
|
||||
posColon = dataURL.indexOf(":"),
|
||||
posSemiColon = dataURL.indexOf(";"),
|
||||
posComma = dataURL.indexOf(","),
|
||||
type = dataURL.substring(posColon+1,posSemiColon),
|
||||
text = dataURL.substring(posComma+1);
|
||||
var update = {type: type, text: text};
|
||||
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getModificationFields(),tiddler,update,this.wiki.getCreationFields()));
|
||||
};
|
||||
|
||||
exports["edit-bitmap"] = EditBitmapWidget;
|
||||
|
||||
@@ -57,6 +57,10 @@ EditShortcutWidget.prototype.render = function(parent,nextSibling) {
|
||||
// Link into the DOM
|
||||
parent.insertBefore(this.inputNode,nextSibling);
|
||||
this.domNodes.push(this.inputNode);
|
||||
// Focus the input Node if focus === "yes" or focus === "true"
|
||||
if(this.shortcutFocus === "yes" || this.shortcutFocus === "true") {
|
||||
this.focus();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -72,6 +76,7 @@ EditShortcutWidget.prototype.execute = function() {
|
||||
this.shortcutStyle = this.getAttribute("style");
|
||||
this.shortcutTooltip = this.getAttribute("tooltip");
|
||||
this.shortcutAriaLabel = this.getAttribute("aria-label");
|
||||
this.shortcutFocus = this.getAttribute("focus");
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -118,12 +123,22 @@ EditShortcutWidget.prototype.handleKeydownEvent = function(event) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
focus the input node
|
||||
*/
|
||||
EditShortcutWidget.prototype.focus = function() {
|
||||
if(this.inputNode.focus && this.inputNode.select) {
|
||||
this.inputNode.focus();
|
||||
this.inputNode.select();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget needed re-rendering
|
||||
*/
|
||||
EditShortcutWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.placeholder || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.style || changedAttributes.tooltip || changedAttributes["aria-label"]) {
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.placeholder || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.style || changedAttributes.tooltip || changedAttributes["aria-label"] || changedAttributes.focus) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else if(changedTiddlers[this.shortcutTiddler]) {
|
||||
|
||||
@@ -46,6 +46,7 @@ EditWidget.prototype.execute = function() {
|
||||
this.editIndex = this.getAttribute("index");
|
||||
this.editClass = this.getAttribute("class");
|
||||
this.editPlaceholder = this.getAttribute("placeholder");
|
||||
this.editTabIndex = this.getAttribute("tabindex");
|
||||
// Choose the appropriate edit widget
|
||||
this.editorType = this.getEditorType();
|
||||
// Make the child widgets
|
||||
@@ -56,7 +57,8 @@ EditWidget.prototype.execute = function() {
|
||||
field: {type: "string", value: this.editField},
|
||||
index: {type: "string", value: this.editIndex},
|
||||
"class": {type: "string", value: this.editClass},
|
||||
"placeholder": {type: "string", value: this.editPlaceholder}
|
||||
"placeholder": {type: "string", value: this.editPlaceholder},
|
||||
"tabindex": {type: "string", value: this.editTabIndex}
|
||||
},
|
||||
children: this.parseTreeNode.children
|
||||
}]);
|
||||
@@ -90,11 +92,11 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
EditWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
// Refresh if an attribute has changed, or the type associated with the target tiddler has changed
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || (changedTiddlers[this.editTitle] && this.getEditorType() !== this.editorType)) {
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.tabindex || (changedTiddlers[this.editTitle] && this.getEditorType() !== this.editorType)) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -73,13 +73,13 @@ Compute the internal state of the widget
|
||||
KeyboardWidget.prototype.execute = function() {
|
||||
var self = this;
|
||||
// Get attributes
|
||||
this.actions = this.getAttribute("actions");
|
||||
this.message = this.getAttribute("message");
|
||||
this.param = this.getAttribute("param");
|
||||
this.key = this.getAttribute("key");
|
||||
this.tag = this.getAttribute("tag");
|
||||
this.actions = this.getAttribute("actions","");
|
||||
this.message = this.getAttribute("message","");
|
||||
this.param = this.getAttribute("param","");
|
||||
this.key = this.getAttribute("key","");
|
||||
this.tag = this.getAttribute("tag","");
|
||||
this.keyInfoArray = $tw.keyboardManager.parseKeyDescriptors(this.key);
|
||||
this["class"] = this.getAttribute("class");
|
||||
this["class"] = this.getAttribute("class","");
|
||||
if(this.key.substr(0,2) === "((" && this.key.substr(-2,2) === "))") {
|
||||
this.shortcutTiddlers = [];
|
||||
var name = this.key.substring(2,this.key.length -2);
|
||||
|
||||
@@ -183,7 +183,14 @@ LinkWidget.prototype.execute = function() {
|
||||
this.isShadow = this.wiki.isShadowTiddler(this.to);
|
||||
this.hideMissingLinks = (this.getVariable("tv-show-missing-links") || "yes") === "no";
|
||||
// Make the child widgets
|
||||
this.makeChildWidgets();
|
||||
var templateTree;
|
||||
if(this.parseTreeNode.children && this.parseTreeNode.children.length > 0) {
|
||||
templateTree = this.parseTreeNode.children;
|
||||
} else {
|
||||
// Default template is a link to the title
|
||||
templateTree = [{type: "text", text: this.to}];
|
||||
}
|
||||
this.makeChildWidgets(templateTree);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -84,39 +84,50 @@ NavigatorWidget.prototype.getStoryList = function() {
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.saveStoryList = function(storyList) {
|
||||
var storyTiddler = this.wiki.getTiddler(this.storyTitle);
|
||||
this.wiki.addTiddler(new $tw.Tiddler(
|
||||
{title: this.storyTitle},
|
||||
storyTiddler,
|
||||
{list: storyList}
|
||||
));
|
||||
if(this.storyTitle) {
|
||||
var storyTiddler = this.wiki.getTiddler(this.storyTitle);
|
||||
this.wiki.addTiddler(new $tw.Tiddler(
|
||||
{title: this.storyTitle},
|
||||
storyTiddler,
|
||||
{list: storyList}
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.removeTitleFromStory = function(storyList,title) {
|
||||
var p = storyList.indexOf(title);
|
||||
while(p !== -1) {
|
||||
storyList.splice(p,1);
|
||||
p = storyList.indexOf(title);
|
||||
if(storyList) {
|
||||
var p = storyList.indexOf(title);
|
||||
while(p !== -1) {
|
||||
storyList.splice(p,1);
|
||||
p = storyList.indexOf(title);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.replaceFirstTitleInStory = function(storyList,oldTitle,newTitle) {
|
||||
var pos = storyList.indexOf(oldTitle);
|
||||
if(pos !== -1) {
|
||||
storyList[pos] = newTitle;
|
||||
do {
|
||||
pos = storyList.indexOf(oldTitle,pos + 1);
|
||||
if(pos !== -1) {
|
||||
storyList.splice(pos,1);
|
||||
}
|
||||
} while(pos !== -1);
|
||||
} else {
|
||||
storyList.splice(0,0,newTitle);
|
||||
if(storyList) {
|
||||
var pos = storyList.indexOf(oldTitle);
|
||||
if(pos !== -1) {
|
||||
storyList[pos] = newTitle;
|
||||
do {
|
||||
pos = storyList.indexOf(oldTitle,pos + 1);
|
||||
if(pos !== -1) {
|
||||
storyList.splice(pos,1);
|
||||
}
|
||||
} while(pos !== -1);
|
||||
} else {
|
||||
storyList.splice(0,0,newTitle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.addToStory = function(title,fromTitle) {
|
||||
this.wiki.addToStory(title,fromTitle,this.storyTitle,{openLinkFromInsideRiver: this.getAttribute("openLinkFromInsideRiver","top"),openLinkFromOutsideRiver: this.getAttribute("openLinkFromOutsideRiver","top")});
|
||||
if(this.storyTitle) {
|
||||
this.wiki.addToStory(title,fromTitle,this.storyTitle,{
|
||||
openLinkFromInsideRiver: this.getAttribute("openLinkFromInsideRiver","top"),
|
||||
openLinkFromOutsideRiver: this.getAttribute("openLinkFromOutsideRiver","top")
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -279,15 +290,7 @@ NavigatorWidget.prototype.makeDraftTiddler = function(targetTitle) {
|
||||
Generate a title for the draft of a given tiddler
|
||||
*/
|
||||
NavigatorWidget.prototype.generateDraftTitle = function(title) {
|
||||
var c = 0,
|
||||
draftTitle,
|
||||
username = this.wiki.getTiddlerText("$:/status/UserName"),
|
||||
attribution = username ? " by " + username : "";
|
||||
do {
|
||||
draftTitle = "Draft " + (c ? (c + 1) + " " : "") + "of '" + title + "'" + attribution;
|
||||
c++;
|
||||
} while(this.wiki.tiddlerExists(draftTitle));
|
||||
return draftTitle;
|
||||
return this.wiki.generateDraftTitle(title);
|
||||
};
|
||||
|
||||
// Take a tiddler out of edit mode, saving the changes
|
||||
@@ -466,14 +469,14 @@ NavigatorWidget.prototype.handleNewTiddlerEvent = function(event) {
|
||||
},this.wiki.getModificationFields());
|
||||
this.wiki.addTiddler(draftTiddler);
|
||||
// Update the story to insert the new draft at the top and remove any existing tiddler
|
||||
if(storyList.indexOf(draftTitle) === -1) {
|
||||
if(storyList && storyList.indexOf(draftTitle) === -1) {
|
||||
var slot = storyList.indexOf(event.navigateFromTitle);
|
||||
if(slot === -1) {
|
||||
slot = this.getAttribute("openLinkFromOutsideRiver","top") === "bottom" ? storyList.length - 1 : slot;
|
||||
}
|
||||
storyList.splice(slot + 1,0,draftTitle);
|
||||
}
|
||||
if(storyList.indexOf(title) !== -1) {
|
||||
if(storyList && storyList.indexOf(title) !== -1) {
|
||||
storyList.splice(storyList.indexOf(title),1);
|
||||
}
|
||||
this.saveStoryList(storyList);
|
||||
@@ -529,7 +532,7 @@ NavigatorWidget.prototype.handleImportTiddlersEvent = function(event) {
|
||||
var storyList = this.getStoryList(),
|
||||
history = [];
|
||||
// Add it to the story
|
||||
if(storyList.indexOf(IMPORT_TITLE) === -1) {
|
||||
if(storyList && storyList.indexOf(IMPORT_TITLE) === -1) {
|
||||
storyList.unshift(IMPORT_TITLE);
|
||||
}
|
||||
// And to history
|
||||
@@ -590,7 +593,7 @@ NavigatorWidget.prototype.handleFoldOtherTiddlersEvent = function(event) {
|
||||
NavigatorWidget.prototype.handleFoldAllTiddlersEvent = function(event) {
|
||||
var self = this,
|
||||
paramObject = event.paramObject || {},
|
||||
prefix = paramObject.foldedStatePrefix;
|
||||
prefix = paramObject.foldedStatePrefix || "$:/state/folded/";
|
||||
$tw.utils.each(this.getStoryList(),function(title) {
|
||||
self.wiki.setText(prefix + title,"text",null,"hide");
|
||||
});
|
||||
@@ -606,7 +609,6 @@ NavigatorWidget.prototype.handleUnfoldAllTiddlersEvent = function(event) {
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.handleRenameTiddlerEvent = function(event) {
|
||||
event = $tw.hooks.invokeHook("th-renaming-tiddler", event);
|
||||
var paramObject = event.paramObject || {},
|
||||
from = paramObject.from || event.tiddlerTitle,
|
||||
to = paramObject.to;
|
||||
|
||||
@@ -56,32 +56,39 @@ RevealWidget.prototype.render = function(parent,nextSibling) {
|
||||
RevealWidget.prototype.positionPopup = function(domNode) {
|
||||
domNode.style.position = "absolute";
|
||||
domNode.style.zIndex = "1000";
|
||||
var left,top;
|
||||
switch(this.position) {
|
||||
case "left":
|
||||
domNode.style.left = Math.max(0, this.popup.left - domNode.offsetWidth) + "px";
|
||||
domNode.style.top = this.popup.top + "px";
|
||||
left = this.popup.left - domNode.offsetWidth;
|
||||
top = this.popup.top;
|
||||
break;
|
||||
case "above":
|
||||
domNode.style.left = this.popup.left + "px";
|
||||
domNode.style.top = Math.max(0, this.popup.top - domNode.offsetHeight) + "px";
|
||||
left = this.popup.left;
|
||||
top = this.popup.top - domNode.offsetHeight;
|
||||
break;
|
||||
case "aboveright":
|
||||
domNode.style.left = (this.popup.left + this.popup.width) + "px";
|
||||
domNode.style.top = Math.max(0, this.popup.top + this.popup.height - domNode.offsetHeight) + "px";
|
||||
left = this.popup.left + this.popup.width;
|
||||
top = this.popup.top + this.popup.height - domNode.offsetHeight;
|
||||
break;
|
||||
case "right":
|
||||
domNode.style.left = (this.popup.left + this.popup.width) + "px";
|
||||
domNode.style.top = this.popup.top + "px";
|
||||
left = this.popup.left + this.popup.width;
|
||||
top = this.popup.top;
|
||||
break;
|
||||
case "belowleft":
|
||||
domNode.style.left = Math.max(0, this.popup.left + this.popup.width - domNode.offsetWidth) + "px";
|
||||
domNode.style.top = (this.popup.top + this.popup.height) + "px";
|
||||
left = this.popup.left + this.popup.width - domNode.offsetWidth;
|
||||
top = this.popup.top + this.popup.height;
|
||||
break;
|
||||
default: // Below
|
||||
domNode.style.left = this.popup.left + "px";
|
||||
domNode.style.top = (this.popup.top + this.popup.height) + "px";
|
||||
left = this.popup.left;
|
||||
top = this.popup.top + this.popup.height;
|
||||
break;
|
||||
}
|
||||
if(!this.positionAllowNegative) {
|
||||
left = Math.max(0,left);
|
||||
top = Math.max(0,top);
|
||||
}
|
||||
domNode.style.left = left + "px";
|
||||
domNode.style.top = top + "px";
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -94,6 +101,7 @@ RevealWidget.prototype.execute = function() {
|
||||
this.type = this.getAttribute("type");
|
||||
this.text = this.getAttribute("text");
|
||||
this.position = this.getAttribute("position");
|
||||
this.positionAllowNegative = this.getAttribute("positionAllowNegative") === "yes";
|
||||
this["class"] = this.getAttribute("class","");
|
||||
this.style = this.getAttribute("style","");
|
||||
this["default"] = this.getAttribute("default","");
|
||||
@@ -118,10 +126,22 @@ Read the state tiddler
|
||||
*/
|
||||
RevealWidget.prototype.readState = function() {
|
||||
// Read the information from the state tiddler
|
||||
var state = this.stateTitle ? (this.stateField ? this.wiki.getTiddler(this.stateTitle).getFieldString(this.stateField) :
|
||||
(this.stateIndex ? this.wiki.extractTiddlerDataItem(this.stateTitle,this.stateIndex) :
|
||||
this.wiki.getTiddlerText(this.stateTitle))) || this["default"] || this.getVariable("currentTiddler") :
|
||||
(this.stateTiddlerTitle ? this.wiki.getTextReference(this.state,this["default"],this.getVariable("currentTiddler")) : this["default"]);
|
||||
var state,
|
||||
defaultState = this["default"];
|
||||
if(this.stateTitle) {
|
||||
var stateTitleTiddler = this.wiki.getTiddler(this.stateTitle);
|
||||
if(this.stateField) {
|
||||
state = stateTitleTiddler ? stateTitleTiddler.getFieldString(this.stateField) || defaultState : defaultState;
|
||||
} else if(this.stateIndex) {
|
||||
state = stateTitleTiddler ? this.wiki.extractTiddlerDataItem(this.stateTitle,this.stateIndex) || defaultState : defaultState;
|
||||
} else if(stateTitleTiddler) {
|
||||
state = this.wiki.getTiddlerText(this.stateTitle) || defaultState;
|
||||
} else {
|
||||
state = defaultState;
|
||||
}
|
||||
} else {
|
||||
state = this.stateTiddlerTitle ? this.wiki.getTextReference(this.state,this["default"],this.getVariable("currentTiddler")) : this["default"];
|
||||
}
|
||||
if(state === null) {
|
||||
state = this["default"];
|
||||
}
|
||||
@@ -130,10 +150,10 @@ RevealWidget.prototype.readState = function() {
|
||||
this.readPopupState(state);
|
||||
break;
|
||||
case "match":
|
||||
this.isOpen = !!(this.compareStateText(state) == 0);
|
||||
this.isOpen = this.text === state;
|
||||
break;
|
||||
case "nomatch":
|
||||
this.isOpen = !(this.compareStateText(state) == 0);
|
||||
this.isOpen = this.text !== state;
|
||||
break;
|
||||
case "lt":
|
||||
this.isOpen = !!(this.compareStateText(state) < 0);
|
||||
@@ -179,13 +199,13 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
RevealWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.state || changedAttributes.type || changedAttributes.text || changedAttributes.position || changedAttributes["default"] || changedAttributes.animate || changedAttributes.stateTitle || changedAttributes.stateField || changedAttributes.stateIndex) {
|
||||
if(changedAttributes.state || changedAttributes.type || changedAttributes.text || changedAttributes.position || changedAttributes.positionAllowNegative || changedAttributes["default"] || changedAttributes.animate || changedAttributes.stateTitle || changedAttributes.stateField || changedAttributes.stateIndex) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
var currentlyOpen = this.isOpen;
|
||||
this.readState();
|
||||
if(this.isOpen !== currentlyOpen || (this.stateTiddlerTitle && changedTiddlers[this.stateTiddlerTitle])) {
|
||||
if(this.isOpen !== currentlyOpen) {
|
||||
if(this.retain === "yes") {
|
||||
this.updateState();
|
||||
} else {
|
||||
|
||||
@@ -145,6 +145,7 @@ SelectWidget.prototype.execute = function() {
|
||||
this.selectDefault = this.getAttribute("default");
|
||||
this.selectMultiple = this.getAttribute("multiple", false);
|
||||
this.selectSize = this.getAttribute("size");
|
||||
this.selectTooltip = this.getAttribute("tooltip");
|
||||
// Make the child widgets
|
||||
var selectNode = {
|
||||
type: "element",
|
||||
@@ -160,6 +161,9 @@ SelectWidget.prototype.execute = function() {
|
||||
if(this.selectSize) {
|
||||
$tw.utils.addAttributeToParseTreeNode(selectNode,"size",this.selectSize);
|
||||
}
|
||||
if(this.selectTooltip) {
|
||||
$tw.utils.addAttributeToParseTreeNode(selectNode,"title",this.selectTooltip);
|
||||
}
|
||||
this.makeChildWidgets([selectNode]);
|
||||
};
|
||||
|
||||
@@ -169,7 +173,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
SelectWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
// If we're using a different tiddler/field/index then completely refresh ourselves
|
||||
if(changedAttributes.selectTitle || changedAttributes.selectField || changedAttributes.selectIndex) {
|
||||
if(changedAttributes.selectTitle || changedAttributes.selectField || changedAttributes.selectIndex || changedAttributes.selectTooltip) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
// If the target tiddler value has changed, just update setting and refresh the children
|
||||
|
||||
@@ -22,15 +22,17 @@ Options include:
|
||||
document: optional document object to use instead of global document
|
||||
*/
|
||||
var Widget = function(parseTreeNode,options) {
|
||||
if(arguments.length > 0) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
}
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Initialise widget properties. These steps are pulled out of the constructor so that we can reuse them in subclasses
|
||||
*/
|
||||
Widget.prototype.initialise = function(parseTreeNode,options) {
|
||||
// Bail if parseTreeNode is undefined, meaning that the widget constructor was called without any arguments so that it can be subclassed
|
||||
if(parseTreeNode === undefined) {
|
||||
return;
|
||||
}
|
||||
options = options || {};
|
||||
// Save widget info
|
||||
this.parseTreeNode = parseTreeNode;
|
||||
@@ -46,7 +48,21 @@ Widget.prototype.initialise = function(parseTreeNode,options) {
|
||||
this.eventListeners = {};
|
||||
// Hashmap of the widget classes
|
||||
if(!this.widgetClasses) {
|
||||
// Get widget classes
|
||||
Widget.prototype.widgetClasses = $tw.modules.applyMethods("widget");
|
||||
// Process any subclasses
|
||||
$tw.modules.forEachModuleOfType("widget-subclass",function(title,module) {
|
||||
if(module.baseClass) {
|
||||
var baseClass = Widget.prototype.widgetClasses[module.baseClass];
|
||||
if(!baseClass) {
|
||||
throw "Module '" + title + "' is attemping to extend a non-existent base class '" + module.baseClass + "'";
|
||||
}
|
||||
var subClass = module.constructor;
|
||||
subClass.prototype = new baseClass();
|
||||
$tw.utils.extend(subClass.prototype,module.prototype);
|
||||
Widget.prototype.widgetClasses[module.name || module.baseClass] = subClass;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -369,9 +385,10 @@ Widget.prototype.previousSibling = function() {
|
||||
Render the children of this widget into the DOM
|
||||
*/
|
||||
Widget.prototype.renderChildren = function(parent,nextSibling) {
|
||||
$tw.utils.each(this.children,function(childWidget) {
|
||||
childWidget.render(parent,nextSibling);
|
||||
});
|
||||
var children = this.children;
|
||||
for(var i = 0; i < children.length; i++) {
|
||||
children[i].render(parent,nextSibling);
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -439,11 +456,11 @@ Widget.prototype.refreshSelf = function() {
|
||||
Refresh all the children of a widget
|
||||
*/
|
||||
Widget.prototype.refreshChildren = function(changedTiddlers) {
|
||||
var self = this,
|
||||
var children = this.children,
|
||||
refreshed = false;
|
||||
$tw.utils.each(this.children,function(childWidget) {
|
||||
refreshed = childWidget.refresh(changedTiddlers) || refreshed;
|
||||
});
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
refreshed = children[i].refresh(changedTiddlers) || refreshed;
|
||||
}
|
||||
return refreshed;
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user