Welcome to TiddlyWiki created by Jeremy Ruston, Copyright © 2007 UnaMesa Association
| source file:|{{{C:\Users\Paul\Desktop\360raphaelDemo.jpg}}}|
| attached on:|28 January 2009 by PaulReiber|
| description:|attached by FileDropPlugin|
| embedded:|[[360raphaelRenderedImage|360raphaelRenderedImage]] - {{{type=image/jpeg, size=9866 bytes, encoded=13361 bytes}}}|
| local file:|//none//|
| remote link:|//none//|
image
<<<
usage: {{{[img[tooltip|360raphaelRenderedImage]] or [img[tooltip|360raphaelRenderedImage][link]]}}}
[img[tooltip|360raphaelRenderedImage]]
<<<
/% DO NOT EDIT BELOW THIS POINT
---BEGIN_DATA---
image/jpeg;base64,
/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkS
Ew8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJ
CQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy
MjIyMjIyMjIyMjIyMjL/wAARCAFGAX8DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEA
AAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIh
MUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6
Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZ
mqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx
8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREA
AgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAV
YnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hp
anN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPE
xcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3
miiivINAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKZJNHCuZHVR7mgB9F
Y934l0+1B+feR6dPzrBvPHapkRKq/qatQkwsdtSFlX7zAfU15bdeOLpycTH8OKyZ
vFNy5/1jfnWioSY+VnsbXVuvWeMf8CFR/wBo2Y/5eI/zrxV9fuW/iP51EdauT/Ea
r6ux8p7f/aVmf+XmP86et7at0njP/AhXho1q5/vH86euu3K/xn86Pq7DlPdFkRvu
up+hp1eJReJrlCPnatO28aXUZH71vzqXh5C5WetUVwNn48Y4Eu1vqK37PxZY3GA/
yE+hyKzdOSFZm/RUMF3b3KgxSq30PNTVABRRRQAUUUUAFFFFABRRRQAUUUUAFFFF
ABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFRXFzDaxmSaRUUDPJ6
0AS1VvNRtrJC00qgj+HPPSuU1rxosO6O2IAHfPPeuCv9dnunOHbmtoUXLcajc73V
PG6R7kt8KOmT1/z1rjb/AMU3Nyx/eMc89a59nkkOWY03AFdMaUYlqBYlvp5jksag
JdjyxpMikya1StsaKAu0etGBSUUD5ULkUZFJRQOyFyKMik/CigLIXijaKSimHKhf
mHQ1LHdTRHhjUOTS7vWkS4GzZ+Ibm3YHewx711uleOXG1ZmDr6GvOuDQNynKms5U
oyIcD3Wx12yvlG2QK3o1adeCWmqz2zD5jgV2uieNHjAjlYMvo1c06DWxm4no1FU7
HU7bUIw0Mgyf4SeauVg1YQUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFA
BRRRQAUUUUAFFFFABRQSAMngVy3iHxRFZxPDbuC2CCwP14pxi5OyA09V12202Mjc
Gk9Aeleaa34nnvJWO88+n4Vk6jq0t3K3zE5NZuM8muynRUdWXGI+SaSZsuxNN4FI
T6UlbmyjYXNJQPanYA60FDaXBpc0halcQuBRxTC1JuqeZASZozUW+jfS50BLmjNR
b6N9HOgJeKTApm+l3U1JAO2+9Jj2oDUuaq4CUAkUuAaCCKdx3FyDQCyHKnFNoB9a
CXG5taXrs9pIp3sCO+a9K0PxVDeosc7AP2b/ABrxwgHpVi1vZLVwQeBWU6SkZSif
QCsGUMpBB6EUtcD4b8W4CwztuQ+p6V3cUqTRiSNtynoa4pQcXqZtWH0UUVIBRRRQ
AUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFISACScAdzS1y3ifxEllC0EL/N
/EwP+fWnGLk7ICDxP4mW3je3t3x1DN69f0rzG+v5LuViWJBPekvr6S7mJLVVGAK7
6dNRRrGIuMU0nNHWgDNaGqVg+lLj1peBTSaTYDiaYWppamFqzlUSAeWppaoy1NLV
g6rewmyTdSFqjLGkzUXZPOSbvejdUdHPpSFzj91Lu96j59KPwoDnJN3vTg1Q5pcm
ndhzkwanB6g3U4NVKo0WpFgNTgarhqeGreNRMZNjNNxQDTs5rVMBvSncMKQjFJTD
clgne3kDKTx6V3nhfxQYXEUjZQ9R/kVwGcinRSvBIGBqJwUkZSifQcUqTRrJG2VP
Sn1574S8TbNsEzZQ/ofXpXoKsroGU5UjINcE4OLsZNWFoooqQCiiigAooooAKKKK
ACiiigAooooAKKKKACiiobq5S0t2mc8KOB60AZuv6sNNtCFP71hx7e9eQ6tfy3lw
3Jxk966LXtRkvZ3JYnJrnGhxzXdRp8quyomdjaOaYXGeTU9wMZrLmc5rc2Uki6HU
96DKg43VmNcbRjNRfaSDnPNTuNyNZ5VXqaiM6etZktwWXPpVX7SxOBWUrvYnnNkz
p600zL2rKWUk8mnGUnpWXs7kuRomVe5pPPT1rMMpPQ05HOKtUO5nzGorI3c1J8gq
hE5Bq2MkZq1SiguyXco7Ubx2FMC+tLmr5EIfuWglfWoy2KhaTnFUqaZN2WPlNNIW
oQwp+A3es50UWncXODRmmMjL0pocisPZO5ROGp4PpUAbNSKcVosP1Q1PuTg1IDUS
kN9adnBxVRTWjN4q5MDmgr6UwGpFNXexXKM6GndRSlM0g4NVe4nHQktrlrWZWB4z
mvU/CPiAXESW0rcHAU+h/KvKXTIq7o2pPZXa/MRzWdWHMjmmj3qisrQtVTUrJTuB
kUDPPWtWuBqzsQFFFFIAooooAKKKKACiiigAooooAKKKKACuN8VatljbRt8qnB+t
dNql4LKxeTOGxhfrXmF7O1zcsSSea3oQ5ncCvtLkk1DLHxV1VAWo5F4rvsCZg3Uf
UVkTRYNdHPDmsu5hxnikykznrgEE1SMhDEZrTvE5PoKyVQvMfTNSDkTKHcDA61II
hEhJ6nvVuGNfLB9Kp3shA2r1qbCKm8lvxqUMe9Nto8uCetWZIqh1EnYohqWMEiow
pBqwg4rVNWFYsxBeM1cBwgxVOIDIq1vAUdT9KiU7DUSORm7VDhzyTUzZPVaQfSud
1dTeMFYhJZe9M3HNWDEW7Gm/Z29DXRTroidMjDGpFY+tN8sg805VxSq1kbUaNyXz
COvNHyt7GkApdufY1jCrqaVMOraDehqRTTCpB5pyLzXS6qscqp6kqmphzUarUgHF
YOqmzojBxFBxUi1HT0NNTNLXJl5pxj9KavFTociqUrENEar2NQ3ETIQ69QauADNS
Swh4umeK0uctVdTe8Ha61tMoLHHQjPUV6ujrJGrqcqwyDXz3azG0vAc8Zr2Twnqg
vbHymOWQZH+c1zV4W1RidFRRRXMAUUUUAFFFFABRRRQAUUUUAFFFRXMwt7aSUn7q
5/GgDkfF2oZk8hTwgx171yUQy241Z1S4a4u2JJOTmoRhEr0aMeWImNaQK2KRnBFZ
c9yftBANSCfOOa2JLEgBrOuk4Iqw0/vVOe4GDUtDuYd6nJUVneWFPStKZwzE1nTH
5+KTKRMjHZn8qqzoNpJp4lHfiq8spkbHaspMdia0Tc4q68XtVW2IUir6HOSa5Kjd
y0im8e0dKhRucDmrcpD5A6Cq6oQePWtachoswoTyx/CryIPLHFUod3cGtKEApiic
7LUrRELR57GhYTnpVzZ7UhWuRzux+0EigB7VK0K46UsYwOtP5PetVNJEXuzPmts9
KrGJk6itV1PcU3ywy4/Q0nJM6aVRxKCJmplgz2qVYAG4q5FEAOa55ScWbyqJozmg
IXkcVGEwa2SikdKpywhTkdKftromnZvUhVRT8ZpMYpRWak7nUoqwm3NOCEc04DBz
UgxXWp6GbjZ6DQKepwaQDBpxFXGpcmUCdRkVZg+ZSpqtDzVpF2tmt4SvocdVGXfQ
lWJHUV03g3Vjb3Ue5uAef69ayb2IOmRVDTZza3w5xzWklzROTyPoFGDoGHQjIpay
fD16LvS0y2WTg89q1q4GrOwBRRRSAKKKKACiiigAooooAKxPE115Gn+WDy/X6Vt1
xPjC63XHlA8KMVdNXkBymd8xJouXEcRNLCO9UtTlATGea9NaEsxpZv8ASCaeLjjr
WXLLmcjNL5xUdaY2jQe4461n3VxhTzTDOD3qjdzZU80XC1gWUtk5qMjI9zTYATHj
1qUjFPl0BOxVn+XgVHEe5pZ2yGohXMea56isaItRDkYrQGVi96z4socnkVeikDVw
1X2NLaWESMspb1pURUHI71ZXGwkdKqs4VWbqc8UqUm7hYtRxljk8Cr8UaovA61kQ
XLMRnvWxE25BWda/UljzjFRnr0qXFKAPSs4asnYiBIHSnK1ThDigxd8CtJWsNWbE
Az2pTCCOODQp2mpiyFfeudyNooqlcGpFbsaY554pm6lqzpUG0Tk1HIMigNmg81Oq
HGOpCFzTTGQanRealKZFWjpTKyrxRyKl24NRsOa15tCoq7HLyKlC5FRLU0dEW7jn
EfCMPV3Z8mRVdV4zWhGu6EnHbNdlH4zzq0bFVhviOaw7lTFOH963RwxFZeox4ya6
46OxwzVmeieBNQ3AQluHGOTXd1474MvTBdxnPRhXsIIZQQcgjIrjrRtIQtFFFZAF
FFFABRRRQAUUUUAFeZ+IZzNfyHPVjXo9w+y2lb0UmvK9RffeN9a6MOryAiThKxNW
k5IrcPEdcxqr/M1d5PUw9265b2FOZqgQ5kc+tStyDUtjZDI2B1qjK5LAHpV2VeT9
Kz5jhsUblLYuwkbRSyN2qCIkpkUM5zg1XNYErsrzjFWbdf3IqvN83A71oWyYhUfj
WFRplrcCucCmI5Eu0VNIdqk9zzVWBs3BNcriVzFt7k42ZxTEG/g9KjkTIzRDJsfa
1CjZaGia6l+KEbR7VqW/+q47VTt2VwBWvawLtIPNQ4c25M2uhApZjwPxq5DDnGcf
jUojVRwKZg54pcqhsc8iy0IVeqmq+MGnrz1qYQkjOOKh+8KL1KTrg5qJjitF4VK9
Kz5o2B4rGVLU7KUtdSEnJoxTBndzUlNJI9inBJCcg1MFJGajAzVyBNyYqZJGVWKi
7ohC81JgVN5VIYvasUyU0VyuajZKuCOmvHiumMbo0g9SmFqaMYNLswacq81ahqay
WhajXIq9ajMJ9uKrwLlRVy1XBkHtmuynE8ytsyhINstU79MqeKv3QxJx61VuhmLN
b9TgqFXQJjFfAe9e46fL52nwPnOVFeCWLeXqA7DNe2+HJfN0iPnlTjrWGIXUg16K
KK5QCiiigAooooAKKKKAKmpts02c/wCzXllyc3TfWvT9abbpU3PavL5f+PlvrXXh
gCU4iNcnqbctXV3HER+lchqZ+9XYStzJh6n61LkFwB61BGcAU9G/eCoe5dgm6k1k
3XDZ962Hwax9Q4Kn3pRd2W9i3bj9wPpQy9eKfaLm3Q+1TGIFCfehvUS3M1hhgavx
S/L+lU7tdlSK37hMdTWU9Sm7MtysChHrVe3X/TNo6YphkYECn2rjz2J4NRsGjLxT
HOPeqagG9x2xV8sGQ1noNl/GCfvUJJg20y8m6E7lP4Vs6ZeB2CZ5PWs/YAOecU/Q
wPt7Z7Ej9KSQNnTAUjR5/iNSKPWlbjis5a7mLdyuisJORxV9CCoxWe7ESEg4qaOQ
4yPxrJNILE8gGaqOo3fSrDN3NQE7pMVLabN4JlG4h2yZHQ9KZsNa3keZHyOab9iO
elYzdmetRre7Zmei84q9bpinfZSp6VchhAA4qObS4VZpirDu7UjQY7VciTBodeaj
cw5mmZ4i5pk0eADV/wAsbqbPFlBxXdSV4mkJ+8jJMfNATmrbRc03y+a1UTpc9Cza
plKtRJtmb3Wo7RcDFWwuJAfaumC0PNqvVmTeDnNVZuYauXo5qm/+oNU+hyT2MVfk
v1+tey+D5N+lkehB614y/F4v1r1/wS2bBxnsDWVf4TI6miiiuMAooooAKKKKACii
igDP1v8A5BU3+NeXy/8AHy31r1PVhu0uf/d9cV5bONt0w9668MAlx/qTXH6n/FXY
zjMRrkNTXlq7CUYLNtC/jSpL84NMmGYwfQ0yLkfQ1m9zS5aLg1magCQv1qxvO/b7
1Bdk7efWpi7Mu6aL9kf9ET6VbjG6L8az7OQG3AzV2B/kI96mT0Y0tSlqKbYSf89a
ggOYo/TNXdQXfav9KisIBPpwI+8jEf1qfskVbjZh0PvUcZH2wL/eXNXLi3dYhx3x
WaxKXMTH6Uoq5jFsuicoxHanBla4iY8EGmhQ6HioJj+6Ru6tg0ramiqX0Zv7g6Ed
DiodOkMOqhW43EH8+KoLdtE+0nIqUSBpVlQ/MvUe1F31NLJ6o7dXxwaeWB5FVLWd
bq3WQdehHvSybwCA3H61lKD6GXK7hcONwA7U+IEpk1BHC7sMKzfXpV/7O6qAx5PY
DpUSSjG7NqdNydiuXJzjJp8KEvz1q0sKqOlPjQK+cVwqbvdnpqhFRLESfIOKsiMY
6VGmOKsCsua+rMmrEEkIIpAoGBU7dKjQbmxWkFe6C45OKa4zU2zA6U0rWqpslyIg
vSpPL3IRipFSp0jrtpQsiXKxmPBz0pnk89K12gzziojBg9K6FAfttCvBHtqyVwM+
1OVNtLJwhrVKxzSldmHe1Tf/AFJq1eHmqknEJqX0InsYknN4v1r13wR/x4vz2Hev
Ij816v1r2LwYhXTXJ9u9ZV/hMjpqKKK4wCiiigAooooAKKKKAIL1d9lMv+we9eVX
q7bo/WvW2XcjL6jFeW6zEY71x/tGunDPUCo4zGfpXLaonzNXVDmOud1aPDNXcT1O
TkHyMPQ1Vjba5HvV2dcO4qgyss3TrWUtxsTfi7/GlulLg4qu7HzgauD5+aiWjuUm
Q2xKrg+tXUcxnnoarbMZwKkdt0G7uKV7lqXUtlhJEQRwaj00+X5sXrzU1iolt/cU
0wGK4DjvS5XayLkrovBw8ZDDPQj6isnU4lW5iZfukg1eMhiYbuh6GmXEa3EJXuOR
UXs9TFw7C/Y3jY45VhkVm3KlWYEYDVtWFy3kiN+SvrRqVvHNa7oxgjqKpPUhwaZk
W6CePa4+YdDUqodw7MowferUdhIoEqDKkc4pfIYyAkYNMcL8x1Oj24MK46HqK3Es
lwMrWZog/dJmuljX5RQdChrqVo7VUHCgVVlX5yTWtgY6VnTrhjXLiU3E7cOkmV+g
pM4NKajY54Fea10O1FpH6GrcedtVLWJnIOOKvbcCqVKRyVGrjGpYEJOfWnBCxxVm
KPFdVKlbcxch2zIphj5qxwBTSRmu1RRlcjVKmRcU0MKeprSKJbH4qF+tTE4HWqsj
4OK0RFwzzUU7YjNKHyaguX4xTbEtzIvDl6qXBxDU87bpfxqrettjxUvcU9jLtxvv
x9a9q8KxeXpAPqa8b0iMy6gOO9e46LF5WkwL6jNYYh9DMv0UUVygFFFFABRRRQAU
UUUAFef+LLby792x1OfWvQK5jxda74EmA9q0pO0gOHiOVxWZqsWRmtGM7XIqK+j3
xHAr00SzhrhAJjnuMVXu4h5YkXt1rR1GIq2e4Oap4Doy9iKxqFWuYoXdcBferogZ
D04qqymGdW9Dg1txlJYwSO1RLVXEig6bcHHWq5+UMp6VuNAkkfupzWff23lpuA4N
QnZgh2kttBBrXeAH39KxtN5GfeuhQBo8d8V1ct9SlLoZV/DiDI6g5FJHD5sKuvXv
Vy6XMTKaitF8tsdjUOBpe25SeOWFt68jvViG5R1BPGexrUaBZFxgZrKaBoj8o45y
DWM6dtik0y/aStA3ygNGf4TWhJFb3KKyDaw6ism3CnoSh9K0Ykk7Df8A7nX8qzba
3N6dKO5t6XEUUCugiGVFc3pkxDbcnjse1dLA2VHFXF3CcbEnlVBPbBuR1q4Bml8s
ntTlFSVmTGXK7mFJbNmlhsnkcDHFbotV6tQZIIRwRWH1eKdzf6w2rEUNqsSYpXRa
il1Begqq96SMnge9W+VaGer1LmFXmjzQo61nee7nJNKCzcc042JaLzXAHOai+0VU
OWPsKmjQkZNF2S7InEpJAqzCGNRW8OWycVqxQAIB61vGLsYymim4IXJzVN1y3tWt
cRYGKzzGS5rRRM3MbFETk9qoXrAbq1XwiEA9utYV+/aiSsODuzP6yk9cVn6jJgEV
fB2qTWLfSb3wO5qFqwm9TV8K2xmvFOOp717bCnlwon91QK818CWG65jYjhea9Nrk
ryvIlhRRRWIBRRRQAUUUUAFFFFABVLVbb7Vp0qYywGR161doIyMGhOzuB5Dcx+Tc
sOnNDjfGa2fE1gba8cgfKeQcVixNkYr06crxEzl9XtyA1c8GZCQe1dxqltvQnFcj
f2xjJbHHelUKiZl0Ax3Y61JZT/LsJ6UQqJGKGj7MUlz0rJ6aDNBJMHrSygSxGM/V
ariNsZFL5jIMNUMGkyrbO1tPgj5Sa6G1nUgGsSXbJ82MN3qxaTAYUmt4VNLMagmb
N3CHiLrz61Dbw7lGRT4n4x2qRG8s5xlatTRt7N2sPEZUD9DSC3Eq8gZzVuKWJhg9
/WlSLBO05GactUOMbFYWK45GD608WcgGVOasq23hhkZqUEYBDY9jWDRvF6E+nO20
CUZA/vc1vQyQAdvwzXNglSDmpluiP4zWbkkJxudP9qiQcD8zioZNTVejKPoNx/pW
CkplztJP1p4jkc4Ct9en86n2knsieSK3Zem1Jnzjc3ux4/IVVa4kkbGeT2Ap0dnI
Sd4AHXGc1KscoG2ICMdyByfxpclSTsx88I7IhK+WMzE5PRB1qWK3eU7nGB2FT22n
EShnJYnua0fKVRgEcVrHDqPxGU6z2RQ8kLxTzHhMKOverBi6k8Ckdh8uKuTjsjPm
8yFLc+1P4C461I8ixRkk81npcb3Kg8k1ERPU0rIgkD862BIABXPW0yxnGatG9B71
qpmckaNxMNuap+avQVQub8BQM5NVDfHpzmnz9CFE0ZZhz3rAvJN8mAc81NNeHueT
VTIdy2acmaRViK4by4cd6xo1NxequMjNXNQnwDg+1WfDVg1zdqdpOTxip+FXJ3Z6
b4OsRbWBlIwT8orpags7cWtpFCMfKO3rU9efJ3dwCiiikAUUUUAFFFFABRRRQAUU
UUAYfiXTxdWXmqo3J1OO1edsDFMQeK9edBJGyN0YYNeceIdNNndsAOM5B9q6cPOz
swMiZBJHiua1O2/dsCK6VHBXBrN1KMNExFdUxJ2Zw0SGO4rU8kTJuHWoprfEpYdj
Vm2bawPas5K5aGpF2IqG8t8JkCtYQBhkd6juYsxYPWsb2ZRm2sImUKfvAfnRJppQ
grkc9u1WbeMo+RxitiBFlXDAZroUb6k3sYQWa3TJyQKtRXDbQSuVPcVqXVliA4Xi
qlvbbTgdPSpcDeFXuRiVM5U4PoatW9wc4Bp/2FXHAH0qNLUwyNg49jS5ZLZm6nGS
NOILIvPXNWBaK3JH5Vnw+YnVT9RzV5LrbjntSbuJOxKLQDFTwWq4GUBP0qJL0bua
lS6K9FHrnNRJiuX4IArkBB09Kl8gZznA/nWel+6tkhP1pH1MZx5ig+gx/WhVEt2Y
uLNMRosgyc5FDOi8ACsj7fuIwWb0pxuJW5ICj6U/ba6IXI+5oLM3mYBwKlaRY/mY
/SsZroryMlqbummO5icfWplWbFyJGjJd7xwcVE12kUZJOW9KzpZGVcJ1zjJrOmmc
sRv5zUxcpPQV4o0Li/d26jNRxXPk7mJyT0rLZzHtZmJJ6VXa5L5IPGc/4Vq4tIHJ
G0L8liFPHcnvUguztyzYFYcUgY43cD3pZ7kAYB4pxj1Zzym2zQN15jlmb6U8ThRk
1ix3Gec8A06S8GODxWkO5S8zRNwZJMDinedsU1n28wAJJ5NJNc9Qp/z/AJxVO7G2
thkpa4uAg55r03wPpAQCd1+VRkHHeuG8O6Y93dI23qeDXtOm2a2NlHCByB831rnr
zsrIC3RRRXIAUUUUAFFFFABRRRQAUUUUAFFFFABWXrmmi/tCVGZE6e4rUopp2dwP
Hb6J7YuMEYrHlu8gq1ej+KtDBR54U+Vgc4HQ/lXlmoxtBMwIPWu+nNTiJopXMgSQ
nsTUKXKqe2KJdzrWe6upxTGmdBbXqDAJ4qxMyTR/KRmuVWZkPerUV4Rxk1EoJ6od
zYQpnBIBBq9Ey8EHmueeYtyCQaal7IhwWOa0pzS0ZLR2XnK1vtbmo0iG7I75rm01
OQd6sJq7rVuz1C50KgCoZCCxyM81mLrY/iFB1WJueamSutCoyaZfztIKMVp32g/x
4NZh1O3PUkU4X9mx5kxzXNyO+p0e2NRJULDgjj1q0XUqeTWNHd2eci5X8auLe2hH
/HzH09ayqQd9EL2hM5G7hA3PcCmhpCDgY4FL9ss8f8fMXf8AiFRvqNiu7/SY/wAD
VKDtsS6jLcIZRkevYVYZXaL5s9O9ZQ1+whB/eFuewqvc+K0ZSsEJ+pqJQqN2SFKd
zZZApBJ4pWniXq4KjtXJT61cznoQKrPqFyVK7uvpVRw0nuyefQ6C+1Rc7VOBu7Vj
yagAwAGcfrWazTP1OKYQR1NdcKcYKyM7svzXbyYyahe7AVgCO2KpMST605IWPLCq
lKPUNWW0uyKZNeHByetQyMIx1qvnc2c0lJC5Syt0+3atSI8j4qGNU9SavwogGdtH
MFgTcBy1W7K2e6nUDPJqNf3jhEWu88JaA1zKhKkKOSfb/JFE58qGkdL4O0QW8C3M
iYwPlz6119MiiSGJY0ACqMACn158pczuMKKKKkAooooAKKKKACiiigAooooAKKKK
ACiiigBksSTRNHIAVYYINeYeLPDTQyMyrlTypAr1Kq95aR3tu0MoyD0PoauE3Fgf
O0kTQSFGBFVpotw4Fd94n8MvbyuQn0IHUVxMkbxOVcc13JqauhNWMmSM5xUBUqcj
rWtLCGFUpIiM1Ow07jYbjHDGpyokHGKpMmKVJWjPtScb7DJ2VkPTilV6ckyuMd6V
ogeVpXaC1wDA07PvUBV0+lAfFUpCsT59RSbVPamB6dvFXcA8tfWjy/el3CjIouFx
PK96PLHc0uRRuFFwuARaX6Cm7xSGSi4D8570m4Coi9J8zdBUuQajmemjc54p6w92
p7OkY7VDk3sO1hEjC8nrTJZwowtQyXBY4WowpY01HqwuBJc5NSxp+dOjjParkUGO
TTFsJDD0JqyBztUc0AH7qjmuh0LQZLuZMoSScCq0irsW5P4b0GS7uEIjLEn/AD/K
vYNN0+PTrRYUAz/EfWq2i6RHplsPlHmkcn09q1a46lTmYwooorIAooooAKKKKACi
iigAooooAKKKKACiiigAooooAKKKKAK17ZQ30BimUEdj6V5h4l8KPbSMVT5TyGA4
r1iori2iuojHKgZT+lXCbiwPnSaCS3cqwOKgeMOK9U8R+DiA0kKb0PT1Fed3umTW
kh+U12xnGaFbsYkkBB4qs8daxAbgjFQyW4PNDTQJ9zLwVqRLhl681M8JHaoWjpeo
ywk6t1p2xG9KolCKA7r0NLlXQdy2YPQ03y3HvUa3LDrUguh3FLlaATDjtR83oaeL
hDTvOT1o94NCLLehow57VL50fqKQ3CCj3g0GbHNOEJ7mkN0o6Co2uiego5ZMCcRq
tDSolU2ldu9JtJNPkXULkz3JPC1CSznnmnrHUqRE9qe2wiJY+asRwlscVPHb+tTh
VQU0mxXGRwhRUyqznagOalgtZblsKOK7bw94RkuGVtnAPJz05ptqG4W7mToPh2W7
nT5Mkkf0/wAa9Z0bRYdLgXCgzEct6cDip9O0uDTYQkS/NjlqvVx1KjkMKKKKyAKK
KKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAEIDAgjIPBBrnt
Z8K29+rNCArn+E9DXRUU1JrYDxTWPC01rI37tgfpXNy28sDYdTivom5tILuMpNGr
D3Fclq/gqOYM9v8AN/snrXTCv0YHjuFb6+9RPbg9q6zUvCs9s5/dlT9KwZrK4gJB
UkVuuWWwrMyXtyOlRNCe4rTPXBBFNKKw7UOLC5lGKmmOtRoFNMNsKnUd0Zvlmk2G
tA21J9mNFwuihsPvR5Zq/wDZjSi1NF2GhQEdOEVXxbU8W4HajULooLF6CplgJ7Vd
Ear6UoxwACTTUWxXIEt8damCKtTx280x+VDWtY+HZ7hhlSc/5/pTsluFmzGRHkbC
LWzpnh+e7kUFWOT6fSu20fwM20NMvljHce3/ANeu2stKtLFQIowWH8RGTWU66WiH
Y5jQ/BiQqklyMDGdvGeldjFEkMYjjUKo7Cn0Vyyk5bgFFFFSAUUUUAFFFFABRRRQ
AUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUARTW0Nwu2aJ
XGMcisG/8IWd0CYzsJ/vdK6OimpNbAeZah4DmXJSLcP9nmuZuvC1xET8jCvc6jkg
il/1kat9RW0a8kB8+y6Pcxfwn8qrtaXCdUNe+TaFp033oAPpWfL4PsJOhK/hWixC
6isjxAxSjqh/Km7X/uH8q9kfwLbt0kX8qgPgKMnh4/1qvbxCyPItr/3D+VKI5D0Q
/lXrY8Apx88YqaPwJAvWRfwFHt4hZHkK207HhDU8el3Mn8Jr2OLwZZJjc2foKvw+
HNOhx+63H3pPELoFkeO2/hq4lIyrH2xXQaf4GnlxmI4Pc8f5716jFZ20I/dwov4V
PWUq8mM5LT/BNvBhpyOxwv8An6V0drp1rZqBDCoI/iI5q1RWTk3uAUUUVIBRRRQA
UUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQA
UUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQA
UUUUAFFFFABRRRQAUUUUAFFFFABRRRQB/9k=
---END_DATA---
%/
! making one of these documents for your own use
This document began as a //Starter Document// - created via ''new starter...''
You can use ''new starter...'' any time, to create a new starter document with copies of all the baseline tiddlers that are in this document. That's a great way to get started on a new project.
! upgrading your document
This document also includes a means of importing updates to the tiddlers tagged "baseline" - the "baseline updates" functionality will pull in any changes to its baseline tiddlers when run within a local file (a document with a file-colon-slash-slash rather than http-colon-slash-slash) - currently it only pulls baseline tiddlers from http://TiddlyTools.com.
/***
|Name|AnimationEffectsPlugin|
|Source|http://www.TiddlyTools.com/#AnimationEffectsPlugin|
|Documentation|http://www.TiddlyTools.com/#AnimationEffectsPluginInfo|
|Version|3.1.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.2|
|Type|plugin|
|Requires||
|Overrides||
|Description|display content with timer-based animations to manipulate multiple CSS attributes|
|Status|!BETA - EXPERIMENTAL - UNDER DEVELOPMENT - USE WITH CAUTION|
This plugin defines the {{{<<animate>>}}} macro that can be used to peform simple animations of formatted tiddler content by saving/setting/reseting the values of CSS style attributes at specified times. The macro can also be used to smoothly animate CSS styles that use ''numeric values'', by automatically computing a series of incremental values, ranging from //start// to //stop//, for a specified //duration//, with optional "pause-and-reverse" //cycles// to create repeating animations or continuous loops.
!!!!!Documentation
>see [[AnimationEffectsPluginInfo]] for macro syntax
>see [[AnimationEffectsSample]] for a live animation example...
!!!!!Revisions
<<<
2008.01.08 [*.*.*] plugin size reduction: documentation moved to [[AnimationEffectsPluginInfo]]
2008.01.07 [3.1.1] when animation is disabled, set inner container to original DIV/SPAN
2007.12.16 [3.1.0] added support for "add/remove" classname functionality. Also, in handling for "set", only stored previous attribute value if not already saved and, on "reset", clear saved value. This blocks animations from inadvertently overwriting the saved value while simulaneously processing animation sequences that act on the same attribute.
2007.12.08 [3.0.0] Combined ZoomTextPlugin and AnimateTiddler inline script into single plugin
2007.08.03 [2.1.0] converted from ZoomText inline script
2007.07.16 [2.0.0] added TW2.2-compatible Morpher handling for smoother animation on slower systems
2007.02.17 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.AnimationEffectsPlugin= {major: 3, minor: 1, revision: 1, date: new Date(2008,1,7)};
config.macros.animate = {
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var id=new Date().getTime()+Math.random().toString(); // globally unique ID (GUID)
if (params[0] && (params[0].toUpperCase()=="DIV"||params[0].toUpperCase()=="SPAN"))
var nodetype=params.shift().toUpperCase(); // optional param to force DIV/SPAN
var src=params.shift(); if (!src) src="="; // content is first parameter (if no params, animate container)
if (src.substr(0,1)=="=") { // content=DOM element... use "=here" or "=" (without ID) for current container
var target=place;
if (src.length>1 && src.substr(1).toUpperCase()!='HERE') target=document.getElementById(src.substr(1));
if (!target) return; // couldn't locate target element... do nothing.
var nodetype=nodetype||target.nodeName.toUpperCase();
} else { // use content from tiddler or "inline" param
if (src.substr(0,1)=="@") src=store.getTiddlerText(src.substr(1)); // "@TiddlerName"
var nodetype=nodetype||"span";
var target=createTiddlyElement(place,nodetype);
wikify(src,target);
}
if (params[0]) switch(params[0].toUpperCase()) {
case "SAVE":
var s=params[1]; if (!s) return; // must specify style attribute
if (s.substr(0,1)=="+") s=s.substr(1); // ignore leading "+" (if any)
var w=(params[2]!=undefined && config.options.chkAnimate)?parseInt(params[2]):0; // wait time before saving
if (!target.savedStyle) target.savedStyle={};
if (target.savedStyle[s]!==undefined) return; // value already saved... do nothing.
if (!w) { target.savedStyle[s]=target.style[s]; return; } // save style immediately... done.
target.id=target.id||id; // use existing ID if target has one, otherwise assign GUID
var fn='var e=document.getElementById("'+target.id+'"); \
if(e&&e.savedStyle["'+s+'"]==undefined) \
e.savedStyle["'+s+'"]=e.style["'+s+'"]';
setTimeout(fn,w); return; // timer is set... done.
case "SET":
var s=params[1]; if (!s) return; // must specify style attribute
if (s.substr(0,1)=="+") s=s.substr(1); // ignore leading "+" (if any)
var v=params[2]!=undefined?params[2]:""; // value to set
var w=(params[3]!=undefined && config.options.chkAnimate)?parseInt(params[3]):0; // wait time before setting
if (!w) { target.style[s]=v; return; } // set style immediately... done.
target.id=target.id||id; // use existing ID if target has one, otherwise assign GUID
var fn='var e=document.getElementById("'+target.id+'");if(e)e.style["'+s+'"]="'+v+'"';
setTimeout(fn,w); return; // timer is set... done.
case "RESET":
var s=params[1]; if (!s) return; // must specify style attribute
if (s.substr(0,1)=="+") s=s.substr(1); // ignore leading "+" (if any)
var w=(params[2]!=undefined && config.options.chkAnimate)?parseInt(params[2]):0; // wait time before reset
if (!w && target.savedStyle && (s in target.savedStyle))
{ target.style[s]=target.savedStyle[s]; target.savedStyle[s]=undefined; return; } // reset style immediately
target.id=target.id||id; // use existing ID if target has one, otherwise assign GUID
var fn='var e=document.getElementById("'+target.id+'"); \
if(e&&e.savedStyle&&("'+s+'" in e.savedStyle)) \
e.style["'+s+'"]=e.savedStyle["'+s+'"]; e.savedStyle["'+s+'"]=undefined';
setTimeout(fn,w); return; // timer is set... done.
case "ADD":
var add=true; // fall-through for further processing
case "REMOVE":
var c=params[1]; if (!c) return; // must specify a classname
if (c.substr(0,1)=="+") c=c.substr(1); // ignore leading "+" (if any)
var w=(params[2]!=undefined && config.options.chkAnimate)?parseInt(params[2]):0; // wait time before setting
if (!w) { (add?addClass:removeClass)(target,c); return; } // add class immediately... done.
target.id=target.id||id; // use existing ID if target has one, otherwise assign GUID
var fn='var e=document.getElementById("'+target.id+'");if(e)'+(add?'addClass':'removeClass')+'(e,"'+c+'")';
setTimeout(fn,w); return; // timer is set... done.
}
// remove old containers before RE-animating, unless combining effects (using "+style" param)
if (params[0] && params[0].substr(0,1)!="+") cleanup(target);
function cleanup(here) { // recursively finds all animation containers
if (here.childNodes) for (var n=0; n<here.childNodes.length; n++)
if (here.childNodes[n].className=="animationContainer") cleanup(here.childNodes[n]);
if (here.className=="animationContainer") { // move content up a level and remove container
var e=here.firstChild;
while (e) { var next=e.nextSibling; here.parentNode.insertBefore(e,here); e=next; }
removeNode(here);
}
}
// create animation outer "clipping" container and inner "formatting" container
var outer=createTiddlyElement(null,nodetype,null,"animationContainer");
outer.style.overflow="hidden";
var inner=createTiddlyElement(outer,nodetype,id,"animationContainer");
inner.style.position="relative"; inner.style.lineHeight="100%";
target.insertBefore(outer,target.firstChild);
// move content elements into the inner container
var e=target.firstChild.nextSibling;
while (e) { var next=e.nextSibling; inner.insertBefore(e,null); e=next; }
// params and defaults for morph
inner.OriginalType=target.nodeName.toUpperCase(); // SPAN or DIV
inner.What=params[0]?params[0]:'left';
if (inner.What.substr(0,1)=="+") inner.What=inner.What.substr(1); // trim off "+" prefix (if any)
inner.Format=params[1]!=undefined?params[1]:'%0%';
inner.Start=params[2]!=undefined?parseInt(params[2]):100;
inner.Stop=params[3]!=undefined?parseInt(params[3]):0;
inner.Wait=params[4]!=undefined?parseInt(params[4]):0;
inner.Duration=params[5]!=undefined?parseInt(params[5]):2000;
inner.Cycle=params[6]!=undefined?parseInt(params[6]):1
inner.Pause=params[7]!=undefined?parseInt(params[7]):0;
if (!config.options.chkAnimate) { // if not animating
if (inner.Cycle && (inner.Cycle % 2)) inner.Start=inner.Stop; // odd # of cycles: apply ending value
inner.style.display=inner.OriginalType!="DIV"?"inline":"block"; // restore original display style
var outer=inner.parentNode; if (outer && outer.parentNode) // remove outer clipping container
{ outer.parentNode.insertBefore(inner,outer); removeNode(outer); }
}
inner.style[inner.What]=inner.Format.format([inner.Start]); // set initial style value
if (inner.What=="fontSize" && inner.Start<=0) inner.style.display="none"; // hide text if initial size is 0
if (config.options.chkAnimate) setTimeout("config.macros.animate.morph('"+inner.id+"')",inner.Wait); // ANIMATE!
},
//}}}
//{{{
// animation 'tick' handler (timer callback)
morph: function(id) {
var inner=document.getElementById(id); if (!inner) return;
var p = [{style: inner.What, start: inner.Start, end: inner.Stop, template: inner.Format}];
var c = function(inner,p) { // reverse and re-animate until cycle count==0 (use -1 for continuous looping)
if (inner.Cycle==0 || inner.Cycle==1) {
// finished animation... discard outer container but keep inner container to display final style(s)
inner.style.display=inner.OriginalType!="DIV"?"inline":"block"; // restore original display style
if (p[0].style=="fontSize" && p[0].end<=0) inner.style.display="none"; // hide text if final size=0
var outer=inner.parentNode; if (outer && outer.parentNode) // remove outer clipping container
{ outer.parentNode.insertBefore(inner,outer); removeNode(outer); }
}
else { // reverse-and-repeat
inner.Cycle--; var t=inner.Start; inner.Start=inner.Stop; inner.Stop=t;
setTimeout("config.macros.animate.morph('"+inner.id+"')",inner.Pause);
}
};
inner.style.display=inner.nodeName.toUpperCase()!="DIV"?"inline":"block"; // show starting content
anim.startAnimating(new Morpher(inner,inner.Duration,p,c));
}
};
//}}}
//{{{
// for backward-compatibility with retired [[ZoomTextPlugin]]
config.macros.zoomText = {
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
// convert old params to new params and invoke new handler
var Text=params[0]!=undefined?params[0]:"";
if (Text.substr(0,1)=="@") Text=store.getTiddlerText(Text.substr(1));
var Wait=params[1]!=undefined?parseInt(params[1]):0;
var Start=params[2]!=undefined?parseInt(params[2]):1;
var Stop=params[3]!=undefined?parseInt(params[3]):100;
var Duration=params[4]!=undefined?parseInt(params[4]):config.animDuration;
var Cycle=params[5]!=undefined?parseInt(params[5]):0
var Pause=params[6]!=undefined?parseInt(params[6]):0;
var newParams=[Text,"fontSize","%0%",Start,Stop,Wait,Duration,Cycle,Pause];
var newParamString=["[["+Text+"]]","fontSize","%0%",Start,Stop,Wait,Duration,Cycle,Pause].join(" ");
return config.macros.animate.handler(place,macroName,newParams,wikifier,newParamString,tiddler)
}
}
//}}}
/***
|Name|AnimationEffectsPlugin|
|Source|http://www.TiddlyTools.com/#AnimationEffectsPlugin|
|Documentation|http://www.TiddlyTools.com/#AnimationEffectsPluginInfo|
|Version|3.1.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.2|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for AnimationEffectsPlugin|
|Status|!BETA - EXPERIMENTAL - UNDER DEVELOPMENT - USE WITH CAUTION|
This plugin defines the {{{<<animate>>}}} macro that can be used to peform simple animations of formatted tiddler content by saving/setting/reseting the values of CSS style attributes at specified times. The macro can also be used to smoothly animate CSS styles that use ''numeric values'', by automatically computing a series of incremental values, ranging from //start// to //stop//, for a specified //duration//, with optional "pause-and-reverse" //cycles// to create repeating animations or continuous loops.
!!!!!Examples
>Please see [[AnimationEffectsSample]] for a live animation example...
!!!!!Usage
<<<
The macro syntax is:
{{{
<<animate type source style format start stop wait duration cycles pause>>
<<animate type source "set" style value wait>>
<<animate source "save" style wait>>
<<animate source "reset" style wait>>
<<animate source "add" classname wait>>
<<animate source "remove" classname wait>>
}}}
> //note: default values are shown in parentheses for //optional// parameters. To ensure the correct order and number of parameters in the macro, you should enter these default values as 'placeholders' when using non-default values for other parameters. Of course, if all the remaining values that follow a non-default parameter are default values, they do not need to be specified, and can be safely omitted.//
where:
* ''//type// (="span")''<br>is either ''div'' or ''span'', and forces the animation container to be a "DIV" or "SPAN" element (i.e., displayed on a separate line, or inline with other content), which can affect how the specified CSS style will be applied. When this param is omitted (which is the general use case), the animation container defaults to the same type as the original content. When using a parameter with "inline" content (see below), a span element is created by default.
* ''//source//''<br>specifies the source content to be animated, and can be one of:
**''"text to display"''<br>inline wiki-syntax content, entered directly as a //quoted// macro parameter. The {{{<<animate>>}}} macro automatically creates a container at the current location and renders the content into it before animating.
**''@~TiddlerName''<br>as above, but retrieves and renders wiki-syntax content from another tiddler.
**''=elementID''<br>indicates a specific DOM element, by assigned ID (e.g., "mainMenu", "displayArea", "sidebar", etc.). The macro will animate this content from it's original location.
**''='' (or ''=here'')<br>indicates the current containing DOM element (i.e, the one in which the {{{<<animate>>}}} macro is embedded. The animation will affect all content that //precedes the macro// within the current container.
* ''"set"'', ''"save"'', ''"reset"'', ''"add"'', ''"remove"''<br>are keywords to indicate how to process the rest of the macro parameters. If ''set'' is used, the remaining parameters are interpeted as //style//, //value//, and //wait//, respectively, and the macro assigns the value to the specified style at the indicated time. The ''save'' and ''reset'' keywords expect only //style// and //wait// parameters following the keyword, where ''save'' retains a copy of the current CSS style value so that you can later use ''reset'' to re-assign the original saved value back to the specified CSS style. The ''add'' and ''remove'' keywords expect and //classname// and //wait// value, and adds/removes the specified classname from the animated element. If no keyword (or ''morph'') is specified, the remaining macro parameters are used to calculate and apply multiple incremental CSS values for smooth animation processing (a.k.a., "morphing").
* ''//style// (="left")''<br>indicates the CSS attribute to be animated (e.g., "left", "marginTop", "width", "fontSize", etc.). Note: if you embed more than one {{{<<animate>>}}} macro in the same container (to simultaneously alter multiple CSS attributes), only the //''last''// animation effect will be applied. To combine several effects, you must precede the //style// parameter value with a "+" symbol for all uses of {{{<<animate>>}}} //except// for the first occurrence within that container, which must //NOT// have a "+" symbol).
* ''//format// (="%0%")''<br>provides a 'text template' for generating CSS attribute values during animation, by using "%0" as a substitution marker to be automatically replaced by the current animation value, combined with a CSS measurement type (e.g., px, em, %, in, cm). For example: "%0px" produces pixel-based values (e.g., "27px", "342.873px", etc.), while "%0%" generates percentage-based relative measurements, (e.g., "-100%", "42%", etc.), and "%0em" results in measurements that are relative to the current font size (em).
* ''//start// (=-100) and //stop// (=0)'' or ''//value// (="")''<br>define the initial and ending values for the CSS attribute being animated. Note that, except when using the alternative ''set'' keyword syntax, these values must be numeric, as they are used to //calculate// the incremental values for each 'tick' of the animation processing.
* ''//wait// (=0)''<br>indicates the number of milliseconds to wait before starting the animation sequence. All animation macros that are embedded in the same content begin simultaneously. The //wait// value allows you to use several effects in sequence, by defining the start of each effect so that it does not begin until the previous one has completed.
* ''//duration// (=2000)''<br>indicates the number of milliseconds during which to animate from the //start// value to the //stop// value.
* ''//cycles// (=1)'' and ''//pause// (=1000)''<br>indicates the number of "reverse-and-repeat" cycles to perform and the pause (in milliseconds) in between each part of the cycle. When cycles=1 (or zero, or is omitted entirely), animation progresses from //start// to //stop// just once. However, if cycles>1, then the animation can pause for a specified amount of time before swapping the //start// and //stop// values and continuing ''//in reverse//''. A value of cycles=2 performs the animation twice, completing a single loop from //start// to //stop// and then back to //start// again, while cycles=3 does 1.5 loops (ending with the //stop// value), and cycles=4 does 2 complete loops (ending with the //start// value), etc. To loop forever, specify a cycle value of "-1".
In addition to the {{{<<animate>>}}} macro, the plugin also defines the following macro for backward-compatibility with the now retired [[ZoomTextPlugin]]:
{{{
<<zoomText "text to display" wait start stop duration cycles pause>>
<<zoomText @TiddlerName wait start stop duration cycles pause>>
}}}
This permits rendering of existing tiddlers that already contain the {{{<<zoomText>>}}} macro without needing to update those tiddlers. However, use of this older syntax is deprecated in favor of the more robust and flexible {{{<<animate>>}}} syntax described above.
<<<
/***
|Name|AnimeJPlugin|
|Source|http://www.TiddlyTools.com/#AnimeJPlugin|
|Documentation|http://www.TiddlyTools.com/#AnimeJPlugin|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|InlineJavacriptPlugin|
|Overrides||
|Description|wrapper for AnimeJ library functions |
|Status|ALPHA/EXPERIMENTAL - SUBJECT TO RAPID CHANGE|
This plugin contains a //compacted// copy of the AnimeJ function library
!!!!!Documentation
<<<
TBD
<<<
!!!!!Usage
<<<
Use [[InlineJavascriptPlugin]] to invoke AnimeJ functions from within tiddler content.
See http://www.codeplex.com/animej for more documentation
<<<
!!!!!Examples (requires InlineJavascriptPlugin)
<<<
<script show>
//TBD
</script>
<<<
!!!!!Revisions
<<<
2009.02.17 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.AnimeJPlugin ={major: 1, minor: 0, revision: 0, date: new Date(2009,2,17)};
//}}}
// // COMPACT LIBRARY
//{{{
/* http://www.codeplex.com/animej */
var __DependenciesManager;function BlueScreen(msg) {if (document.body) {alert('onloaded');var d = document.createElement('div'), k;var values = { 'position': 'absolute', 'top': 0, 'left': 0, 'width': '100%',
'height': '100%', 'background': 'Blue', 'color': 'White', 'fontFamily': 'Fixedsys, monospace' };for (k in values) d.style[k] = values[k];d.innerHTML = 'INTERNAL ERROR: '+msg;d.onclick = function () { document.body.removeChild(d); };document.body.appendChild(d);} else {document.write('<div style="z-index: 1000; position: absolute; left: 0; top: 0; margin: 0; padding: 0; width: 100%; height: 100%; background: Blue; color: White; font-family: Fixedsys, monospace" onclick="this.parentNode.removeChild(this);">INTERNAL ERROR: '+msg+'</div>');}
throw "INTERNAL ERROR: " + msg;}
function RegisterScript(name, version, description) {if (! __DependenciesManager) __DependenciesManager = {};__DependenciesManager[name + ", version=" + version] = description;}
function Require(scripts) {var i, msg = null;for (i = 0; i < scripts.length; i++) {var el = scripts[i], k, strong = typeof(el) != "string";if (strong && !el.Name) {msg = "Invalid require statement!";BlueScreen(msg);return;}
var toadd = strong ? el.Name + ' (version ' + el.Version + ')' : el;for (k in __DependenciesManager)if (!strong) {if (k.indexOf(el) == 0) {toadd = null;break;}} else {if (k.indexOf(el.Name) == 0) {var v = parseInt(k.substring(k.indexOf(", version=") + 10));if (el.Version && el.Version <= v) {toadd = null;break;}}}
if (toadd)if (msg) msg += ", " + toadd;else msg = toadd;}
if (msg) BlueScreen('Missing libraries are <br><br>' + msg);}
RegisterScript('AnimeJ', 1, 'AnimeJ animation library');function AnimeJHeap() {var obj = this;var pos = 0;var left = function(idx) {return (2 * (idx + 1) - 1);}
var right = function (idx) {return (2 * (idx + 1));}
var parent = function (idx) {return (Math.floor((idx + 1) / 2) - 1);}
var swap = function (a, b) {var tmp = obj[a];obj[a] = obj[b];obj[b] = tmp;}
var percolateUp = function (p) {var par = parent(p);while ((p > 0) && (obj[p].Due < obj[par].Due)) {swap(p, par);p = par;par = parent(p);}}
var percolateDown = function (p) {var l = left(p), r = right(p);if (l < pos) {if (r < pos) {if (obj[l].Due > obj[r].Due) {swap(p, r);percolateDown(r);} else {swap(p, l);percolateDown(l);}} else {swap(p, l);percolateDown(l);}} else if (p != pos - 1) {swap(p, pos - 1);percolateUp(p);}}
this.Count = function () { return pos; }
this.Insert = function (el) {this[pos] = el;percolateUp(pos++);}
this.Top = function () {if (pos)return this[0];return null;}
this.Remove = function () {var ret = null;if (!pos) return ret;ret = this[0];percolateDown(0);this[pos--] = null;return ret;}
this.RemoveTask = function (t) {var i, ret = -1;for (i = 0; i < pos; i++)if (this[i].Task == t) {ret = this[i].Due;percolateDown(i);this[pos--] = null;break;}
return ret;}
this.ToString = function () {var i, ret = "";for (i = 0; i < pos; i++)ret += " <i>" + i + ":</i> " + this[i].Due;return ret;}}
function AnimeJTask() {this.OnPause = function () {};this.OnResume = function () {};this.OnStop = function () {};this.DoAction = function (delay) {};}
var AnimeJTimerRunning = null;function AnimeJTimer() {this.Start = new Date();this.Heap = new AnimeJHeap();this.Time = function () {return new Date() - this.Start;}
this.SetAlertMillis = function(what, when) {var exp = when + this.Time();this.Heap.Insert({ 'Due': exp, 'Task': what });if (AnimeJTimerRunning != null && this.Heap.Top().Due == exp) {clearTimeout(AnimeJTimerRunning);AnimeJTimerRunning = null;}
if (AnimeJTimerRunning == null) {AnimeJTimerRunning = true;var tosleep = this.Heap.Top().Due - this.Time();tosleep = 0 > tosleep ? 1 : tosleep;AnimeJTimerRunning = setTimeout('AnimeJTimerTick()', tosleep);}}
this.RemoveTask = function (t) {var v = this.Heap.RemoveTask(t);if (v > -1) {v = v - this.Time();if (v < 0) v = 0;}
return v;}
this.SetAlertDate = function (what, when) {var t = when - this.Start;this.SetAlertMillis(what, t);}}
var AnimeJGlobalTimer = new AnimeJTimer();function AnimeJTimerTick() {var t = AnimeJGlobalTimer;var currt = t.Time() + 10;while (t.Heap.Count() > 0 && currt >= t.Heap.Top().Due) {var el = t.Heap.Remove();el.Task.DoAction(currt - el.Due);}
if (t.Heap.Count() > 0) {currt = t.Time();AnimeJTimerRunning = setTimeout('AnimeJTimerTick()', t.Heap.Top().Due - currt);} else {AnimeJTimerRunning = null;}}
function AnimeJConv() {}
AnimeJConv.Int = function (from, to, v) {return Math.floor(from + (to - from)*v);};AnimeJConv.Float = function (from, to, v) {return from + (to - from)*v;};AnimeJConv.Discrete = function (from, to, v) {return v < 0.5 ? from : to;};AnimeJConv.IntList = function (from, to, v) {var ret = new Array(), i;for (i = 0; i < from.length; i++)ret.push(Math.floor(from[i] + (to[i] - from[i])*v));return ret;};AnimeJConv.FloatList = function (from, to, v) {var ret = new Array(), i;for (i = 0; i < from.length; i++)ret.push(from[i] + (to[i] - from[i])*v);return ret;};function AnimeJLinearInterpolator(obj, prop, steps, conv, prefix, suffix) {var i, last = 0.0;if (steps.length < 2) throw "Invalid steps: length less than 2";if (steps[0].t != 0.0) throw "Invalid steps: timeline must start at 0.0!";if (steps[steps.length - 1].t != 1.0) throw "Invalid steps: timeline must end with 1.0!";for (i = 1; i < steps.length; i++) {if (steps[i].t > 1.0 || steps[i].t < 0.0 || steps[i].t <= last)throw "Invalid steps: invalid value "+(steps[i].t) +"!";last = steps[i].t;}
this.Compute = function (v) {var idx;for (idx = 1; idx < steps.length; idx++)if (steps[idx].t >= v) break;idx--;var val = conv(steps[idx].v, steps[idx + 1].v, (v - steps[idx].t)/(steps[idx + 1].t - steps[idx].t));if (typeof(obj) == 'function')obj(val);else obj[prop] = prefix + val + suffix;}}
function AnimeJInterpolatedTask(interp, ms, stepms) {this.Duration = ms;this.Start = - 1;this.OnPause = function() {if (this.Start != -1)this.Start = AnimeJGlobalTimer.Time() - this.Start;}
this.OnResume = function() {if (this.Start != -1)this.Start = AnimeJGlobalTimer.Time() - this.Start;}
this.OnStop = function() {this.Start = -1;}
this.DoAction = function (d) {if (this.Start == -1)this.Start = AnimeJGlobalTimer.Time();var t = AnimeJGlobalTimer.Time();var v = (t - this.Start) / this.Duration;v = v > 1 ? 1 : v;interp.Compute(v);var t1 = AnimeJGlobalTimer.Time();var next = stepms - d + t1 - t;if (v < 1)AnimeJGlobalTimer.SetAlertMillis(this, next);else this.Start = -1;}}
function AnimeJTimelineCallBackTask(t, prop) {this.OnPause = function () {};this.OnResume = function () {};this.OnStop = function () {};this.DoAction = function (d) {if (t[prop])(t[prop])(d);}}
function AnimeJFunctionCallbackTask(fun) {this.OnPause = function () {};this.OnResume = function () {};this.OnStop = function () {};this.DoAction = function (d) {fun(d);}}
function Timeline() {var Paused = 0;var OnEndCB = null;var Data = {};var Running = false;this.IsPaused = function () {return Paused != 0;}
this.IsRunning = function () {return Running;}
this.InternalOnEnd = function (d) {Runnning = false;if (this['OnEnd']) this['OnEnd'](d);}
this.Run = function () {Running = true;var max = 0;for (v in Data) {var el = Data[v];var startAt = parseInt(v);var i = 0;if (startAt > max) max = startAt;for (i = 0; i < el.length; i++) {if (el[i].Duration && (startAt + el[i].Duration) > max) max = startAt + el[i].Duration;AnimeJGlobalTimer.SetAlertMillis(el[i], startAt);}}
var tm = this;OnEndCB = new AnimeJTimelineCallBackTask(tm, 'InternalOnEnd');AnimeJGlobalTimer.SetAlertMillis(OnEndCB, max);}
this.SetAt = function (timems, task) {if (Data[timems])Data[timems].push(task);else Data[timems] = new Array(task);}
this.Stop = function () {Running = false;Paused = 0;var t = AnimeJGlobalTimer;var tm, i, v;if (OnEndCB != null) {tm = t.RemoveTask(OnEndCB);OnEndCB = null;}
for (v in Data) {var el = Data[v];for (i = 0; i < el.length; i++) {tm = t.RemoveTask(el[i]);el[i].OnStop();}}}
this.Pause = function () {if (Paused) return;Paused = 1;var t = AnimeJGlobalTimer;var tm, i, v;if (OnEndCB != null) {tm = t.RemoveTask(OnEndCB);if (tm > -1)OnEndCB.Paused = tm;else OnEndCB = null;}
for (v in Data) {var el = Data[v];for (i = 0; i < el.length; i++) {tm = t.RemoveTask(el[i]);if (tm == 0) tm = 1;el[i].OnPause();if (tm > -1)el[i].Paused = tm;}}}
this.Resume = function () {if (!Paused) throw "Timeline not paused!";Paused = 0;var t = AnimeJGlobalTimer;var tm, i, v;if (OnEndCB != null) {t.SetAlertMillis(OnEndCB, OnEndCB.Paused);OnEndCB.Paused = 0;}
for (v in Data) {var el = Data[v];for (i = 0; i < el.length; i++) {if (el[i].Paused) {t.SetAlertMillis(el[i], el[i].Paused);el[i].Paused = 0;}
el[i].OnResume();}}}}
var AnimeIsIE = navigator.appVersion.indexOf("MSIE") != -1;function AnimeJInterp() {}
AnimeJInterp.px = function (time, tstep, obj, prop, fromOrSteps, to) {if (typeof(fromOrSteps) == 'number')fromOrSteps = [ { t: 0.0, v: fromOrSteps}, { t: 1.0, v: to } ];return new AnimeJInterpolatedTask(new AnimeJLinearInterpolator(obj, prop, fromOrSteps, AnimeJConv.Int, '', 'px'), time, tstep);};AnimeJInterp.alpha = function (time, tstep, style, fromOrSteps, to) {if (typeof(fromOrSteps) == 'number')fromOrSteps = [ { t: 0.0, v: fromOrSteps}, { t: 1.0, v: to } ];if (AnimeIsIE) {var i;for (i = 0; i < fromOrSteps.length; i++)fromOrSteps[i].v = Math.floor(fromOrSteps[i].v * 100);return new AnimeJInterpolatedTask(new AnimeJLinearInterpolator(style, 'filter', fromOrSteps, AnimeJConv.Int, 'alpha(opacity=', ')'), time, tstep);}
return new AnimeJInterpolatedTask(new AnimeJLinearInterpolator(style, 'opacity', fromOrSteps, AnimeJConv.Float, '', ''), time, tstep);};AnimeJInterp.fiv = function (time, tstep, fun, fromOrSteps, to) {if (to)fromOrSteps = [ { t: 0.0, v: fromOrSteps}, { t: 1.0, v: to } ];return new AnimeJInterpolatedTask(new AnimeJLinearInterpolator(fun, null, fromOrSteps, AnimeJConv.Int, '', ''), time, tstep);};AnimeJInterp.ffv = function (time, tstep, fun, fromOrSteps, to) {if (to)fromOrSteps = [ { t: 0.0, v: fromOrSteps}, { t: 1.0, v: to } ];return new AnimeJInterpolatedTask(new AnimeJLinearInterpolator(fun, null, fromOrSteps, AnimeJConv.Float, '', ''), time, tstep);};AnimeJInterp.fia = function (time, tstep, fun, fromOrSteps, to) {if (to)fromOrSteps = [ { t: 0.0, v: fromOrSteps}, { t: 1.0, v: to } ];return new AnimeJInterpolatedTask(new AnimeJLinearInterpolator(fun, null, fromOrSteps, AnimeJConv.IntList, '', ''), time, tstep);};AnimeJInterp.ffa = function (time, tstep, fun, fromOrSteps, to) {if (to)fromOrSteps = [ { t: 0.0, v: fromOrSteps}, { t: 1.0, v: to } ];return new AnimeJInterpolatedTask(new AnimeJLinearInterpolator(fun, null, fromOrSteps, AnimeJConv.FloatList, '', ''), time, tstep);};
//}}}
<html><input type="text" width="120px"></input></html><script label="<<">
// var txt = btn.parentNode.getElementsByTagName('input')[0];
var txt=place.previousSibling.firstChild;
var t = new Timeline();
if (txt.style.display == 'none') {
txt.style.display = 'inline';
t.SetAt(0, AnimeJInterp.px(1000, 30, txt.style, 'width', 0, 120));
t.SetAt(0, AnimeJInterp.alpha(1000, 30, txt.style, 0.0, 1.0));
t.OnEnd = function () { place.innerHTML = '<<'; };
} else {
t.SetAt(0, AnimeJInterp.px(1000, 30, txt.style, 'width', 120, 0));
t.SetAt(0, AnimeJInterp.alpha(1000, 30, txt.style, 1.0, 0.0));
t.OnEnd = function (d) { place.innerHTML = '>>'; txt.style.display = 'none'; };
}
t.Run();
</script>
/%
|Name|AppendToTiddler|
|Source|http://www.TiddlyTools.com/#AppendToTiddler|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires||
|Overrides||
|Description|append a single-line of input to the end of the current tiddler|
Usage: <<tiddler AppendToTiddler with: datefmt>>
where 'datefmt' is *optional*
%/<html><hide linebreaks><form style="white-space:nowrap" onsubmit="this.btn.onclick(); return false">
<input type="text" name="in" style="width:90%" value="">
<input type="button" name="btn" style="width:8%" value="ok" onclick="
if (!this.form.in.value.length) return false;
if (this.form.in.value==this.form.in.defaultValue) return false;
var here=story.findContainingTiddler(this); if (!here) return false;
var title=here.getAttribute('tiddler');
var tid=store.getTiddler(title);
var now=new Date();
var datefmt=''; if ('$1'!='$'+'1') datefmt='$1 ';
var txt=(tid?tid.text:'')+'\n'+now.formatString(datefmt)+this.form.in.value;
var who=tid?tid.modifier:config.options.txtUserName;
var when=tid?tid.modified:now;
var tags=tid?tid.tags:[];
var fields=tid?tid.fields:{};
store.saveTiddler(title,title,txt,who,when,tags,fields);
"></form></html>
text/plain
.txt .text .js .vbs .asp .cgi .pl
----
text/html
.htm .html .hta .htx .mht
----
text/comma-separated-values
.csv
----
text/javascript
.js
----
text/css
.css
----
text/xml
.xml .xsl .xslt
----
image/gif
.gif
----
image/jpeg
.jpg .jpe .jpeg
----
image/png
.png
----
image/bmp
.bmp
----
image/tiff
.tif .tiff
----
audio/basic
.au .snd
----
audio/wav
.wav
----
audio/x-pn-realaudio
.ra .rm .ram
----
audio/x-midi
.mid .midi
----
audio/mp3
.mp3
----
audio/m3u
.m3u
----
video/x-ms-asf
.asf
----
video/avi
.avi
----
video/mpeg
.mpg .mpeg
----
video/quicktime
.qt .mov .qtvr
----
application/pdf
.pdf
----
application/rtf
.rtf
----
application/postscript
.ai .eps .ps
----
application/wordperfect
.wpd
----
application/mswrite
.wri
----
application/msexcel
.xls .xls3 .xls4 .xls5 .xlw
----
application/msword
.doc
----
application/mspowerpoint
.ppt .pps
----
application/x-director
.swa
----
application/x-shockwave-flash
.swf
----
application/x-zip-compressed
.zip
----
application/x-gzip
.gz
----
application/x-rar-compressed
.rar
----
application/octet-stream
.com .exe .dll .ocx
----
application/java-archive
.jar
[[AttachFilePlugin]] reads binary data from locally-stored files (e.g., images, PDFs, mp3's, etc.) and converts it to base64-encoded text that is stored in tiddlers tagged with<<tag attachment>>. [[AttachFilePluginFormatters]] allows you to use those tiddlers in place of the external path/file references that are normally part of the image and external links wiki syntax.
[[FileDropPlugin]] and [[FileDropPluginConfig]] allow you to quickly create attachment tiddlers simply by dragging files directly from your system's desktop folder display and dropping it onto an open TiddlyWiki document. Text files are automatically created as simple tiddlers, while binary files are automatically encoded and attached.
/***
|Name|AttachFilePlugin|
|Source|http://www.TiddlyTools.com/#AttachFilePlugin|
|Documentation|http://www.TiddlyTools.com/#AttachFilePluginInfo|
|Version|3.9.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|AttachFilePluginFormatters, AttachFileMIMETypes|
|Overrides||
|Description|Store binary files as base64-encoded tiddlers with fallback links for separate local and/or remote file storage|
Store or link binary files (such as jpg, gif, pdf or even mp3) within your TiddlyWiki document and then use them as images or links from within your tiddler content.
> Important note: As of version 3.6.0, in order to //render// images and other binary attachments created with this plugin, you must also install [[AttachFilePluginFormatters]], which extends the behavior of the TiddlyWiki core formatters for embedded images ({{{[img[tooltip|image]]}}}), linked embedded images ({{{[img[tooltip|image][link]]}}}), and external/"pretty" links ({{{[[label|link]]}}}), so that these formatter will process references to attachment tiddlers as if a normal file reference had been provided. |
!!!!!Documentation
>see [[AttachFilePluginInfo]]
!!!!!Inline interface (live)
>see [[AttachFile]] (shadow tiddler)
><<tiddler AttachFile>>
!!!!!Revisions
<<<
2008.07.21 [3.9.0] Fixup for FireFox 3: use HTML with separate text+button control instead of type='file' control
|please see [[AttachFilePluginInfo]] for additional revision details|
2005.07.20 [1.0.0] Initial Release
<<<
!!!!!Code
***/
// // version
//{{{
version.extensions.AttachFilePlugin= {major: 3, minor: 9, revision: 0, date: new Date(2008,7,21)};
// shadow tiddler
config.shadowTiddlers.AttachFile="<<attach inline>>";
// add 'attach' backstage task (insert before built-in 'importTask')
if (config.tasks) { // for TW2.2b or above
config.tasks.attachTask = {
text: "attach",
tooltip: "Attach a binary file as a tiddler",
content: "<<attach inline>>"
}
config.backstageTasks.splice(config.backstageTasks.indexOf("importTask"),0,"attachTask");
}
config.macros.attach = {
// // lingo
//{{{
label: "attach file",
tooltip: "Attach a file to this document",
linkTooltip: "Attachment: ",
typeList: "AttachFileMIMETypes",
titlePrompt: " enter tiddler title...",
MIMEPrompt: "<option value=''>select MIME type...</option><option value='editlist'>[edit list...]</option>",
localPrompt: " enter local path/filename...",
URLPrompt: " enter remote URL...",
tiddlerErr: "Please enter a tiddler title",
sourceErr: "Please enter a source path/filename",
storageErr: "Please select a storage method: embedded, local or remote",
MIMEErr: "Unrecognized file format. Please select a MIME type",
localErr: "Please enter a local path/filename",
URLErr: "Please enter a remote URL",
fileErr: "Invalid path/file or file not found",
sourceReport: "| source file:|{{{%0}}}|\n",
nosourceReport: "| source file:|//none//|\n",
dateReport: "| attached on:|%0 by %1|\n",
notesReport: "| description:|%0|\n",
dataReport: "| embedded:|[[%0|%0]] - {{{type=%1, size=%2 bytes, encoded=%3 bytes}}}|\n",
nodataReport: "| embedded:|//none//|\n",
localReport: "| local file:|/%LOCAL_LINK%/[[%0|%1]]|\n",
nolocalReport: "| local file:|//none//|\n",
URLReport: "| remote link:|/%REMOTE_LINK%/[[%0|%0]]|\n",
noURLReport: "| remote link:|//none//|\n",
imageReport: "image\n<<<\nusage: {{{[img[tooltip|%0]] or [img[tooltip|%0][link]]}}}\n[img[tooltip|%0]]\n<<<\n",
dataBlock: "\n/% DO NOT EDIT BELOW THIS POINT\n---BEGIN_DATA---\n%0;base64,\n%1\n---END_DATA---\n%/",
//}}}
// // macro definition
//{{{
handler:
function(place,macroName,params) {
if (params && !params[0]) { createTiddlyButton(place,this.label,this.tooltip,this.toggleAttachPanel); return; }
var id=params.shift();
this.createAttachPanel(place,id+"_attachPanel",params);
document.getElementById(id+"_attachPanel").style.position="static";
document.getElementById(id+"_attachPanel").style.display="block";
},
//}}}
//{{{
createAttachPanel:
function(place,panel_id,params) {
if (!panel_id || !panel_id.length) var panel_id="_attachPanel";
// remove existing panel (if any)
var panel=document.getElementById(panel_id); if (panel) panel.parentNode.removeChild(panel);
// set styles for this panel
setStylesheet(this.css,"attachPanel");
// create new panel
var title=""; if (params && params[0]) title=params.shift();
var types=this.MIMEPrompt+this.formatListOptions(store.getTiddlerText(this.typeList)); // get MIME types
panel=createTiddlyElement(place,"span",panel_id,"attachPanel",null);
var html=this.html.replace(/%id%/g,panel_id);
html=html.replace(/%title%/g,title);
html=html.replace(/%disabled%/g,title.length?"disabled":"");
html=html.replace(/%IEdisabled%/g,config.browser.isIE?"disabled":"");
html=html.replace(/%types%/g,types);
panel.innerHTML=html;
if (config.browser.isGecko) { // FF3 FIXUP
document.getElementById("attachSource").style.display="none";
document.getElementById("attachFixPanel").style.display="block";
}
return panel;
},
//}}}
//{{{
toggleAttachPanel:
function (e) {
if (!e) var e = window.event;
var parent=resolveTarget(e).parentNode;
var panel = document.getElementById("_attachPanel");
if (panel==undefined || panel.parentNode!=parent)
panel=config.macros.attach.createAttachPanel(parent,"_attachPanel");
var isOpen = panel.style.display=="block";
if(config.options.chkAnimate)
anim.startAnimating(new Slider(panel,!isOpen,e.shiftKey || e.altKey,"none"));
else
panel.style.display = isOpen ? "none" : "block" ;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
return(false);
},
//}}}
//{{{
formatListOptions:
function(text) {
if (!text || !text.trim().length) return "";
// get MIME list content from text
var parts=text.split("\n----\n");
var out="";
for (var p=0; p<parts.length; p++) {
var lines=parts[p].split("\n");
var label=lines.shift(); // 1st line=display text
var value=lines.shift(); // 2nd line=item value
out +='<option value="%1">%0</option>'.format([label,value]);
}
return out;
},
//}}}
// // interface definition
//{{{
css:
".attachPanel { display: none; position:absolute; z-index:10; width:35em; right:105%; top:0em;\
background-color: #eee; color:#000; font-size: 8pt; line-height:110%;\
border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;\
padding: 0.5em; margin:0em; -moz-border-radius:1em;-webkit-border-radius:1em; text-align:left }\
.attachPanel form { display:inline;border:0;padding:0;margin:0; }\
.attachPanel select { width:99%;margin:0px;font-size:8pt;line-height:110%;}\
.attachPanel input { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%}\
.attachPanel textarea { width:98%;margin:0px;height:2em;font-size:8pt;line-height:110%}\
.attachPanel table { width:100%;border:0;margin:0;padding:0;color:inherit; }\
.attachPanel tbody, .attachPanel tr, .attachPanel td { border:0;margin:0;padding:0;color:#000; }\
.attachPanel .box { border:1px solid black; padding:.3em; margin:.3em 0px; background:#f8f8f8; -moz-border-radius:5px;-webkit-border-radius:5px; }\
.attachPanel .chk { width:auto;border:0; }\
.attachPanel .btn { width:auto; }\
.attachPanel .btn2 { width:49%; }\
",
//}}}
//{{{
html:
'<form>\
attach from source file\
<input type="file" id="attachSource" name="source" size="56"\
onChange="config.macros.attach.onChangeSource(this)">\
<div id="attachFixPanel" style="display:none"><!-- FF3 FIXUP -->\
<input type="text" id="attachFixSource" style="width:90%"\
title="Enter a path/file to attach"\
onChange="config.macros.attach.onChangeSource(this);">\
<input type="button" style="width:7%" value="..."\
title="Enter a path/file to attach"\
onClick="config.macros.attach.askForFilename(document.getElementById(\'attachFixSource\'));">\
</div><!--end FF3 FIXUP-->\
<div class="box">\
<table style="border:0"><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
embed data <input type=checkbox class=chk name="useData" %IEdisabled% \
onclick="if (!this.form.MIMEType.value.length)\
this.form.MIMEType.selectedIndex=this.checked?1:0; "> \
</td><td style="border:0">\
<select size=1 name="MIMEType" \
onchange="this.title=this.value; if (this.value==\'editlist\')\
{ this.selectedIndex=this.form.useData.checked?1:0; story.displayTiddler(null,config.macros.attach.typeList,2); return; }">\
<option value=""></option>\
%types%\
</select>\
</td></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
local link <input type=checkbox class=chk name="useLocal"\
onclick="this.form.local.value=this.form.local.defaultValue=this.checked?config.macros.attach.localPrompt:\'\';"> \
</td><td style="border:0">\
<input type=text name="local" size=15 autocomplete=off value=""\
onchange="this.form.useLocal.checked=this.value.length" \
onkeyup="this.form.useLocal.checked=this.value.length" \
onfocus="if (!this.value.length) this.value=config.macros.attach.localPrompt; this.select()">\
</td></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
remote link <input type=checkbox class=chk name="useURL"\
onclick="this.form.URL.value=this.form.URL.defaultValue=this.checked?config.macros.attach.URLPrompt:\'\';\"> \
</td><td style="border:0">\
<input type=text name="URL" size=15 autocomplete=off value=""\
onfocus="if (!this.value.length) this.value=config.macros.attach.URLPrompt; this.select()"\
onchange="this.form.useURL.checked=this.value.length;"\
onkeyup="this.form.useURL.checked=this.value.length;">\
</td></tr></table>\
</div>\
<table style="border:0"><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
attach as \
</td><td style="border:0" colspan=2>\
<input type=text name="tiddlertitle" size=15 autocomplete=off value="%title%"\
onkeyup="if (!this.value.length) { this.value=config.macros.attach.titlePrompt; this.select(); }"\
onfocus="if (!this.value.length) this.value=config.macros.attach.titlePrompt; this.select()" %disabled%>\
</td></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
description \
</td><td style="border:0" colspan=2>\
<input type=text name="notes" size=15 autocomplete=off>\
</td></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
add tags \
</td><td style="border:0">\
<input type=text name="tags" size=15 autocomplete=off value="" onfocus="this.select()">\
</td><td style="width:40%;text-align:right;border:0">\
<input type=button class=btn2 value="attach"\
onclick="config.macros.attach.onClickAttach(this)"><!--\
--><input type=button class=btn2 value="close"\
onclick="var panel=document.getElementById(\'%id%\'); if (panel) panel.parentNode.removeChild(panel);">\
</td></tr></table>\
</form>',
//}}}
// // control processing
//{{{
onChangeSource:
function(here) {
var form=here.form;
var list=form.MIMEType;
var theFilename = here.value;
var theExtension = theFilename.substr(theFilename.lastIndexOf('.')).toLowerCase();
// if theFilename is in current document folder, remove path prefix and use relative reference
var h=document.location.href; folder=getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf("/")+1)));
if (theFilename.substr(0,folder.length)==folder) theFilename='./'+theFilename.substr(folder.length);
else theFilename='file:///'+theFilename; // otherwise, use absolute reference
theFilename=theFilename.replace(/\\/g,"/"); // fixup: change \ to /
form.useLocal.checked = true;
form.local.value = theFilename;
form.useData.checked = !form.useData.disabled;
list.selectedIndex=1;
for (var i=0; i<list.options.length; i++) // find matching MIME type
if (list.options[i].value.indexOf(theExtension)!=-1) { list.selectedIndex = i; break; }
if (!form.tiddlertitle.disabled)
form.tiddlertitle.value=theFilename.substr(theFilename.lastIndexOf('/')+1); // get tiddlername from filename
},
//}}}
//{{{
onClickAttach:
function (here) {
clearMessage();
// get input values
var form=here.form;
var src=form.source; if (config.browser.isGecko) src=document.getElementById("attachFixSource");
var theDate=(new Date()).formatString(config.macros.timeline.dateFormat);
var theSource = src.value!=src.defaultValue?src.value:"";
var theTitle=form.tiddlertitle.value;
var theLocal = form.local.value!=form.local.defaultValue?form.local.value:"";
var theURL = form.URL.value!=form.URL.defaultValue?form.URL.value:"";
var theNotes = form.notes.value;
var theTags = "attachment excludeMissing "+form.tags.value;
var useData=form.useData.checked;
var useLocal=form.useLocal.checked;
var useURL=form.useURL.checked;
var theMIMEType = form.MIMEType.value.length?form.MIMEType.options[form.MIMEType.selectedIndex].text:"";
// validate checkboxes and get filename
if (useData) {
if (theSource.length) { if (!theLocation) var theLocation=theSource; }
else { alert(this.sourceErr); src.focus(); return false; }
}
if (useLocal) {
if (theLocal.length) { if (!theLocation) var theLocation = theLocal; }
else { alert(this.localErr); form.local.focus(); return false; }
}
if (useURL) {
if (theURL.length) { if (!theLocation) var theLocation = theURL; }
else { alert(this.URLErr); form.URL.focus(); return false; }
}
if (!(useData||useLocal||useURL))
{ form.useData.focus(); alert(this.storageErr); return false; }
if (!theLocation)
{ src.focus(); alert(this.sourceErr); return false; }
if (!theTitle || !theTitle.trim().length || theTitle==this.titlePrompt)
{ form.tiddlertitle.focus(); alert(this.tiddlerErr); return false; }
// if not already selected, determine MIME type based on filename extension (if any)
if (useData && !theMIMEType.length && theLocation.lastIndexOf('.')!=-1) {
var theExt = theLocation.substr(theLocation.lastIndexOf('.')).toLowerCase();
var theList=form.MIMEType;
for (var i=0; i<theList.options.length; i++)
if (theList.options[i].value.indexOf(theExt)!=-1)
{ var theMIMEType=theList.options[i].text; theList.selectedIndex=i; break; }
}
// attach the file
return this.createAttachmentTiddler(theSource, theDate, theNotes, theTags, theTitle,
useData, useLocal, useURL, theLocal, theURL, theMIMEType);
},
getMIMEType:
function(src,def) {
var ext = src.substr(src.lastIndexOf('.')).toLowerCase();
var list=store.getTiddlerText(this.typeList);
if (!list || !list.trim().length) return def;
// get MIME list content from tiddler
var parts=list.split("\n----\n");
for (var p=0; p<parts.length; p++) {
var lines=parts[p].split("\n");
var mime=lines.shift(); // 1st line=MIME type
var match=lines.shift(); // 2nd line=matching extensions
if (match.indexOf(ext)!=-1) return mime;
}
return def;
},
createAttachmentTiddler:
function (theSource, theDate, theNotes, theTags, theTitle,
useData, useLocal, useURL, theLocal, theURL, theMIMEType, noshow) {
// encode the data
if (useData) {
if (!theMIMEType.length) {
alert(this.MIMEErr);
form.MIMEType.selectedIndex=1; form.MIMEType.focus();
return false;
}
var theData = this.readFile(theSource); if (!theData) { return false; }
displayMessage('encoding '+theSource);
var theEncoded = this.encodeBase64(theData);
displayMessage('file size='+theData.length+' bytes, encoded size='+theEncoded.length+' bytes');
}
// generate tiddler and refresh
var theText = "";
theText +=theSource.length?this.sourceReport.format([theSource]):this.nosourceReport;
theText +=this.dateReport.format([theDate,config.options.txtUserName]);
theText +=theNotes.length?this.notesReport.format([theNotes]):"";
theText +=useData?this.dataReport.format([theTitle,theMIMEType,theData.length,theEncoded.length]):this.nodataReport;
theText +=useLocal?this.localReport.format([theLocal,theLocal.replace(/\\/g,"/")]):this.nolocalReport;
theText +=useURL?this.URLReport.format([theURL]):this.noURLReport;
theText +=(theMIMEType.substr(0,5)=="image")?this.imageReport.format([theTitle]):"";
theText +=useData?this.dataBlock.format([theMIMEType,theEncoded]):"";
store.saveTiddler(theTitle,theTitle,theText,config.options.txtUserName,new Date(),theTags);
var panel=document.getElementById("attachPanel"); if (panel) panel.style.display="none";
if (!noshow) { story.displayTiddler(null,theTitle); story.refreshTiddler(theTitle,null,true); }
displayMessage('attached "'+theTitle+'"');
return true;
},
//}}}
// // base64 conversion
//{{{
encodeBase64:
function (theData) {
if (!theData) return null;
// encode as base64
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var out="";
var chr1,chr2,chr3="";
var enc1,enc2,enc3,enc4="";
for (var count=0,i=0; i<theData.length; ) {
chr1=theData.charCodeAt(i++);
chr2=theData.charCodeAt(i++);
chr3=theData.charCodeAt(i++);
enc1=chr1 >> 2;
enc2=((chr1 & 3) << 4) | (chr2 >> 4);
enc3=((chr2 & 15) << 2) | (chr3 >> 6);
enc4=chr3 & 63;
if (isNaN(chr2)) enc3=enc4=64;
else if (isNaN(chr3)) enc4=64;
out+=keyStr.charAt(enc1)+keyStr.charAt(enc2)+keyStr.charAt(enc3)+keyStr.charAt(enc4);
chr1=chr2=chr3=enc1=enc2=enc3=enc4="";
count+=4; if (count>60) { out+='\n'; count=0; } // add line break every 60 chars for readability
}
return out;
},
decodeBase64: function(input) {
var out="";
var chr1,chr2,chr3;
var enc1,enc2,enc3,enc4;
var i = 0;
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
input=input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
do {
enc1=keyStr.indexOf(input.charAt(i++));
enc2=keyStr.indexOf(input.charAt(i++));
enc3=keyStr.indexOf(input.charAt(i++));
enc4=keyStr.indexOf(input.charAt(i++));
chr1=(enc1 << 2) | (enc2 >> 4);
chr2=((enc2 & 15) << 4) | (enc3 >> 2);
chr3=((enc3 & 3) << 6) | enc4;
out=out+String.fromCharCode(chr1);
if (enc3!=64) out=out+String.fromCharCode(chr2);
if (enc4!=64) out=out+String.fromCharCode(chr3);
} while (i<input.length);
return out;
},
//}}}
// // I/O functions
//{{{
readFile: // read local BINARY file data
function(filePath) {
if(!window.Components) { return null; }
try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
catch(e) { alert("access denied: "+filePath); return null; }
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
try { file.initWithPath(filePath); } catch(e) { alert("cannot read file - invalid path: "+filePath); return null; }
if (!file.exists()) { alert("cannot read file - not found: "+filePath); return null; }
var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
inputStream.init(file, 0x01, 00004, null);
var bInputStream = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);
bInputStream.setInputStream(inputStream);
return(bInputStream.readBytes(inputStream.available()));
},
//}}}
//{{{
writeFile:
function(filepath,data) {
// TBD: decode base64 and write BINARY data to specified local path/filename
return(false);
},
//}}}
//{{{
askForFilename: // for FF3 fixup
function(target) {
var msg=config.messages.selectFile;
if (target && target.title) msg=target.title; // use target field tooltip (if any) as dialog prompt text
// get local path for current document
var path=getLocalPath(document.location.href);
var p=path.lastIndexOf("/"); if (p==-1) p=path.lastIndexOf("\\"); // Unix or Windows
if (p!=-1) path=path.substr(0,p+1); // remove filename, leave trailing slash
var file=""
var result=window.mozAskForFilename(msg,path,file,true); // FF3 FIXUP ONLY
if (target && result.length) // set target field and trigger handling
{ target.value=result; target.onchange(); }
return result;
}
};
//}}}
//{{{
if (window.mozAskForFilename===undefined) { // also defined by CoreTweaks (for ticket #604)
window.mozAskForFilename=function(msg,path,file,mustExist) {
if(!window.Components) return false;
try {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
picker.init(window, msg, mustExist?nsIFilePicker.modeOpen:nsIFilePicker.modeSave);
var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
thispath.initWithPath(path);
picker.displayDirectory=thispath;
picker.defaultExtension='';
picker.defaultString=file;
picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
if (picker.show()!=nsIFilePicker.returnCancel)
var result=picker.file.persistentDescriptor;
}
catch(ex) { displayMessage(ex.toString()); }
return result;
}
}
//}}}
/***
|Name|AttachFilePluginFormatters|
|Source|http://www.TiddlyTools.com/#AttachFilePluginFormatters|
|Version|3.7.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1.3|
|Type|plugin|
|Requires||
|Overrides|'image' and 'prettyLink' formatters, TiddlyWiki.prototype.getRecursiveTiddlerText|
|Description|run-time library for displaying attachment tiddlers|
This plugin provides "stand-alone" processing for //rendering// attachment tiddlers created by [[AttachFilePlugin]]. Attachment tiddlers are tagged with<<tag attachment>>and contain binary file content (e.g., jpg, gif, pdf, mp3, etc.) that has been stored directly as base64 text-encoded data or can be loaded from external files stored on a local filesystem or remote web server.
NOTE: This plugin does not include the "control panel" and supporting functions needed to //create// new attachment tiddlers. Those features are provided by [[AttachFilePlugin]], which can be installed while building your document, and then safely omitted to reduce the overall file size when you publish your finished document (assuming you don't intend to create any additional attachment tiddlers in that document)
!!!!!Formatters
<<<
This plugin extends the behavior of the following TiddlyWiki core "wikify()" formatters:
* embedded images: {{{[img[tooltip|image]]}}}
* linked embedded images: {{{[img[tooltip|image][link]]}}}
* external/"pretty" links: {{{[[label|link]]}}}
''Please refer to AttachFilePlugin (source: http://www.TiddlyTools.com/#AttachFilePlugin) for additional information.''
<<<
!!!!!Revisions
<<<
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.29 [3.7.0] more code reduction: removed upload handling from AttachFilePlugin (saves ~7K!)
2007.10.28 [3.6.0] removed duplicate formatter code from AttachFilePlugin (saves ~10K!) and updated documentation accordingly. This plugin ([[AttachFilePluginFormatters]]) is now //''required''// in order to display attached images/binary files within tiddler content.
2006.05.20 [3.4.0] through 2007.03.01 [3.5.3] sync with AttachFilePlugin
2006.05.13 [3.2.0] created from AttachFilePlugin v3.2.0
<<<
!!!!!Code
***/
// // version
//{{{
version.extensions.AttachFilePluginFormatters= {major: 3, minor: 7, revision: 0, date: new Date(2007,10,28)};
//}}}
//{{{
if (config.macros.attach==undefined) config.macros.attach= { };
//}}}
//{{{
if (config.macros.attach.isAttachment==undefined) config.macros.attach.isAttachment=function (title) {
var tiddler = store.getTiddler(title);
if (tiddler==undefined || tiddler.tags==undefined) return false;
return (tiddler.tags.indexOf("attachment")!=-1);
}
//}}}
//{{{
// test for local file existence
// Returns true/false without visible error display
// Uses Components for FF and ActiveX FSO object for MSIE
if (config.macros.attach.fileExists==undefined) config.macros.attach.fileExists=function(theFile) {
var found=false;
// DEBUG: alert('testing fileExists('+theFile+')...');
if(window.Components) {
try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
catch(e) { return false; } // security access denied
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
try { file.initWithPath(theFile); }
catch(e) { return false; } // invalid directory
found = file.exists();
}
else { // use ActiveX FSO object for MSIE
var fso = new ActiveXObject("Scripting.FileSystemObject");
found = fso.FileExists(theFile)
}
// DEBUG: alert(theFile+" "+(found?"exists":"not found"));
return found;
}
//}}}
//{{{
if (config.macros.attach.getAttachment==undefined) config.macros.attach.getAttachment=function(title) {
// extract embedded data, local and remote links (if any)
var startmarker="---BEGIN_DATA---\n";
var endmarker="\n---END_DATA---";
var pos=0; var endpos=0;
var text = store.getTiddlerText(title);
var embedded="";
var locallink="";
var remotelink="";
// look for embedded data, convert to data: URI
if ((pos=text.indexOf(startmarker))!=-1 && (endpos=text.indexOf(endmarker))!=-1)
embedded="data:"+(text.substring(pos+startmarker.length,endpos)).replace(/\n/g,'');
if (embedded.length && !config.browser.isIE)
return embedded; // use embedded data if any... except for IE, which doesn't support data URI
// no embedded data... fallback to local/remote reference links...
// look for 'attachment link markers'
if ((pos=text.indexOf("/%LOCAL_LINK%/"))!=-1)
locallink=text.substring(text.indexOf("|",pos)+1,text.indexOf("]]",pos));
if ((pos=text.indexOf("/%REMOTE_LINK%/"))!=-1)
remotelink=text.substring(text.indexOf("|",pos)+1,text.indexOf("]]",pos));
// document is being served remotely... use remote URL (if any) (avoids security alert)
if (remotelink.length && document.location.protocol!="file:")
return remotelink;
// local link only... return link without checking file existence (avoids security alert)
if (locallink.length && !remotelink.length)
return locallink;
// local link, check for file exist... use local link if found
if (locallink.length) {
if (this.fileExists(getLocalPath(locallink))) return locallink;
// maybe local link is relative... add path from current document and try again
var pathPrefix=document.location.href; // get current document path and trim off filename
var slashpos=pathPrefix.lastIndexOf("/"); if (slashpos==-1) slashpos=pathPrefix.lastIndexOf("\\");
if (slashpos!=-1 && slashpos!=pathPrefix.length-1) pathPrefix=pathPrefix.substr(0,slashpos+1);
if (this.fileExists(getLocalPath(pathPrefix+locallink))) return locallink;
}
// no embedded data, no local (or not found), fallback to remote URL (if any)
if (remotelink.length)
return remotelink;
return ""; // attachment URL doesn't resolve
}
//}}}
//{{{
if (config.macros.attach.init_formatters==undefined) config.macros.attach.init_formatters=function() {
if (this.initialized) return;
// find the formatter for "image" and replace the handler
for (var i=0; i<config.formatters.length && config.formatters[i].name!="image"; i++);
if (i<config.formatters.length) config.formatters[i].handler=function(w) {
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) // Simple bracketted link
{
var e = w.output;
if(lookaheadMatch[5])
{
var link = lookaheadMatch[5];
// ELS -------------
var external=config.formatterHelpers.isExternalLink(link);
if (external)
{
if (config.macros.attach.isAttachment(link))
{
e = createExternalLink(w.output,link);
e.href=config.macros.attach.getAttachment(link);
e.title = config.macros.attach.linkTooltip + link;
}
else
e = createExternalLink(w.output,link);
}
else
e = createTiddlyLink(w.output,link,false,null,w.isStatic);
// ELS -------------
addClass(e,"imageLink");
}
var img = createTiddlyElement(e,"img");
if(lookaheadMatch[1])
img.align = "left";
else if(lookaheadMatch[2])
img.align = "right";
if(lookaheadMatch[3])
img.title = lookaheadMatch[3];
img.src = lookaheadMatch[4];
// ELS -------------
if (config.macros.attach.isAttachment(lookaheadMatch[4]))
img.src=config.macros.attach.getAttachment(lookaheadMatch[4]);
// ELS -------------
w.nextMatch = this.lookaheadRegExp.lastIndex;
}
}
//}}}
//{{{
// find the formatter for "prettyLink" and replace the handler
for (var i=0; i<config.formatters.length && config.formatters[i].name!="prettyLink"; i++);
if (i<config.formatters.length) {
config.formatters[i].handler=function(w) {
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var e;
var text = lookaheadMatch[1];
if(lookaheadMatch[3]) {
// Pretty bracketted link
var link = lookaheadMatch[3];
if (config.macros.attach.isAttachment(link)) {
e = createExternalLink(w.output,link);
e.href=config.macros.attach.getAttachment(link);
e.title=config.macros.attach.linkTooltip+link;
}
else e = (!lookaheadMatch[2] && config.formatterHelpers.isExternalLink(link))
? createExternalLink(w.output,link)
: createTiddlyLink(w.output,link,false,null,w.isStatic);
} else {
e = createTiddlyLink(w.output,text,false,null,w.isStatic);
}
createTiddlyText(e,text);
w.nextMatch = this.lookaheadRegExp.lastIndex;
}
}
} // if "prettyLink" formatter found
this.initialized=true;
}
//}}}
//{{{
config.macros.attach.init_formatters(); // load time init
//}}}
//{{{
if (TiddlyWiki.prototype.coreGetRecursiveTiddlerText==undefined) {
TiddlyWiki.prototype.coreGetRecursiveTiddlerText = TiddlyWiki.prototype.getRecursiveTiddlerText;
TiddlyWiki.prototype.getRecursiveTiddlerText = function(title,defaultText,depth) {
return config.macros.attach.isAttachment(title)?
config.macros.attach.getAttachment(title):this.coreGetRecursiveTiddlerText.apply(this,arguments);
}
}
//}}}
| source file|{{{...\images\meow.gif}}}|
| attached on|15 May 2006 by ELSDesignStudios|
| embedded data|[[meow.gif|AttachFileSample]] - {{{type=image/gif, size=3399 bytes, encoded=4602 bytes}}}|
| ~LocalFile|/%LOCAL_LINK%/[[images/meow.gif|images/meow.gif]]|
| ~RemoteLink|/%REMOTE_LINK%/[[http://www.TiddlyTools.com/images/meow.gif|http://www.TiddlyTools.com/images/meow.gif]]|
image
<<<
usage: {{{[img[tooltip|AttachFileSample]] or [img[tooltip|AttachFileSample][link]]}}})
[img[tooltip|AttachFileSample]]
<<<
/% DO NOT EDIT BELOW THIS POINT
---BEGIN_DATA---
image/gif;base64,
R0lGODlhOABQAPcAAAAACAAAEAAICAgICAgLDBAQCAQQGRAIEBgICBAQEBAQGBAY
FBoOEhwUFCEYEBgYGA4cIBkgGyEcHCEhISkYGCkcHCEpHCklIRAgMRkmNSElKSEp
NikeKykpKSExQiE5QjEhJTEpITEpKSkpMSkxISk1KTExITExKSktNTEpMTEpOTEx
MSk5MSkxOSkxQik5PTkrKTkxMTE8KTFCMTExOTExQjE5PTFCPTk3MzlCMTkxQjk5
QkI0MzlGPUg9M01JNi88TTlEUkI8REJCSkZDRFBDQkY/UFA/TjNMUkNOS1JKSkpW
Rj1KWEpKWj9OXEVZZlhMRlVLVVpSUlReUFdSYFVhX1JSa1VfbmBbU11ia2dcV3Fj
XVpldWVkb2tnb3tnbGZ1ZHV6aWVwe3d5c2N4iXN3gntzgHeBiYd2dYWHeoh/jIKL
kJWEfZmUh5CNlJ+VkICPn46XpZiSo5WfoJycnKaemaGcqKWlpZWnraWtqa2qoq2l
rZavvKW4xK2lta2ws/8A/7WcjLWllLWlpbWlrb2tnMatnLWtpbWtrb2trbWttb2t
tbWtvbW1pca1pbW1ra21va21xrW1tbW1vbW1xrW9tb21rb21tb21vb21xr29rb29
tca9sca1vc69rda9ra29wa3GxrW9vbW9xq29zrHGyrPB0rXG1r29vb29xr29zr3G
vb3Gxr3Gzr3G1sa9vcbGtc7GtdbGtcbGvc7GvdbGvd7Gvca9xsa9zsbGxsbGzsbG
1s7DyNbGxtbGzs7G1rjQ2MbO0sbO3sbW1s7Owc7OzsbW3sbe3s7O1s7W0tbQx+HU
zNDQ29bW1tvb1ufa1sPW6dDW4dbW3trY4sni7dbk797e3tbx9N7n3ufe3t7e597n
597i7+fe597s9N73++fn3ufn5+fn7+fv5+fv7+/e5+/r4vfr4ufn9+fv9+fv/+/n
7+/v8/Pz7/fv9+/v/+f3++f//+/39+/3/+//9+////f37/f39/f3//f/9/f////3
7//39//3////9////yH5BAEAAIAALAAAAAA4AFAAQAj+AAEJHEiwoMGDCBMqXIiw
iA8tXbxIgXHhgY+FICSIiCFFihIeXRgm9OKlDJMqYs506UIDRIUKD7w8kLCiAw0q
0ao8WCFhwgQqDx7E+EJHm0gpUaI0ibKDBo0dXeakazEkxYUOGjRMSQOmQw874eR9
IHNPXrFba5Y8CLNDyYULGlZQRVjtzJCmTnew2AGp2j19gAGTC6ctnLvDZfWR07Aj
CJAd4fTduxctFapbiDKTQ7gjSZcsT6PQqLmCxhA78v4GnuxOHuGzeei8kVLkh5I1
b9y80XPp0q1s+lK7E3eQjSIvbqJAEiPGjR0/c9REqyavtTx9rVtn09asmJsvbMb+
uLlcrFn3YsqsiRM33M3CDlkUsWMnT978cM206Y/WjH+187cEGOArqKCiCCJ00DEH
HXXkIdJBEgQVlEsS1iThAwlg+EAXcNgBySiQQILKJWOM8YYy2Tyo4oqA5HELMtxx
VwyLNA5UxAUxxPBWjTjGIIIWNSKUhhddUFFFU0O89BZjQ9DQwYUPVKABCEJg8cYZ
K5aRxRNM0JDCCimkQMUONXUAwlVOKbGDGHhAMEczgemjTV2jXeCTBqZFoZASVDDR
xGildTbHX3zUgJeTZ0Cimj5kBLHDEEM0IU59cd6TDmHm7WFQNHDAwcVoT5m2Qg2t
AJPYau6wY01/2ohTjDb+Z91hhiK3FMiILnkcWIw1iLlz0BuPquHEFaDWtEMVclyX
Wpz1pUNONdKkkkoWyEGSqyKXvYJeNtmEo6pRCEkyaX3ykMPOYOWSw41+2rDTGjnd
NoMMMsXoUkw05SFzXnlnFaiIikpOIIEUbrzaSit+RPFWByK4ocoordzC74iKKHLG
Fmm4kQciQSIkgQQIIEAAAQ+Q/IDIIieQAAFROPcHI9heUodh2ujT8c0CzcEdt8Ph
7DONGgwxxs+A7BADEUT4SOMEMWyBBRYiEA2ID16oYYYZDsXwQGNOMHGFFUz4ucMF
ND2qRBdmeDEE0Uq0IccWSuDQwdwXXrBCkxVFKOH+VVB8UceMNHohxhVNipDCEBqk
oIGUTu70AA4P3PUEYG6cEQXiM0lwwRBryKNiF1dcwYQQDK+wQxZijGYmnk+tsEIV
GrgTZ6VniMHUCHZ3EAWQCWlRxe+X47BCy8UEc08GcmfVwVUxLDHFECPoE01TTWhj
TRQimBBDEW64QUYTZczBhBcJCTFEFKODSkMUZcAJWDWMjDJHGW4089df3DiRBRDg
wzE7YPLgji5uIQmEzIMaeHgU+nbwqCaEaFEAXI82rqOav8gDLgOzjj5c9YpbXEIR
2bjHLQ5yBjdw4QxjGs0OOvA6MQSjGrNLjX2akQ1U0KEMXlACDYh0uS3M4Q3+CeoA
HbKBmHuE4yBJ6EEXUveomiBuCKhwA3AqOJmypIMb+ILEH1ChhTXoIUEbqwMiXsEL
ZThjOOEgB8cO4gYqKOEMDNxhFKjQBFmFw4IAZM25uJOKMWyhi35gxFk6WAxnqOcw
5wKcQdAgJz84shrVcIMfRpEOSMqjGtGoTnVSJY78dIcRf2ADFPwgsbM0Q2LmaRVm
GNKGYmzSPvYxFzsqOZ12dSsbACrlq85Sq1sQ6EBrfBAReHI1baTjUuGIhjZ0UZkC
3cI89CqPeQrkBzq4IQ1nWMOCCsijoPhgBUKoQstokJUJQOkBSlADJVqRimKgghEw
e4MW0KCxZvisIif+QwCUMnShkD2ABmaQAyQoMYoCXYINdCgGcKRmEAkRQAErI4DK
giIHP/wBEoy4hDvN0wxfMXRFo7CXNYh4j492TBG7VJVJV1oQKDBUCzi6WZQuUAai
+UAEPvDRBWikEaTxIGo/EwIP/igFH0hARZoTwRC+8AUtFEFqPlCCFryghZtSRE8H
6cIOHnABH0iBWl4wwxGgupIiKUEIPqjAqKhihSY4igYjMGcHUrCDKIS1hFKTAlVF
AwIq1W19NMCnhCRQgRBAAQ28SIPP1nCGNBTDaXfZQQoq8LGgYAVSILjQBC6wAyEQ
AQ11SFGNuvC7P+2ACXO4i+kipNYHdIBMppn+hxteRyYqCEwCOJDCHDyqIixoQQxu
leyXojA3rFxgBK57ixcmcNozAOYeeAjCGWZiN7hM4AmjUFEVmpCFJrjuSxEhE1ZA
YLq7KQFS0RjU/+5xhjI0YQcauEBesKoQM2QBUp113dzm4CjFZaVM8RWCGwA4u3sA
owmq1cAE8GQF+iJECXNkwg6E11kmuCEdGSATCLISlyqAwXkQSI0TuACHdBTjDh0A
gwmw0EAyiWElCilCEvDrlKfsoAzC0Ecc9uI6DXDVxxPwwgjuAQc8NSEa3UiDMngh
u3v8oXZ3QIYX/KCQIdCxKYGiQhei8dw5tHEIXqjCHGAImHR8QAhAuEL+FsrwP8E0
QxdwVogC71JjIXShFdcJDH6sUQxFQJAccHCvE87Qh0WVJRrhCJCBFEKNK0yYgZ3N
wgrcAIl0zK414qAPAPPsXQvBSR7TrNiBJKGPNyAkGsbgA1NcxwLXuQEPwrA0s9wR
Dms8N1XuOOYQJLCF/ESDPwOsVR7glCoSliEOZWCgapNwJDm0AoKSqc49FEGFMtyh
VqhIWArWoAgF5WEPLmqDfGTXM4M8oQxXSF2kxpSFHbTADX/wS6XIBatmSKILQzAc
pMIkhTSo4Q1pGGM2NqmYg1xhd2sYTQqcdAEqJMENmSywJtnBnVsoopomagMQGVSH
QVziFc1AETn+qmNPg1CBCkFwQxC+RKa71bUMsnvuZDRZrmog45138HKu6FCxzGhr
VdkQRzhEexAiZRMFe2nSClB3B21AsIrycNav34lDN9wiDwW6TBmdEQ720NoaCTmD
GqgghnbvQA7ppt8twnKq+rwLktHIgxbaAIU1+AEVxSgGL3hRSF5tkFt3QEgsdOyG
O1zUDWVgxK/1lQ53jbwsnNzOKf2giDdAgQ54zzu/aLgePi9kMqZIRzBGMYpfV6Px
laxGu7BjH3FkwxqrwvYYftDO7jxTl2dBRBsYcongkKtcs4w63AszmGaIA1ZnyTtH
zaN5iQVIEXpwj0iw4Abr1OdcFKcPu/T+I/lc8rJftapYbOrAItNhQRHyyLS5CMOf
fb0qGvqqV949WDE63MEN2qRDbGgUg+WtQARbdnr/cUq6wAg5NwfK1H7TdAl+kAd5
4AYYswYJ8gpBQllcNTdj4AWMEAxyAAE+JiFKIB6jcAvBUC8jAjNugAUmQgfBVCNB
AVsLVwVZwAQPYE5Q8hZ/MAqM0AonqAiDoAXioQdEFyTnVIRBoTIJoAAg0AVyYAeR
ACIjgghh8AaoMFI+gyEhgwAJoE9QQgBaqAAvWAaBdBmXcQd1ACdl8VE6kk8ZsoVJ
CFEJMGl2MAdzADOv8AYdpQ+8wFIDUTIj44VBAQgeQlC1ogvNgAouykAHFMiHCkEJ
qtAK0rQqjKgipWcNvyE7k6gip8QOXTeEmcgQbAAI3VByNBIQAAA7
---END_DATA---
%/
| source file|{{{...images\meow2.jpg}}}|
| attached on|15 May 2006 by ELSDesignStudios|
| embedded data|//none//|
| local link|/%LOCAL_LINK%/[[images/meow2.jpg|images/meow2.jpg]]|
| remote link|/%REMOTE_LINK%/[[http://www.TiddlyTools.com/images/meow2.jpg|http://www.TiddlyTools.com/images/meow2.jpg]]|
image
<<<
usage: {{{[img[tooltip|AttachFileSample2]] or [img[tooltip|AttachFileSample2][link]]}}})
[img[tooltip|AttachFileSample2]]
<<<
This document began life as a "basics" document from [[TiddlyTools|http://www.TiddlyTools.com]]
<br>^^~TiddlyWiki v<<version>> plus BasicsPackage^^
^^@@font-size:80%;{{block{
''//a [[TiddlyTools|http://www.TiddlyTools.com]] ~QuickStart™ document. All rights retained.//''}}}@@^^
/%
|Description|enter FAQ list item text here|
%/
{{small{
__enter FAQ display title text here__
enter FAQ content here
}}}
<!--{{{-->
<!--
|Name|BookmarkViewTemplate|
|Source|http://www.TiddlyTools.com/#BookmarkViewTemplate|
|Version||
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands, WikifyPlugin, TaggedTemplateTweak|
|Overrides||
|Description|custom template used to display tiddlers tagged with "Bookmark"|
Usage:
Create a tiddler and enter URL, description and author using a 'slice table':
|''URL:''|Enter a URL|
|''Description:''|enter a description|
|''Author:''|enter author/moderator info|
Tag the tiddler with "bookmark" (or "Bookmark")
-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></span>
<div class='title' macro='view title'></div>
<span class='subtitle'>
<span style='white-space:nowrap' macro='view modified date [[DDD, MMM DDth YYYY]]'></span>
</span>
<div class='tagClear'></div>
<div class='viewer'>
<div class='floatleft' macro='wikify "{{big{[[%0|%1]]}}}<br>" here::Description here::URL'></div>
<div class='toolbar'>
<a class='button' href='javascript:;'
onclick='window.history.go(-1);' title='go back one page'>back</a>
<a class='button' href='javascript:;'
onclick='window.history.go(+1);' title='go foward one page'>forward</a>
<a class='button' href='javascript:;'
onclick='var f=this.parentNode.parentNode.getElementsByTagName("iframe")[0];
f.src=f.src'
title='reload current page'>reload</a>
<a class='button' href='javascript:;'
onclick='var f=this.parentNode.parentNode.getElementsByTagName("iframe")[0];
var w=prompt("Enter a new frame width (use px, em, cm, in, or %)","100%");
if (!w||!w.length) return; if (!w.replace(/[0-9]*/,"").length) w+="px";
f.style.width=w;'
title='set frame width'>width</a>
<a class='button' href='javascript:;'
onclick='var f=this.parentNode.parentNode.getElementsByTagName("iframe")[0];
var h=prompt("Enter a new frame height (use px, em, cm, or in)","500");
if (!h||!h.length) return; if (!h.replace(/[0-9]*/,"").length) h+="px";
f.style.height=h;'
title='set frame height'>height</a>
<a class='button' href='javascript:;'
onclick='var f=this.parentNode.parentNode.getElementsByTagName("iframe")[0];
var show=f.style.display=="none";
f.style.display=show?"block":"none";
this.innerHTML=show?"hide":"show";'
title="toggle display of this frame (but DON'T reload content)">hide</a>
</div><div class='tagClear'
macro='wikify [[<html><iframe src="%0" height="500" width="100%" style="background:#fff"></iframe></html>]] here::URL'>
</div>
<div macro='view text wikified'></div>
</div>
<span macro="tiddler SolidTiddlerBorder" style='display:none'></span>
<!--}}}-->
/%
|Name|BreadcrumbsCommand|
|Source|http://www.TiddlyTools.com/#BreadcrumbsCommand|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|BreadcrumbsPlugin|
|Overrides||
|Description|"crumbs" command displays current breadcrumbs list in a popup|
%/<html><hide linebreaks><a href="javascript:;" class="TiddlyLink" title="tiddlers viewed during this session"
onclick="var p=Popup.create(this); if (!p) return;
var d=createTiddlyElement(p,'div');
d.style.whiteSpace='normal'; d.style.width='auto'; d.style.padding='2px';
wikify('\<\<breadcrumbs [[\<html\>\<hr\>\</html\>]] [[<br>]]\>\>',d);
Popup.show(p,false); event.cancelBubble = true; if (event.stopPropagation) event.stopPropagation();
return(false);"
>crumbs</a></html>
/***
|Name|BreadcrumbsPlugin|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#BreadcrumbsPlugin|
|Documentation|http://www.TiddlyTools.com/#BreadcrumbsPluginInfo|
|Version|2.0.0|
|License|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.displayTiddler,TiddlyWiki.prototype.deleteTiddler|
|Options|##Configuration|
|Description|list/jump to tiddlers viewed during this session plus "back" button/macro|
This plugin provides a list of links to all tiddlers opened during the session, creating a "trail of breadcrumbs" from one tiddler to the next, allowing you to quickly navigate to any previously viewed tiddler, or select 'home' to reset the display to the initial set of tiddlers that were open at the start of the session (i.e., when the document was loaded into the browser).
!!!!!Documentation
<<<
see [[BreadcrumbsPluginInfo]]
<<<
!!!!!Configuration
<<<
<<option chkCreateDefaultBreadcrumbs>> automatically create breadcrumbs display (if needed)
<<option chkShowBreadcrumbs>> show/hide breadcrumbs display
<<option chkReorderBreadcrumbs>> re-order breadcrumbs when visiting a previously viewed tiddler
<<option chkBreadcrumbsHideHomeLink>> omit 'Home' link from breadcrumbs display
<<option chkShowStartupBreadcrumbs>> show breadcrumbs for 'startup' tiddlers
<<option chkBreadcrumbsReverse>> show breadcrumbs in reverse order (most recent first)
<<option chkBreadcrumbsLimit>> limit breadcrumbs display to {{twochar{<<option txtBreadcrumbsLimit>>}}} items
<<option chkBreadcrumbsLimitOpenTiddlers>> limit open tiddlers to {{twochar{<<option txtBreadcrumbsLimitOpenTiddlers>>}}} items
<<<
!!!!!Revisions
<<<
2008.05.01 [2.0.0] added 'limit open tiddlers' feature (with safety check for tiddler in edit mode)
| Please see [[BreadcrumbsPluginInfo]] for previous revision details |
2006.02.01 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.BreadcrumbsPlugin= {major: 2, minor: 0, revision: 0, date: new Date("May 1, 2008")};
var co=config.options; // abbreviation
// show/hide display option (default is to SHOW breadcrumbs)
if (co.chkShowBreadcrumbs===undefined) co.chkShowBreadcrumbs=true;
// REORDER breadcrumbs when visiting previously viewed tiddler (default)
if (co.chkReorderBreadcrumbs===undefined) co.chkReorderBreadcrumbs=true;
// create default breadcrumbs display as needed (default is to CREATE)
if (co.chkCreateDefaultBreadcrumbs===undefined) co.chkCreateDefaultBreadcrumbs=true;
// show breadcrumbs for 'startup' tiddlers (default is FALSE = only show crumbs for tiddlers opened after startup)
if (co.chkShowStartupBreadcrumbs===undefined) co.chkShowStartupBreadcrumbs=false;
// show crumbs in reverse order (most recent first)
if (co.chkBreadcrumbsReverse===undefined) co.chkBreadcrumbsReverse=false;
// limit number of crumbs displayed
if (co.chkBreadcrumbsLimit===undefined) co.chkBreadcrumbsLimit=false;
if (co.txtBreadcrumbsLimit===undefined) co.txtBreadcrumbsLimit=5;
// limit number of open tiddlers
if (co.chkBreadcrumbsLimitOpenTiddlers===undefined) co.chkBreadcrumbsLimitOpenTiddlers=false;
if (co.txtBreadcrumbsLimitOpenTiddlers===undefined) co.txtBreadcrumbsLimitOpenTiddlers=3;
// omit home link from breadcrumbs display
if (co.chkBreadcrumbsHideHomeLink===undefined) co.chkBreadcrumbsHideHomeLink=false;
config.macros.breadcrumbs = {
crumbs: [], // the list of current breadcrumbs
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var area=createTiddlyElement(place,"span",null,"breadCrumbs",null);
area.setAttribute("homeSep",params[0]?params[0]:this.homeSeparator); // custom home separator
area.setAttribute("crumbSep",params[1]?params[1]:this.crumbSeparator); // custom crumb separator
this.render(area);
},
add: function (title) {
var thisCrumb = title;
var ind = this.crumbs.indexOf(thisCrumb);
if(ind === -1)
this.crumbs.push(thisCrumb);
else if (config.options.chkReorderBreadcrumbs)
this.crumbs.push(this.crumbs.splice(ind,1)[0]); // reorder crumbs
else
this.crumbs=this.crumbs.slice(0,ind+1); // trim crumbs
if (config.options.chkBreadcrumbsLimitOpenTiddlers)
this.limitOpenTiddlers();
this.refresh();
return false;
},
getAreas: function() {
var crumbAreas=[];
// find all DIVs with classname=="breadCrumbs"
// Note: use try/catch to avoid "Bad NPObject as private data" fatal error caused when
// some versions of embedded QuickTime player element is accessed by hasClass() function.
var all=document.getElementsByTagName("*");
for (var i=0; i<all.length; i++)
try{ if (hasClass(all[i],"breadCrumbs")) crumbAreas.push(all[i]); } catch(e) {;}
// find single DIV w/fixed ID (backward compatibility)
var byID=document.getElementById("breadCrumbs")
if (byID && !hasClass(byID,"breadCrumbs")) crumbAreas.push(byID);
if (!crumbAreas.length && config.options.chkCreateDefaultBreadcrumbs) {
// no existing crumbs display areas... create one...
var defaultArea = createTiddlyElement(null,"span",null,"breadCrumbs",null);
defaultArea.style.display= "none";
var targetArea= document.getElementById("tiddlerDisplay");
targetArea.parentNode.insertBefore(defaultArea,targetArea);
crumbAreas.push(defaultArea);
}
return crumbAreas;
},
refresh: function() {
var crumbAreas=this.getAreas();
for (var i=0; i<crumbAreas.length; i++) {
crumbAreas[i].style.display = config.options.chkShowBreadcrumbs?"block":"none";
removeChildren(crumbAreas[i]);
this.render(crumbAreas[i]);
}
},
render: function(here) {
var out=""
var homeSep=here.getAttribute("homeSep"); if (!homeSep) homeSep=this.homeSeparator;
var crumbSep=here.getAttribute("crumbSep"); if (!crumbSep) crumbSep=this.crumbSeparator;
if (!config.options.chkBreadcrumbsHideHomeLink) {
createTiddlyButton(here,"Home",null,this.home,"tiddlyLink tiddlyLinkExisting");
out+=homeSep;
}
for (c=0; c<this.crumbs.length; c++) // remove non-existing tiddlers from crumbs
if (!store.tiddlerExists(this.crumbs[c]) && !store.isShadowTiddler(this.crumbs[c]))
this.crumbs.splice(c,1);
var count=this.crumbs.length;
if (config.options.chkBreadcrumbsLimit && config.options.txtBreadcrumbsLimit<count)
count=config.options.txtBreadcrumbsLimit;
var list=[];
for (c=this.crumbs.length-count; c<this.crumbs.length; c++) list.push('[['+this.crumbs[c]+']]');
if (config.options.chkBreadcrumbsReverse) list.reverse();
out+=list.join(crumbSep);
wikify(out,here);
},
home: function() {
story.closeAllTiddlers();
restart();
config.macros.breadcrumbs.crumbs = [];
var crumbAreas=config.macros.breadcrumbs.getAreas();
for (var i=0; i<crumbAreas.length; i++) crumbAreas[i].style.display = "none";
return false;
},
limitOpenTiddlers: function() {
var limit=config.options.txtBreadcrumbsLimitOpenTiddlers; if (limit<1) limit=1;
for (c=this.crumbs.length-1; c>=0; c--) {
var tid=this.crumbs[c];
var elem=document.getElementById(story.idPrefix+tid);
if (elem) { // tiddler is displayed
if (limit <=0) { // display limit has been reached
if (elem.getAttribute("dirty")=="true") { // tiddler is being edited
var msg="'"+tid+"' is currently being edited.\n\n";
msg+="Press OK to save and close this tiddler\nor press Cancel to leave it opened";
if (confirm(msg)) { story.saveTiddler(tid); story.closeTiddler(tid); }
}
else
story.closeTiddler(this.crumbs[c]);
}
limit--;
}
}
}
};
if (config.macros.breadcrumbs.homeSeparator==undefined) // note: not a cookie
config.macros.breadcrumbs.homeSeparator=" | ";
if (config.macros.breadcrumbs.crumbSeparator==undefined) // note: not a cookie
config.macros.breadcrumbs.crumbSeparator=" > ";
config.commands.previousTiddler = {
text: 'back',
tooltip: 'view the previous tiddler',
hideReadOnly: false,
dateFormat: 'DDD, MMM DDth YYYY hh:0mm:0ss',
handler: function(event,src,title) {
var here=story.findContainingTiddler(src); if (!here) return;
var crumbs=config.macros.breadcrumbs.crumbs;
if (crumbs.length>1) {
var crumb=crumbs[crumbs.length-2];
story.displayTiddler(here,crumb);
}
else
config.macros.breadcrumbs.home();
return false;
}
};
config.macros.previousTiddler= {
label: 'back',
prompt: 'view the previous tiddler',
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var label=params.shift(); if (!label) label=this.label;
var prompt=params.shift(); if (!prompt) prompt=this.prompt;
createTiddlyButton(place,label,prompt,function() {
var crumbs=config.macros.breadcrumbs.crumbs;
if (crumbs.length>1) {
var crumb=crumbs[crumbs.length-2];
story.displayTiddler(place,crumb);
}
else
config.macros.breadcrumbs.home();
});
}
}
// hijack story.displayTiddler() so crumbs can be refreshed when a tiddler is displayed
if (Story.prototype.breadCrumbs_coreDisplayTiddler==undefined)
Story.prototype.breadCrumbs_coreDisplayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler,template,animate,slowly)
{
var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
this.breadCrumbs_coreDisplayTiddler.apply(this,arguments);
// if not displaying tiddler during document startup, then add it to the breadcrumbs
// note: 'startingUp' flag is a global, set/reset by the core init() function
if (!startingUp || config.options.chkShowStartupBreadcrumbs) config.macros.breadcrumbs.add(title);
}
// hijack store.removeTiddler() so crumbs can be refreshed when a tiddler is deleted
if (TiddlyWiki.prototype.breadCrumbs_coreRemoveTiddler==undefined)
TiddlyWiki.prototype.breadCrumbs_coreRemoveTiddler=TiddlyWiki.prototype.removeTiddler;
TiddlyWiki.prototype.removeTiddler= function(title)
{
this.breadCrumbs_coreRemoveTiddler.apply(this,arguments);
config.macros.breadcrumbs.refresh();
}
//}}}
/***
|Name|BreadcrumbsPluginInfo|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#BreadcrumbsPlugin|
|Documentation|http://www.TiddlyTools.com/#BreadcrumbsPluginInfo|
|Version|2.0.0|
|License|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.displayTiddler,TiddlyWiki.prototype.removeTiddler|
|Description|Documentation for BreadcrumbsPlugin|
This plugin provides a list of links to all tiddlers opened during the session, creating a "trail of breadcrumbs" from one tiddler to the next, allowing you to quickly navigate to any previously viewed tiddler, or select 'home' to reset the display to the initial set of tiddlers that were open at the start of the session (i.e., when the document was loaded into the browser).
!!!!!Usage
<<<
syntax:
{{{
<<breadcrumbs homeSeparator crumbSeparator>>
}}}
By default, the breadcrumbs are displayed as a continuous, //horizontal// word-wrapped line of text, using default character sequences for ''homeSeparator'' (" | ") and ''crumbSeparator'' (" > "). The //optional// ''homeSeparator'' and ''crumbSeparator'' macro parameters allow you to specify alternative separators. For example, to display the breadcrumbs //vertically// (in a stack, rather than a row), set the separator values to use {{{[[<br>]]}}}... and, to display a horizontal line as the home separator, use {{{[[<html><hr></html>]]}}}.
<<<
!!!!!Examples:
<<<
{{{
<<breadcrumbs>>
}}}
<<breadcrumbs>>
{{{
<<breadcrumbs [[<html><hr></html>]] [[<br>]]>>
}}}
<<breadcrumbs [[<html><hr></html>]] [[<br>]]>>
<<<
!!!!!Customization
<<<
Using CSS and a few of the plugin configuration options (see below), you can make the breadcrumbs display resemble browser tabs by adding the following to your [[StyleSheet]]:
{{{
.breadCrumbs { border-bottom:1px solid; }
.breadCrumbs a {
border: 1px solid; padding: 0px 1em;
-moz-border-radius-topleft:.5em; -moz-border-radius-topright:.5em;
-webkit-border-top-left-radius:.5em; -webkit-border-top-right-radius:.5em;
}
}}}
and this in [[ConfigTweaks]] (tagged with systemConfig, of course):
{{{
config.options.chkShowStartupBreadcrumbs=true;
config.options.chkBreadcrumbsLimitOpenTiddlers=true;
config.options.txtBreadcrumbsLimitOpenTiddlers=1;
config.macros.breadcrumbs.homeSeparator=" ";
config.macros.breadcrumbs.crumbSeparator=" ";
}}}
<<<
!!!!!Configuration
<<<
__''display placement:''__
<<option chkCreateDefaultBreadcrumbs>> automatically create breadcrumbs display (if needed)
{{{<<option chkCreateDefaultBreadcrumbs>>}}}
>By default, the plugin automatically creates the "breadCrumbs" display element at the top of the story column, just above the tiddlerDisplay area. To manually control the display and placement of the breadcrumbs display, you can define a DIV with class="breadCrumbs" in a custom [[PageTemplate]] or embed the {{{<<breadcrumbs>>}}} macro in specific tiddler content.
>
>For example, to add the breadcrumbs below the mainMenu, change this:
{{{
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
}}}
>to:
{{{
<div id='mainMenu'>
<div refresh='content' tiddler='MainMenu'></div>
<div id='breadCrumbs' class='breadCrumbs'></div>
</div>
}}}
>You can also block automatic creation of the breadcrumbs display by setting
{{{
config.options.chkCreateDefaultBreadcrumbs=false;
}}}
>in a [[CookieJar]]/[[ConfigTweaks]] plugin tiddler.
__''other settings:''__
<<option chkShowBreadcrumbs>> show/hide breadcrumbs display
{{{<<option chkShowBreadcrumbs>>}}}
>This checkbox toggles the visibility of the breadcrumbs display. However, the display is not updated until the next crumb is added (or a previous crumb is clicked on). For immediate effect, the [[ToggleBreadcrumbs]] script uses [[InlineJavascriptPlugin]] to synchronize the checkbox setting and the breadcrumbs display.
<<option chkReorderBreadcrumbs>> re-order breadcrumbs when visiting a previously viewed tiddler
{{{<<option chkReorderBreadcrumbs>>}}}
>When visiting a previously viewed tiddler, the title of the most-recently displayed tiddler is simply moved to the end of the list and individual breadcrumbs are not removed from the list unless the underlying tiddler is deleted. When ''re-ordering'' is disabled, the breadcrumbs list is ''trimmed'' so that all crumbs following that tiddler are removed from the list.
<<option chkBreadcrumbsHideHomeLink>> omit 'Home' link from breadcrumbs display
{{{<<option chkBreadcrumbsHideHomeLink>>}}}
>Enabling this option suppresses the automatic display of the "Home" link (and home separator). To manually add the home link elsewhere in your document, use the following HTML:
{{{
<html><a href="javascript:;" onclick="config.macros.breadcrumbs.home()">home</a></html>
}}}
<<option chkShowStartupBreadcrumbs>> show breadcrumbs for 'startup' tiddlers
{{{<<option chkShowStartupBreadcrumbs>>}}}
>Breadcrumbs are usually only added for tiddlers that are opened after the document has been loaded, and not for tiddlers displayed during initial startup (e.g., [[DefaultTiddlers]]). Enabling this option displays breadcrumbs for all viewed tiddlers, regardless of when they are opened.
<<option chkBreadcrumbsReverse>> show breadcrumbs in reverse order
{{{<<option chkBreadcrumbsReverse>>}}}
>As tiddlers are displayed, breadcrumbs are usually added to the //end// of the list. Enabling this option displays breadcrumbs in reverse order, so that the most recently visited tiddlers are listed first.
<<option chkBreadcrumbsLimit>> limit breadcrumbs display to {{twochar{<<option txtBreadcrumbsLimit>>}}} items
{{{<<option chkBreadcrumbsLimit>>}}} and {{{<<option txtBreadcrumbsLimit>>}}}
>By default, breadcrumbs are displayed for all tiddlers that have been visited (unless the list is being 'trimmed' by disabling the chkReorderBreadcrumbs option above). Enabling this option limits the display of the list to a maximum specified number of breadcrumbs.
<<option chkBreadcrumbsLimitOpenTiddlers>> limit open tiddlers to {{twochar{<<option txtBreadcrumbsLimitOpenTiddlers>>}}} items
{{{<<option chkBreadcrumbsLimitOpenTiddlers>>}}} and {{{<<option txtBreadcrumbsLimitOpenTiddlers>>}}}
>By default, tiddlers remain open (e.g., displayed in the story column) until you explicitly close them. When this option is enabled, only the most recently opened tiddlers will remain open: ''any tiddlers in excess of the specified limit are automatically closed.'' //Note: for 'data safety', if a tiddler is being edited, you will be asked for permission to "save-and-close" that tiddler or leave it open (even if that would exceed the specified limit).//
<<<
!!!!!Revisions
<<<
2008.05.01 [2.0.0] added 'limit open tiddlers' feature (with safety check for tiddler in edit mode)
2008.04.06 [1.9.1] corrected 'limit' logic so that //last// N crumbs are shown instead of //first// N crumbs. Also, added chkBreadcrumbsHideHomeLink
2008.04.04 [1.9.0] added chkBreadcrumbsReverse and chk/txtBreadcrumbsLimit
2008.03.29 [1.8.4] in displayTiddler(), get title from tiddler object (if needed). Fixes errors caused when calling function passes a tiddler *object* instead of a tiddler *title*
2008.03.24 [1.8.3] include shadow tiddlers in breadcrumbs list. Also changed settings so that "reordering" breadcrumbs is the default, instead of "trimming" the list
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.26 [1.8.2] documentation cleanup
2007.10.18 [1.8.1] in GetAreas(), use try/catch to avoid "Bad NPObject as private data" fatal error caused when embedded QuickTime player element is accessed by hasClass() function.
2007.10.02 [1.8.0] major documentation and code cleanup. Moved config.breadCrumbs.* to config.macros.breadcrumbs.* to consolidate objects. Also, fixed homeSeparator and crumbSeparator default handling.
2007.10.02 [1.7.0] added config.options.chkShowStartupBreadcrumbs option
2007.09.16 [1.6.1] in getAreas(), removed errant use of 'place' (was causing fatal error when creating default breadcrumbs display element). Also, added chkCreateDefaultBreadcrumbs configuration setting to enable/disable automatic creation of a default breadcrumbs display.
2007.09.16 [1.6.0] re-wrote refresh() to enable multiple display instances, by finding elements with "breadCrumbs" classname. Fallback to fixed ID (="breadCrumbs") is still used for backward-compatibility. move rendering code from refresh() to separate render() function, and added definition for {{{<<breadCrumbs>>}}} macro to support embedding breadcrumbs displays in tiddler content.
2007.09.15 [1.5.9.1] updated documentation
2007.09.15 [1.5.9] defined homeSeparator (" | ") and crumbSeparator (" > ") as object properties so that they can be redefined as desired for different layouts (e.g., using 'newline' for the crumbSeparator will arrange crumbs in a column rather than a row.
2007.06.21 [1.5.8.1] in home(), return false to prevent IE from attempting to navigate away...
2007.05.26 [1.5.8] added support for {{{<<option chkReorderBreadcrumbs>>}}} to toggle trim vs. re-order behavior when visiting previously viewed tiddlers
2007.05.25 [1.5.7] added support for {{{<<option chkShowBreadcrumbs>>}}} to toggle //display// of breadcrumbs
2007.05.24 [1.5.6] in refresh(), remove non-existing tiddler titles from crumb list. Also, hijack removeTiddler() so crumbs can be updated after tiddler is deleted.
2007.04.11 [1.5.5] added optional params to previousTiddler macro handler() to allow alternative label and tooltip text (instead of default "back")
2007.03.02 [1.5.4] in refresh(), for TW2.2, look for "storyDisplay" instead of "tiddlerDisplay" but keep fallback to "tiddlerDisplay" for TW2.1 or earlier
2007.02.24 [1.5.3] changed from hijack of onClickTiddlerLink to hijack of displayTiddler() so that ALL displayed tiddlers are recorded in the crumbs, including programmatically displayed tiddlers opened by macros, scripts, etc., (such as [[GotoPlugin]], among many others) in addition to those opened by clicks on links.
2007.02.24 [1.5.2.0] eliminated global space clutter by moving function and data declarations so they are contained inside config.breadCrumbs object.
2007.02.06 [1.5.1] added "previousTiddler" macro (for use in sidebar)
2007.02.05 [1.5.0] added "previousTiddler" toolbar command (aka, "back")
2006.08.04 [1.4.0.1] change spaces to tabs
2006.08.04 [1.4.0] modified from 1.4.0 distro: in refresh(), set {{{display:none/block}}} instead of {{{visibility:hidden/visible}}}. In home(), check for valid crumbArea before setting style.
2006.08.02 [1.4.0] Fixed bug, the redefined onClickTiddlerLink_orig_breadCrumbs works incorrectly on IE
2006.07.20 [1.3.0] Runs compatibly with TW 2.1.0 (rev #403+)
2006.02.07 [1.2.0] change global array breadCrumbs to config.breadCrumbs by Eric's suggestion
2006.02.04 [1.1.0] JSLint checked
2006.02.01 [1.0.0] initial release
<<<
/***
|Name|CheckboxPlugin|
|Source|http://www.TiddlyTools.com/#CheckboxPlugin|
|Documentation|http://www.TiddlyTools.com/#CheckboxPluginInfo|
|Version|2.4.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Add checkboxes to your tiddler content|
This plugin extends the TiddlyWiki syntax to allow definition of checkboxes that can be embedded directly in tiddler content. Checkbox states are preserved by:
* by setting/removing tags on specified tiddlers,
* or, by setting custom field values on specified tiddlers,
* or, by saving to a locally-stored cookie ID,
* or, automatically modifying the tiddler content (deprecated)
When an ID is assigned to the checkbox, it enables direct programmatic access to the checkbox DOM element, as well as creating an entry in TiddlyWiki's config.options[ID] internal data. In addition to tracking the checkbox state, you can also specify custom javascript for programmatic initialization and onClick event handling for any checkbox, so you can provide specialized side-effects in response to state changes.
!!!!!Documentation
>see [[CheckboxPluginInfo]]
!!!!!Revisions
<<<
2008.01.08 [*.*.*] plugin size reduction: documentation moved to [[CheckboxPluginInfo]]
2008.01.05 [2.4.0] set global "window.place" to current checkbox element when processing checkbox clicks. This allows init/beforeClick/afterClick handlers to reference RELATIVE elements, including using "story.findContainingTiddler(place)". Also, wrap handlers in "function()" so "return" can be used within handler code.
|please see [[CheckboxPluginInfo]] for additional revision details|
2005.12.07 [0.9.0] initial BETA release
<<<
!!!!!Code
***/
//{{{
version.extensions.CheckboxPlugin = {major: 2, minor: 4, revision:0 , date: new Date(2008,1,5)};
//}}}
//{{{
config.checkbox = { refresh: { tagged:true, tagging:true, container:true } };
config.formatters.push( {
name: "checkbox",
match: "\\[[xX_ ][\\]\\=\\(\\{]",
lookahead: "\\[([xX_ ])(=[^\\s\\(\\]{]+)?(\\([^\\)]*\\))?({[^}]*})?({[^}]*})?({[^}]*})?\\]",
handler: function(w) {
var lookaheadRegExp = new RegExp(this.lookahead,"mg");
lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
// get params
var checked=(lookaheadMatch[1].toUpperCase()=="X");
var id=lookaheadMatch[2];
var target=lookaheadMatch[3];
if (target) target=target.substr(1,target.length-2).trim(); // trim off parentheses
var fn_init=lookaheadMatch[4];
var fn_clickBefore=lookaheadMatch[5];
var fn_clickAfter=lookaheadMatch[6];
var tid=story.findContainingTiddler(w.output); if (tid) tid=tid.getAttribute("tiddler");
var srctid=w.tiddler?w.tiddler.title:null;
config.macros.checkbox.create(w.output,tid,srctid,w.matchStart+1,checked,id,target,config.checkbox.refresh,fn_init,fn_clickBefore,fn_clickAfter);
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
}
}
} );
config.macros.checkbox = {
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
if(!(tiddler instanceof Tiddler)) { // if no tiddler passed in try to find one
var here=story.findContainingTiddler(place);
if (here) tiddler=store.getTiddler(here.getAttribute("tiddler"))
}
var srcpos=0; // "inline X" not applicable to macro syntax
var target=params.shift(); if (!target) target="";
var defaultState=params[0]=="checked"; if (defaultState) params.shift();
var id=params.shift(); if (id && !id.length) id=null;
var fn_init=params.shift(); if (fn_init && !fn_init.length) fn_init=null;
var fn_clickBefore=params.shift();
if (fn_clickBefore && !fn_clickBefore.length) fn_clickBefore=null;
var fn_clickAfter=params.shift();
if (fn_clickAfter && !fn_clickAfter.length) fn_clickAfter=null;
var refresh={ tagged:true, tagging:true, container:false };
this.create(place,tiddler.title,tiddler.title,0,defaultState,id,target,refresh,fn_init,fn_clickBefore,fn_clickAfter);
},
create: function(place,tid,srctid,srcpos,defaultState,id,target,refresh,fn_init,fn_clickBefore,fn_clickAfter) {
// create checkbox element
var c = document.createElement("input");
c.setAttribute("type","checkbox");
c.onclick=this.onClickCheckbox;
c.srctid=srctid; // remember source tiddler
c.srcpos=srcpos; // remember location of "X"
c.container=tid; // containing tiddler (may be null if not in a tiddler)
c.tiddler=tid; // default target tiddler
c.refresh = {};
c.refresh.container = refresh.container;
c.refresh.tagged = refresh.tagged;
c.refresh.tagging = refresh.tagging;
place.appendChild(c);
// set default state
c.checked=defaultState;
// track state in config.options.ID
if (id) {
c.id=id.substr(1); // trim off leading "="
if (config.options[c.id]!=undefined)
c.checked=config.options[c.id];
else
config.options[c.id]=c.checked;
}
// track state in (tiddlername|tagname) or (fieldname@tiddlername)
if (target) {
var pos=target.indexOf("@");
if (pos!=-1) {
c.field=pos?target.substr(0,pos):"checked"; // get fieldname (or use default "checked")
c.tiddler=target.substr(pos+1); // get specified tiddler name (if any)
if (!c.tiddler || !c.tiddler.length) c.tiddler=tid; // if tiddler not specified, default == container
if (store.getValue(c.tiddler,c.field)!=undefined)
c.checked=(store.getValue(c.tiddler,c.field)=="true"); // set checkbox from saved state
} else {
var pos=target.indexOf("|"); if (pos==-1) var pos=target.indexOf(":");
c.tag=target;
if (pos==0) c.tag=target.substr(1); // trim leading "|" or ":"
if (pos>0) { c.tiddler=target.substr(0,pos); c.tag=target.substr(pos+1); }
if (!c.tag.length) c.tag="checked";
var t=store.getTiddler(c.tiddler);
if (t && t.tags)
c.checked=t.isTagged(c.tag); // set checkbox from saved state
}
}
// trim off surrounding { and } delimiters from init/click handlers
if (fn_init) c.fn_init="(function(){"+fn_init.trim().substr(1,fn_init.length-2)+"})()";
if (fn_clickBefore) c.fn_clickBefore="(function(){"+fn_clickBefore.trim().substr(1,fn_clickBefore.length-2)+"})()";
if (fn_clickAfter) c.fn_clickAfter="(function(){"+fn_clickAfter.trim().substr(1,fn_clickAfter.length-2)+"})()";
c.init=true; c.onclick(); c.init=false; // compute initial state and save in tiddler/config/cookie
},
onClickCheckbox: function(event) {
window.place=this;
if (this.init && this.fn_init) // custom function hook to set initial state (run only once)
{ try { eval(this.fn_init); } catch(e) { displayMessage("Checkbox init error: "+e.toString()); } }
if (!this.init && this.fn_clickBefore) // custom function hook to override changes in checkbox state
{ try { eval(this.fn_clickBefore) } catch(e) { displayMessage("Checkbox onClickBefore error: "+e.toString()); } }
if (this.id)
// save state in config AND cookie (only when ID starts with 'chk')
{ config.options[this.id]=this.checked; if (this.id.substr(0,3)=="chk") saveOptionCookie(this.id); }
if (this.srctid && this.srcpos>0 && (!this.id || this.id.substr(0,3)!="chk") && !this.tag && !this.field) {
// save state in tiddler content only if not using cookie, tag or field tracking
var t=store.getTiddler(this.srctid); // put X in original source tiddler (if any)
if (t && this.checked!=(t.text.substr(this.srcpos,1).toUpperCase()=="X")) { // if changed
t.set(null,t.text.substr(0,this.srcpos)+(this.checked?"X":"_")+t.text.substr(this.srcpos+1),null,null,t.tags);
if (!story.isDirty(t.title)) story.refreshTiddler(t.title,null,true);
store.setDirty(true);
}
}
if (this.field) {
if (this.checked && !store.tiddlerExists(this.tiddler))
store.saveTiddler(this.tiddler,this.tiddler,"",config.options.txtUserName,new Date());
// set the field value in the target tiddler
store.setValue(this.tiddler,this.field,this.checked?"true":"false");
// DEBUG: displayMessage(this.field+"@"+this.tiddler+" is "+this.checked);
}
if (this.tag) {
if (this.checked && !store.tiddlerExists(this.tiddler))
store.saveTiddler(this.tiddler,this.tiddler,"",config.options.txtUserName,new Date());
var t=store.getTiddler(this.tiddler);
if (t) {
var tagged=(t.tags && t.tags.indexOf(this.tag)!=-1);
if (this.checked && !tagged) { t.tags.push(this.tag); store.setDirty(true); }
if (!this.checked && tagged) { t.tags.splice(t.tags.indexOf(this.tag),1); store.setDirty(true); }
}
// if tag state has been changed, update display of corresponding tiddlers (unless they are in edit mode...)
if (this.checked!=tagged) {
if (this.refresh.tagged) {
if (!story.isDirty(this.tiddler)) // the TAGGED tiddler in view mode
story.refreshTiddler(this.tiddler,null,true);
else // the TAGGED tiddler in edit mode (with tags field)
config.macros.checkbox.refreshEditorTagField(this.tiddler,this.tag,this.checked);
}
if (this.refresh.tagging)
if (!story.isDirty(this.tag)) story.refreshTiddler(this.tag,null,true); // the TAGGING tiddler
}
}
if (!this.init && this.fn_clickAfter) // custom function hook to react to changes in checkbox state
{ try { eval(this.fn_clickAfter) } catch(e) { displayMessage("Checkbox onClickAfter error: "+e.toString()); } }
// refresh containing tiddler (but not during initial rendering, or we get an infinite loop!) (and not when editing container)
if (!this.init && this.refresh.container && this.container!=this.tiddler)
if (!story.isDirty(this.container)) story.refreshTiddler(this.container,null,true); // the tiddler CONTAINING the checkbox
return true;
},
refreshEditorTagField: function(title,tag,set) {
var tagfield=story.getTiddlerField(title,"tags");
if (!tagfield||tagfield.getAttribute("edit")!="tags") return; // if no tags field in editor (i.e., custom template)
var tags=tagfield.value.readBracketedList();
if (tags.contains(tag)==set) return; // if no change needed
if (set) tags.push(tag); // add tag
else tags.splice(tags.indexOf(tag),1); // remove tag
for (var t=0;t<tags.length;t++) tags[t]=String.encodeTiddlyLink(tags[t]);
tagfield.value=tags.join(" "); // reassemble tag string (with brackets as needed)
return;
}
}
//}}}
/***
|Name|ClickifyPlugin|
|Source|http://www.TiddlyTools.com/#ClickifyPlugin|
|Documentation|http://www.TiddlyTools.com/#ClickifyPlugin|
|Version|1.0.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|re-compute parameters when a 'command link' macro is clicked|
!!!!!Usage
<<<
Normally, when you use a //computed parameter// in a macro, it's value is determined when the macro is rendered. The {{{<<clickify>>}}} macro can be used to force the macro parameters of an 'on-click' command link (such as created by the {{{<<newTiddler>>}}} macro) to be automatically re-computed when the command link is clicked, rather than when it is initially displayed. This allows use of computed values that depend upon data that may change between the time the macro is rendered and when it's action is actually triggered by a click.
To apply this extended processing to any macro that creates a command link, simply insert the 'clickify' keyword in front of the usual macro name, like this:
{{{
<<clickify macroName param param param ...>>
}}}
<<<
!!!!!Example
<<<
When {{{<<newTiddler>>}}} is clicked, prompt for a title and set default text to current timestamp:
{{{
<<clickify newTiddler title:{{prompt('enter a title','NewTiddler')}} text:{{new Date()}}>>
}}}
><<clickify newTiddler title:{{prompt('enter a title','NewTiddler')}} text:{{new Date()}}>>
<<<
!!!!!Revisions
<<<
2009.02.08 [1.0.1] make sure command link has been rendered before trying to modify it
2009.01.25 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.ClickifyPlugin={major: 1, minor: 0, revision: 1, date: new Date(2009,2,8)};
config.macros.clickify={
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var cmd='<<'+paramString+'>>';
var e=createTiddlyElement(place,'span');
wikify(cmd.replace(/alert\(|prompt\(|confirm\(/g,'isNaN('),e);
var b=e.getElementsByTagName('a')[0]; if (!b) return;
b.setAttribute('cmd',cmd);
b.onclick=function(ev) {
var cmd=this.getAttribute('cmd');
var e=createTiddlyElement(this.parentNode,'span');
e.style.display='none';
wikify(cmd,e);
e.getElementsByTagName('a')[0].onclick();
this.parentNode.removeChild(e);
}
}
}
//}}}
/%
|Name|CloseOtherTiddlers|
|Source|http://www.TiddlyTools.com/#CloseOtherTiddlers|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires||
|Overrides||
|Description|close all other tiddlers when a tiddler is viewed - equivalent to pressing "close others" toolbar command|
Usage: <<tiddler CloseOtherTiddlers>>
%/<script>
var here=story.findContainingTiddler(place); if (!here) return;
story.closeAllTiddlers(here.getAttribute("tiddler"));
</script>
/***
|Name|CollapseTiddlersPlugin|
|Source|http://gensoft.revhost.net/Collapse.html|
|Version|2008.10.05|
|Author|Bradley Meck (modified by ELS)|
|License|unknown|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|CollapsedTemplate|
|Overrides||
|Description|show/hide content of a tiddler while leaving tiddler title visible|
|ELS 10/5/2008: collapseAll() and expandAll(): added "return false" to button handlers to prevent IE page transition |
|ELS 3/6/2008: refactored code for size reduction, readability, and I18N/L10N-readiness. Also added 'folded' flag to tiddler elements (for use by other plugins that need to know if tiddler is folded (e.g., [[SinglePageModePlugin]]) |
|ELS 10/11/2007: moved [[FoldFirst]] inline script and converted to {{{<<foldFirst>>}}} macro. |
|ELS 9/12/2007: suspend/resume SinglePageMode (SPM/TPM/BPM) when folding/unfolding tiddlers |
|ELS 6/5/2007: add "return false" at the end of each command handler to prevent IE 'page transition' problem. |
|ELS 3/30/2007: add a shadow definition for CollapsedTemplate. Tweak ViewTemplate shadow so "fold/unfold" and "focus" toolbar items automatically appear when using default templates. Remove error check for "CollapsedTemplate" existence, since shadow version will now always work as a fallback. |
|ELS 2/24/2006: added fallback to "CollapsedTemplate" if "WebCollapsedTemplate" is not found |
|ELS 2/6/2006: added check for 'readOnly' flag to use alternative "WebCollapsedTemplate" |
***/
//{{{
config.shadowTiddlers.CollapsedTemplate=
"<!--{{{-->\
<div class='toolbar' macro='toolbar expandTiddler collapseOthers closeTiddler closeOthers +editTiddler permalink references jump'></div>\
<div class='title' macro='view title'></div>\
<!--}}}-->";
// automatically tweak shadow ViewTemplate to add "collapseTiddler collapseOthers" commands
config.shadowTiddlers.ViewTemplate=config.shadowTiddlers.ViewTemplate.replace(/closeTiddler/,"collapseTiddler collapseOthers closeTiddler");
config.commands.collapseTiddler = {
text: "fold",
tooltip: "Collapse this tiddler",
collapsedTemplate: "CollapsedTemplate",
webCollapsedTemplate: "WebCollapsedTemplate",
handler: function(event,src,title) {
var e = story.findContainingTiddler(src); if (!e) return false;
// don't fold tiddlers that are being edited!
if(story.isDirty(e.getAttribute("tiddler"))) return false;
var t=config.commands.collapseTiddler.getCollapsedTemplate();
config.commands.collapseTiddler.saveTemplate(e);
config.commands.collapseTiddler.display(title,t);
e.setAttribute("folded","true");
return false;
},
getCollapsedTemplate: function() {
if (readOnly&&store.tiddlerExists(this.webCollapsedTemplate))
return this.webCollapsedTemplate;
else
return this.collapsedTemplate
},
saveTemplate: function(e) {
if (e.getAttribute("savedTemplate")==undefined)
e.setAttribute("savedTemplate",e.getAttribute("template"));
},
// fold/unfold tiddler with suspend/resume of single/top/bottom-of-page mode
display: function(title,t) {
var opt=config.options;
var saveSPM=opt.chkSinglePageMode; opt.chkSinglePageMode=false;
var saveTPM=opt.chkTopOfPageMode; opt.chkTopOfPageMode=false;
var saveBPM=opt.chkBottomOfPageMode; opt.chkBottomOfPageMode=false;
story.displayTiddler(null,title,t);
opt.chkBottomOfPageMode=saveBPM;
opt.chkTopOfPageMode=saveTPM;
opt.chkSinglePageMode=saveSPM;
}
}
config.commands.expandTiddler = {
text: "unfold",
tooltip: "Expand this tiddler",
handler: function(event,src,title) {
var e = story.findContainingTiddler(src); if (!e) return false;
var t = e.getAttribute("savedTemplate");
config.commands.collapseTiddler.display(title,t);
e.setAttribute("folded","false");
return false;
}
}
config.macros.collapseAll = {
text: "collapse all",
tooltip: "Collapse all tiddlers",
handler: function(place,macroName,params,wikifier,paramString,tiddler){
createTiddlyButton(place,this.text,this.tooltip,function(){
story.forEachTiddler(function(title,tiddler){
if(story.isDirty(title)) return;
var t=config.commands.collapseTiddler.getCollapsedTemplate();
config.commands.collapseTiddler.saveTemplate(tiddler);
config.commands.collapseTiddler.display(title,t);
tiddler.folded=true;
});
return false;
})
}
}
config.macros.expandAll = {
text: "expand all",
tooltip: "Expand all tiddlers",
handler: function(place,macroName,params,wikifier,paramString,tiddler){
createTiddlyButton(place,this.text,this.tooltip,function(){
story.forEachTiddler(function(title,tiddler){
var t=config.commands.collapseTiddler.getCollapsedTemplate();
if(tiddler.getAttribute("template")!=t) return; // re-display only if collapsed
var t=tiddler.getAttribute("savedTemplate");
config.commands.collapseTiddler.display(title,t);
tiddler.folded=false;
});
return false;
})
}
}
config.commands.collapseOthers = {
text: "focus",
tooltip: "Expand this tiddler and collapse all others",
handler: function(event,src,title) {
var e = story.findContainingTiddler(src); if (!e) return false;
story.forEachTiddler(function(title,tiddler) {
if(story.isDirty(title)) return;
var t=config.commands.collapseTiddler.getCollapsedTemplate();
if (e==tiddler) t=e.getAttribute("savedTemplate");
config.commands.collapseTiddler.saveTemplate(tiddler);
config.commands.collapseTiddler.display(title,t);
tiddler.folded=(e!=tiddler);
})
return false;
}
}
// {{{<<foldFirst>>}}} macro forces tiddler to be folded when *initially* displayed.
// Subsequent re-render does NOT re-fold tiddler, but closing/re-opening tiddler DOES cause it to fold first again.
config.macros.foldFirst = {
handler: function(place,macroName,params,wikifier,paramString,tiddler){
var e=story.findContainingTiddler(place);
if (e.getAttribute("foldedFirst")=="true") return; // already been folded once
var title=e.getAttribute("tiddler")
var t=config.commands.collapseTiddler.getCollapsedTemplate();
config.commands.collapseTiddler.saveTemplate(e);
config.commands.collapseTiddler.display(title,t);
e.setAttribute("folded","true");
e.setAttribute("foldedFirst","true"); // only when tiddler is first rendered
return false;
}
}
//}}}
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::CollapsedToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier wikified'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<span macro="tiddler DottedTiddlerBorder" style='display:none'></span>
<!--}}}-->
{{SecondaryPale BGPrimaryMid{reverse video!}}}
{{outline BGPrimaryPale{in a box!}}}
/***
|Name|CopyTiddlerPlugin|
|Source|http://www.TiddlyTools.com/#CopyTiddlerPlugin|
|Version|3.2.3|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.3|
|Type|plugin|
|Requires||
|Overrides||
|Description|Quickly create a copy of any existing tiddler|
!!!Usage
<<<
This plugin automatically updates the default (shadow) ToolbarCommands slice definitions to insert the ''copyTiddler'' command (which appears as ''copy'' in the tiddler toolbar).
When you select the ''copy'' command, a new tiddler is opened with a title of "{{{TiddlerName (n)}}}" containing copies of the text/tags/fields from the original //source tiddler//, where ''(n)'' is the next available number (starting with 1, of course). Note: If you copy while //editing// a tiddler, the current values that are displayed in the existing tiddler editor are used (including any unsaved changes you may have made to those values), and the new tiddler is immediately opened for editing.
Note: if you are already using customized toolbar definitions, you will need to manually add the ''copyTiddler'' toolbar command to your existing ToolbarCommands tiddler, e.g.:
{{{
|EditToolbar|... copyTiddler ... |
}}}
The plugin also provides a macro that allows you to embed a ''copy'' command directly in specific tiddler content:
{{{
<<copyTiddler TidderName label:"..." prompt:"...">>
}}}
where
* ''TiddlerName'' (optional)<br>specifies the //source// tiddler to be copied. If omitted, the current containing tiddler (if any) will be copied.
* ''label:"..."'' (optional)<br>specifies text to use for the embedded link (default="copy TiddlerName")
* ''prompt:"..."'' (optional)<br>specifies mouseover 'tooltip' help text for link
//Note: to use non-default label/prompt values with the current containing tiddler, use "" for the TiddlerName//
<<<
!!!Revisions
<<<
2009.03.02 [3.2.3] refactored code (again) to restore use of config.commands.copyTiddler.* custom settings
2009.02.13 [3.2.2] in click(), fix calls to displayTiddler() to use current tiddlerElem and use getTiddlerText() to permit copying of shadow tiddler content
2009.01.30 [3.2.1] fixed handling for copying field values when in edit mode
2009.01.23 [3.2.0] refactored code and added {{{<<copyTiddler TiddlerName>>}}} macro
2008.12.18 [3.1.4] corrected code for finding next (n) value when 'sparse' handling is in effect (thanks to RussThomas for identifying and diagnosing the problem)
2008.11.14 [3.1.3] added optional 'sparse' setting (avoids 'filling in' missing numbers that may have been previously deleted)
2008.11.14 [3.1.2] added optional 'zeroPad' setting
2008.11.14 [3.1.1] moved hard-coded '(n)' regex into 'suffixPattern' object property so it can be customized
2008.09.26 [3.1.0] changed new title generation to use '(n)' suffix instead of 'Copy of' prefix
2008.05.20 [3.0.3] in handler, when copying from VIEW mode, create duplicate array from existing tags array before saving new tiddler.
2007.12.19 [3.0.2] in handler, when copying from VIEW mode, duplicate custom fields before saving new tiddler. Thanks to bug report from Ken Girard.
2007.09.26 [3.0.1] in handler, use findContainingTiddler(src) to get tiddlerElem (and title). Allows 'copy' command to find correct tiddler when transcluded using {{{<<tiddler>>}}} macro or enhanced toolbar inclusion (see [[CoreTweaks]])
2007.06.28 [3.0.0] complete re-write to handle custom fields and alternative view/edit templates
2007.05.17 [2.1.2] use store.getTiddlerText() to retrieve tiddler content, so that SHADOW tiddlers can be copied correctly when in VIEW mode
2007.04.01 [2.1.1] in copyTiddler.handler(), fix check for editor fields by ensuring that found field actually has edit=='text' attribute
2007.02.05 [2.1.0] in copyTiddler.handler(), if editor fields (textfield and/or tagsfield) can't be found (i.e., tiddler is in VIEW mode, not EDIT mode), then get text/tags values from stored tiddler instead of active editor fields. Allows use of COPY toolbar directly from VIEW mode (based on a request from LaurentCharles)
2006.12.12 [2.0.0] completely rewritten so plugin just creates a new tiddler EDITOR with a copy of the current tiddler EDITOR contents, instead of creating the new tiddler in the STORE by copying the current tiddler values from the STORE.
2005.xx.xx [1.0.0] original version by Tim Morgan
<<<
!!!Code
***/
//{{{
version.extensions.CopyTiddlerPlugin= {major: 3, minor: 2, revision: 3, date: new Date(2009,3,2)};
// automatically tweak shadow EditTemplate to add 'copyTiddler' toolbar command (following 'cancelTiddler')
config.shadowTiddlers.ToolbarCommands=config.shadowTiddlers.ToolbarCommands.replace(/cancelTiddler/,'cancelTiddler copyTiddler');
config.commands.copyTiddler = {
text: 'copy',
hideReadOnly: true,
tooltip: 'Make a copy of this tiddler',
notitle: 'this tiddler',
prefix: '',
suffixText: ' (%0)',
suffixPattern: / \(([0-9]+)\)$/,
zeroPad: 0,
sparse: false,
handler: function(event,src,title)
{ return config.commands.copyTiddler.click(src,event); },
click: function(here,ev) {
var tiddlerElem=story.findContainingTiddler(here);
var template=tiddlerElem?tiddlerElem.getAttribute('template'):null;
var title=here.getAttribute('from');
if (!title || !title.length) {
if (!tiddlerElem) return false;
else title=tiddlerElem.getAttribute('tiddler');
}
var root=title.replace(this.suffixPattern,''); // title without suffix
// find last matching title
var last=title;
if (this.sparse) { // don't fill-in holes... really find LAST matching title
var tids=store.getTiddlers('title','excludeLists');
for (var t=0; t<tids.length; t++) if (tids[t].title.startsWith(root)) last=tids[t].title;
}
// get next number (increment from last matching title)
var n=1; var match=this.suffixPattern.exec(last); if (match) n=parseInt(match[1])+1;
var newTitle=this.prefix+root+this.suffixText.format([String.zeroPad(n,this.zeroPad)]);
// if not sparse mode, find the next hole to fill in...
while (store.tiddlerExists(newTitle)||document.getElementById(story.idPrefix+newTitle))
{ n++; newTitle=this.prefix+root+this.suffixText.format([String.zeroPad(n,this.zeroPad)]); }
if (!story.isDirty(title)) { // if tiddler is not being EDITED
// duplicate stored tiddler (if any)
var text=store.getTiddlerText(title,'');
var newtags=[]; var newfields={};
var tid=store.getTiddler(title); if (tid) {
for (var t=0; t<tid.tags.length; t++) newtags.push(tid.tags[t]);
store.forEachField(tid,function(t,f,v){newfields[f]=v;},true);
}
store.saveTiddler(newTitle,newTitle,text,
config.options.txtUserName,new Date(),newtags, newfields, true); // clear changecount
story.displayTiddler(tiddlerElem,newTitle,template);
} else {
story.displayTiddler(tiddlerElem,newTitle,template);
var fields=config.commands.copyTiddler.gatherFields(tiddlerElem); // get current editor fields
var newTiddlerElem=document.getElementById(story.idPrefix+newTitle);
for (var f=0; f<fields.length; f++) { // set fields in new editor
if (fields[f].name=='title') fields[f].value=newTitle; // rename title in new tiddler
var fieldElem=config.commands.copyTiddler.findField(newTiddlerElem,fields[f].name);
if (fieldElem) {
if (fieldElem.getAttribute('type')=='checkbox')
fieldElem.checked=fields[f].value;
else
fieldElem.value=fields[f].value;
}
}
}
story.focusTiddler(newTitle,'title');
return false;
},
findField: function(tiddlerElem,field) {
var inputs=tiddlerElem.getElementsByTagName('input');
for (var i=0; i<inputs.length; i++) {
if (inputs[i].getAttribute('type')=='checkbox' && inputs[i].field == field) return inputs[i];
if (inputs[i].getAttribute('type')=='text' && inputs[i].getAttribute('edit') == field) return inputs[i];
}
var tas=tiddlerElem.getElementsByTagName('textarea');
for (var i=0; i<tas.length; i++) if (tas[i].getAttribute('edit') == field) return tas[i];
var sels=tiddlerElem.getElementsByTagName('select');
for (var i=0; i<sels.length; i++) if (sels[i].getAttribute('edit') == field) return sels[i];
return null;
},
gatherFields: function(tiddlerElem) { // get field names and values from current tiddler editor
var fields=[];
// get checkboxes and edit fields
var inputs=tiddlerElem.getElementsByTagName('input');
for (var i=0; i<inputs.length; i++) {
if (inputs[i].getAttribute('type')=='checkbox')
if (inputs[i].field) fields.push({name:inputs[i].field,value:inputs[i].checked});
if (inputs[i].getAttribute('type')=='text')
if (inputs[i].getAttribute('edit')) fields.push({name:inputs[i].getAttribute('edit'),value:inputs[i].value});
}
// get textareas (multi-line edit fields)
var tas=tiddlerElem.getElementsByTagName('textarea');
for (var i=0; i<tas.length; i++)
if (tas[i].getAttribute('edit')) fields.push({name:tas[i].getAttribute('edit'),value:tas[i].value});
// get selection lists (droplist or listbox)
var sels=tiddlerElem.getElementsByTagName('select');
for (var i=0; i<sels.length; i++)
if (sels[i].getAttribute('edit')) fields.push({name:sels[i].getAttribute('edit'),value:sels[i].value});
return fields;
}
};
//}}}
// // MACRO DEFINITION
//{{{
config.macros.copyTiddler = {
label: 'copy',
prompt: 'Make a copy of %0',
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var title=params.shift();
params=paramString.parseParams('anon',null,true,false,false);
var label =getParam(params,'label',this.label+(title?' '+title:''));
var prompt =getParam(params,'prompt',this.prompt).format([title||this.notitle]);
var b=createTiddlyButton(place,label,prompt,
function(ev){return config.commands.copyTiddler.click(this,ev)});
b.setAttribute('from',title||'');
},
};
//}}}
/***
|Name|CoreTweaks|
|Source|http://www.TiddlyTools.com/#CoreTweaks|
|Version|use with TW2.4.3|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.2.0|
|Type|plugin|
|Requires||
|Overrides|various|
|Description|a small collection of overrides to TW core functions|
This tiddler contains changes TW core functions to provide minor changes in standard features or behavior. It is hoped that some of these tweaks may someday be added into the TW core, so that these adjustments will be available without needing these add-on definitions.
>''Note: the changes contained in this tiddler are generally applicable for version 2.4.3 of TiddlyWiki.''
>Please view [[CoreTweaksArchive]] for tweaks that may be used with earlier versions of TiddlyWiki.
***/
//{{{
// calculate TW version number - used to determine which tweaks should be applied
var ver=version.major+version.minor/10+version.revision/100;
//}}}
/***
----
***/
// // open tickets:
// // {{block{
/***
!!!890 add conditional test to """<<tiddler>>""" macro
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/890 - OPEN
This tweak extends the {{{<<tiddler>>}}} macro syntax so you can include a javascript-based //test expression// to determine if the tiddler transclusion should be performed:
{{{
<<tiddler TiddlerName if:{{...}} with: param param etc.>>
}}}
If the test is ''true'', then the tiddler is transcluded as usual. If the test is ''false'', then the transclusion is skipped and //no output is produced//.
***/
//{{{
config.macros.tiddler.if_handler = config.macros.tiddler.handler;
config.macros.tiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
params = paramString.parseParams('name',null,true,false,true);
if (!getParam(params,'if',true)) return;
this.if_handler.apply(this,arguments);
};
//}}}
// // }}}}}}// // {{block{
/***
!!!831 backslash-quoting for embedding newlines in 'line-mode' formats
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/831 - OPEN
This tweak pre-processes source content to convert 'double-backslash-newline' into {{{<br>}}} before wikify(), so that literal newlines can be embedded in line-mode wiki syntax (e.g., tables, bullets, etc.)
***/
//{{{
window.coreWikify = wikify;
window.wikify = function(source,output,highlightRegExp,tiddler)
{
if (source) arguments[0]=source.replace(/\\\\\n/mg,'<br>');
coreWikify.apply(this,arguments);
}
//}}}
// // }}}}}}// // {{block{
/***
!!!829 """<<tag>>""" macro - sortby parameter
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/829 - OPEN
This tweak adds an optional 'sortby' parameter to the """<<tag tagname label tip sortby>>""" macro, as well as the """<<allTags excludeTag sortby>>""" macro used to generate the sidebar contents 'tags' list. Specify the field on which the contents of each tag popup is to be sorted, with a '+' or '-' prefix to indicate ascending/descending order, respectively.
Example: """<<tag systemConfig "plugins" "list plugins by date, most recent first" "-modified">>"""
Try it: <<tag systemConfig "plugins" "list plugins by date, most recent first" "-modified">>
Similarly, to change the sort order used by the popups from all tags shown in the sidebar contents, edit the [[TagTags]] shadow tiddler and enter: """<<allTags excludeLists -modified>>"""
***/
//{{{
// hijack tag handler() to add 'sortby' attribute to tag button
config.macros.tag.CoreTweaksSortTags_handler=config.macros.tag.handler;
config.macros.tag.handler = function(place,macroName,params)
{
this.CoreTweaksSortTags_handler.apply(this,arguments);
var btn=place.lastChild;
if (params[3]) btn.setAttribute('sortby',params[3]);
}
// tweak <<allTags>> macro to add 'sortby' attribute to each tag button
var fn=config.macros.allTags.handler;
var lines=fn.toString().split('\n');
lines.splice(lines.length-2,0,['if(params[1]) btn.setAttribute("sortby",params[1]);']);
fn=lines.join('\n');
eval('config.macros.allTags.handler='+fn);
// tweak tag event handler to:
// * use tag filtering (only if '[' is present in tag value)
// * use optional 'sortby' attribute
// * save 'sortby' value in 'open all' command (for displaying tiddlers in sorted order)
var fn=onClickTag;
fn=fn.toString().replace(
/store.getTaggedTiddlers\(tag\);/g,
'(tag.indexOf("[")==-1?store.getTaggedTiddlers(tag):store.filterTiddlers(tag));'
+'var sortby=this.getAttribute("sortby");'
+'if(sortby&&sortby.length) store.sortTiddlers(tagged,sortby);'
);
fn=fn.toString().replace(
/openAll.setAttribute\("tag",\s*tag\);/g,
'openAll.setAttribute("tag",tag); openAll.setAttribute("sortby",sortby);'
);
eval(fn);
// tweak 'open all' event handler to use 'sortby' attribute
var fn=onClickTagOpenAll;
fn=fn.toString().replace(
/story.displayTiddlers\(this,\s*tiddlers\);/g,
'var sortby=this.getAttribute("sortby");'
+'if(sortby&&sortby.length) store.sortTiddlers(tiddlers,sortby);'
+'story.displayTiddlers(this,tiddlers);'
);
eval(fn);
//}}}
// // }}}}}}// // {{block{
/***
!!!824 ~WindowTitle - alternative to combined ~SiteTitle/~SiteSubtitle in window titlebar
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/824 - OPEN
This tweak allows definition of an optional [[WindowTitle]] tiddler that, when present, provides alternative text for display in the browser window's titlebar, instead of using the combined text content from [[SiteTitle]] and [[SiteSubtitle]] (which will still be displayed as usual in the TiddlyWiki document header area).
Note: this ticket replaces http://trac.tiddlywiki.org/ticket/401 (closed), which proposed using a custom [[PageTitle]] tiddler for this purpose. ''If you were using the previous '401 ~PageTitle' tweak, you will need to rename [[PageTitle]] to [[WindowTitle]] to continue to use your custom window title text''
***/
//{{{
config.shadowTiddlers.WindowTitle='<<tiddler SiteTitle>> - <<tiddler SiteSubtitle>>';
window.getPageTitle=function() { return wikifyPlain('WindowTitle'); }
store.addNotification('WindowTitle',refreshPageTitle); // so title stays in sync with tiddler changes
//}}}
// // }}}}}}// // {{block{
/***
!!!784 allow tiddler sections in TiddlyLinks to be used as anchor points for intra-tiddler scrolling.
>http://trac.tiddlywiki.org/ticket/784 - OPEN - Please see separate [[SectionLinksPlugin]]
!!!683 FireFox3 Import bug: 'browse' button replacement
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/683 - OPEN
The web standard 'type=file' input control that has been used as a local path/file picker for TiddlyWiki no longer works as expected in FireFox3, which has, for security reasons, limited javascript access to this control so that *no* local filesystem path information can be revealed, even when it is intentional and necessary, as it is with TiddlyWiki. This tweak provides alternative HTML source that patches the backstage import panel. It replaces the 'type=file' input control with a text+button combination of controls that invokes a system-native secure 'file-chooser' dialog box to provide TiddlyWiki with access to a complete path+filename so that TW functions properly locate user-selected local files.
>Note: ''This tweak also requires http://trac.tiddlywiki.org/ticket/604 - cross-platform askForFilename()''
***/
//{{{
if (window.Components) {
var fixhtml='<input name="txtBrowse" style="width:30em"><input type="button" value="..."'
+' onClick="window.browseForFilename(this.previousSibling,true)">';
var cmi=config.macros.importTiddlers;
cmi.step1Html=cmi.step1Html.replace(/<input type='file' size=50 name='txtBrowse'>/,fixhtml);
}
merge(config.messages,{selectFile:'Please enter or select a file'}); // ready for I18N translation
window.browseForFilename=function(target,mustExist) { // note: both params are optional
var msg=config.messages.selectFile;
if (target && target.title) msg=target.title; // use target field tooltip (if any) as dialog prompt text
// get local path for current document
var path=getLocalPath(document.location.href);
var p=path.lastIndexOf('/'); if (p==-1) p=path.lastIndexOf('\\'); // Unix or Windows
if (p!=-1) path=path.substr(0,p+1); // remove filename, leave trailing slash
var file=''
var result=window.askForFilename(msg,path,file,mustExist); // requires #604
if (target && result.length) // set target field and trigger handling
{ target.value=result; target.onchange(); }
return result;
}
//}}}
// // }}}}}}// // {{block{
/***
!!!604 cross-platform askForFilename()
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/604 - OPEN
invokes a system-native secure 'file-chooser' dialog box to provide TiddlyWiki with access to a complete path+filename so that TW functions properly locate user-selected local files.
***/
//{{{
window.askForFilename=function(msg,path,file,mustExist) {
var r = window.mozAskForFilename(msg,path,file,mustExist);
if(r===null || r===false)
r = window.ieAskForFilename(msg,path,file,mustExist);
if(r===null || r===false)
r = window.javaAskForFilename(msg,path,file,mustExist);
if(r===null || r===false)
r = prompt(msg,path+file);
return r||'';
}
window.mozAskForFilename=function(msg,path,file,mustExist) {
if(!window.Components) return false;
try {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
picker.init(window, msg, mustExist?nsIFilePicker.modeOpen:nsIFilePicker.modeSave);
var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
thispath.initWithPath(path);
picker.displayDirectory=thispath;
picker.defaultExtension='html';
picker.defaultString=file;
picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
if (picker.show()!=nsIFilePicker.returnCancel)
var result=picker.file.persistentDescriptor;
}
catch(ex) { displayMessage(ex.toString()); }
return result;
}
window.ieAskForFilename=function(msg,path,file,mustExist) {
if(!config.browser.isIE) return false;
try {
var s = new ActiveXObject('UserAccounts.CommonDialog');
s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
s.FilterIndex=3; // default to HTML files;
s.InitialDir=path;
s.FileName=file;
return s.showOpen()?s.FileName:'';
}
catch(ex) { displayMessage(ex.toString()); }
return result;
}
window.javaAskForFilename=function(msg,path,file,mustExist) {
if(!document.applets['TiddlySaver']) return false;
// TBD: implement java-based askFile(...) function
try { return document.applets['TiddlySaver'].askFile(msg,path,file,mustExist); }
catch(ex) { displayMessage(ex.toString()); }
}
//}}}
// // }}}}}}// // {{block{
/***
!!!657 wrap tabs onto multiple lines
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/657 - OPEN
This tweak inserts an extra space element following each tab, allowing them to wrap onto multiple lines if needed.
***/
//{{{
config.macros.tabs.handler = function(place,macroName,params)
{
var cookie = params[0];
var numTabs = (params.length-1)/3;
var wrapper = createTiddlyElement(null,'div',null,'tabsetWrapper ' + cookie);
var tabset = createTiddlyElement(wrapper,'div',null,'tabset');
tabset.setAttribute('cookie',cookie);
var validTab = false;
for(var t=0; t<numTabs; t++) {
var label = params[t*3+1];
var prompt = params[t*3+2];
var content = params[t*3+3];
var tab = createTiddlyButton(tabset,label,prompt,this.onClickTab,'tab tabUnselected');
createTiddlyElement(tab,'span',null,null,' ',{style:'font-size:0pt;line-height:0px'}); // ELS
tab.setAttribute('tab',label);
tab.setAttribute('content',content);
tab.title = prompt;
if(config.options[cookie] == label)
validTab = true;
}
if(!validTab)
config.options[cookie] = params[1];
place.appendChild(wrapper);
this.switchTab(tabset,config.options[cookie]);
};
//}}}
// // }}}}}}// // {{block{
/***
!!!628 hide 'no such macro' errors
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/628 - OPEN
When invoking a macro that is not defined, this tweak prevents the display of the 'error in macro... no such macro' message. This is useful when rendering tiddler content or templates that reference macros that are defined by //optional// plugins that have not been installed in the current document.
<<option chkHideMissingMacros>> hide 'no such macro' error messages
***/
//{{{
if (config.options.chkHideMissingMacros===undefined)
config.options.chkHideMissingMacros=false;
window.coreTweaks_missingMacro_invokeMacro = window.invokeMacro;
window.invokeMacro = function(place,macro,params,wikifier,tiddler) {
if (!config.macros[macro] || !config.macros[macro].handler)
if (config.options.chkHideMissingMacros) return;
window.coreTweaks_missingMacro_invokeMacro.apply(this,arguments);
}
//}}}
// // }}}}}}// // {{block{
/***
!!!608/609/610 toolbars - toggles, separators and transclusion
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/608 - OPEN (more/less toggle)
http://trac.tiddlywiki.org/ticket/609 - OPEN (separators)
http://trac.tiddlywiki.org/ticket/610 - OPEN (wikify tiddler/slice/section content)
This combination tweak extends the """<<toolbar>>""" macro to add use of '<' to insert a 'less' menu command (the opposite of '>' == 'more'), as well as use of '*' to insert linebreaks and "!" to insert a vertical line separator between toolbar items. In addition, this tweak add the ability to use references to tiddlernames, slices, or sections and render their content inline within the toolbar, allowing easy creation of new toolbar commands using TW content (such as macros, links, inline scripts, etc.)
To produce a one-line style, with "less" at the end, use
| ViewToolbar| foo bar baz > yabba dabba doo < |
resulting in:
{{{
foo bar baz more
and
foo bar baz yabba dabba doo less
}}}
or to use the CoreTweaks? two-line style:
| ViewToolbar| foo bar baz > < * yabba dabba doo |
which would produce:
{{{
foo bar baz more
and
foo bar baz less
yabba dabba doo
}}}
''see [[ToolbarCommands]] for examples of how these features can be used''
***/
//{{{
merge(config.macros.toolbar,{
moreLabel: 'more\u25BC',
morePrompt: 'Show additional commands',
lessLabel: '\u25C4less',
lessPrompt: 'Hide additional commands',
separator: '|'
});
config.macros.toolbar.onClickMore = function(ev) {
var e = this.nextSibling;
e.style.display = 'inline'; // show menu
this.style.display = 'none'; // hide button
return false;
};
config.macros.toolbar.onClickLess = function(ev) {
var e = this.parentNode;
var m = e.previousSibling;
e.style.display = 'none'; // hide menu
m.style.display = 'inline'; // show button
return false;
};
config.macros.toolbar.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
for(var t=0; t<params.length; t++) {
var c = params[t];
switch(c) {
case '!': // ELS - SEPARATOR (added)
createTiddlyText(place,this.separator);
break;
case '*': // ELS - LINEBREAK (added)
createTiddlyElement(place,'BR');
break;
case '<': // ELS - LESS COMMAND (added)
var btn = createTiddlyButton(place,
this.lessLabel,this.lessPrompt,config.macros.toolbar.onClickLess,'moreCommand');
break;
case '>':
var btn = createTiddlyButton(place,
this.moreLabel,this.morePrompt,config.macros.toolbar.onClickMore,'moreCommand');
var e = createTiddlyElement(place,'span',null,'moreCommand');
e.style.display = 'none';
place = e;
break;
default:
var theClass = '';
switch(c.substr(0,1)) {
case '+':
theClass = 'defaultCommand';
c = c.substr(1);
break;
case '-':
theClass = 'cancelCommand';
c = c.substr(1);
break;
}
if(c in config.commands)
this.createCommand(place,c,tiddler,theClass);
else { // ELS - WIKIFY TIDDLER/SLICE/SECTION (added)
if (c.substr(0,1)=='~') c=c.substr(1); // ignore leading ~
var txt=store.getTiddlerText(c);
if (txt) {
// trim any leading/trailing newlines
txt=txt.replace(/^\n*/,'').replace(/\n*$/,'');
// trim PRE format wrapper if any
txt=txt.replace(/^\{\{\{\n/,'').replace(/\n\}\}\}$/,'');
// render content into toolbar
wikify(txt,createTiddlyElement(place,'span'),null,tiddler);
}
} // ELS - end WIKIFY CONTENT
break;
}
}
};
//}}}
// // }}}}}}// // {{block{
/***
!!!529 IE fixup - case-sensitive element lookup of tiddler elements
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/529 - OPEN
This tweak hijacks the standard browser function, document.getElementById(), to work-around the case-INsensitivity error in Internet Explorer (all versions up to and including IE7) //''Note: This tweak is only applied when using IE, and only for lookups of rendered tiddler elements within the containing 'tiddlerDisplay' element.''//
***/
//{{{
if (config.browser.isIE) {
document.coreTweaks_coreGetElementById=document.getElementById;
document.getElementById=function(id) {
var e=document.coreTweaks_coreGetElementById(id);
if (!e || !e.parentNode || e.parentNode.id!='tiddlerDisplay') return e;
for (var i=0; i<e.parentNode.childNodes.length; i++)
if (id==e.parentNode.childNodes[i].id) return e.parentNode.childNodes[i];
return null;
};
}
//}}}
// // }}}}}}// // {{block{
/***
!!!471 'creator' field for new tiddlers
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/471 - OPEN
This tweak HIJACKS the core's saveTiddler() function to automatically add a 'creator' field to a tiddler when it is FIRST created. You can use """<<view creator>>""" (or """<<view creator wikified>>""" if you prefer) to show this value embedded directly within the tiddler content, or {{{<span macro="view creator"></span>}}} in the ViewTemplate and/or EditTemplate to display the creator value in each tiddler.
***/
//{{{
// hijack saveTiddler()
TiddlyWiki.prototype.CoreTweaks_creatorSaveTiddler=TiddlyWiki.prototype.saveTiddler;
TiddlyWiki.prototype.saveTiddler=function(title,newTitle,newBody,modifier,modified,tags,fields)
{
var existing=store.tiddlerExists(title);
var tiddler=this.CoreTweaks_creatorSaveTiddler.apply(this,arguments);
if (!existing) store.setValue(title,'creator',config.options.txtUserName);
return tiddler;
}
//}}}
// // }}}}}}
// // closed: won't fix //(leave as core tweaks)//
// // {{block{
/***
!!!637 TiddlyLink tooltip - custom formatting
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/637 - CLOSED: WON'T FIX
This tweak modifies the tooltip format that appears when you mouseover a link to a tiddler. It adds an option to control the date format, as well as displaying the size of the tiddler (in bytes)
Tiddler link tooltip format:
{{stretch{<<option txtTiddlerLinkTootip>>}}}
^^where: %0=title, %1=username, %2=modification date, %3=size in bytes, %4=description slice^^
Tiddler link tooltip date format:
{{stretch{<<option txtTiddlerLinkTooltipDate>>}}}
***/
//{{{
config.messages.tiddlerLinkTooltip='%0 - %1, %2 (%3 bytes) - %4';
config.messages.tiddlerLinkTooltipDate='DDD, MMM DDth YYYY 0hh12:0mm AM';
config.options.txtTiddlerLinkTootip=
config.options.txtTiddlerLinkTootip||config.messages.tiddlerLinkTooltip;
config.options.txtTiddlerLinkTooltipDate=
config.options.txtTiddlerLinkTooltipDate||config.messages.tiddlerLinkTooltipDate;
Tiddler.prototype.getSubtitle = function() {
var modifier = this.modifier;
if(!modifier) modifier = config.messages.subtitleUnknown;
var modified = this.modified;
if(modified) modified = modified.formatString(config.options.txtTiddlerLinkTooltipDate);
else modified = config.messages.subtitleUnknown;
var descr=store.getTiddlerSlice(this.title,'Description')||'';
return config.options.txtTiddlerLinkTootip.format([this.title,modifier,modified,this.text.length,descr]);
};
//}}}
// // }}}}}}// // {{block{
/***
!!!607 add HREF link on permaview command
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/607 - CLOSED: WON'T FIX
This tweak automatically sets the HREF for the 'permaview' sidebar command link so you can use the 'right click' context menu for faster, easier bookmarking. Note that this does ''not'' automatically set the permaview in the browser's current location URL... it just sets the HREF on the command link. You still have to click the link to apply the permaview.
***/
//{{{
config.macros.permaview.handler = function(place)
{
var btn=createTiddlyButton(place,this.label,this.prompt,this.onClick);
addEvent(btn,'mouseover',this.setHREF);
addEvent(btn,'focus',this.setHREF);
};
config.macros.permaview.setHREF = function(event){
var links = [];
story.forEachTiddler(function(title,element) {
links.push(String.encodeTiddlyLink(title));
});
var newURL=document.location.href;
var hashPos=newURL.indexOf('#');
if (hashPos!=-1) newURL=newURL.substr(0,hashPos);
this.href=newURL+'#'+encodeURIComponent(links.join(' '));
}
//}}}
// // }}}}}}// // {{block{
/***
!!!458 add permalink-like HREFs on internal TiddlyLinks
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/458 - CLOSED: WON'T FIX
This tweak assigns a permalink-like HREF to internal Tiddler links (which normally do not have any HREF defined). This permits the link's context menu (right-click) to include 'open link in another window/tab' command. Based on a request from Dustin Spicuzza.
***/
//{{{
window.coreTweaks_createTiddlyLink=window.createTiddlyLink;
window.createTiddlyLink=function(place,title,includeText,theClass,isStatic,linkedFromTiddler,noToggle)
{
// create the core button, then add the HREF (to internal links only)
var link=window.coreTweaks_createTiddlyLink.apply(this,arguments);
if (!isStatic)
link.href=document.location.href.split('#')[0]+'#'+encodeURIComponent(String.encodeTiddlyLink(title));
return link;
}
//}}}
// // }}}}}}
// // <<foldHeadings>>
/***
|Name|DOMViewerPlugin|
|Source|http://www.TiddlyTools.com/#DOMViewerPlugin|
|Version|1.8.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|display internal Document Object Model for wiki-formatted content|
Whenever TiddlyWiki renders a given tiddler, it creates a 'tree' of DOM (Document Object Model) elements that represent the information that is displayed by the browser. You can use the ''DOMViewer'' macro to examine the internal DOM elements that are produced by TiddlyWiki's formatter (the 'wikifier'), or elements directly produced by embedded macros that create custom formatted output. This can be particularly helpful when trying to fine tune the layout and appearance of your tiddler content.
!!!!! Usage/Example:
<<<
syntax: {{{<<DOMViewer rows:nn indent:xxxx inline path elementID|tiddlertitle>>}}}
DOMViewer creates a textarea control and reports the DOM tree for the current 'insertion point' where the DOMViewer macro is being placed. ''inline'' flag uses TiddlyWiki rendering instead of textarea control. ''path'' shows the relative location of each child element in the DOM tree, using subscript notation, ''[elementID or tiddlertitle]'' displays DOM elements starting from the node with the specified ID. If that ID is not found in the DOM tree, the macro attempts to open a tiddler with that title and then displays the DOM elements that were rendered for that tiddler.
<<DOMViewer tiddlerDOMViewerPlugin>>
<<<
!!!!!Revisions
<<<
2007.09.27 [1.8.0] split DOMViewer macro into separate plugin (see [[TidIDEPlugin]])
|please see [[TidIDEPluginInfo]] for additional revision details|
2006.04.15 [0.5.0] Initial ALPHA release. Converted from inline script.
<<<
!!!!!Code
***/
//{{{
version.extensions.DOMViewerPlugin= {major: 1, minor: 8, revision: 0, date: new Date(2006,9,27)};
config.macros.DOMViewer = {
handler: function(place,macroName,params) {
// set default params
var inline=false;
var theRows=15;
var theIndent="| ";
var showPath=false;
var theTarget=place;
// unpack options parameters
if (params[0]=='inline') { inline=true; theIndent=">"; params.shift(); }
if (params[0]&&(params[0].substr(0,7)=="indent:")) { theIndent=params[0].substr(7); params.shift(); }
if (params[0]&&(params[0].substr(0,5)=="rows:")) { theRows=params[0].substr(5); params.shift(); }
if (params[0]=='path') { showPath=true; params.shift(); }
if (params[0]) {
theTarget=document.getElementById(params[0]);
if (!theTarget)
if (store.getTiddler(params[0])!=undefined) {
theTarget=document.getElementById("tiddler"+params[0]);
if (!theTarget && confirm("DOMViewer asks:\n\nIs it OK to open tiddler '"+params[0]+"' now?")) {
story.displayTiddler(null,params[0],1,null,null,false);
theTarget=document.getElementById("tiddler"+params[0]);
}
}
params.shift();
}
// generate and display DOM tree
if (inline) {
var out=this.getNodeTree(theTarget,theIndent,showPath,inline);
wikify(out,place);
}
else {
var out=this.getNodeTree(theTarget,theIndent,showPath,inline);
var css=".DOMViewer{width:100%;font-size:8pt;color:inherit;background:transparent;border:0px;}";
setStylesheet(css,"DOMViewerStylesheet");
var theTextArea=createTiddlyElement(place,"textarea",null,"DOMViewer",out);
theTextArea.rows=theRows;
theTextArea.cols=60;
theTextArea.wrap="off";
theTextArea.theTarget=theTarget;
theTextArea.theIndent=theIndent;
theTextArea.showPath=showPath;
}
},
getNodeTree: function(theNode,theIndent,showPath,inline,thePrefix,thePath) {
if (!theNode) return "";
if (!thePrefix) thePrefix="";
if (!thePath) thePath="";
var mquote='"'+(inline?"{{{":"");
var endmquote=(inline?"}}}":"")+'"';
// generate output for this node
var out = thePrefix;
if (showPath && thePath.length)
out += (inline?"//":"")+thePath.substr(1)+":"+(inline?"//":"")+"\r\n"+thePrefix;
if (theNode.className=="DOMViewer")
return out+'[DOMViewer]\r\n'; // avoid self-referential recursion
out += (inline?"''":"")+theNode.nodeName.toUpperCase()+(inline?"''":"");
if (theNode.nodeName=="#text")
out += ' '+mquote+theNode.nodeValue.replace(/\n/g,'\\n')+endmquote;
if (theNode.className)
out += ' class='+mquote+theNode.className+endmquote;
if (theNode.type)
out += ' type='+mquote+theNode.type+endmquote;
if (theNode.id)
out += ' id='+mquote+theNode.id+endmquote;
if (theNode.name)
out += " "+theNode.name+(theNode.value?"="+mquote+theNode.value+endmquote:"");
if (theNode.href)
out += ' href='+mquote+theNode.href+endmquote;
if (theNode.src)
out += ' src='+mquote+theNode.src+endmquote;
if (theNode.attributes && theNode.getAttribute("tiddlyLink")!=undefined)
out += ' tiddler='+mquote+theNode.getAttribute("tiddlyLink")+endmquote;
out += "\r\n";
// recursively generate output for child nodes
thePath=thePath+"."+theNode.nodeName.toLowerCase();
thePrefix=theIndent+thePrefix;
for (var i=0;i<theNode.childNodes.length;i++) {
var thisChild=theNode.childNodes.item(i);
var theNum=(inline?"~~":"(")+(i+1)+(inline?"~~":")");
out += this.getNodeTree(thisChild,theIndent,showPath,inline,thePrefix,thePath+theNum);
}
return out;
}
}
//}}}
FunMouseMoveDemo
FunMouseMoveDemoMultiImageTrickery
FlockingDemo
QuadrantEffect
RaphaelEmbeddedImageDemo10
TiddlyWiki FireFox TiddlyTools TiddlyTech HowTo $1
/***
|Name|DisableWikiLinksPlugin|
|Source|http://www.TiddlyTools.com/#DisableWikiLinksPlugin|
|Version|1.6.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Tiddler.prototype.autoLinkWikiWords, 'wikiLink' formatter|
|Options|##Configuration|
|Description|selectively disable TiddlyWiki's automatic ~WikiWord linking behavior|
This plugin allows you to disable TiddlyWiki's automatic ~WikiWord linking behavior, so that WikiWords embedded in tiddler content will be rendered as regular text, instead of being automatically converted to tiddler links. To create a tiddler link when automatic linking is disabled, you must enclose the link text within {{{[[...]]}}}.
!!!!!Usage
<<<
You can block automatic WikiWord linking behavior for any specific tiddler by ''tagging it with<<tag excludeWikiWords>>'' (see configuration below) or, check a plugin option to disable automatic WikiWord links to non-existing tiddler titles, while still linking WikiWords that correspond to existing tiddlers titles or shadow tiddler titles. You can also block specific selected WikiWords from being automatically linked by listing them in [[DisableWikiLinksList]] (see configuration below), separated by whitespace. This tiddler is optional and, when present, causes the listed words to always be excluded, even if automatic linking of other WikiWords is being permitted.
Note: WikiWords contained in default ''shadow'' tiddlers will be automatically linked unless you select an additional checkbox option lets you disable these automatic links as well, though this is not recommended, since it can make it more difficult to access some TiddlyWiki standard default content (such as AdvancedOptions or SideBarTabs)
<<<
!!!!!Configuration
<<<
<<option chkDisableWikiLinks>> Disable ALL automatic WikiWord tiddler links
<<option chkAllowLinksFromShadowTiddlers>> ... except for WikiWords //contained in// shadow tiddlers
<<option chkDisableNonExistingWikiLinks>> Disable automatic WikiWord links for non-existing tiddlers
Disable automatic WikiWord links for words listed in: <<option txtDisableWikiLinksList>>
Disable automatic WikiWord links for tiddlers tagged with: <<option txtDisableWikiLinksTag>>
<<<
!!!!!Revisions
<<<
2008.07.22 [1.6.0] hijack tiddler changed() method to filter disabled wiki words from internal links[] array (so they won't appear in the missing tiddlers list)
2007.06.09 [1.5.0] added configurable txtDisableWikiLinksTag (default value: "excludeWikiWords") to allows selective disabling of automatic WikiWord links for any tiddler tagged with that value.
2006.12.31 [1.4.0] in formatter, test for chkDisableNonExistingWikiLinks
2006.12.09 [1.3.0] in formatter, test for excluded wiki words specified in DisableWikiLinksList
2006.12.09 [1.2.2] fix logic in autoLinkWikiWords() (was allowing links TO shadow tiddlers, even when chkDisableWikiLinks is TRUE).
2006.12.09 [1.2.1] revised logic for handling links in shadow content
2006.12.08 [1.2.0] added hijack of Tiddler.prototype.autoLinkWikiWords so regular (non-bracketed) WikiWords won't be added to the missing list
2006.05.24 [1.1.0] added option to NOT bypass automatic wikiword links when displaying default shadow content (default is to auto-link shadow content)
2006.02.05 [1.0.1] wrapped wikifier hijack in init function to eliminate globals and avoid FireFox 1.5.0.1 crash bug when referencing globals
2005.12.09 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.DisableWikiLinksPlugin= {major: 1, minor: 6, revision: 0, date: new Date(2008,7,22)};
if (config.options.chkDisableNonExistingWikiLinks==undefined) config.options.chkDisableNonExistingWikiLinks= false;
if (config.options.chkDisableWikiLinks==undefined) config.options.chkDisableWikiLinks=false;
if (config.options.txtDisableWikiLinksList==undefined) config.options.txtDisableWikiLinksList="DisableWikiLinksList";
if (config.options.chkAllowLinksFromShadowTiddlers==undefined) config.options.chkAllowLinksFromShadowTiddlers=true;
if (config.options.txtDisableWikiLinksTag==undefined) config.options.txtDisableWikiLinksTag="excludeWikiWords";
// find the formatter for wikiLink and replace handler with 'pass-thru' rendering
initDisableWikiLinksFormatter();
function initDisableWikiLinksFormatter() {
for (var i=0; i<config.formatters.length && config.formatters[i].name!="wikiLink"; i++);
config.formatters[i].coreHandler=config.formatters[i].handler;
config.formatters[i].handler=function(w) {
// supress any leading "~" (if present)
var skip=(w.matchText.substr(0,1)==config.textPrimitives.unWikiLink)?1:0;
var title=w.matchText.substr(skip);
var exists=store.tiddlerExists(title);
var inShadow=w.tiddler && store.isShadowTiddler(w.tiddler.title);
// check for excluded Tiddler
if (w.tiddler && w.tiddler.isTagged(config.options.txtDisableWikiLinksTag))
{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }
// check for specific excluded wiki words
var t=store.getTiddlerText(config.options.txtDisableWikiLinksList);
if (t && t.length && t.indexOf(w.matchText)!=-1)
{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }
// if not disabling links from shadows (default setting)
if (config.options.chkAllowLinksFromShadowTiddlers && inShadow)
return this.coreHandler(w);
// check for non-existing non-shadow tiddler
if (config.options.chkDisableNonExistingWikiLinks && !exists)
{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }
// if not enabled, just do standard WikiWord link formatting
if (!config.options.chkDisableWikiLinks)
return this.coreHandler(w);
// just return text without linking
w.outputText(w.output,w.matchStart+skip,w.nextMatch)
}
}
Tiddler.prototype.coreAutoLinkWikiWords = Tiddler.prototype.autoLinkWikiWords;
Tiddler.prototype.autoLinkWikiWords = function()
{
// if all automatic links are not disabled, just return results from core function
if (!config.options.chkDisableWikiLinks)
return this.coreAutoLinkWikiWords.apply(this,arguments);
return false;
}
Tiddler.prototype.disableWikiLinks_changed = Tiddler.prototype.changed;
Tiddler.prototype.changed = function()
{
this.disableWikiLinks_changed.apply(this,arguments);
// remove excluded wiki words from links array
var t=store.getTiddlerText(config.options.txtDisableWikiLinksList,"").readBracketedList();
if (t.length) for (var i=0; i<t.length; i++)
if (this.links.contains(t[i]))
this.links.splice(this.links.indexOf(t[i]),1);
};
//}}}
This package helps you to //''discover''// the connections and interrelationships between the tiddlers contained in a TiddlyWiki document. This is particularly useful where the contents of a document are not already known, such as when a document has been edited by several people, or has gradually changed over an extended period of time.
There is a lot of interesting data available from the census bureau in
the form of generalized ArcView Shapefiles
http://www.census.gov/geo/www/cob/shape_info.html
arcview is an open format from ESRI (esri.com) sort of like pdf in its use
There are interesting things that can be done e.g. organizing census
data within zip
http://www.census.gov/geo/www/cob/zt_metadata.html
and lots or other things one could do
There is free software to do it
It's a google project http://code.google.com/p/geodjango-basic-apps/
http://code.djangoproject.com/wiki/GeoDjango &
http://geodjango.org/
that's based on a free python project to do it
http://www.djangoproject.com/
a good article on it
http://www.geoconnexion.com/uploads/opensource_14_intv7i9.pdf
& slide show
http://geodjango.org/presentations/GeoDjango%20-%20A%20world-class%20Geographic%20Web%20Framework%20(DjangoCon%20-%20Sept.%206,%202008).pdf
I think there's a pony in this for putting together something very
useful and profitable (with contributions back to the community).
<script>
var tid=story.findContainingTiddler(place);
if (tid) tid.style.border="1px dotted "+store.getTiddlerSlice("ColorPalette","SecondaryDark");
</script>
/***
|Name|EditFieldPlugin|
|Source|http://www.TiddlyTools.com/#EditFieldPlugin|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|extend core edit macro for use in ViewTemplates or direct embedding in tiddler content|
This plugin extends the core {{{<<edit fieldname #OfLines>>}}} macro for use in a ViewTemplate or directly embedded in tiddler content.
!!!!!Usage
<<<
Normally, when you edit a tiddler, any changes you make are saved (or discarded) when you press the "done" (or "cancel") command in the tiddler editor's toolbar. However, when in a 'view mode' context, these command items are not available, and so the TiddlyWiki core commands cannot be used to trigger the 'save/discard' handling once you have decided that your input activities are complete.
This plugin extends the core's input field handling, so that when:
{{{
<<edit fieldname numberOfLines>>
}}}
is used in tiddler content, or:
{{{
<span macro='edit fieldname numberOfLines'></span>
}}}
is used in a ViewTemplate definition, you will be automatically prompted to save/discard your changes (if any) as soon as you press ENTER or move away ('onBlur' handling) from that input field (if the content has been changed). You can also abandon your changes to input field content by pressing ESCAPE (you will be asked to confirm before discarding changes).
You can change the browser-defined default width of an input field by surrounding the edit field by using custom CSS class wrappers, defined in the StyleSheet tiddler. For example:
{{{
.stretch input { width:99%; }
.stretch textarea { width:99%; }
.onechar input { width:1em; }
.twochar input { width:2em; }
.threechar input { width:3em; }
.fourchar input { width:4em; }
.fivechar input { width:5em; }
}}}
>Note: the 'fixed' width values in the above example are only approximate. The actual width rendered by your browser will vary based on the current font-family and font-size that is applied to the field.
<<<
!!!!!Examples
<<<
*"""<<edit foobar>>"""<br> <<edit foobar>>
*"""{{threechar{<<edit foobar>>}}}"""<br> {{threechar{<<edit foobar>>}}}
*"""<<edit tags>>"""<br> <<edit tags>>
*"""{{stretch{<<edit text 10>>}}}"""<br> {{stretch{<<edit text 10>>}}}
<<<
!!!!!Revisions
<<<
2007.08.22 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.EditFieldPlugin= {major: 1, minor: 0, revision: 0, date: new Date(2007,8,22)};
config.macros.edit.editFieldPlugin_savedHandler=config.macros.edit.handler;
config.macros.edit.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
// let core create edit field
config.macros.edit.editFieldPlugin_savedHandler.apply(this,arguments);
// get edit field or textarea
var fieldType=params[0]=="text"||params[1]?'textarea':'input';
var ins=place.getElementsByTagName(fieldType);
var e=ins[ins.length-1];
if (fieldType=="textarea" && params[1]) e.style.height=params[1]+"em"; // force height for textarea field
// if viewing tiddler, add autosave handlers
var here=story.findContainingTiddler(place);
if (here && here.getAttribute("template").indexOf("ViewTemplate")!=-1) {
story.setDirty(tiddler.title,false); // clear tiddler ("dirty") flag set by core when field was created
var field=e.getAttribute("edit");
var val=store.getValue(tiddler.title,field); if (!val) val="";
e.setAttribute("currval",val); // remember starting value
e.setAttribute("tiddler",tiddler.title); // remember target tiddler
e.onkeydown=function(ev) { // ENTER key=save (for single-line edit fields only)
var event=ev?ev:window.event;
this.setAttribute("keyCode",event.keyCode); // save last keyCode for blur() handler
if (event.keyCode==13 && this.nodeName.toUpperCase()!="TEXTAREA")
this.saveField(); // save input to tiddler field
}
e.onblur=function(ev) { // accept or reject input when focus moves away from field
var event=ev?ev:window.event;
var tid=this.getAttribute("tiddler"); if (!tid || !tid.length) return;
var field=this.getAttribute("edit");
if (this.value!=this.getAttribute("currval")) { // if value has changed
if (this.getAttribute("keyCode")=="27") { // if user pressed ESC
var msg="Abandon changes to %0@%1?".format([field,tid]);
if (confirm(msg)) this.value=this.getAttribute("currval"); // reset to starting value
this.id=new Date().getTime(); // set unique ID
setTimeout("document.getElementById('"+this.id+"').focus()",1); // restore focus (after blur completes)
} else { // other focus change events
var msg="Save changes to %0@%1?".format([field,tid]);
if (confirm(msg)) this.saveField(); // save input to tiddler field, then continue blur
else this.value=this.getAttribute("currval"); // reset to starting value, then continue blur
}
}
};
e.saveField=function() { // save input value to tiddler field (create, touch or rename tiddler as needed)
var tid=this.getAttribute("tiddler"); if (!tid || !tid.length) return;
var field=this.getAttribute("edit");
var title=(field=="title")?this.value:tid;
if (!title.length) { // prevent blank tiddler title from being used
this.value=this.getAttribute("currval"); // reset to starting value
this.id=new Date().getTime(); // set unique ID
setTimeout("displayMessage('Please enter a non-blank value')",1); // notify user
setTimeout("document.getElementById('"+this.id+"').focus()",2); // set focus to continue editing
return;
}
var t=store.getTiddler(tid);
store.suspendNotifications();
var anim=config.options.chkAnimate; config.options.chkAnimate=false; // suspend animation
var who=t&&config.options.chkForceMinorUpdate?t.modifier:config.options.txtUserName;
var when=t&&config.options.chkForceMinorUpdate?t.modified:new Date();
store.saveTiddler(t?tid:title,title,t?t.text:"",who,when,t?t.tags:[],t?t.fields:null);
store.setValue(title,field,this.value); // save value in tiddler field
this.setAttribute("currval",this.value); // remember new starting value
if (tid!=title) // if title changed, display renamed tiddler in place of current one
{ story.displayTiddler(story.findContainingTiddler(this),title); story.closeTiddler(tid); }
if (field=="text") // if tiddler content changed, refresh tiddler display
{ story.refreshTiddler(title,null,true); }
config.options.chkAnimate=anim; // resume animation
store.resumeNotifications();
store.notify(title,true);
};
}
}
//}}}
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<span macro='resizeEditor'></span>
<span macro='setUserName'></span>
<!--}}}-->
/%
|Name|EmbedTiddlers|
|Source|http://www.TiddlyTools.com/#EmbedTiddlers|
|Version|1.2.2|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|transclude a list of tiddlers in a specific order|
usage:
<<tiddler EmbedTiddlers with: "TiddlerName [[TiddlerName with spaces]] TiddlerName ...">>
or
<<tiddler EmbedTiddlers with: @TiddlerName>>
or
<<tiddler EmbedTiddlers with: =tagValue sortby>>
where
@TiddlerName
specifies a //separate// tiddler containing the space-separated,
bracketed list of tiddlers to transclude (e.g., DefaultTiddlers)
=tagValue
embeds all tiddlers tagged with the indicated value
sortby (optional)
specifies a tiddler field for sorting the results (default="title")
"+" or "-" prefix indicates the sort direction (ascending/descending),
e.g., "-modified" sorts by tiddler modification date, most recent first
Note: if MatchTagsPlugin is installed, you can use FULL BOOLEAN LOGIC EXPRESSIONS
in place of the "tagValue" (following the leading "="). However, because the boolean
expression will contain spaces, it MUST be enclosed in [[...]], like this:
<<tiddler EmbedTiddlers with: [[=settings AND NOT systemConfig]]>>
%/<script>
var list='$1';
var sortby='title'; if ('$2'!='$'+'2') sortby='$2';
var tids=[];
if (list.substr(0,1)=='=') {
var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
var tagged=store.sortTiddlers(fn.apply(store,[list.substr(1)]),sortby);
for (var t=0; t<tagged.length; t++) tids.push(tagged[t].title);
} else {
if (list.substr(0,1)=='@') list=store.getTiddlerText(list.substr(1),'');
var tids=list.readBracketedList();
}
var out='';
for (var i=0; i<tids.length; i++) out+='<<tiddler [['+tids[i]+']]>>';
return out;
</script>
<<tiddler {{tiddler.title+'##render'}} with: {{tiddler.title+'##PathData'}} Path1 100% 500 black>>
<<tiddler {{tiddler.title+'##render'}} with: {{tiddler.title+'##PathData'}} Path2 100% 300 #abc>>/%
!PathData
red
M240,350 l 50,-25 a25,25 -30 0,1 50,-25 l 50,-25 a25,50 -30 0,1 50,-25 l 50,-25 a25,75 -30 0,1 50,-25 l 50,-25 a25,100 -30 0,1 50,-25 l 50,-25
blue
M220,350 l 50,-25 a25,25 -30 0,1 50,-25 l 50,-25 a25,50 -30 0,1 50,-25 l 50,-25 a25,75 -30 0,1 50,-25 l 50,-25 a25,100 -30 0,1 50,-25 l 50,-25
green
M200,350 l 50,-25 a25,25 -30 0,1 50,-25 l 50,-25 a25,50 -30 0,1 50,-25 l 50,-25 a25,75 -30 0,1 50,-25 l 50,-25 a25,100 -30 0,1 50,-25 l 50,-25
!end
!render
<script>
// USAGE: <<tiddler ##render with: SourceTiddlerName raphaelObjectID width height backgroundColor>>
var lines=store.getTiddlerText('$1').split('\n');
var holder = createTiddlyElement(place,'div',null,'holder_$2');
var r = Raphael(holder, '$3', '$4');
var out=[]; for (var i=0; i<lines.length; i=i+2) {
var color=lines[i]; var path=lines[i+1];
var x=r.path({id: '$2_'+color, stroke: color, 'stroke-width': '5' }, path);
}
</script><html><style>
.holder_$2 { border:1px solid; background:$5; }
</style></html>
!end
%/
{{holder{<script>
var s=place.style; s.position='absolute'; s.top=s.left='0px'; s.width='100%';
var text = 'TiddlyTools';
var attr = {"font": '18pt "Verdana"', opacity: 0.5};
var R = Raphael(place,200,200);
var txt = [];
txt[0] = R.text(100, 100, text).attr(attr).attr("fill", "#0f0");
txt[1] = R.text(100, 100, text).attr(attr).attr("fill", "#f00");
txt[2] = R.text(100, 100, text).attr(attr).attr("fill", "#00f");
place.onmousemove=function (e) { var ev=e||window.event;
var x=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX()); // mouse X
var diff=x-this.lastX||x;
txt[0].rotate(diff); txt[1].rotate(diff*1.5); txt[2].rotate(diff*2);
this.lastX=x;
};
</script>}}}
/***
|Name|ExportTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#ExportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ExportTiddlersPluginInfo|
|Version|2.8.5|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|select and extract tiddlers from your ~TiddlyWiki documents and save them to a separate file|
This plugin provides a control panel to select/export tiddlers to another TiddlyWiki document. You can also save just the selected tiddlers as a TiddlyWiki '~PureStore' file (much smaller files!), or create plain-text output for manual copy/paste into other applications or XML files that can be used to publish an ~RSS news feed.
!!!!!Documentation
>see [[ExportTiddlersPluginInfo]]
!!!!!Inline control panel (live):
><<exportTiddlers inline>>
!!!!!Revisions
<<<
2009.02.26 [2.8.5] use macro-specific definition of $() function abbreviation (avoids conflict with JQuery)
|please see [[ExportTiddlersPluginInfo]] for additional revision details|
2005.10.09 [0.0.0] development started
<<<
!!!!!Code
***/
//{{{
// version
version.extensions.ExportTiddlersPlugin= {major: 2, minor: 8, revision: 5, date: new Date(2009,2,26)};
// default shadow definition
config.shadowTiddlers.ExportTiddlers='<<exportTiddlers inline>>';
// add 'export' backstage task (following built-in import task)
if (config.tasks) { // TW2.2 or above
config.tasks.exportTask = {
text:'export',
tooltip:'Export selected tiddlers to another file',
content:'<<exportTiddlers inline>>'
}
config.backstageTasks.splice(config.backstageTasks.indexOf('importTask')+1,0,'exportTask');
}
config.macros.exportTiddlers = {
$: function(id) { return document.getElementById(id); }, // abbreviation
label: 'export tiddlers',
prompt: 'Copy selected tiddlers to an export document',
okmsg: '%0 tiddlers written to %1',
failmsg: 'An error occurred while creating %1',
mergeprompt: '%0\nalready contains tiddler definitions.\n'
+'\nPress OK to add new/revised tiddlers to current file contents.'
+'\nPress Cancel to completely replace file contents',
mergestatus: 'Merged %0 new/revised tiddlers with %1 previously saved tiddlers',
statusmsg: '%0 tiddler%1 - %2 selected for export',
newdefault: 'export.html',
datetimefmt: '0MM/0DD/YYYY 0hh:0mm:0ss', // for 'filter date/time' edit fields
type_TW: 'tw', type_PS: 'ps', type_TX: 'tx', type_NF: 'nf', // file type tokens
type_map: { // map filetype param alternatives/abbreviations to token values
tiddlywiki:'tw', tw:'tw', wiki: 'tw',
purestore: 'ps', ps:'ps', store:'ps',
plaintext: 'tx', tx:'tx', text: 'tx',
newsfeed: 'nf', nf:'nf', xml: 'nf', rss:'nf'
},
handler: function(place,macroName,params) {
if (params[0]!='inline')
{ createTiddlyButton(place,this.label,this.prompt,this.togglePanel); return; }
var panel=this.createPanel(place);
panel.style.position='static';
panel.style.display='block';
},
createPanel: function(place) {
var panel=this.$('exportPanel');
if (panel) { panel.parentNode.removeChild(panel); }
setStylesheet(this.css,'exportTiddlers');
panel=createTiddlyElement(place,'span','exportPanel',null,null)
panel.innerHTML=this.html;
this.initFilter();
this.refreshList(0);
var fn=this.$('exportFilename');
if (window.location.protocol=='file:' && !fn.value.length) {
// get new target path/filename
var newPath=getLocalPath(window.location.href);
var slashpos=newPath.lastIndexOf('/'); if (slashpos==-1) slashpos=newPath.lastIndexOf('\\');
if (slashpos!=-1) newPath=newPath.substr(0,slashpos+1); // trim filename
fn.value=newPath+this.newdefault;
}
return panel;
},
togglePanel: function(e) { var e=e||window.event;
var cme=config.macros.exportTiddlers; // abbrev
var parent=resolveTarget(e).parentNode;
var panel=cme.$('exportPanel');
if (panel==undefined || panel.parentNode!=parent)
panel=cme.createPanel(parent);
var isOpen=panel.style.display=='block';
if(config.options.chkAnimate)
anim.startAnimating(new Slider(panel,!isOpen,e.shiftKey || e.altKey,'none'));
else
panel.style.display=isOpen?'none':'block' ;
if (panel.style.display!='none') { // update list and set focus when panel is made visible
cme.refreshList(0);
cme.$('exportFilename').focus();
cme.$('exportFilename').select();
}
e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation(); return(false);
},
css: '\
#exportPanel {\
display: none; position:absolute; z-index:12; width:35em; right:105%; top:6em;\
background-color: #eee; color:#000; font-size: 8pt; line-height:110%;\
border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;\
padding: 0.5em; margin:0em; -moz-border-radius:1em;-webkit-border-radius:1em;\
}\
#exportPanel a, #exportPanel td a { color:#009; display:inline; margin:0px; padding:1px; }\
#exportPanel table { \
width:100%; border:0px; padding:0px; margin:0px;\
font-size:8pt; line-height:110%; background:transparent;\
}\
#exportPanel tr { border:0px;padding:0px;margin:0px; background:transparent; }\
#exportPanel td { color:#000; border:0px;padding:0px;margin:0px; background:transparent; }\
#exportPanel select { width:98%;margin:0px;font-size:8pt;line-height:110%;}\
#exportPanel input { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%; }\
#exportPanel textarea { width:98%;padding:0px;margin:0px;overflow:auto;font-size:8pt; }\
#exportPanel .box { \
border:1px solid black; padding:3px; margin-bottom:5px; \
background:#f8f8f8; -moz-border-radius:5px;-webkit-border-radius:5px; }\
#exportPanel .topline { border-top:2px solid black; padding-top:3px; margin-bottom:5px; }\
#exportPanel .rad { width:auto;border:0 }\
#exportPanel .chk { width:auto;border:0 }\
#exportPanel .btn { width:auto; }\
#exportPanel .btn1 { width:98%; }\
#exportPanel .btn2 { width:48%; }\
#exportPanel .btn3 { width:32%; }\
#exportPanel .btn4 { width:24%; }\
#exportPanel .btn5 { width:19%; }\
',
html: '\
<!-- target path/file -->\
<div>\
export to path/filename:<br>\
<input type="text" id="exportFilename" size=40 style="width:93%"><input \
type="button" id="exportBrowse" value="..." title="select or enter a local folder/file..." style="width:5%" \
onclick="var fn=config.macros.exportTiddlers.askForFilename(this); if (fn.length) this.previousSibling.value=fn; ">\
</div>\
<!-- output format -->\
<div>\
output file format:\
<select id="exportFormat" size=1>\
<option value="TW">TiddlyWiki HTML document (includes core code)</option>\
<option value="PS">TiddlyWiki "PureStore" HTML file (tiddler data only)</option>\
<option value="TX">TiddlyWiki plain text TXT file (tiddler source listing)</option>\
<option value="NF">RSS NewsFeed XML file</option>\
</select>\
</div>\
<!-- notes -->\
<div>\
notes:<br>\
<textarea id="exportNotes" rows=3 cols=40 style="height:4em;margin-bottom:5px;" onfocus="this.select()"></textarea> \
</div>\
<!-- list of tiddlers -->\
<table><tr align="left"><td>\
select:\
<a href="JavaScript:;" id="exportSelectAll"\
onclick="config.macros.exportTiddlers.process(this)" title="select all tiddlers">\
all </a>\
<a href="JavaScript:;" id="exportSelectChanges"\
onclick="config.macros.exportTiddlers.process(this)" title="select tiddlers changed since last save">\
changes </a> \
<a href="JavaScript:;" id="exportSelectOpened"\
onclick="config.macros.exportTiddlers.process(this)" title="select tiddlers currently being displayed">\
opened </a> \
<a href="JavaScript:;" id="exportSelectRelated"\
onclick="config.macros.exportTiddlers.process(this)" title="select tiddlers related to the currently selected tiddlers">\
related </a> \
<a href="JavaScript:;" id="exportToggleFilter"\
onclick="config.macros.exportTiddlers.process(this)" title="show/hide selection filter">\
filter </a> \
</td><td align="right">\
<a href="JavaScript:;" id="exportListSmaller"\
onclick="config.macros.exportTiddlers.process(this)" title="reduce list size">\
– </a>\
<a href="JavaScript:;" id="exportListLarger"\
onclick="config.macros.exportTiddlers.process(this)" title="increase list size">\
+ </a>\
</td></tr></table>\
<select id="exportList" multiple size="10" style="margin-bottom:5px;"\
onchange="config.macros.exportTiddlers.refreshList(this.selectedIndex)">\
</select><br>\
</div><!--box-->\
<!-- selection filter -->\
<div id="exportFilterPanel" style="display:none">\
<table><tr align="left"><td>\
selection filter\
</td><td align="right">\
<a href="JavaScript:;" id="exportHideFilter"\
onclick="config.macros.exportTiddlers.process(this)" title="hide selection filter">hide</a>\
</td></tr></table>\
<div class="box">\
<input type="checkbox" class="chk" id="exportFilterStart" value="1"\
onclick="config.macros.exportTiddlers.showFilterFields(this)"> starting date/time<br>\
<table cellpadding="0" cellspacing="0"><tr valign="center"><td width="50%">\
<select size=1 id="exportFilterStartBy" \
onchange="config.macros.exportTiddlers.showFilterFields(this);">\
<option value="0">today</option>\
<option value="1">yesterday</option>\
<option value="7">a week ago</option>\
<option value="30">a month ago</option>\
<option value="file">file date</option>\
<option value="other">other (mm/dd/yyyy hh:mm)</option>\
</select>\
</td><td width="50%">\
<input type="text" id="exportStartDate" onfocus="this.select()"\
onchange="config.macros.exportTiddlers.$(\'exportFilterStartBy\').value=\'other\';">\
</td></tr></table>\
<input type="checkbox" class="chk" id="exportFilterEnd" value="1"\
onclick="config.macros.exportTiddlers.showFilterFields(this)"> ending date/time<br>\
<table cellpadding="0" cellspacing="0"><tr valign="center"><td width="50%">\
<select size=1 id="exportFilterEndBy" \
onchange="config.macros.exportTiddlers.showFilterFields(this);">\
<option value="0">today</option>\
<option value="1">yesterday</option>\
<option value="7">a week ago</option>\
<option value="30">a month ago</option>\
<option value="file">file date</option>\
<option value="other">other (mm/dd/yyyy hh:mm)</option>\
</select>\
</td><td width="50%">\
<input type="text" id="exportEndDate" onfocus="this.select()"\
onchange="config.macros.exportTiddlers.$(\'exportFilterEndBy\').value=\'other\';">\
</td></tr></table>\
<input type="checkbox" class="chk" id=exportFilterTags value="1"\
onclick="config.macros.exportTiddlers.showFilterFields(this)"> match tags<br>\
<input type="text" id="exportTags" onfocus="this.select()">\
<input type="checkbox" class="chk" id=exportFilterText value="1"\
onclick="config.macros.exportTiddlers.showFilterFields(this)"> match titles/tiddler text<br>\
<input type="text" id="exportText" onfocus="this.select()">\
</div> <!--box-->\
</div> <!--panel-->\
<!-- action buttons -->\
<div style="text-align:center">\
<input type=button class="btn4" onclick="config.macros.exportTiddlers.process(this)"\
id="exportFilter" value="apply filter">\
<input type=button class="btn4" onclick="config.macros.exportTiddlers.process(this)"\
id="exportStart" value="export tiddlers">\
<input type=button class="btn4" onclick="config.macros.exportTiddlers.process(this)"\
id="exportDelete" value="delete tiddlers">\
<input type=button class="btn4" onclick="config.macros.exportTiddlers.process(this)"\
id="exportClose" value="close">\
</div><!--center-->\
',
process: function(which) { // process panel control interactions
var theList=this.$('exportList'); if (!theList) return;
var count = 0;
var total = store.getTiddlers('title').length;
switch (which.id) {
case 'exportFilter':
count=this.filterExportList();
var panel=this.$('exportFilterPanel');
if (count==-1) { panel.style.display='block'; break; }
this.$('exportStart').disabled=(count==0);
this.$('exportDelete').disabled=(count==0);
this.displayStatus(count,total);
if (count==0) { alert('No tiddlers were selected'); panel.style.display='block'; }
break;
case 'exportStart':
this.go();
break;
case 'exportDelete':
this.deleteTiddlers();
break;
case 'exportHideFilter':
case 'exportToggleFilter':
var panel=this.$('exportFilterPanel')
panel.style.display=(panel.style.display=='block')?'none':'block';
break;
case 'exportSelectChanges':
var lastmod=new Date(document.lastModified);
for (var t = 0; t < theList.options.length; t++) {
if (theList.options[t].value=='') continue;
var tiddler=store.getTiddler(theList.options[t].value); if (!tiddler) continue;
theList.options[t].selected=(tiddler.modified>lastmod);
count += (tiddler.modified>lastmod)?1:0;
}
this.$('exportStart').disabled=(count==0);
this.$('exportDelete').disabled=(count==0);
this.displayStatus(count,total);
if (count==0) alert('There are no unsaved changes');
break;
case 'exportSelectAll':
for (var t = 0; t < theList.options.length; t++) {
if (theList.options[t].value=='') continue;
theList.options[t].selected=true;
count += 1;
}
this.$('exportStart').disabled=(count==0);
this.$('exportDelete').disabled=(count==0);
this.displayStatus(count,count);
break;
case 'exportSelectOpened':
for (var t=0; t<theList.options.length; t++) theList.options[t].selected=false;
var tiddlerDisplay=this.$('tiddlerDisplay');
for (var t=0; t<tiddlerDisplay.childNodes.length;t++) {
var tiddler=tiddlerDisplay.childNodes[t].id.substr(7);
for (var i=0; i<theList.options.length; i++) {
if (theList.options[i].value!=tiddler) continue;
theList.options[i].selected=true; count++; break;
}
}
this.$('exportStart').disabled=(count==0);
this.$('exportDelete').disabled=(count==0);
this.displayStatus(count,total);
if (count==0) alert('There are no tiddlers currently opened');
break;
case 'exportSelectRelated':
// recursively build list of related tiddlers
function getRelatedTiddlers(tid,tids) {
var t=store.getTiddler(tid); if (!t || tids.contains(tid)) return tids;
tids.push(t.title);
if (!t.linksUpdated) t.changed();
for (var i=0; i<t.links.length; i++)
if (t.links[i]!=tid) tids=getRelatedTiddlers(t.links[i],tids);
return tids;
}
// for all currently selected tiddlers, gather up the related tiddlers (including self) and select them as well
var tids=[];
for (var i=0; i<theList.options.length; i++)
if (theList.options[i].selected) tids=getRelatedTiddlers(theList.options[i].value,tids);
// select related tiddlers (includes original selected tiddlers)
for (var i=0; i<theList.options.length; i++)
theList.options[i].selected=tids.contains(theList.options[i].value);
this.displayStatus(tids.length,total);
break;
case 'exportListSmaller': // decrease current listbox size
var min=5;
theList.size-=(theList.size>min)?1:0;
break;
case 'exportListLarger': // increase current listbox size
var max=(theList.options.length>25)?theList.options.length:25;
theList.size+=(theList.size<max)?1:0;
break;
case 'exportClose':
this.$('exportPanel').style.display='none';
break;
}
},
displayStatus: function(count,total) {
var txt=this.statusmsg.format([total,total!=1?'s':'',!count?'none':count==total?'all':count]);
clearMessage(); displayMessage(txt);
return txt;
},
refreshList: function(selectedIndex) {
var theList = this.$('exportList'); if (!theList) return;
// get the sort order
var sort;
if (!selectedIndex) selectedIndex=0;
if (selectedIndex==0) sort='modified';
if (selectedIndex==1) sort='title';
if (selectedIndex==2) sort='modified';
if (selectedIndex==3) sort='modifier';
if (selectedIndex==4) sort='tags';
// unselect headings and count number of tiddlers actually selected
var count=0;
for (var t=5; t < theList.options.length; t++) {
if (!theList.options[t].selected) continue;
if (theList.options[t].value!='')
count++;
else { // if heading is selected, deselect it, and then select and count all in section
theList.options[t].selected=false;
for ( t++; t<theList.options.length && theList.options[t].value!=''; t++) {
theList.options[t].selected=true;
count++;
}
}
}
// disable 'export' and 'delete' buttons if no tiddlers selected
this.$('exportStart').disabled=(count==0);
this.$('exportDelete').disabled=(count==0);
// show selection count
var tiddlers = store.getTiddlers('title');
if (theList.options.length) this.displayStatus(count,tiddlers.length);
// if a [command] item, reload list... otherwise, no further refresh needed
if (selectedIndex>4) return;
// clear current list contents
while (theList.length > 0) { theList.options[0] = null; }
// add heading and control items to list
var i=0;
var indent=String.fromCharCode(160)+String.fromCharCode(160);
theList.options[i++]=
new Option(tiddlers.length+' tiddlers in document', '',false,false);
theList.options[i++]=
new Option(((sort=='title' )?'>':indent)+' [by title]', '',false,false);
theList.options[i++]=
new Option(((sort=='modified')?'>':indent)+' [by date]', '',false,false);
theList.options[i++]=
new Option(((sort=='modifier')?'>':indent)+' [by author]', '',false,false);
theList.options[i++]=
new Option(((sort=='tags' )?'>':indent)+' [by tags]', '',false,false);
// output the tiddler list
switch(sort) {
case 'title':
for(var t = 0; t < tiddlers.length; t++)
theList.options[i++] = new Option(tiddlers[t].title,tiddlers[t].title,false,false);
break;
case 'modifier':
case 'modified':
var tiddlers = store.getTiddlers(sort);
// sort descending for newest date first
tiddlers.sort(function (a,b) {if(a[sort] == b[sort]) return(0); else return (a[sort] > b[sort]) ? -1 : +1; });
var lastSection = '';
for(var t = 0; t < tiddlers.length; t++) {
var tiddler = tiddlers[t];
var theSection = '';
if (sort=='modified') theSection=tiddler.modified.toLocaleDateString();
if (sort=='modifier') theSection=tiddler.modifier;
if (theSection != lastSection) {
theList.options[i++] = new Option(theSection,'',false,false);
lastSection = theSection;
}
theList.options[i++] = new Option(indent+indent+tiddler.title,tiddler.title,false,false);
}
break;
case 'tags':
var theTitles = {}; // all tiddler titles, hash indexed by tag value
var theTags = new Array();
for(var t=0; t<tiddlers.length; t++) {
var title=tiddlers[t].title;
var tags=tiddlers[t].tags;
if (!tags || !tags.length) {
if (theTitles['untagged']==undefined) { theTags.push('untagged'); theTitles['untagged']=new Array(); }
theTitles['untagged'].push(title);
}
else for(var s=0; s<tags.length; s++) {
if (theTitles[tags[s]]==undefined) { theTags.push(tags[s]); theTitles[tags[s]]=new Array(); }
theTitles[tags[s]].push(title);
}
}
theTags.sort();
for(var tagindex=0; tagindex<theTags.length; tagindex++) {
var theTag=theTags[tagindex];
theList.options[i++]=new Option(theTag,'',false,false);
for(var t=0; t<theTitles[theTag].length; t++)
theList.options[i++]=new Option(indent+indent+theTitles[theTag][t],theTitles[theTag][t],false,false);
}
break;
}
theList.selectedIndex=selectedIndex; // select current control item
this.$('exportStart').disabled=true;
this.$('exportDelete').disabled=true;
this.displayStatus(0,tiddlers.length);
},
askForFilename: function(here) {
var msg=here.title; // use tooltip as dialog box message
var path=getLocalPath(document.location.href);
var slashpos=path.lastIndexOf('/'); if (slashpos==-1) slashpos=path.lastIndexOf('\\');
if (slashpos!=-1) path = path.substr(0,slashpos+1); // remove filename from path, leave the trailing slash
var filetype=this.$('exportFormat').value.toLowerCase();
var defext='html';
if (filetype==this.type_TX) defext='txt';
if (filetype==this.type_NF) defext='xml';
var file=this.newdefault.replace(/html$/,defext);
var result='';
if(window.Components) { // moz
try {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
picker.init(window, msg, nsIFilePicker.modeSave);
var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
thispath.initWithPath(path);
picker.displayDirectory=thispath;
picker.defaultExtension=defext;
picker.defaultString=file;
picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.persistentDescriptor;
}
catch(e) { alert('error during local file access: '+e.toString()) }
}
else { // IE
try { // XPSP2 IE only
var s = new ActiveXObject('UserAccounts.CommonDialog');
s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|XML files|*.xml|';
s.FilterIndex=defext=='txt'?2:'html'?3:'xml'?4:1;
s.InitialDir=path;
s.FileName=file;
if (s.showOpen()) var result=s.FileName;
}
catch(e) { // fallback
var result=prompt(msg,path+file);
}
}
return result;
},
initFilter: function() {
this.$('exportFilterStart').checked=false; this.$('exportStartDate').value='';
this.$('exportFilterEnd').checked=false; this.$('exportEndDate').value='';
this.$('exportFilterTags').checked=false; this.$('exportTags').value='';
this.$('exportFilterText').checked=false; this.$('exportText').value='';
this.showFilterFields();
},
showFilterFields: function(which) {
var show=this.$('exportFilterStart').checked;
this.$('exportFilterStartBy').style.display=show?'block':'none';
this.$('exportStartDate').style.display=show?'block':'none';
var val=this.$('exportFilterStartBy').value;
this.$('exportStartDate').value
=this.getFilterDate(val,'exportStartDate').formatString(this.datetimefmt);
if (which && (which.id=='exportFilterStartBy') && (val=='other'))
this.$('exportStartDate').focus();
var show=this.$('exportFilterEnd').checked;
this.$('exportFilterEndBy').style.display=show?'block':'none';
this.$('exportEndDate').style.display=show?'block':'none';
var val=this.$('exportFilterEndBy').value;
this.$('exportEndDate').value
=this.getFilterDate(val,'exportEndDate').formatString(this.datetimefmt);
if (which && (which.id=='exportFilterEndBy') && (val=='other'))
this.$('exportEndDate').focus();
var show=this.$('exportFilterTags').checked;
this.$('exportTags').style.display=show?'block':'none';
var show=this.$('exportFilterText').checked;
this.$('exportText').style.display=show?'block':'none';
},
getFilterDate: function(val,id) {
var result=0;
switch (val) {
case 'file':
result=new Date(document.lastModified);
break;
case 'other':
result=new Date(this.$(id).value);
break;
default: // today=0, yesterday=1, one week=7, two weeks=14, a month=31
var now=new Date(); var tz=now.getTimezoneOffset()*60000; now-=tz;
var oneday=86400000;
if (id=='exportStartDate')
result=new Date((Math.floor(now/oneday)-val)*oneday+tz);
else
result=new Date((Math.floor(now/oneday)-val+1)*oneday+tz-1);
break;
}
return result;
},
filterExportList: function() {
var theList = this.$('exportList'); if (!theList) return -1;
var filterStart=this.$('exportFilterStart').checked;
var val=this.$('exportFilterStartBy').value;
var startDate=config.macros.exportTiddlers.getFilterDate(val,'exportStartDate');
var filterEnd=this.$('exportFilterEnd').checked;
var val=this.$('exportFilterEndBy').value;
var endDate=config.macros.exportTiddlers.getFilterDate(val,'exportEndDate');
var filterTags=this.$('exportFilterTags').checked;
var tags=this.$('exportTags').value;
var filterText=this.$('exportFilterText').checked;
var text=this.$('exportText').value;
if (!(filterStart||filterEnd||filterTags||filterText)) {
alert('Please set the selection filter');
this.$('exportFilterPanel').style.display='block';
return -1;
}
if (filterStart&&filterEnd&&(startDate>endDate)) {
var msg='starting date/time:\n'
msg+=startDate.toLocaleString()+'\n';
msg+='is later than ending date/time:\n'
msg+=endDate.toLocaleString()
alert(msg);
return -1;
}
// if filter by tags, get list of matching tiddlers
// use getMatchingTiddlers() (if MatchTagsPlugin is installed) for full boolean expressions
// otherwise use getTaggedTiddlers() for simple tag matching
if (filterTags) {
var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
var t=fn.apply(store,[tags]);
var tagged=[];
for (var i=0; i<t.length; i++) tagged.push(t[i].title);
}
// scan list and select tiddlers that match all applicable criteria
var total=0;
var count=0;
for (var i=0; i<theList.options.length; i++) {
// get item, skip non-tiddler list items (section headings)
var opt=theList.options[i]; if (opt.value=='') continue;
// get tiddler, skip missing tiddlers (this should NOT happen)
var tiddler=store.getTiddler(opt.value); if (!tiddler) continue;
var sel=true;
if ( (filterStart && tiddler.modified<startDate)
|| (filterEnd && tiddler.modified>endDate)
|| (filterTags && !tagged.contains(tiddler.title))
|| (filterText && (tiddler.text.indexOf(text)==-1) && (tiddler.title.indexOf(text)==-1)))
sel=false;
opt.selected=sel;
count+=sel?1:0;
total++;
}
return count;
},
deleteTiddlers: function() {
var list=this.$('exportList'); if (!list) return;
var tids=[];
for (i=0;i<list.length;i++)
if (list.options[i].selected && list.options[i].value.length)
tids.push(list.options[i].value);
if (!confirm('Are you sure you want to delete these tiddlers:\n\n'+tids.join(', '))) return;
store.suspendNotifications();
for (t=0;t<tids.length;t++) {
var tid=store.getTiddler(tids[t]); if (!tid) continue;
var msg="'"+tid.title+"' is tagged with 'systemConfig'.\n\n";
msg+='Removing this tiddler may cause unexpected results. Are you sure?'
if (tid.tags.contains('systemConfig') && !confirm(msg)) continue;
store.removeTiddler(tid.title);
story.closeTiddler(tid.title);
}
store.resumeNotifications();
alert(tids.length+' tiddlers deleted');
this.refreshList(0); // reload listbox
store.notifyAll(); // update page display
},
go: function() {
if (window.location.protocol!='file:') // make sure we are local
{ displayMessage(config.messages.notFileUrlError); return; }
// get selected tidders, target filename, target type, and notes
var list=this.$('exportList'); if (!list) return;
var tids=[]; for (var i=0; i<list.options.length; i++) {
var opt=list.options[i]; if (!opt.selected||!opt.value.length) continue;
var tid=store.getTiddler(opt.value); if (!tid) continue;
tids.push(tid);
}
if (!tids.length) return; // no tiddlers selected
var target=this.$('exportFilename').value.trim();
if (!target.length) {
displayMessage('A local target path/filename is required',target);
return;
}
var filetype=this.$('exportFormat').value.toLowerCase();
var notes=this.$('exportNotes').value.replace(/\n/g,'<br>');
var total={val:0};
var out=this.assembleFile(target,filetype,tids,notes,total);
var link='file:///'+target.replace(/\\/g,'/');
var samefile=link==decodeURIComponent(window.location.href);
var p=getLocalPath(document.location.href);
if (samefile) {
if (config.options.chkSaveBackups) { var t=loadOriginal(p);if(t)saveBackup(p,t); }
if (config.options.chkGenerateAnRssFeed && saveRss instanceof Function) saveRss(p);
}
var ok=saveFile(target,out);
displayMessage((ok?this.okmsg:this.failmsg).format([total.val,target]),link);
},
plainTextHeader:
'// Source'+':\n//\t%0\n'
+'// Title:\n//\t%1\n'
+'// Subtitle:\n//\t%2\n'
+'// Created:\n//\t%3 by %4\n'
+'// Application:\n//\tTiddlyWiki %5 / %6 %7\n',
plainTextTiddler:
'\n// ----- %0 (by %1 on %2) -----\n\n%3',
plainTextFooter:
'',
newsFeedHeader:
'<'+'?xml version="1.0"?'+'>\n'
+'<rss version="2.0">\n'
+'<channel>\n'
+'<title>%1</title>\n'
+'<link>%0</link>\n'
+'<description>%2</description>\n'
+'<language>en-us</language>\n'
+'<copyright>Copyright '+(new Date().getFullYear())+' %4</copyright>\n'
+'<pubDate>%3</pubDate>\n'
+'<lastBuildDate>%3</lastBuildDate>\n'
+'<docs>http://blogs.law.harvard.edu/tech/rss</docs>\n'
+'<generator>TiddlyWiki %5 / %6 %7</generator>\n',
newsFeedTiddler:
'\n%0\n',
newsFeedFooter:
'</channel></rss>',
pureStoreHeader:
'<html><body>'
+'<style type="text/css">'
+' #storeArea {display:block;margin:1em;}'
+' #storeArea div {padding:0.5em;margin:1em;border:2px solid black;height:10em;overflow:auto;}'
+' #pureStoreHeading {width:100%;text-align:left;background-color:#eeeeee;padding:1em;}'
+'</style>'
+'<div id="pureStoreHeading">'
+' TiddlyWiki "PureStore" export file<br>'
+' Source'+': <b>%0</b><br>'
+' Title: <b>%1</b><br>'
+' Subtitle: <b>%2</b><br>'
+' Created: <b>%3</b> by <b>%4</b><br>'
+' TiddlyWiki %5 / %6 %7<br>'
+' Notes:<hr><pre>%8</pre>'
+'</div>'
+'<div id="storeArea">',
pureStoreTiddler:
'%0\n%1',
pureStoreFooter:
'</div><!--POST-BODY-START-->\n<!--POST-BODY-END--></body></html>',
assembleFile: function(target,filetype,tids,notes,total) {
var revised='';
var now = new Date().toLocaleString();
var src=convertUnicodeToUTF8(document.location.href);
var title = convertUnicodeToUTF8(wikifyPlain('SiteTitle').htmlEncode());
var subtitle = convertUnicodeToUTF8(wikifyPlain('SiteSubtitle').htmlEncode());
var user = convertUnicodeToUTF8(config.options.txtUserName.htmlEncode());
var twver = version.major+'.'+version.minor+'.'+version.revision;
var v=version.extensions.ExportTiddlersPlugin; var pver = v.major+'.'+v.minor+'.'+v.revision;
var headerargs=[src,title,subtitle,now,user,twver,'ExportTiddlersPlugin',pver,notes];
switch (filetype) {
case this.type_TX: // plain text
var header=this.plainTextHeader.format(headerargs);
var footer=this.plainTextFooter;
break;
case this.type_NF: // news feed (XML)
headerargs[0]=store.getTiddlerText('SiteUrl','');
var header=this.newsFeedHeader.format(headerargs);
var footer=this.newsFeedFooter;
break;
case this.type_PS: // PureStore (no code)
var header=this.pureStoreHeader.format(headerargs);
var footer=this.pureStoreFooter;
break;
case this.type_TW: // full TiddlyWiki
default:
var currPath=getLocalPath(window.location.href);
var original=loadFile(currPath);
if (!original) { displayMessage(config.messages.cantSaveError); return; }
var posDiv = locateStoreArea(original);
if (!posDiv) { displayMessage(config.messages.invalidFileError.format([currPath])); return; }
var header = original.substr(0,posDiv[0]+startSaveArea.length)+'\n';
var footer = '\n'+original.substr(posDiv[1]);
break;
}
var out=this.getData(target,filetype,tids);
var revised = header+convertUnicodeToUTF8(out.join('\n'))+footer;
// if full TW, insert page title and language attr, and reset all MARKUP blocks...
if (filetype==this.type_TW) {
var newSiteTitle=convertUnicodeToUTF8(getPageTitle()).htmlEncode();
revised=revised.replaceChunk('<title'+'>','</title'+'>',' ' + newSiteTitle + ' ');
revised=updateLanguageAttribute(revised);
var titles=[]; for (var i=0; i<tids.length; i++) titles.push(tids[i].title);
revised=updateMarkupBlock(revised,'PRE-HEAD',
titles.contains('MarkupPreHead')? 'MarkupPreHead' :null);
revised=updateMarkupBlock(revised,'POST-HEAD',
titles.contains('MarkupPostHead')?'MarkupPostHead':null);
revised=updateMarkupBlock(revised,'PRE-BODY',
titles.contains('MarkupPreBody')? 'MarkupPreBody' :null);
revised=updateMarkupBlock(revised,'POST-SCRIPT',
titles.contains('MarkupPostBody')?'MarkupPostBody':null);
}
total.val=out.length;
return revised;
},
formatItem: function(s,f,t,u) {
if (f==this.type_TW)
var r=s.getSaver().externalizeTiddler(s,t);
if (f==this.type_PS)
var r=config.macros.exportTiddlers.pureStoreTiddler.format([t.title,s.getSaver().externalizeTiddler(s,t)]);
if (f==this.type_NF)
var r=this.newsFeedTiddler.format([t.saveToRss(u)]);
if (f==this.type_TX)
var r=this.plainTextTiddler.format([t.title,t.modifier,t.modified.toLocaleString(),t.text]);
return r||'';
},
getData: function(target,filetype,tids) {
// output selected tiddlers and gather list of titles (for use with merge)
var out=[]; var titles=[];
var url=store.getTiddlerText('SiteUrl','');
for (var i=0; i<tids.length; i++) {
out.push(this.formatItem(store,filetype,tids[i],url));
titles.push(tids[i].title);
}
// if TW or PureStore format, ask to merge with existing tiddlers (if any)
if (filetype==this.type_TW || filetype==this.type_PS) {
var text=loadFile(target);
if (text && text.length) {
var remoteStore=new TiddlyWiki();
if (remoteStore.importTiddlyWiki(convertUTF8ToUnicode(text))
&& confirm(this.mergeprompt.format([target]))) {
var existing=remoteStore.getTiddlers('title');
for (var i=0; i<existing.length; i++)
if (!titles.contains(existing[i].title))
out.push(this.formatItem(remoteStore,filetype,existing[i],url));
displayMessage(this.mergestatus.format([tids.length,out.length-tids.length]));
}
}
}
return out;
}
}
//}}}
/***
|Name|ExportTiddlersPluginInfo|
|Source|http://www.TiddlyTools.com/#ExportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ExportTiddlersPluginInfo|
|Version|2.8.5|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|Documentation for ExportTiddlersPlugin|
ExportTiddlersPlugin provides an interactive control panel that allows you to select and extract tiddlers from your ~TiddlyWiki document, and write them into another file, using one of several different file formats:
* ~TiddlyWiki - a complete, stand-alone, standard TiddlyWiki HTML document
* ~PureStore - a small HTML archive file containing tiddler data only (no core code)
* ~PlainText - a simple TXT text file with tiddler source listings
* ~NewsFeed - an XML-format file that can be published for RSS syndication.
!!!!!Usage
<<<
{{{
<<exportTiddlers>> (sidebar menu item)
<<exportTiddlers inline>> (embedded control panel)
}}}
Inline control panel (live):
<<exportTiddlers inline>>
Optional "special tiddlers" used by this plugin:
* SiteUrl<br>URL for official server-published version of document being viewed (used in XML export). Default: //none//
<<<
!!!!!Revisions
<<<
2009.02.26 [2.8.5] use macro-specific definition of $() function abbreviation (avoids conflict with JQuery)
2008.09.29 [2.8.4] in getData(), convert existing TW file from UTF8 to Unicode before merging to correct handling of international characters and symbols.
2008.09.26 [2.8.3] in go(), if rewriting *current* file and chkSaveBackups and/or chkGenerateAnRssFeed is enabled, then write a backup file or RSS feed, respectively.
2008.09.24 [2.8.2] in assembleFile(), make sure that markup block is updated if corresponding Markup* tiddler is exported.
2008.09.19 [2.8.1] in formatItem(), removed unnecessary convertUnicodeToUTF8() (was causing double-conversion!)
2008.09.11 [2.8.0] extensive code cleanup: moved all global functions inside macro object. Re-wrote file generator and I/O to support TiddlyWiki, PlainText, PureStore, and NewsFeed file formats. Replaced inline 'match tags' code with use of getMatchingTiddlers() from [[MatchTagsPlugin]] (if installed), with fallback to core getTaggedTiddlers() otherwise.
2008.05.27 [2.7.0] added ability to 'merge' with existing export file. Also, revised 'matchTags' functionality to be more robust and more efficient
2008.05.12 [2.6.1] automatically add 'export' task to backstage (moved from BackstageTweaks)
2008.03.10 [2.6.0] added "delete tiddlers" button
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.11.10 [2.5.1] removed debugging alert messages from promptForExportFilename()
2007.10.31 [2.5.0] code reduction: removed incomplete/unused interface and supporting functions for exporting directly to http, https or ftp servers. Plugin now supports exporting to local file only. Transferring that file is now left to other mechanisms, such as email attachments, FTP uploads, portable media (USB,CD,DVD,...), etc. Also, updated "save as TiddlyWiki document" output to correctly generate TW2.2 compatible file format.
2007.10.30 [2.4.2] added automatic shadow tiddler definition for [[ExportTiddlers]]
2007.07.16 [2.4.1] in exportTWHeader(), reset HTML source 'markup' so installed markup is NOT copied to new file.
2007.06.30 [2.4.0] added "select related tiddlers" feature. Recursively scans the tiddler links[] info to find all tiddlers referenced by any of the currently selected tiddler, and then selects them all (including the original tiddlers). //Theoretically//, selecting all related tiddlers should ensure that the exported file contains all tiddlers needed to properly render all of the originally selected tiddlers.
2007.04.19 [2.3.0] in exportData(), pass SiteURL value as param to saveToRss(). Fixes 'undefined' appearing in tiddler link in XML output. Also, in refreshExportList(), added 'sort by tags'. Also, added 'group select'... selecting a heading (date,author,tag) auto-selects all tiddlers in that group.
2007.03.02 [2.2.6] in onClickExportButton(), when selecting open tiddlers for TW2.2, look for "storyDisplay" instead of "tiddlerDisplay" but keep fallback to "tiddlerDisplay" for TW2.1 or earlier
2007.03.01 [2.2.5] removed hijack of store.saveChanges() (was catching save on http:, but there are other solutions that do a much better job of handling save to server.
2006.11.08 [2.2.4] added promptForExportFilename() and replaced type="file" control with edit field + browse button ("...").
2006.10.12 [2.2.3] in exportDIVFooter(), write POST-BODY-START/END markers for compatibility with TW2.1 core file format. Based on report from Jose Gonzalez.
2006.05.11 [2.2.2] in createExportPanel, removed call to addNotification() to no longer auto-refresh the list every time a tiddler is changed. Instead, call refreshExportList(0) only when the panel is first rendered and each time it is made visible. Prevents unneeded feedback messages from being displayed and increases overall document performance, since the listbox is no longer being updated each time a tiddler is saved.
2006.05.02 [2.2.1] Use displayMessage() to show number of selected tiddlers instead of updating listbox 'header' item after each selection. Prevents awkward 'scroll-to-top' behavior that made multi-select via ctrl-click nearly impossible. Reported by Paul Reiber.
2006.04.29 [2.2.0] New features: "Notes" are free-form text that is inserted in the header of a TWDIV export file. When exporting to a server, the "notify" checkbox indicates that server-side script processing should send an email message when the export file is stored on the server. Comma-separated addresses may be typed in, or pre-defined in the SiteNotify tiddler.
2006.03.29 [2.1.3] added calls to convertUnicodeToUTF8() for generated output, so it better handles international characters.
2006.02.12 [2.1.2] added var to unintended global 'tags' in matchTags(). Avoids FF1501 bug when filtering by tags. (based on report by TedPavlic)
2006.02.04 [2.1.1] added var to variables that were unintentionally global. Avoids FireFox 1.5.0.1 crash bug when referencing global variables
2006.02.02 [2.1.0] Added support for output of complete TiddlyWiki documents. Let's you use ExportTiddlers to generate 'starter' documents from selected tiddlers.
2006.01.21 [2.0.1] Defer initial panel creation and only register a notification function when panel first is created
in saveChanges 'hijack', create panel as needed. Note: if window.event is not available to identify the click location, the export panel is positioned relative to the 'tiddlerDisplay' element of the TW document.
2005.12.27 [2.0.0] Update for TW2.0
Defer initial panel creation and only register a notification function when panel first is created
2005.12.24 [0.9.5] Minor adjustments to CSS to force correct link colors regardless of TW stylesheet selection
2005.12.16 [0.9.4] Dynamically create/remove exportPanel as needed to ensure only one instance of interface elements exists, even if there are multiple instances of macro embedding.
2005.11.15 [0.9.2] added non-Ajax post function to bypass javascript security restrictions on cross-domain I/O. Moved AJAX functions to separate tiddler (no longer needed here). Generalized HTTP server to support UnaWiki servers
2005.11.08 [0.9.1] moved HTML, CSS and control initialization into exportInit() function and call from macro handler instead of at load time. This allows exportPanel to be placed within the same containing element as the "export tiddlers" button, so that relative positioning can be achieved.
2005.10.28 [0.9.0] added 'select opened tiddlers' feature. Based on a suggestion by Geoff Slocock
2005.10.24 [0.8.3] Corrected hijack of 'save changes' when using http:
2005.10.18 [0.8.2] added AJAX functions
2005.10.18 [0.8.1] Corrected timezone handling when filtering for date ranges. Improved error checking/reporting for invalid filter values and filters that don't match any tiddlers. Exporting localfile-to-localfile is working for IE and FF. Exporting server-to-localfile works in IE (after ActiveX warnings), but has security issues in FF. Cross-domain exporting (localfile/server-to-server) is under development. More style tweaks, minor text changes and some assorted layout cleanup.
2005.10.17 [0.8.0] First pre-release.
2005.10.16 [0.7.0] filter by tags
2005.10.15 [0.6.0] filter by title/text
2005.10.14 [0.5.0] export to local file (DIV or XML)
2005.10.14 [0.4.0] filter by start/end date
2005.10.13 [0.3.0] panel interaction
2005.10.11 [0.2.0] panel layout
2005.10.10 [0.1.0] code framework
2005.10.09 [0.0.0] development started
<<<
/***
|Name|FAQViewerPlugin|
|Source|http://www.TiddlyTools.com/#FAQViewerPlugin|
|Version|1.4.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|select and display FAQ tiddlers from a droplist, sorted by date|
!!!!!Usage
<<<
{{{<<faqViewer startwith:TiddlerName tagname classname sortby dateformat>>}}}
where:
*''startwith:TiddlerName'' (optional)<br>
*''tagname'' (optional)<br>specifies the set of tiddlers to include in the FAQ list (default='faq')
*''classname'' (optional)<br>specifies a CSS class to be applied surrounding the FAQ tiddler content
*''sortby'' (optional)<br>specifies the name of a tiddler field to sort by. Use "+" or "-" as a prefix on the fieldname to indicate ascending or descending order, respectively (default='-modified'). You can also use the special keyword, ''Description'', to sort alphabetically based on the value of a slice named "Description", that can be defined in each FAQ tiddler. Note: if a particular FAQ tiddler has no description slice, the title of the tiddler is used as a fallback.
*''dateformat'' (optional)<br>specifies the formatting for dates displayed in the list. Use " " (a single space) to suppress the date display.
examples:
{{{<<faqViewer>>}}}
{{smallform small{<<faqViewer>>}}}
{{{<<faqViewer package outline +title " ">>}}}
{{smallform small{<<faqViewer package outline +title " ">>}}}
<<<
!!!!!Revisions
<<<
2008.10.21 [1.4.2] removed animation (was interfering with "overflow:scroll" CSS)
2008.09.30 [1.4.1] corrected filter by tag handling broken in 1.4.0
2008.09.29 [1.4.0] added optional "startwith:TiddlerName" param
2008.09.24 [1.3.1] added animation when opening/closing faq content panel
2008.09.21 [1.3.0] sort by "description" slice values. also added "previous" and "next" buttons for sequential viewing of FAQ articles
2008.09.20 [1.2.0] optional 'sortby' and 'dateformat' params
2008.01.20 [1.1.0] support for alternative 'target' tag instead of "faq" (default)
2007.10.15 [1.0.0] converted to true plugin
2007.02.01 [0.0.0] inline script
<<<
!!!!!Code
***/
//{{{
version.extensions.FAQViewerPlugin={major: 1, minor: 4, revision: 1, date: new Date(2008,9,30)};
config.shadowTiddlers.FAQViewer="{{smallform{<<faqViewer>>}}}";
config.macros.faqViewer= {
dateFormat:"YYYY.0MM.0DD 0hh:0mm - ",
startparam: "startwith:",
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
// create form
if (params[0]&¶ms[0].substr(0,this.startparam.length)==this.startparam)
{ var startwith=params[0].substr(this.startparam.length); params.shift(); }
var console=createTiddlyElement(place,"span");
console.innerHTML=this.html.replace(/%classname%/,params[1]||"");
this.go(console.getElementsByTagName("form")[0],startwith, params[0],params[2],params[3]);
},
go: function(f,startwith,targetType,sortby,dateformat) {
var targetType=targetType||"faq";
var sortby=sortby||"-modified";
var dateformat=dateformat||this.dateFormat;
var datefield=sortby.indexOf('created')!=-1?'created':'modified';
f.targetType.value=targetType;
f.sortBy.value=sortby;
f.dateFmt.value=dateformat;
var lists=f.getElementsByTagName("select"); if (!lists.length) return;
var FAQList=lists[0]; var taglist=lists[1];
while (FAQList.options[0]) FAQList.options[0]=null; // empty FAQList
if (f.search.value!=f.search.defaultValue) var find=f.search.value;
var tiddlers=store.getTaggedTiddlers(targetType,"modified").reverse();
if (tiddlers && sortby) {
if (sortby.indexOf('escription')==-1) // sort by tiddler field
tiddlers=store.sortTiddlers(tiddlers,sortby);
else
tiddlers.sort(function(a,b){ // sort by description slice (or title, if no slice)
var da=store.getTiddlerSlice(a.title,"Description")||a.title;
var db=store.getTiddlerSlice(b.title,"Description")||b.title;
return da==db?0:(da>db?+1:-1);
});
}
var matchcount=0; var tags=[]; var selectedIndex=0;
FAQList.options[0]=new Option("select an item...","",false,false);
for (var i=0; i<tiddlers.length; i++) {
for (var t=0; t<tiddlers[i].tags.length; t++)
tags.pushUnique(tiddlers[i].tags[t]); // collect other tags
if (find && find.length && tiddlers[i].text.indexOf(find)==-1) continue;
if (taglist.value && taglist.value.length && !tiddlers[i].tags.contains(taglist.value)) continue;
matchcount++;
var d=store.getTiddlerSlice(tiddlers[i].title,"Description")||tiddlers[i].title;
d=tiddlers[i][datefield].formatString(dateformat)+d;
FAQList.options[FAQList.options.length]=new Option(d,tiddlers[i].title,false,false);
if (tiddlers[i].title==startwith) selectedIndex=i+1;
}
FAQList.options[0].text="select an item... ["+tiddlers.length+" item"+(tiddlers.length!=1?"s":"");
if (find && find.length || taglist.value.length)
FAQList.options[0].text+=", "+matchcount+" match"+(matchcount!=1?"es":"");
FAQList.options[0].text+="]";
FAQList.selectedIndex=selectedIndex;
if (selectedIndex) config.macros.faqViewer.show(f,startwith);
if (!taglist.options.length) { // only load tag list the first time, since it doesn't change
while (taglist.options[0]) taglist.options[0]=null; // empty taglist
taglist.options[0]=new Option("filter by tag...","",false,false);
var tagcount=0;
for (var t=0; t<tags.length; t++) {
if (tags[t].toLowerCase()==targetType) continue;
if (tags[t].indexOf("exclude")!=-1) continue;
taglist.options[taglist.options.length]
=new Option(tags[t],tags[t],false,false);
tagcount++;
}
if (!tagcount) taglist.options[taglist.options.length]
=new Option("no category tags found","",false,false);
}
},
show: function(f,v) {
var fmt=this.faqlayout;
if (store.getTaggedTiddlers(v).length) fmt=this.packagelayout;
var target=f.getElementsByTagName("div")[0];
removeChildren(target);
wikify(fmt.format([v]),target);
target.style.display="block";
f.prev.parentNode.style.display="block";
f.next.focus();
f.done.disabled=!v.length;
},
faqlayout:
"{{toolbar floatright fine{//now viewing: //[[%0]] }}}<<tiddler [[%0]]>>",
packagelayout:
"{{toolbar floatright fine{//now viewing: //[[%0]] }}}\n"
+"{{floatright borderleft fine{<<tagging [[%0]]>>}}}<<tiddler [[%0]]>>{{clear block{}}}",
html:
"<form onsubmit='return false;' style='display:inline;margin:0;padding:0;white-space:nowrap;'><!-- \
--><input type='hidden' name='targetType' value='faq'><!-- \
--><input type='hidden' name='sortBy' value='-modified'><!-- \
--><input type='hidden' name='dateFmt' value='YYYY.0MM.0DD 0hh:0mm - '><!-- \
--><select name='list' size=1 style='width:50%' \
onchange='if (!this.value.length) this.form.done.onclick(); \
else config.macros.faqViewer.show(this.form,this.value);'><!-- \
--></select><!-- \
--><select name='taglist' size=1 style='width:12%' \
title='list only items that have a specific category tag' \
onchange='var f=this.form; f.done.onclick(); \
config.macros.faqViewer.go(f,\"\",f.targetType.value,f.sortBy.value,f.dateFmt.value)'><!-- \
--></select><!-- \
--><input type='text' name='search' value='enter search text...' style='width:20%' \
title='list only items that contain the search text (use blank to match all)' \
onfocus='this.select()' \
onkeyup=' if (event.keyCode==13) this.form.find.onclick(); \
if (!this.value.length) {this.value=this.defaultValue; this.select(); this.form.find.onclick();}'><!-- \
--><input type='button' name='find' value='find' style='width:6%' \
title='list only items that contain the search text ' \
onclick='var f=this.form; f.done.onclick(); \
config.macros.faqViewer.go(f,\"\",f.targetType.value,f.sortBy.value,f.dateFmt.value)'><!-- \
--><input type='button' name='reset' value='reset' style='width:6%' \
title='reset FAQViewer to default ' \
onclick='var f=this.form; f.done.onclick(); \
f.search.value=f.search.defaultValue; f.taglist.selectedIndex=0; \
config.macros.faqViewer.go(f,\"\",f.targetType.value,f.sortBy.value,f.dateFmt.value)'><!-- \
--><input type='button' name='done' value='done' disabled style='width:6%' \
title='hide current item display' \
onclick='var target=this.form.getElementsByTagName(\"div\")[0]; \
target.style.display=\"none\"; removeChildren(target); \
this.form.prev.parentNode.style.display=\"none\"; \
this.form.list.selectedIndex=0; this.disabled=true;'><!-- \
--><div class=\"%classname%\" style=\"display:none;white-space:normal;\"></div><!-- \
--><span style='text-align:right;display:none;overflow:auto;'><!-- \
--><input type='button' name='prev' value='◄ prev' style='float:left;font-size:80%;' \
title='view previous item' \
onclick='var f=this.form; var i=f.list.selectedIndex-1; \
f.list.selectedIndex=i<0?f.list.length-1:i; f.list.onchange();'><!-- \
--><input type='button' name='next' value='next ►' style='float:right;font-size:80%;' \
title='view next item' \
onclick='var f=this.form; var i=f.list.selectedIndex+1; \
f.list.selectedIndex=i>f.list.length-1?0:i; f.list.onchange();'><!-- \
--></span><!-- \
--></form>\
"
}
//}}}
<!--{{{-->
<!--
|Name|FaqViewTemplate|
|Source|http://www.TiddlyTools.com/#FaqViewTemplate|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands, FAQViewerPlugin|
|Overrides||
|Description|custom version of view template used to display tiddlers tagged with 'faq'|
-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></span>
<span class='title' macro='view title'></span>
<span class='subtitle'>
<span style='white-space:nowrap' macro='view modified date [[DDD, MMM DDth YYYY]]'></span>
</span>
<div class='viewer smallform' macro='faqViewer {{"startwith:"+tiddler.title}}' title=' '></div>
<div class='toolbar' style='line-height:100%;margin-top:.5em;'><a href="javascript:;"
onclick="window.scrollTo(0,ensureVisible(story.findContainingTiddler(this)));return false;"
onmouseover="this.title='scroll to top of '+story.findContainingTiddler(this).getAttribute('tiddler')">▲</a>
</div>
<!--}}}-->
/***
|FileDropPlugin|h
|author : BradleyMeck|
|version : 0.1.1|
|date : Nov 13 2006|
|usage : drag a file onto the TW to have it be made into a tiddler|
|browser(s) supported : Mozilla|
Note: this version has been 'tweaked' by Eric Shulman (http://www.TiddlyTools.com) to add suspend/resume notification handling to improve performance when multiple files are dropped at once.
!Trouble Shooting
*If the plugin does not seem to work, open up the page "about:config" (just type it in the address bar) and make sure @@color(blue):signed.applets.codebase_principal_support@@ is set to @@color(blue):true@@
!Revisions
*Multiple File Dropping API updated, to end all capturing events after yours return a value that makes if(myFunctionsReturnValue) evaluate to true
*Added support for multiple file drop handlers
**Use the config.macros.fileDrop.addEventListener(@@color(green):String Flavor@@, @@color(green):Function handler(nsiFile){}@@, @@color(green):Boolean addToFront@@) function
***Standard Flavor is "application/x-moz-file"
***addToFront gives your handler priority over all others at time of add
*Old plugin would disallow drops of text vetween applications because it didn't check if the transfer was a file.
!Example Handler
*Adds simple file import control, add this to a tiddler tagged {{{systemConfig}}} to make file dropping work
{{{
config.macros.fileDrop.addEventListener("application/x-moz-file",function(nsiFile)
{
if(
confirm("You have dropped the file \""+nsiFile.path+"\" onto the page, it will be imported as a tiddler. Is that ok?")
)
{
var newDate = new Date();
var title = prompt("what would you like to name the tiddler?");
store.saveTiddler(title,title,loadFile(nsiFile.path),config.options.txtUserName,newDate,[]);
}
return true;
})
}}}
!Example Handler without popups and opening the tiddler on load
*Adds simple file import control, add this to a tiddler tagged {{{systemConfig}}} to make file dropping work
{{{
config.macros.fileDrop.addEventListener("application/x-moz-file",function(nsiFile)
{
var newDate = new Date();
store.saveTiddler(nsiFile.path,nsiFile.path,loadFile(nsiFile.path),config.options.txtUserName,newDate,[]);
story.displayTiddler(null,nsiFile.path)
return true;
})
}}}
!Code
***/
//{{{
config.macros.fileDrop = {version : {major : 0, minor : 0, revision: 1}};
config.macros.fileDrop.customDropHandlers = [];
config.macros.fileDrop.dragDropHandler = function(evt) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
// Load in the native DragService manager from the browser.
var dragService = Components.classes["@mozilla.org/widget/dragservice;1"].getService(Components.interfaces.nsIDragService);
// Load in the currently-executing Drag/drop session.
var dragSession = dragService.getCurrentSession();
// Create an instance of an nsITransferable object using reflection.
var transferObject = Components.classes["@mozilla.org/widget/transferable;1"].createInstance();
// Bind the object explicitly to the nsITransferable interface. We need to do this to ensure that
// methods and properties are present and work as expected later on.
transferObject = transferObject.QueryInterface(Components.interfaces.nsITransferable);
// I've chosen to add only the x-moz-file MIME type. Any type can be added, and the data for that format
// will be retrieved from the Drag/drop service.
transferObject.addDataFlavor("application/x-moz-file");
// Get the number of items currently being dropped in this drag/drop operation.
var numItems = dragSession.numDropItems;
// ELS 2007.12.03: performance improvement when dropping multiple files
if (numItems>1) {
clearMessage();
displayMessage("Reading "+numItems+" files...");
store.suspendNotifications();
}
for (var i = 0; i < numItems; i++)
{
// Get the data for the given drag item from the drag session into our prepared
// Transfer object.
dragSession.getData(transferObject, i);
// We need to pass in Javascript 'Object's to any XPConnect method which
// requires OUT parameters. The out value will then be saved as a new
// property called Object.value.
var dataObj = {};
var dropSizeObj = {};
for(var ind = 0; ind < config.macros.fileDrop.customDropHandlers.length; ind++)
{
var item = config.macros.fileDrop.customDropHandlers[ind];
if(dragSession.isDataFlavorSupported(item.flavor))
{
transferObject.getTransferData(item.flavor, dataObj, dropSizeObj);
var droppedFile = dataObj.value.QueryInterface(Components.interfaces.nsIFile);
// Display all of the returned parameters with an Alert dialog.
var result = item.handler.call(item,droppedFile);
// Since the event is handled, prevent it from going to a higher-level event handler.
evt.stopPropagation();
evt.preventDefault();
if(result){break;}
}
}
}
// ELS 2007.12.03: performance improvement and feedback after dropping multiple files
if (numItems>1) {
store.resumeNotifications();
store.notifyAll();
displayMessage(numItems+" files have been processed");
}
}
if(!window.event)
{
// Register the event handler, and set the 'capture' flag to true so we get this event
// before it bubbles up through the browser.
window.addEventListener("dragdrop", config.macros.fileDrop.dragDropHandler , true);
}
config.macros.fileDrop.addEventListener = function(paramflavor,func,inFront)
{
var obj = {};
obj.flavor = paramflavor;
obj.handler = func;
if(!inFront)
{config.macros.fileDrop.customDropHandlers.push(obj);}
else{config.macros.fileDrop.customDropHandlers.shift(obj);}
}
//}}}
/***
|Name|FileDropPluginConfig|
|Source|http://www.TiddlyTools.com/#FileDropPluginConfig|
|Version|1.5.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|FileDropPlugin, AttachFilePlugin|
|Overrides||
|Options|##Configuration|
|Description|Adds drag-and-drop handlers for creating binary attachments or directory lists|
__TiddlyTools FileDrop+AttachFile extended handler:__
* use just filename instead of whole path as tiddler title
* check for existing tiddler and prompt for new name
* handle folder drops (drops each file or creates a file list in a tiddler)
* use AttachFilePlugin if MIME type is not text/plain
* autotag created tiddlers (e.g., "temporary", "dropped", etc.)
* option to suppress automatic display of newly created tiddlers
* suspend/resume notifications when handling multiple files (performance improvement)
!!!!!Configuration
<<<
<<option chkFileDropTrimFilename>> Omit file extensions from tiddler titles when creating new tiddlers
{{{usage: <<option chkFileDropTrimFilename>> }}}
<<option chkFileDropDisplay>> Automatically display newly created tiddlers
{{{usage: <<option chkFileDropDisplay>> }}}
Tag newly created tiddlers with: <<option txtFileDropTags>>
{{{usage: <<option txtFileDropTags>>}}}
__FileDrop+AttachFile configuration options:__
<<option chkFileDropAttachLocalLink>> Include reference to local path/filename
{{{usage: <<option chkFileDropAttachLocalLink>> }}}
<<option chkFileDropAttachEncodeData>> Include binary file data as encoded "base64" text
{{{usage: <<option chkFileDropAttachEncodeData>> }}}
...only if file is smaller than: <<option txtFileDropAttachDataLimit>> bytes
{{{usage: <<option txtFileDropAttachDataLimit>>}}}
See [[FileDropPlugin]] for more documentation on handler implementation specifics, including sample code for default drop handlers.
<<<
!!!!!Revisions
<<<
2008.08.11 [1.5.1] added chkFileDropAttachLocalLink option to allow suppression of local path/file link
2007.01.01 [0.9.9] initial release with extensions for AttachFilePlugin
<<<
!!!!!Code
***/
//{{{
if (config.options.chkFileDropAttachEncodeData==undefined)
config.options.chkFileDropAttachEncodeData=true;
if (config.options.chkFileDropAttachLocalLink==undefined)
config.options.chkFileDropAttachLocalLink=true;
if (config.options.txtFileDropAttachDataLimit==undefined)
config.options.txtFileDropAttachDataLimit=32768;
if (config.options.txtFileDropTags==undefined)
config.options.txtFileDropTags="";
if (config.options.chkFileDropDisplay==undefined)
config.options.chkFileDropDisplay=true;
if (config.options.chkFileDropTrimFilename==undefined)
config.options.chkFileDropTrimFilename=false;
config.macros.fileDrop.addEventListener("application/x-moz-file",function(nsiFile)
{
var header="Index of %0\n^^(as of %1)^^\n|!filename| !size | !modified |\n";
var item="|[[%0|%1]]| %2|%3|\n";
var footer="Total of %0 bytes in %1 files\n";
var now=new Date();
var files=[nsiFile];
if (nsiFile.isDirectory()) {
var folder=nsiFile.directoryEntries;
var files=[];
while (folder.hasMoreElements()) {
var f=folder.getNext().QueryInterface(Components.interfaces.nsILocalFile);
if (f instanceof Components.interfaces.nsILocalFile && !f.isDirectory()) files.push(f);
}
var msg=nsiFile.path.replace(/\\/g,"/")+"\n\n";
msg+="contains "+files.length+" files... ";
msg+="select OK to attach all files or CANCEL to create a list...";
if (!confirm(msg)) { // create a list in a tiddler
var title=nsiFile.leafName; // tiddler name is last directory name in path
while (title && title.length && store.tiddlerExists(title)) {
if (confirm(config.messages.overwriteWarning.format([title]))) break; // use existing title
title=prompt("Please enter a different tiddler title for this file",nsiFile.path.replace(/\\/g,"/"));
}
if (!title || !title.length) return true; // aborted by user... we're done!
var text=header.format([nsiFile.path.replace(/\\/g,"/"),now.toLocaleString()]);
var total=0;
for (var i=0; i<files.length; i++) { var f=files[i];
var name=f.leafName;
if (config.options.chkFileDropTrimFilename)
{ var p=name.split("."); if (p.length>1) p.pop(); name=p.join("."); }
var path="file:///"+f.path.replace(/\\/g,"/");
var size=f.fileSize; total+=size;
var when=new Date(f.lastModifiedTime).formatString("YYYY.0MM.0DD 0hh:0mm:0ss");
text+=item.format([name,path,size,when]);
}
text+=footer.format([total,files.length]);
var newtags=config.options.txtFileDropTags?config.options.txtFileDropTags.readBracketedList():[];
store.saveTiddler(null,title,text,config.options.txtUserName,now,newtags);
if (config.options.chkFileDropDisplay) story.displayTiddler(null,title);
return true;
}
}
if (files.length>1) store.suspendNotifications();
for (i=0; i<files.length; i++) {
var file=files[i];
if (file.isDirectory()) continue; // skip over nested directories
var type="text/plain";
var title=file.leafName; // tiddler name is file name
if (config.options.chkFileDropTrimFilename)
{ var p=title.split("."); if (p.length>1) p.pop(); title=p.join("."); }
var path=file.path;
var size=file.fileSize;
while (title && title.length && store.tiddlerExists(title)) {
if (confirm(config.messages.overwriteWarning.format([title]))) break; // use existing title
title=prompt("Please enter a different tiddler title for this file",path.replace(/\\/g,"/"));
}
if (!title || !title.length) continue; // cancelled by user... skip this file
if (config.macros.attach) {
type=config.macros.attach.getMIMEType(file.leafName,"");
if (!type.length)
type=prompt("Unrecognized file type. Please enter a MIME type for this file","text/plain");
if (!type||!type.length) continue; // cancelled by user... skip this file
}
var newtags=config.options.txtFileDropTags?config.options.txtFileDropTags.readBracketedList():[];
if (type=="text/plain")
store.saveTiddler(null,title,loadFile(path),config.options.txtUserName,now,newtags);
else {
// only encode data if enabled and file is smaller than limit. Default is 32768 (32K) bytes.
var embed=config.options.chkFileDropAttachEncodeData
&& file.fileSize<config.options.txtFileDropAttachDataLimit;
newtags.push("attachment"); newtags.push("excludeMissing");
var localfile="";
if (config.options.chkFileDropAttachLocalLink) {
// if file is in current document folder,
// remove path prefix and use relative reference
var localfile=path;
var h=document.location.href;
folder=getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf("/")+1)));
if (localfile.substr(0,folder.length)==folder)
localfile='./'+localfile.substr(folder.length);
}
config.macros.attach.createAttachmentTiddler(path,
now.formatString(config.macros.timeline.dateFormat),
"attached by FileDropPlugin", newtags,
title, embed, config.options.chkFileDropAttachLocalLink, false,
localfile, "", type,!config.options.chkFileDropDisplay);
}
if (config.options.chkFileDropDisplay) story.displayTiddler(null,title);
}
if (files.length>1) { store.resumeNotifications(); store.notifyAll(); }
if (window.FFDEBUG) console.log(new Date()-now);
return true;
})
//}}}
<html><div id='paperBox' style='width:100%; height:100%;'></div></html>
<script show>
rp2.init();
</script>
/%
|Name|FoldOtherTiddlers|
|Source|http://www.TiddlyTools.com/#FoldOtherTiddlers|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires||
|Overrides||
|Description|fold all other tiddlers when a tiddler is viewed - equivalent to pressing "focus" toolbar command|
Usage: <<tiddler FoldOtherTiddlers>>
%/<script>
if (!config.commands.collapseTiddler) return;
var here=story.findContainingTiddler(place); if (!here) return;
config.commands.collapseOthers.handler(null,here,here.getAttribute('tiddler'));
</script>
/***
|Name|FramedLinksPlugin|
|Source|http://www.TiddlyTools.com/#FramedLinksPlugin|
|Version|1.1.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|createExternalLink|
|Options|##Configuration|
|Description|clicking an external link opens an IFRAME following the link instead of opening a new tab/window|
This plugin causes clicks on external links to be rendered as inline frames (~IFRAMEs) instead of opening new browser tabs/windows.
!!!!!Usage
<<<
Use standard TiddlyWiki external link syntax into your tiddler content. If {{{chkFramedLinks}}} is enabled or the tiddler is tagged with 'framedLinks' (see Configuration), then whenever you click the external link an IFRAME will be dynamically added to the content. Clicking on the link again removes the IFRAME. Hold down any modifier (shift, control, or alt) while clicking a link ''temporarily'' bypasses the IFRAME handling and use the standard link handling behavior.
<<<
!!!!!Configuration
<<<
<<option chkFramedLinks>> display inline frames for all external links
{{{<<option chkFramedLinks>>}}}
<<option chkFramedLinksTag>> display inline frames for external links in tiddlers tagged with: <<option txtFramedLinksTag>>
{{{<<option chkFramedLinksTag>> <<option txtFramedLinksTag>>}}}
IFRAME size (CSS units: %, em, px, cm, in) - width: <<option txtFrameWidth>> height: <<option txtFrameHeight>>
{{{<<option txtFrameWidth>> <<option txtFrameHeight>>}}}
<<<
!!!!!Examples
<<<
Try these links:
*http://www.TiddlyWiki.com
*http://www.TiddlyTools.com
*http://groups.google.com/group/TiddlyWiki/topics
<<<
!!!!!Revisions
<<<
2008.11.14 [1.1.1] fixed handling for external links embedded in //shadow// tiddlers
2008.09.13 [1.1.0] added support to selectively enable embedded IFRAMEs if the containing tiddler is tagged with 'framedLinks'
2007.11.29 [1.0.5] added slider animation and improved CSS handling for IFRAME height/width to maximize display area
2007.11.29 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.FramedLinksPlugin= {major: 1, minor: 1, revision: 1, date: new Date(2008,11,14)};
var co=config.options; // abbreviation
if (co.chkFramedLinks==undefined) co.chkFramedLinks=false;
if (co.chkFramedLinksTag==undefined) co.chkFramedLinksTag=true;
if (co.txtFramedLinksTag==undefined) co.txtFramedLinksTag="framedLinks";
if (co.txtFrameWidth==undefined) co.txtFrameWidth="100%";
if (co.txtFrameHeight==undefined) co.txtFrameHeight="80%";
window.framedLinks_createExternalLink=createExternalLink;
window.createExternalLink=function(place,url)
{
var link=this.framedLinks_createExternalLink.apply(this,arguments);
link.onclick=function(ev) { var e=ev?ev:window.event;
var co=config.options; // abbreviation
var here=story.findContainingTiddler(this);
if (here) var tid=store.getTiddler(here.getAttribute("tiddler"));
var enabled=co.chkFramedLinks || co.chkFramedLinksTag && tid && tid.isTagged(co.txtFramedLinksTag);
if (!enabled || e.ctrlKey || e.shiftKey || e.altKey) return; // BYPASS
var p=this.parentNode;
var f=this.nextSibling?this.nextSibling.firstChild:null; // get the IFRAME... maybe...
var w=co.txtFrameWidth; if (!w || !w.length) w="100%";
var h=co.txtFrameHeight; if (!h || !h.length) h="80%";
if (h.indexOf("%")) h=(findWindowHeight()*h.replace(/%/,"")/100)+"px"; // calc height as % of window
var showing=f && f.nodeName.toUpperCase()=="IFRAME"; // does IFRAME really exist?
var stretchCell=p.nodeName.toUpperCase()=="TD" && w.indexOf("%")!=-1 && w.replace(/%/,"")>=100;
if (!showing) { // create an iframe
link.style.display="block"; // force IFRAME onto line following link
if (stretchCell) { p.setAttribute("savedWidth",p.style.width); p.style.width="100%"; } // adjust TD so IFRAME stretches
var wrapper=createTiddlyElement(null,"span"); // wrapper for slider animation
wrapper.setAttribute("url",this.href); // for async loading of frame after animation completes
var f=createTiddlyElement(wrapper,"iframe"); // create IFRAME
f.style.backgroundColor="#fff"; f.style.width=w; f.style.height=h;
p.insertBefore(wrapper,this.nextSibling);
function loadURL(wrapper) { var f=wrapper.firstChild; var url=wrapper.getAttribute("url");
var d=f.contentDocument?f.contentDocument:(f.contentWindow?f.contentWindow.document:f.document);
d.open(); d.writeln("<html>connecting to "+url+"</html>"); d.close();
try { f.src=url; } // if the iframe can't handle the href
catch(e) { alert(e.description?e.description:e.toString()); } // ... then report the error
window.scrollTo(0,ensureVisible(wrapper));
}
if (!co.chkAnimate) loadURL(wrapper);
else {
var morph=new Slider(wrapper,true);
morph.callback=loadURL;
morph.properties.push({style: 'width', start: 0, end: 100, template: '%0%'});
anim.startAnimating(morph);
}
} else { // remove iframe
link.style.display="inline"; // restore link style
if (stretchCell) p.style.width=p.getAttribute("savedWidth"); // restore previous width of TD
if (!co.chkAnimate) p.removeChild(f.parentNode);
else {
var morph=new Slider(f.parentNode,false,false,"all");
morph.properties.push({style: 'width', start: 100, end: 0, template: '%0%'});
anim.startAnimating(morph);
}
}
e.cancelBubble=true; if (e.stopPropagation) e.stopPropagation(); return false;
}
return link;
}
//}}}
{{center{
{{picture{[img[i-blur]]}}}<script>
var img = place.lastChild.firstChild;
var h=img.offsetHeight;
var w=img.offsetWidth;
img.style.display = "none";
var off=Math.sqrt( h*h + w*w );
var r = Raphael(place, off, off); // speaking of what to render and where... let's make a canvas r to play with
var i = r.image(img.src, (off-w)/2, (off-h)/2, w, h).attr({opacity: .5});
var j = r.image(img.src, (off-w)/2, (off-h)/2, w, h).attr({opacity: .5});
place.onmousemove=function (e) { var ev=e||window.event;
var x=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX()); // mouse X
var deltax=x-this.lastX||x;
var y=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY()); // mouse X
var deltay=y-this.lastY||y;
i.rotate(deltay);//.scale(100-deltax, 100-deltax);
j.rotate(deltax);//.scale(100+deltax, 100+deltax);
this.lastX=x;
this.lastY=y;
};
</script>
}}}
{{center{
{{picture{[img[ice_ice_baby_by_p0stfrau]][img[i-blur]]}}}<script>
var img = place.lastChild.firstChild;
var other_img = place.lastChild.firstChild.nextSibling;
var h=img.offsetHeight;
var w=img.offsetWidth;
var o_h = other_img.offsetHeight;
var o_w = other_img.offsetWidth;
img.style.display = "none";
other_img.style.display = "none";
var i_off=Math.sqrt( h*h + w*w );
var o_off=Math.sqrt( o_h*o_h + o_w*o_w );
var off = Math.max(i_off,o_off);
var r = Raphael(place, off, off);
var i = r.image(img.src, (off-w)/2, (off-h)/2, w, h).attr({opacity: .25});
var j = r.image(img.src, (off-w)/2, (off-h)/2, w, h).attr({opacity: .25});
var o_i = r.image(other_img.src, (off-o_w)/2, (off-o_h)/2, o_w, o_h).attr({opacity: .25});
var o_j = r.image(other_img.src, (off-o_w)/2, (off-o_h)/2, o_w, o_h).attr({opacity: .25});
place.onmousemove=function (e) { var ev=e||window.event;
var x=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX()); // mouse X
var deltax=x-this.lastX||x;
var y=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY()); // mouse X
var deltay=y-this.lastY||y;
i.rotate(deltay);//.scale(100-deltax, 100-deltax);
j.rotate(deltax);//.scale(100+deltax, 100+deltax);
o_i.rotate(-deltax);o_j.rotate(-deltay);
this.lastX=x;
this.lastY=y;
};
</script>
}}}
{{center{
{{picture{[img[mirrors]][img[mirrors]][img[mirrors]]}}}<script>
var img = place.lastChild.firstChild;
var other_img = place.lastChild.firstChild.nextSibling;
var oo_img = place.lastChild.firstChild.nextSibling.nextSibling;
var h=img.offsetHeight;
var w=img.offsetWidth;
var o_h = other_img.offsetHeight;
var o_w = other_img.offsetWidth;
var oo_h = oo_img.offsetHeight;
var oo_w = oo_img.offsetWidth;
img.style.display = "none";
other_img.style.display = "none";
oo_img.style.display = "none";
var i_off=Math.sqrt( h*h + w*w );
var o_off=Math.sqrt( o_h*o_h + o_w*o_w );
var oo_off=Math.sqrt( oo_h*oo_h + oo_w*oo_w );
var off = Math.max(i_off,o_off);
off = Math.max(off, oo_off);
var r = Raphael(place, off, off);
var i = r.image(img.src, (off-w)/2, (off-h)/2, w, h).attr({opacity: (1/6)});
var j = r.image(img.src, (off-w)/2, (off-h)/2, w, h).attr({opacity: (1/6)});
var o_i = r.image(other_img.src, (off-o_w)/2, (off-o_h)/2, o_w, o_h).attr({opacity: (1/6)});
var o_j = r.image(other_img.src, (off-o_w)/2, (off-o_h)/2, o_w, o_h).attr({opacity: (1/6)});
var oo_i = r.image(oo_img.src, (off-oo_w)/2, (off-oo_h)/2, oo_w, oo_h).attr({opacity: (1/6)});
var oo_j = r.image(oo_img.src, (off-oo_w)/2, (off-oo_h)/2, oo_w, oo_h).attr({opacity: (1/6)});
place.onmousemove=function (e) { var ev=e||window.event;
var x=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX()); // mouse X
var deltax=x-this.lastX||x;
var y=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY()); // mouse X
var deltay=y-this.lastY||y;
i.rotate(deltay);j.rotate(deltax);
o_i.rotate(-deltax);o_j.rotate(-deltay);
oo_i.rotate(-deltay);oo_j.rotate(deltax);
this.lastX=x;
this.lastY=y;
};
</script>
}}}
/%
|Name|GetTheFAQs|
|Source|http://www.TiddlyTools.com/#GetTheFAQs|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin, LoadTiddlersPlugin, FAQViewerPlugin|
|Overrides||
|Description|autoload FAQ articles from external document|
Usage:
<<tiddler GetTheFAQs>>
<<tiddler GetTheFAQs with: location tag tiddlername>>
where:
* 'location' is a URL, a relative path/file, or a TiddlerName that refers to a TiddlyWiki document containing the set of tiddlers to be automatically imported into the current document. If no location parameter is provided, the contents of a tiddler named [[SiteFAQ]] will be used. If [[SiteFAQ]] is not present, you will be prompted to enter a location (default='faq.html'). If a location refers to an existing tiddlername , the //contents// of that tiddler are used as the actual source location.
* 'tag' indicates the tag to match when retrieving tiddlers (default="faq").
* 'tiddlername' specifies the desired target tiddler title (default=none).
The script imports tiddlers from the indicated location only when there are no tiddlers in the current document that match the tag value, or the target tiddler (if specified) does not exist in the current document. Otherwise, a FAQViewer interface is automatically displayed (if [[FAQViewerPlugin]] is installed) for easy viewing of the set of tagged tiddlers that have just been imported.
%/<<tiddler HideTiddlerTags>><script>
// defaults and messages
var defaultsrc ='faq.html';
var defaulttag ='faq';
var loadcmd ='<<loadTiddlers [[tag:%0]] [[%1]] quiet nodirty noreport temporary>>';
var viewcmd ='<<tiddler FAQViewer>>';
var askmsg ="Enter the location of a TiddlyWiki document containing '%0' tiddlers";
var confirmmsg ="Press OK to import '%0' tiddlers from:";
var loadingmsg ="'%0' tiddlers are being imported... please wait...";
var notloadedmsg='{{block{'
+"//There are no '%0' tiddlers currently loaded.// "
+"''Please refresh this tiddler to import the '%0' archive...''\n"
+"//To view the archive directly, please visit:// ''[[%1|%1]]''"
+'}}}';
// get source, tag and target tiddler
var src='$1'; if (src=='$'+'1') src='';
var tag='$2'; if (tag=='$'+'2') tag=defaulttag;
var target='$3'; if (target=='$'+'3') target='';
// if target or tagged tiddlers already in document, just show the viewer
if (store.tiddlerExists(target)||store.getTaggedTiddlers(tag,'excludeLists').length)
return viewcmd;
// if src is an existing tiddlername, get tiddler content as src
src=store.getTiddlerText(src,src);
// if no src, use [[SiteFAQ]] or default value
if (!src.length) src=store.getTiddlerText('SiteFAQ',defaultsrc);
// ask for permission to import tiddlers or change src
var s=prompt(confirmmsg.format([tag]),src);
if (!s||!s.length) return notloadedmsg.format([tag,src]); // cancelled
// if s is an existing tiddlername, get tiddler content as src
src=store.getTiddlerText(s,s);
// show 'please wait' message when using remote async file access (XMLHttpRequest)
var async=document.location.protocol!='file:'||src.substr(0,4)=='http';
if (async) setTimeout('displayMessage("'+loadingmsg.format([tag])+'")',1);
// start the import!
return loadcmd.format([tag,src]);
</script>
{{{
-------------------OO---------
--------------------OO--------
-------------------O----------
------------------------------
--------------------------O---
--------------------------O-O-
--------------------------OO--
------------------------------
------OO----------------------
-----OO-----------------------
-------O----------------------
------------------------------
-------------------------O----
--------------------------OO--
-------------------------OO---
----OOO-----------------------
------O-----------------------
-----O------------------------
------------------------------
-----------O-O----------------
-----------OO-----------------
------------O-----------------
------------------------------
--------------------OOO-------
--------------------O---------
---------------------O--------
------------------------------
-----------O------------------
------------O-----------------
----------OOO-----------------
}}}
{{{
--------------------------------------
------------------------O-------------
----------------------O-O-------------
------------OO------OO------------OO--
-----------O---O----OO------------OO--
OO--------O-----O---OO----------------
OO--------O---O-OO----O-O-------------
----------O-----O-------O-------------
-----------O---O----------------------
------------OO------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
-------------------------------------#
-------------------------------------#
-----------------------------------###
}}}
/***
|Name|GotoPlugin|
|Source|http://www.TiddlyTools.com/#GotoPlugin|
|Documentation|http://www.TiddlyTools.com/#GotoPluginInfo|
|Version|1.7.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|view any tiddler by entering it's title - displays list of possible matches|
''View a tiddler by typing its title and pressing //enter//.'' As you type, a list of possible matches is displayed. You can scroll-and-click (or use arrows+enter) to select/view a tiddler, or press //escape// to close the listbox to resume typing. When the listbox is ''//not//'' being displayed, press //escape// to clear the current text input and start over.
!!!!!Documentation
>see [[GotoPluginInfo]]
!!!!!Revisions
<<<
2008.12.15 [1.7.1] up arrow from input field now moves to end of droplist (search for input). Also, shift+enter cam now be used to quickly invoke search for text.
|please see [[GotoPluginInfo]] for additional revision details|
2006.05.05 [0.0.0] started
<<<
!!!!!Code
***/
//{{{
version.extensions.GotoPlugin= {major: 1, minor: 7, revision: 1, date: new Date(2008,12,15)};
// automatically tweak shadow SideBarOptions to add <<gotoTiddler>> macro above <<search>>
config.shadowTiddlers.SideBarOptions=config.shadowTiddlers.SideBarOptions.replace(/<<search>>/,"{{button{goto}}}\n<<gotoTiddler>><<search>>");
config.macros.gotoTiddler= {
listMaxSize: 10,
listHeading: 'Found %0 matching title%1...',
searchItem: "Search for '%0'...",
handler:
function(place,macroName,params,wikifier,paramString,tiddler) {
var quiet =params.contains("quiet");
var search =params.contains("search");
params = paramString.parseParams("anon",null,true,false,false);
var instyle =getParam(params,"inputstyle","");
var liststyle =getParam(params,"liststyle","");
var filter =getParam(params,"filter","");
var html=this.html;
var keyevent=window.event?"onkeydown":"onkeypress"; // IE event fixup for ESC handling
html=html.replace(/%keyevent%/g,keyevent);
html=html.replace(/%search%/g,search);
html=html.replace(/%quiet%/g,quiet);
html=html.replace(/%instyle%/g,instyle);
html=html.replace(/%liststyle%/g,liststyle);
html=html.replace(/%filter%/g,filter);
if (config.browser.isIE) html=this.IEtableFixup.format([html]);
createTiddlyElement(place,"span").innerHTML=html;
},
html:
'<form onsubmit="return false" style="display:inline;margin:0;padding:0">\
<input name=gotoTiddler type=text autocomplete="off" accesskey="G" style="%instyle%"\
title="Enter title text... DOWN=select from list, ENTER=open/create tiddler, SHIFT-ENTER=search for text"\
onclick="this.form.list.style.display=\'none\';"\
onfocus="this.select(); this.setAttribute(\'accesskey\',\'G\');"\
%keyevent%="return config.macros.gotoTiddler.inputEscKeyHandler(event,this,this.form.list);"\
onkeyup="return config.macros.gotoTiddler.inputKeyHandler(event,this,%quiet%,%search%);">\
<select name=list style="%liststyle%;display:none;position:absolute"\
onchange="if (!this.selectedIndex) this.selectedIndex=1;"\
onblur="this.style.display=\'none\';"\
%keyevent%="return config.macros.gotoTiddler.selectKeyHandler(event,this,this.form.gotoTiddler);"\
onclick="return config.macros.gotoTiddler.processItem(this.value,this.form.gotoTiddler,this);">\
</select><input name="filter" type="hidden" value="%filter%">\
</form>',
IEtableFixup:
"<table style='width:100%;display:inline;padding:0;margin:0;border:0;'>\
<tr style='padding:0;margin:0;border:0;'><td style='padding:0;margin:0;border:0;'>\
%0</td></tr></table>",
getItems:
function(val,filter) {
if (!this.items.length || val.length<2) { // starting new search, refresh cached list of tiddlers/shadows/tags
this.items=new Array();
if (filter.length) {
var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
var tiddlers=store.sortTiddlers(fn.apply(store,[filter]),'title');
} else
var tiddlers=store.getTiddlers("title","excludeLists");
for(var t=0; t<tiddlers.length; t++) this.items.push(tiddlers[t].title);
if (!filter.length) {
for (var t in config.shadowTiddlers) this.items.pushUnique(t);
var tags=store.getTags();
for(var t=0; t<tags.length; t++) this.items.pushUnique(tags[t][0]);
}
}
var found = [];
var match=val.toLowerCase();
for(var i=0; i<this.items.length; i++)
if (this.items[i].toLowerCase().indexOf(match)!=-1) found.push(this.items[i]);
return found;
},
items: [], // cached list of tiddlers/shadows/tags
getItemSuffix:
function(t) {
if (store.tiddlerExists(t)) return ""; // tiddler
if (store.isShadowTiddler(t)) return " (shadow)"; // shadow
return " (tag)"; // tag
},
keyProcessed:
function(ev) { // utility function: exits handler and prevents browser from processing the keystroke
ev.cancelBubble=true; // IE4+
try{event.keyCode=0;}catch(e){}; // IE5
if (window.event) ev.returnValue=false; // IE6
if (ev.preventDefault) ev.preventDefault(); // moz/opera/konqueror
if (ev.stopPropagation) ev.stopPropagation(); // all
return false;
},
inputEscKeyHandler:
function(event,here,list) {
var key=event.keyCode;
// escape... hide list (2nd esc=clears input)
if (key==27) {
if (list.style.display=="none")
here.value=here.defaultValue;
list.style.display="none";
return this.keyProcessed(event);
}
return true; // key bubbles up
},
inputKeyHandler:
function(event,here,quiet,search) {
var key=event.keyCode;
var list=here.form.list;
var filter=here.form.filter;
// non-printing chars bubble up, except for a few:
if (key<48) switch(key) {
// backspace=8, enter=13, space=32, up=38, down=40, delete=46
case 8: case 13: case 32: case 38: case 40: case 46: break; default: return true;
}
// blank input... if down/enter... fall through (list all)... else, and hide list
if (!here.value.length && !(key==40 || key==13))
{ list.style.display="none"; return this.keyProcessed(event); }
// make sure list is shown (unless quiet option)
list.style.display=!quiet?"block":"none";
// non-blank input... enter=show/create tiddler, SHIFT-enter=search for text
if (key==13) return this.processItem(event.shiftKey?'*':here.value,here,list);
// up or down key... shows and moves to list...
if (key==38 || key==40) { list.style.display="block"; list.focus(); }
// if list is showing, fill it with found results...
if (list.style.display!="none") {
var indent='\xa0\xa0\xa0';
var found = this.getItems(here.value,filter.value); // find matching items...
found.sort(); // alpha by title
while (list.length > 0) list.options[0]=null; // clear list
var hdr=this.listHeading.format([found.length,found.length==1?"":"s"]);
list.options[0]=new Option(hdr,"",false,false);
for (var t=0; t<found.length; t++) list.options[list.length]=
new Option(indent+found[t]+this.getItemSuffix(found[t]),found[t],false,false);
if (search)
list.options[list.length]=new Option(this.searchItem.format([here.value]),"*",false,false);
list.size=(list.length<this.listMaxSize?list.length:this.listMaxSize); // resize list...
list.selectedIndex=key==38?list.length-1:key==40?1:0;
}
return true; // key bubbles up
},
selectKeyHandler:
function(event,list,editfield) {
if (event.keyCode==27) // escape... hide list, move to edit field
{ editfield.focus(); list.style.display="none"; return this.keyProcessed(event); }
if (event.keyCode==13 && list.value.length) // enter... view selected item
{ this.processItem(list.value,editfield,list); return this.keyProcessed(event); }
return true; // key bubbles up
},
processItem:
function(title,here,list) {
if (!title.length) return;
list.style.display='none';
if (title=="*") { story.search(here.value); return false; } // do full-text search
here.value=title;
story.displayTiddler(null,title); // show selected tiddler
return false;
}
}
//}}}
/***
|Name|GotoPluginInfo|
|Source|http://www.TiddlyTools.com/#GotoPlugin|
|Documentation|http://www.TiddlyTools.com/#GotoPluginInfo|
|Version|1.7.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|Documentation for GotoPlugin|
''View a tiddler by typing its title and pressing //enter//.'' As you type, a list of possible matches is displayed. You can scroll-and-click (or use arrows+enter) to select/view a tiddler, or press //escape// to close the listbox to resume typing. When the listbox is ''//not//'' being displayed, press //escape// to clear the current text input and start over.
!!!!!Usage/Examples
<<<
| //IMPORTANT NOTE:// ''As of version 1.4.0 (2007.04.25),<br>to avoid conflict with javascript reserved keywords<br>the {{{<<goto>>}}} macro has been renamed to {{{<<gotoTiddler>>}}}'' |
syntax: {{{<<gotoTiddler quiet search inputstyle:... liststyle:... filter:...>>}}}
All parameters are optional.
* ''quiet'' (//keyword//)<br>prevents //automatic// display of the list as each character is typed. To view the list when ''quiet'', use //down// or //enter//.
* ''search'' (//keyword//)<br>adds an extra 'command item' to the list that can be used to invoke a full-text search using the entered value. This can be especially useful when no matching tiddler titles have been found.
* ''inputstyle:'' and ''liststyle:''<br>are CSS declarations that modify the default input and listbox styles, respectively. Note: the CSS styles must be surrounded by ({{{"..."}}} or {{{'...'}}}) or ({{{[[...]]}}}) (e.g., {{{liststyle:"border:1px dotted blue;color:green;..."}}}.
* ''filter:''<br>is a single tag value (or a boolean tag expression if MatchTagsPlugin is installed), and is used to limit the search to only those tiddlers matching the indicated tag or tag expression (e.g., {{{<<gotoTiddler filter:"faq or help">>}}})
{{{<<gotoTiddler>>}}}
<<gotoTiddler>>
{{{<<gotoTiddler search>>}}}
<<gotoTiddler search>>
{{{<<gotoTiddler quiet>>}}}
<<gotoTiddler quiet>>
{{{<<gotoTiddler filter:"faq">>}}}
<<gotoTiddler filter:"faq">>
{{{<<gotoTiddler inputstyle:"width:20em" liststyle:"width:20em">>}}}
<<gotoTiddler inputstyle:"width:20em" liststyle:"width:20em">>
<<<
!!!!!Configuration
<<<
You can create a tiddler tagged with <<tag systemConfig>> to control the maximum height of the listbox of tiddlers/shadows/tags. //The default values are shown below://
//{{{
config.macros.gotoTiddler.listMaxSize=10;
//}}}
<<<
!!!!!Revisions
<<<
2008.12.15 [1.7.1] up arrow from input field now moves to end of droplist (search for input). Also, shift+enter cam now be used to quickly invoke search for text.
2008.10.16 [1.7.0] in macro handler(), changed to use //named// params instead of positional params, and added optional "filter:" param for tag filtering. Removed 'insert' handling (now provided by [[QuickEditPlugin]]).
2008.10.02 [1.6.1] for IE, wrap controls in a table. Corrects placement of listbox so it is below input field.
2008.10.02 [1.6.0] added 'search' param for optional "Search for:" item that invokes full text search (especially useful when no title matches are found)
2008.02.17 [1.5.0] ENTER key always displays tiddler based on current input regardless of whether input matches any existing tiddler
2007.10.31 [1.4.3] removed extra trailing comma on last property of config.macros.gotoTiddler object. This fixes an error under InternetExplorer that was introduced 6 days ago... sure, I should have found it sooner, but... WHY DON'T PEOPLE TELL ME WHEN THINGS ARE BROKEN!!!!
2007.10.25 [1.4.2] added onclick handler for input field, so that clicking in field hides the listbox.
2007.10.25 [1.4.1] re-wrote getItems() to cache list of tiddlers/shadows/tags and use case-folded simple text match instead of regular expression to find matching tiddlers. This *vastly* reduces processing overhead between keystrokes, especially for documents with many (>1000) tiddlers. Also, removed local definition of replaceSelection(), now supported directly by the TW2.2+ core, as well as via backward-compatible plugin
2007.04.25 [1.4.0] renamed macro from "goto" to "gotoTiddler". This was necessary to avoid a fatal syntax error in Opera (and other browsers) that require strict adherence to ECMAScript 1.5 standards which defines the identifier "goto" as "reserved for FUTURE USE"... *sigh*
2007.04.21 [1.3.2] in html definition, removed DIV around droplist (see 1.2.6 below). It created more layout problems then it solved. :-(
2007.04.01 [1.3.1] in processItem(), ensure that correct textarea field is found by checking for edit=="text" attribute
2007.03.30 [1.3.0] tweak SideBarOptions shadow to automatically add {{{<<goto>>}}} when using default sidebar content
2007.03.30 [1.2.6] in html definition, added DIV around droplist to fix IE problem where list appears next to input field instead of below it.
2007.03.28 [1.2.5] in processItem(), set focus to text area before setting selection (needed for IE to get correct selection 'range')
2007.03.28 [1.2.4] added prompt for 'pretty text' when inserting a link into tiddler content
2007.03.28 [1.2.3] added local copy of core replaceSelection() and modified for different replace logic
2007.03.27 [1.2.2] in processItem(), use story.getTiddlerField() to retrieve textarea control
2007.03.26 [1.2.1] in html, use either 'onkeydown' (IE) or 'onkeypress' (Moz) event to process <esc> key sooner, to prevent <esc> from 'bubbling up' to the tiddler (which will close the current editor).
2007.03.26 [1.2.0] added support for optional "insert" keyword param. When used in [[EditTemplate]], (e.g. {{{<span macro="goto insert"></span>}}}) it triggers alternative processing: instead of displaying the selected tiddler, that tiddler's title is inserted into a tiddler's textarea edit field surrounded by {{{[[...]]}}}.
2006.05.10 [1.1.2] when filling listbox, set selection to 'heading' item... auto-select first tiddler title when down/enter moves focus into listbox
2006.05.08 [1.1.1] added accesskey ("G") to input field html (also set when field gets focus). Also, inputKeyHandler() skips non-printing/non-editing keys.
2006.05.08 [1.1.0] added heading to listbox for better feedback (also avoids problems with 1-line droplist)
2006.05.07 [1.0.0] list matches against tiddlers/shadows/tags. input field auto-completion... 1st enter=complete matching input (or show list)... 2nd enter=view tiddler. optional "quiet" param controls when listbox appears.
2006.05.06 [0.5.0] added handling for enter (13), escape(27), and down(40) keys. Change 'ondblclick' to 'onclick' for list handler to view tiddlers (suggested by Florian Cauvin - prevents unintended trigger of tiddler editor). shadow titles inserted into list instead of appended to the end.
2006.05.05 [0.0.0] started
<<<
/***
|Name|HTMLFormattingPlugin|
|Source|http://www.TiddlyTools.com/#HTMLFormattingPlugin|
|Documentation|http://www.TiddlyTools.com/#HTMLFormattingPluginInfo|
|Version|2.4.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|'HTML' formatter|
|Description|embed wiki syntax formatting inside of HTML content|
The ~HTMLFormatting plugin allows you to ''mix wiki-style formatting syntax within HTML formatted content'' by extending the action of the standard TiddlyWiki formatting handler.
!!!!!Documentation
>see [[HTMLFormattingPluginInfo]]
!!!!!Revisions
<<<
2009.01.05 [2.4.0] in wikifyTextNodes(), pass w.highlightRegExp and w.tiddler to wikify() so that search term highlighting and tiddler-relative macro processing will work
| see [[HTMLFormattingPluginInfo]] for additional revision details |
2005.06.26 [1.0.0] Initial Release (as code adaptation - pre-dates TiddlyWiki plugin architecture!!)
<<<
!!!!!Code
***/
//{{{
version.extensions.HTMLFormattingPlugin= {major: 2, minor: 4, revision: 0, date: new Date(2009,1,5)};
// find the formatter for HTML and replace the handler
initHTMLFormatter();
function initHTMLFormatter()
{
for (var i=0; i<config.formatters.length && config.formatters[i].name!="html"; i++);
if (i<config.formatters.length) config.formatters[i].handler=function(w) {
if (!this.lookaheadRegExp) // fixup for TW2.0.x
this.lookaheadRegExp = new RegExp(this.lookahead,"mg");
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var html=lookaheadMatch[1];
// if <nowiki> is present, just let browser handle it!
if (html.indexOf('<nowiki>')!=-1)
createTiddlyElement(w.output,"span").innerHTML=html;
else {
// if <hide linebreaks> is present, suppress wiki-style literal handling of newlines
if (html.indexOf('<hide linebreaks>')!=-1) html=html.replace(/\n/g,' ');
// remove all \r's added by IE textarea and mask newlines and macro brackets
html=html.replace(/\r/g,'').replace(/\n/g,'\\n').replace(/<</g,'%%(').replace(/>>/g,')%%');
// create span, let browser parse HTML
var e=createTiddlyElement(w.output,"span"); e.innerHTML=html;
// then re-render text nodes as wiki-formatted content
wikifyTextNodes(e,w);
}
w.nextMatch = this.lookaheadRegExp.lastIndex; // continue parsing
}
}
}
// wikify #text nodes that remain after HTML content is processed (pre-order recursion)
function wikifyTextNodes(theNode,w)
{
function unmask(s) { return s.replace(/\%%\(/g,'<<').replace(/\)\%%/g,'>>').replace(/\\n/g,'\n'); }
switch (theNode.nodeName.toLowerCase()) {
case 'style': case 'option': case 'select':
theNode.innerHTML=unmask(theNode.innerHTML);
break;
case 'textarea':
theNode.value=unmask(theNode.value);
break;
case '#text':
var txt=unmask(theNode.nodeValue);
var newNode=createTiddlyElement(null,"span");
theNode.parentNode.replaceChild(newNode,theNode);
wikify(txt,newNode,highlightHack,w.tiddler);
break;
default:
for (var i=0;i<theNode.childNodes.length;i++)
wikifyTextNodes(theNode.childNodes.item(i),w); // recursion
break;
}
}
//}}}
|Name|HTMLFormattingPluginInfo|
|Source|http://www.TiddlyTools.com/#HTMLFormattingPlugin|
|Documentation|http://www.TiddlyTools.com/#HTMLFormattingPluginInfo|
|Version|2.4.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for HTMLFormattingPlugin|
The ~HTMLFormatting plugin allows you to freely ''mix wiki-style formatting syntax within HTML formatted content'' by extending the action of the standard TiddlyWiki formatting handler.
!!!!!Usage
<<<
The shorthand Wiki-style formatting syntax of ~TiddlyWiki is very convenient and enables most content to be reasonably well presented. However, there are times when tried-and-true HTML formatting syntax allows more more precise control of the content display.
When a tiddler is about to be displayed, ~TiddlyWiki looks for tiddler content contained within {{{<html>}}} and {{{</html>}}} markers. When present, the TiddlyWiki core simply passes this content directly to the browser's internal "rendering engine" to process as ~HTML-formatted content. However, TiddlyWiki does not also process the HTML source content for any embedded wiki-formatting syntax it may contain. This means that while you can use HTML formatted content, you cannot mix wiki-formatted content within the HTML formatting.
This plugin extends the TiddlyWiki core processing so that, after the HTML formatting has been processed, all the pieces of text occuring within the HTML block are then processed one piece at a time, so that normal wiki-style formatting can be applied to the individual text pieces.
Note: To bypass this extended processing for a specific section of HTML content, embed ''{{{<nowiki>}}}'' //anywhere// inside the {{{<html>...</html>}}} delimiters, and wiki formatting will not be applied to that content.
<<<
!!!!!Line breaks
<<<
One major difference between Wiki formatting and HTML formatting is how "line breaks" are processed. Wiki formatting treats all line breaks as literal content to be displayed //as-is//. However, because HTML normally ignores line breaks and actually processes them as simple "word separators" instead, many people who write HTML include extra line breaks in their documents, just to make the "source code" easier to read.
Even though you can use HTML tags within your tiddler content, the default treatment for line breaks still follows the Wiki-style rule (i.e., all new lines are displayed as-is). When adding HTML content to a tiddler (especially if you cut-and-paste it from another web page), you should take care to avoid adding extra line breaks to the text.
If removing all the extra line breaks from your HTML content would be a big hassle, you can quickly //override the default Wiki-style line break rule// so that the line breaks use the standard HTML rules, by placing ''{{{<hide linebreaks>}}}'' //anywhere// within the HTML content. This automatically converts all line breaks to spaces before rendering the content, so that the literal line breaks will be processed as simple word-breaks instead.
Note: this does //not// alter the actual tiddler content that is stored in the document, just the manner in which it is displayed. Any line breaks contained in the tiddler will still be there when you edit its content. Also, to include a literal line break when the ''<{{{hide linebreaks}}}>'' tag is present, you will need to use a ''<{{{br}}}>'' or ''<{{{p}}}>'' HTML tag instead of simply typing a line break.
<<<
!!!!!How it works
<<<
The TW core support for HTML does not let you put ANY wiki-style syntax (including TW macros) *inside* the {{{<html>...</html>}}} block. Everything between {{{<html>}}} and {{{</html>}}} is handed to the browser for processing and that is it.
However, not all wiki syntax can be safely passed through the browser's parser. Specifically, any TW macros inside the HTML will get 'eaten' by the browser since the macro brackets, {{{<<...>>}}} use the "<" and ">" that normally delimit the HTML/XML syntax recognized by the browser's parser.
Similarly, you can't use InlineJavascript within the HTML because the {{{<script>...</script>}}} syntax will also be consumed by the browser and there will be nothing left to process afterward. Note: unfortunately, even though the browser removes the {{{<script>...</script>}}} sequence, it doesn't actually execute the embedded javascript code that it removes, so any scripts contained inside of <html> blocks in TW are currently being ignored. :-(
As a work-around to allow TW *macros* (but not inline scripts) to exist inside of <html> formatted blocks of content, the plugin first converts the {{{<<}}} and {{{>>}}} into "%%(" and ")%%", making them "indigestible" so they can pass unchanged through the belly of the beast (the browser's HTML parser).
After the browser has done its job, the wiki syntax sequences (including the "undigested" macros) are contained in #text nodes in the browser-generated DOM elements. The plugin then recursively locates and processes each #text node, converts the %%( and )%% back into {{{<<}}} and {{{>>}}}, passes the result to wikify() for further rendering of the wiki-formatted syntax into a containing SPAN that replaces the previous #text node. At the end of this process, none of the encoded %%( and )%% sequences remain in the rendered tiddler output.
<<<
!!!!!Revisions
<<<
2009.01.05 [2.4.0] in wikifyTextNodes(), pass w.highlightRegExp and w.tiddler to wikify() so that search term highlighting and tiddler-relative macro processing will work
2008.10.02 [2.3.0] added use of {{{<nowiki>}}} marker to bypass all wikification inside a specific HTML block
2008.09.19 [2.2.0] in wikifyTextNodes(), don't wikify the contents of STYLE nodes (thanks to MorrisGray for bug report)
2008.04.26 [*.*.*] plugin size reduction: more documentation moved to HTMLFormattingInfo
2008.01.08 [*.*.*] plugin size reduction: documentation moved to HTMLFormattingInfo
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.06.14 [2.1.5] in formatter, removed call to e.normalize(). Creates an INFINITE RECURSION error in Safari!!!!
2006.09.10 [2.1.4] update formatter for 2.1 compatibility (use this.lookaheadRegExp instead of temp variable)
2006.05.28 [2.1.3] in wikifyTextNodes(), decode the *value* of TEXTAREA nodes, but don't wikify() its children. (thanks to "ayj" for bug report)
2006.02.19 [2.1.2] in wikifyTextNodes(), put SPAN element into tiddler DOM (replacing text node), BEFORE wikifying the text content. This ensures that the 'place' passed to any macros is correctly defined when the macro is evaluated, so that calls to story.findContainingTiddler(place) will work as expected. (Thanks for bug report from GeoffSlocock)
2006.02.05 [2.1.1] wrapped wikifier hijack in init function to eliminate globals and avoid FireFox 1.5.0.1 crash bug when referencing globals
2005.12.01 [2.1.0] don't wikify #TEXT nodes inside SELECT and TEXTAREA elements
2005.11.06 [2.0.1] code cleanup
2005.10.31 [2.0.0] replaced hijack wikify() with hijack config.formatters["html"] and simplified recursive WikifyTextNodes() code
2005.10.09 [1.0.2] combined documentation and code into a single tiddler
2005.08.05 [1.0.1] moved HTML and CSS definitions into plugin code instead of using separate tiddlers
2005.07.26 [1.0.1] Re-released as a plugin. Added <{{{html}}}>...</{{{nohtml}}}> and <{{{hide newlines}}}> handling
2005.06.26 [1.0.0] Initial Release (as code adaptation - pre-dates TiddlyWiki plugin architecture!!)
<<<
<script>
config.options.chkShowLeftSidebar=config.options.chkShowRightSidebar=false;
document.getElementById('mainMenu').style.display=document.getElementById('sidebar').style.display='none';
document.getElementById('displayArea').style.marginLeft=document.getElementById('displayArea').style.marginRight='1em';
config.refreshers.content(document.getElementById('storyMenu'));
</script>
/%
|Name|HideTiddlerBackground|
|Source|http://www.TiddlyTools.com/#HideTiddlerBackground|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|hide a tiddler's background and border (if any)|
Usage: <<tiddler HideTiddlerBackground>>
%/<script>
var t=story.findContainingTiddler(place);
if (!t || t.id=="HideTiddlerBackground") return;
var nodes=t.getElementsByTagName("*");
for (var i=0; i<nodes.length; i++) if (hasClass(nodes[i],"viewer")) {
var s=nodes[i].style;
s.backgroundImage="none";
s.backgroundColor="transparent"
s.borderColor="transparent";
s.borderWidth=0;
s.margin=0;
s.padding=0;
break;
}
</script>
/%
|Name|HideTiddlerSubtitle|
|Source|http://www.TiddlyTools.com/#HideTiddlerSubtitle|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|hide a tiddler's subtitle (dates/created by) display|
Usage: <<tiddler HideTiddlerSubtitle>>
%/<script>
var t=story.findContainingTiddler(place);
if (!t || t.id=="tiddlerHideTiddlerSubtitle") return;
var nodes=t.getElementsByTagName("*");
for (var i=0; i<nodes.length; i++)
if (hasClass(nodes[i],"subtitle"))
nodes[i].style.display="none";
</script>
/%
|Name|HideTiddlerTags|
|Source|http://www.TiddlyTools.com/#HideTiddlerTags|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|hide a tiddler's tagged/tagging display elements|
Usage: <<tiddler HideTiddlerTags>>
%/<script>
var t=story.findContainingTiddler(place);
if (!t || t.id=="tiddlerHideTiddlerTags") return;
var nodes=t.getElementsByTagName("div");
for (var i=0; i<nodes.length; i++)
if (hasClass(nodes[i],"tagged"))
nodes[i].style.display="none";
</script>
/%
|Name|HideTiddlerTitle|
|Source|http://www.TiddlyTools.com/#HideTiddlerTitle|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|hide a tiddler's title display elements (name, dates, and author)|
Usage: <<tiddler HideTiddlerTitle>>
%/<script>
var t=story.findContainingTiddler(place);
if (!t || t.id=="tiddlerHideTiddlerTitle") return;
var nodes=t.getElementsByTagName("*");
for (var i=0; i<nodes.length; i++)
if (hasClass(nodes[i],"title")||hasClass(nodes[i],"subtitle"))
nodes[i].style.display="none";
</script>
/%
|Name|HideTiddlerToolbar|
|Source|http://www.TiddlyTools.com/#HideTiddlerToolbar|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|hide a tiddler's toolbar display|
Usage: <<tiddler HideTiddlerToolbar>>
%/<script>
var t=story.findContainingTiddler(place);
if (!t || t.id=="tiddlerHideTiddlerToolbar") return;
var nodes=t.getElementsByTagName("*");
for (var i=0; i<nodes.length; i++)
if (hasClass(nodes[i],"toolbar"))
nodes[i].style.display="none";
</script>
/***
|Name|ImageSizePlugin|
|Source|http://www.TiddlyTools.com/#ImageSizePlugin|
|Version|1.2.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin,formatter|
|Requires||
|Overrides|'image' formatter|
|Description|adds support for resizing images|
This plugin adds optional syntax to scale an image to a specified width and height and/or interactively resize the image with the mouse.
!!!!!Usage
<<<
The extended image syntax is:
{{{
[img(w+,h+)[...][...]]
}}}
where ''(w,h)'' indicates the desired width and height (in CSS units, e.g., px, em, cm, in, or %). Use ''auto'' (or a blank value) for either dimension to scale that dimension proportionally (i.e., maintain the aspect ratio). You can also calculate a CSS value 'on-the-fly' by using a //javascript expression// enclosed between """{{""" and """}}""". Appending a plus sign (+) to a dimension enables interactive resizing in that dimension (by dragging the mouse inside the image). Use ~SHIFT-click to show the full-sized (un-scaled) image. Use ~CTRL-click to restore the starting size (either scaled or full-sized).
<<<
!!!!!Examples
<<<
{{{
[img(100px+,75px+)[images/meow2.jpg]]
}}}
[img(100px+,75px+)[images/meow2.jpg]]
{{{
[<img(34%+,+)[images/meow.gif]]
[<img(21% ,+)[images/meow.gif]]
[<img(13%+, )[images/meow.gif]]
[<img( 8%+, )[images/meow.gif]]
[<img( 5% , )[images/meow.gif]]
[<img( 3% , )[images/meow.gif]]
[<img( 2% , )[images/meow.gif]]
[img( 1%+,+)[images/meow.gif]]
}}}
[<img(34%+,+)[images/meow.gif]]
[<img(21% ,+)[images/meow.gif]]
[<img(13%+, )[images/meow.gif]]
[<img( 8%+, )[images/meow.gif]]
[<img( 5% , )[images/meow.gif]]
[<img( 3% , )[images/meow.gif]]
[<img( 2% , )[images/meow.gif]]
[img( 1%+,+)[images/meow.gif]]
{{tagClear{
}}}
<<<
!!!!!Revisions
<<<
2009.02.24 [1.2.1] cleanup width/height regexp, use '+' suffix for resizing
2009.02.22 [1.2.0] added stretchable images
2008.01.19 [1.1.0] added evaluated width/height values
2008.01.18 [1.0.1] regexp for "(width,height)" now passes all CSS values to browser for validation
2008.01.17 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.ImageSizePlugin= {major: 1, minor: 2, revision: 1, date: new Date(2009,2,24)};
//}}}
//{{{
var f=config.formatters[config.formatters.findByField("name","image")];
f.match="\\[[<>]?[Ii][Mm][Gg](?:\\([^,]*,[^\\)]*\\))?\\[";
f.lookaheadRegExp=/\[([<]?)(>?)[Ii][Mm][Gg](?:\(([^,]*),([^\)]*)\))?\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg;
f.handler=function(w) {
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var floatLeft=lookaheadMatch[1];
var floatRight=lookaheadMatch[2];
var width=lookaheadMatch[3];
var height=lookaheadMatch[4];
var tooltip=lookaheadMatch[5];
var src=lookaheadMatch[6];
var link=lookaheadMatch[7];
// Simple bracketted link
var e = w.output;
if(link) { // LINKED IMAGE
if (config.formatterHelpers.isExternalLink(link)) {
if (config.macros.attach && config.macros.attach.isAttachment(link)) {
// see [[AttachFilePluginFormatters]]
e = createExternalLink(w.output,link);
e.href=config.macros.attach.getAttachment(link);
e.title = config.macros.attach.linkTooltip + link;
} else
e = createExternalLink(w.output,link);
} else
e = createTiddlyLink(w.output,link,false,null,w.isStatic);
addClass(e,"imageLink");
}
var img = createTiddlyElement(e,"img");
if(floatLeft) img.align="left"; else if(floatRight) img.align="right";
if(width||height) {
var x=width.trim(); var y=height.trim();
var stretchW=(x.substr(x.length-1,1)=='+'); if (stretchW) x=x.substr(0,x.length-1);
var stretchH=(y.substr(y.length-1,1)=='+'); if (stretchH) y=y.substr(0,y.length-1);
if (x.substr(0,2)=="{{")
{ try{x=eval(x.substr(2,x.length-4))} catch(e){displayMessage(e.description||e.toString())} }
if (y.substr(0,2)=="{{")
{ try{y=eval(y.substr(2,y.length-4))} catch(e){displayMessage(e.description||e.toString())} }
img.style.width=x.trim(); img.style.height=y.trim();
config.formatterHelpers.addStretchHandlers(img,stretchW,stretchH);
}
if(tooltip) img.title = tooltip;
// GET IMAGE SOURCE
if (config.macros.attach && config.macros.attach.isAttachment(src))
src=config.macros.attach.getAttachment(src); // see [[AttachFilePluginFormatters]]
else if (config.formatterHelpers.resolvePath) { // see [[ImagePathPlugin]]
if (config.browser.isIE || config.browser.isSafari) {
img.onerror=(function(){
this.src=config.formatterHelpers.resolvePath(this.src,false);
return false;
});
} else
src=config.formatterHelpers.resolvePath(src,true);
}
img.src=src;
w.nextMatch = this.lookaheadRegExp.lastIndex;
}
}
config.formatterHelpers.addStretchHandlers=function(e,stretchW,stretchH) {
e.title=((stretchW||stretchH)?'DRAG=stretch/shrink, ':'')
+'SHIFT-CLICK=show full size, CTRL-CLICK=restore initial size';
e.statusMsg='width=%0, height=%1';
e.style.cursor='move';
e.originalW=e.style.width;
e.originalH=e.style.height;
e.minW=Math.max(e.offsetWidth/20,10);
e.minH=Math.max(e.offsetHeight/20,10);
e.stretchW=stretchW;
e.stretchH=stretchH;
e.onmousedown=function(ev) { var ev=ev||window.event;
this.sizing=true;
this.startX=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX());
this.startY=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY());
this.startW=this.offsetWidth;
this.startH=this.offsetHeight;
return false;
};
e.onmousemove=function(ev) { var ev=ev||window.event;
if (this.sizing) {
var s=this.style;
var currX=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX());
var currY=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY());
var newW=(currX-this.offsetLeft)/(this.startX-this.offsetLeft)*this.startW;
var newH=(currY-this.offsetTop )/(this.startY-this.offsetTop )*this.startH;
if (this.stretchW) s.width =Math.floor(Math.max(newW,this.minW))+'px';
if (this.stretchH) s.height=Math.floor(Math.max(newH,this.minH))+'px';
clearMessage(); displayMessage(this.statusMsg.format([s.width,s.height]));
}
return false;
};
e.onmouseup=function(ev) { var ev=ev||window.event;
if (ev.shiftKey) { this.style.width=this.style.height=''; }
if (ev.ctrlKey) { this.style.width=this.originalW; this.style.height=this.originalH; }
this.sizing=false;
clearMessage();
return false;
};
e.onmouseout=function(ev) { var ev=ev||window.event;
this.sizing=false;
clearMessage();
return false;
};
}
//}}}
The plugins in this package provide interactive functionality for importing/exporting tiddlers to/from other TiddlyWiki documents. Additional plugins provide enhanced local/remote file I/O features, including "save as", "save from web" and "upload" functionality.
/***
|Name|ImportTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#ImportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ImportTiddlersPluginInfo|
|Version|4.4.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|config.macros.importTiddlers.handler|
|Description|interactive controls for import/export with filtering.|
This plugin lets you selectively combine tiddlers from any two TiddlyWiki documents. An interactive control panel lets you pick a document to import from, and then select which tiddlers to import, with prompting for skip, rename, merge or replace actions when importing tiddlers that match existing titles. Automatically add tags to imported tiddlers so they are easy to find later on. Generates a detailed report of import 'history' in ImportedTiddlers.
!!!!!Documentation
<<<
see [[ImportTiddlersPluginInfo]] for details
<<<
!!!!!interactive control panel:
<<<
<<importTiddlers inline>>
{{clear{
^^(see also: [[ImportTiddlers]] shadow tiddler)^^}}}
<<<
!!!!!Installation Notes
<<<
* As of 6/27/2007, 'patch' functions that provide backward-compatibility with TW2.1.x and earlier have been split into a separate [[ImportTiddlersPluginPatch]] tiddler to reduce installation overhead for //this// plugin. You only need to install the additional plugin tiddler when using ImportTiddlersPlugin in documents using TW2.1.x or earlier.
* As of 3/21/2007, the interactive {{{<<importTiddlers>>}}} and non-interactive {{{<<loadTiddlers>>}}} macro definitions and related code have been split into separate [[ImportTiddlersPlugin]] and [[LoadTiddlersPlugin]] to permit selective installation of either the interactive and/or non-interactive macro functions.
* Quick Installation Tip: If you are using an unmodified version of TiddlyWiki (core release version <<version>>), you can get a new, empty TiddlyWiki with the Import Tiddlers plugin pre-installed (''[[download from here|TW+ImportExport.html]]''), and then simply import all your content from your old document into this new, empty document.
<<<
!!!!!Revisions
<<<
2009.02.26 [4.4.1] use macro-specific definition of $() function abbreviation (avoids conflict with JQuery)
|please see [[ImportTiddlersPluginInfo]] for additional revision details|
2005.07.20 [1.0.0] Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.ImportTiddlersPlugin= {major: 4, minor: 4, revision: 1, date: new Date(2009,2,26)};
// IE needs explicit global scoping for functions/vars called from browser events
window.onClickImportButton=onClickImportButton;
window.refreshImportList=refreshImportList;
// default cookie/option values
if (!config.options.chkImportReport) config.options.chkImportReport=true;
// default shadow definition
config.shadowTiddlers.ImportTiddlers='<<importTiddlers inline>>';
// use shadow tiddler content in backstage panel
if (config.tasks) config.tasks.importTask.content='<<tiddler ImportTiddlers>>' // TW2.2 or above
//}}}
//{{{
// backward-compatiblity for TW2.0.x and TW1.2.x
if (config.macros.importTiddlers==undefined) config.macros.importTiddlers={};
if (typeof merge=='undefined') {
function merge(dst,src,preserveExisting) {
for(var i in src) { if(!preserveExisting || dst[i] === undefined) dst[i] = src[i]; }
return dst;
}
}
if (config.browser.isGecko===undefined)
config.browser.isGecko=(config.userAgent.indexOf('gecko')!=-1);
//}}}
//{{{
merge(config.macros.importTiddlers,{
$: function(id) { return document.getElementById(id); }, // abbreviation
label: 'import tiddlers',
prompt: 'Copy tiddlers from another document',
openMsg: 'Opening %0',
openErrMsg: 'Could not open %0 - error=%1',
readMsg: 'Read %0 bytes from %1',
foundMsg: 'Found %0 tiddlers in %1',
filterMsg: "Filtered %0 tiddlers matching '%1'",
summaryMsg: '%0 tiddler%1 in the list',
summaryFilteredMsg: '%0 of %1 tiddler%2 in the list',
plural: 's are',
single: ' is',
countMsg: '%0 tiddlers selected for import',
processedMsg: 'Processed %0 tiddlers',
importedMsg: 'Imported %0 of %1 tiddlers from %2',
loadText: 'please load a document...',
closeText: 'close',
doneText: 'done',
startText: 'import',
stopText: 'stop',
local: true, // default to import from local file
src: '', // path/filename or URL of document to import (retrieved from SiteUrl)
proxy: '', // URL for remote proxy script (retrieved from SiteProxy)
useProxy: false, // use specific proxy script in front of remote URL
inbound: null, // hash-indexed array of tiddlers from other document
newTags: '', // text of tags added to imported tiddlers
addTags: true, // add new tags to imported tiddlers
listsize: 10, // # of lines to show in imported tiddler list
importTags: true, // include tags from remote source document when importing a tiddler
keepTags: true, // retain existing tags when replacing a tiddler
sync: false, // add 'server' fields to imported tiddlers (for sync function)
lastFilter: '', // most recent filter (URL hash) applied
lastAction: null, // most recent collision button performed
index: 0, // current processing index in import list
sort: '' // sort order for imported tiddler listbox
});
//}}}
//{{{
// hijack core macro handler
if (config.macros.importTiddlers.coreHandler==undefined)
config.macros.importTiddlers.coreHandler=config.macros.importTiddlers.handler;
config.macros.importTiddlers.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
if (!params[0] || params[0].toLowerCase()=='core') { // default to built in
if (config.macros.importTiddlers.coreHandler)
config.macros.importTiddlers.coreHandler.apply(this,arguments);
else
createTiddlyButton(place,this.label,this.prompt,onClickImportMenu);
} else if (params[0]=='link') { // show link to floating panel
createTiddlyButton(place,params[1]||this.label,params[2]||this.prompt,onClickImportMenu);
} else if (params[0]=='inline') {// show panel as INLINE tiddler content
createImportPanel(place);
this.$('importPanel').style.position='static';
this.$('importPanel').style.display='block';
} else if (config.macros.loadTiddlers)
config.macros.loadTiddlers.handler(place,macroName,params); // any other params: loadtiddlers
}
//}}}
//{{{
// Handle link click to create/show/hide control panel
function onClickImportMenu(e) { var e=e||window.event;
var parent=resolveTarget(e).parentNode;
var panel=document.getElementById('importPanel');
if (panel==undefined || panel.parentNode!=parent) panel=createImportPanel(parent);
var isOpen=panel.style.display=='block';
if(config.options.chkAnimate)
anim.startAnimating(new Slider(panel,!isOpen,false,'none'));
else
panel.style.display=isOpen?'none':'block';
e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation(); return(false);
}
//}}}
//{{{
// Create control panel: HTML, CSS
function createImportPanel(place) {
var cmi=config.macros.importTiddlers; // abbrev
var panel=cmi.$('importPanel');
if (panel) { panel.parentNode.removeChild(panel); }
setStylesheet(cmi.css,'importTiddlers');
panel=createTiddlyElement(place,'span','importPanel',null,null)
panel.innerHTML=cmi.html;
refreshImportList();
var siteURL=store.getTiddlerText('SiteUrl'); if (!siteURL) siteURL='';
cmi.$('importSourceURL').value=siteURL;
cmi.src=siteURL;
var siteProxy=store.getTiddlerText('SiteProxy'); if (!siteProxy) siteProxy='SiteProxy';
cmi.$('importSiteProxy').value=siteProxy;
cmi.proxy=siteProxy;
if (config.browser.isGecko) { // FF3 FIXUP
cmi.$('fileImportSource').style.display='none';
cmi.$('importLocalPanelFix').style.display='block';
}
return panel;
}
//}}}
//{{{
config.macros.importTiddlers.css = '\
#importPanel {\
display: none; position:absolute; z-index:11; width:35em; right:105%; top:3em;\
background-color: #eee; color:#000; font-size: 8pt; line-height:110%;\
border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;\
padding: 0.5em; margin:0em; -moz-border-radius:1em;-webkit-border-radius:1em;\
}\
#importPanel a, #importPanel td a { color:#009; display:inline; margin:0px; padding:1px; }\
#importPanel table { width:100%; border:0px; padding:0px; margin:0px; font-size:8pt; line-height:110%; background:transparent; }\
#importPanel tr { border:0px;padding:0px;margin:0px; background:transparent; }\
#importPanel td { color:#000; border:0px;padding:0px;margin:0px; background:transparent; }\
#importPanel select { width:100%;margin:0px;font-size:8pt;line-height:110%;}\
#importPanel input { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%}\
#importPanel .box { border:1px solid #000; background-color:#eee; padding:3px 5px; margin-bottom:5px; -moz-border-radius:5px;-webkit-border-radius:5px;}\
#importPanel .topline { border-top:1px solid #999; padding-top:2px; margin-top:2px; }\
#importPanel .rad { width:auto; }\
#importPanel .chk { width:auto; margin:1px;border:0; }\
#importPanel .btn { width:auto; }\
#importPanel .btn1 { width:98%; }\
#importPanel .btn2 { width:48%; }\
#importPanel .btn3 { width:32%; }\
#importPanel .btn4 { width:23%; }\
#importPanel .btn5 { width:19%; }\
#importPanel .importButton { padding: 0em; margin: 0px; font-size:8pt; }\
#importPanel .importListButton { padding:0em 0.25em 0em 0.25em; color: #000000; display:inline }\
#backstagePanel #importPanel { left:10%; right:auto; }\
';
//}}}
//{{{
config.macros.importTiddlers.html = '\
<!-- source and report -->\
<table><tr><td align=left>\
import from\
<input type="radio" class="rad" name="importFrom" id="importFromFile" value="file" CHECKED\
onclick="onClickImportButton(this,event)" title="show file controls"> local file\
<input type="radio" class="rad" name="importFrom" id="importFromWeb" value="http"\
onclick="onClickImportButton(this,event)" title="show web controls"> web server\
</td><td align=right>\
<input type=checkbox class="chk" id="chkImportReport" checked\
onClick="config.options[\'chkImportReport\']=this.checked;"> create report\
</td></tr></table>\
\
<div class="box" id="importSourcePanel" style="margin:.5em">\
<div id="importLocalPanel" style="display:block;margin-bottom:2px;"><!-- import from local file -->\
enter or browse for source path/filename<br>\
<input type="file" id="fileImportSource" size=57 style="width:100%"\
onKeyUp="config.macros.importTiddlers.src=this.value"\
onChange="config.macros.importTiddlers.src=this.value;document.getElementById(\'importLoad\').onclick()">\
<div id="importLocalPanelFix" style="display:none"><!-- FF3 FIXUP -->\
<input type="text" id="fileImportSourceFix" style="width:90%"\
title="Enter a path/file to import"\
onKeyUp="config.macros.importTiddlers.src=this.value"\
onChange="config.macros.importTiddlers.src=this.value;document.getElementById(\'importLoad\').onclick()">\
<input type="button" id="fileImportSourceFixButton" style="width:7%" value="..."\
title="Select a path/file to import"\
onClick="var r=config.macros.importTiddlers.askForFilename(this); if (!r||!r.length) return;\
document.getElementById(\'fileImportSourceFix\').value=r;\
config.macros.importTiddlers.src=r;\
document.getElementById(\'importLoad\').onclick()">\
</div><!--end FF3 FIXUP-->\
</div><!--end local-->\
<div id="importHTTPPanel" style="display:none;margin-bottom:2px;"><!-- import from http server -->\
<table><tr><td align=left>\
enter a URL or <a href="javascript:;" id="importSelectFeed"\
onclick="onClickImportButton(this,event)" title="select a pre-defined \'systemServer\' URL">\
select a server</a><br>\
</td><td align=right>\
<input type="checkbox" class="chk" id="importUsePassword"\
onClick="config.macros.importTiddlers.usePassword=this.checked;\
config.macros.importTiddlers.showPanel(\'importIDPWPanel\',this.checked,true);">password\
<input type="checkbox" class="chk" id="importUseProxy"\
onClick="config.macros.importTiddlers.useProxy=this.checked;\
config.macros.importTiddlers.showPanel(\'importSiteProxy\',this.checked,true);">proxy\
</td></tr></table>\
<input type="text" id="importSiteProxy" style="display:none;margin-bottom:1px" onfocus="this.select()" value="SiteProxy"\
onKeyUp="config.macros.importTiddlers.proxy=this.value"\
onChange="config.macros.importTiddlers.proxy=this.value;">\
<input type="text" id="importSourceURL" onfocus="this.select()" value="SiteUrl"\
onKeyUp="config.macros.importTiddlers.src=this.value"\
onChange="config.macros.importTiddlers.src=this.value;">\
<div id="importIDPWPanel" style="text-align:center;margin-top:2px;display:none";>\
username: <input type=text id="txtImportID" style="width:25%" \
onChange="config.options.txtRemoteUsername=this.value;">\
password: <input type=password id="txtImportPW" style="width:25%" \
onChange="config.options.txtRemotePassword=this.value;">\
</div><!--end idpw-->\
</div><!--end http-->\
</div><!--end source-->\
\
<div class="box" id="importSelectPanel" style="display:none;margin:.5em;">\
<table><tr><td align=left>\
select:\
<a href="javascript:;" id="importSelectAll"\
onclick="onClickImportButton(this);return false;" title="SELECT all tiddlers">\
all</a>\
<a href="javascript:;" id="importSelectNew"\
onclick="onClickImportButton(this);return false;" title="SELECT tiddlers not already in destination document">\
added</a>\
<a href="javascript:;" id="importSelectChanges"\
onclick="onClickImportButton(this);return false;" title="SELECT tiddlers that have been updated in source document">\
changes</a>\
<a href="javascript:;" id="importSelectDifferences"\
onclick="onClickImportButton(this);return false;" title="SELECT tiddlers that have been added or are different from existing tiddlers">\
differences</a>\
</td><td align=right>\
<a href="javascript:;" id="importListSmaller"\
onclick="onClickImportButton(this);return false;" title="SHRINK list size">\
– </a>\
<a href="javascript:;" id="importListLarger"\
onclick="onClickImportButton(this);return false;" title="GROW list size">\
+ </a>\
<a href="javascript:;" id="importListMaximize"\
onclick="onClickImportButton(this);return false;" title="MAXIMIZE/RESTORE list size">\
= </a>\
</td></tr></table>\
<select id="importList" size=8 multiple\
onchange="setTimeout(\'refreshImportList(\'+this.selectedIndex+\')\',1)">\
<!-- NOTE: delay refresh so list is updated AFTER onchange event is handled -->\
</select>\
<div style="text-align:center">\
<a href="javascript:;"\
title="click for help using filters..."\
onclick="alert(\'A filter consists of one or more space-separated combinations of:\\n\\ntiddler titles\\ntag:[[tagvalue]]\\ntag:[[tag expression]] (requires MatchTagsPlugin)\\nstory:[[TiddlerName]]\\nsearch:[[searchtext]]\\n\\nUse a blank filter for all tiddlers.\')"\
>filter</a>\
<input type="text" id="importLastFilter" style="margin-bottom:1px; width:65%"\
title="Enter a combination of one or more filters. Use a blank filter for all tiddlers."\
onfocus="this.select()" value=""\
onKeyUp="config.macros.importTiddlers.lastFilter=this.value"\
onChange="config.macros.importTiddlers.lastFilter=this.value;">\
<input type="button" id="importApplyFilter" style="width:20%" value="apply"\
title="filter list of tiddlers to include only those that match certain criteria"\
onclick="onClickImportButton(this)">\
</div>\
</div><!--end select-->\
\
<div class="box" id="importOptionsPanel" style="text-align:center;margin:.5em;display:none;">\
apply tags: <input type=checkbox class="chk" id="chkImportTags" checked\
onClick="config.macros.importTiddlers.importTags=this.checked;">from source \
<input type=checkbox class="chk" id="chkKeepTags" checked\
onClick="config.macros.importTiddlers.keepTags=this.checked;">keep existing \
<input type=checkbox class="chk" id="chkAddTags" \
onClick="config.macros.importTiddlers.addTags=this.checked;\
config.macros.importTiddlers.showPanel(\'txtNewTags\',this.checked,true);\
if (this.checked) document.getElementById(\'txtNewTags\').focus();">add tags<br>\
<input type=text id="txtNewTags" style="margin-top:4px;display:none;" size=15\ onfocus="this.select()" \
title="enter tags to be added to imported tiddlers" \
onKeyUp="config.macros.importTiddlers.newTags=this.value;\
document.getElementById(\'chkAddTags\').checked=this.value.length>0;" autocomplete=off>\
<nobr><input type=checkbox class="chk" id="chkSync" \
onClick="config.macros.importTiddlers.sync=this.checked;">\
link imported tiddlers to source document (for sync later)</nobr>\
</div><!--end options-->\
\
<div id="importButtonPanel" style="text-align:center">\
<input type=button id="importLoad" class="importButton btn3" value="open"\
title="load listbox with tiddlers from source document"\
onclick="onClickImportButton(this)">\
<input type=button id="importOptions" class="importButton btn3" value="options..."\
title="set options for tags, sync, etc."\
onclick="onClickImportButton(this)">\
<input type=button id="importStart" class="importButton btn3" value="import"\
title="start/stop import of selected source tiddlers into current document"\
onclick="onClickImportButton(this)">\
<input type=button id="importClose" class="importButton btn3" value="done"\
title="clear listbox or hide control panel"\
onclick="onClickImportButton(this)">\
</div>\
\
<div class="none" id="importCollisionPanel" style="display:none;margin:.5em 0 .5em .5em;">\
<table><tr><td style="width:65%" align="left">\
<table><tr><td align=left>\
tiddler already exists:\
</td><td align=right>\
<input type=checkbox class="chk" id="importApplyToAll" \
onclick="document.getElementById(\'importRename\').disabled=this.checked;"\
checked>apply to all\
</td></tr></table>\
<input type=text id="importNewTitle" size=15 autocomplete=off">\
</td><td style="width:34%" align="center">\
<input type=button id="importMerge"\
class="importButton" style="width:47%" value="merge"\
title="append the incoming tiddler to the existing tiddler"\
onclick="onClickImportButton(this)"><!--\
--><input type=button id="importSkip"\
class="importButton" style="width:47%" value="skip"\
title="do not import this tiddler"\
onclick="onClickImportButton(this)"><!--\
--><br><input type=button id="importRename"\
class="importButton" style="width:47%" value="rename"\
title="rename the incoming tiddler"\
onclick="onClickImportButton(this)"><!--\
--><input type=button id="importReplace"\
class="importButton" style="width:47%" value="replace"\
title="discard the existing tiddler"\
onclick="onClickImportButton(this)">\
</td></tr></table>\
</div><!--end collision-->\
';
//}}}
//{{{
// process control interactions
function onClickImportButton(which,event) {
var cmi=config.macros.importTiddlers; // abbreviation
var list=cmi.$('importList'); if (!list) return;
var thePanel=cmi.$('importPanel');
var theCollisionPanel=cmi.$('importCollisionPanel');
var theNewTitle=cmi.$('importNewTitle');
var count=0;
switch (which.id)
{
case 'importFromFile': // show local panel
case 'importFromWeb': // show HTTP panel
cmi.local=(which.id=='importFromFile');
cmi.showPanel('importLocalPanel',cmi.local);
cmi.showPanel('importHTTPPanel',!cmi.local);
break;
case 'importOptions': // show/hide options panel
cmi.showPanel('importOptionsPanel',cmi.$('importOptionsPanel').style.display=='none');
break;
case 'fileImportSource':
case 'importLoad': // load import source into hidden frame
importReport(); // if an import was in progress, generate a report
cmi.inbound=null; // clear the imported tiddler buffer
refreshImportList(); // reset/resize the listbox
if (cmi.src=='') break;
// Load document, read it's DOM and fill the list
cmi.loadRemoteFile(cmi.src,cmi.filterTiddlerList);
break;
case 'importSelectFeed': // select a pre-defined systemServer feed URL
var p=Popup.create(which); if (!p) return;
var tids=store.getTaggedTiddlers('systemServer');
if (!tids.length)
createTiddlyText(createTiddlyElement(p,'li'),'no pre-defined server feeds');
for (var t=0; t<tids.length; t++) {
var u=store.getTiddlerSlice(tids[t].title,'URL');
var d=store.getTiddlerSlice(tids[t].title,'Description');
if (!d||!d.length) d=store.getTiddlerSlice(tids[t].title,'description');
if (!d||!d.length) d=u;
createTiddlyButton(createTiddlyElement(p,'li'),tids[t].title,d,
function(){
var u=this.getAttribute('url');
document.getElementById('importSourceURL').value=u;
config.macros.importTiddlers.src=u;
document.getElementById('importLoad').onclick();
},
null,null,null,{url:u});
}
Popup.show(p,false);
event.cancelBubble = true;
if (event.stopPropagation) event.stopPropagation();
return(false);
// create popup with feed list
// onselect, insert feed URL into input field.
break;
case 'importSelectAll': // select all tiddler list items (i.e., not headings)
importReport(); // if an import was in progress, generate a report
for (var t=0,count=0; t < list.options.length; t++) {
if (list.options[t].value=='') continue;
list.options[t].selected=true;
count++;
}
clearMessage(); displayMessage(cmi.countMsg.format([count]));
cmi.$('importStart').disabled=!count;
break;
case 'importSelectNew': // select tiddlers not in current document
importReport(); // if an import was in progress, generate a report
for (var t=0,count=0; t < list.options.length; t++) {
list.options[t].selected=false;
if (list.options[t].value=='') continue;
list.options[t].selected=!store.tiddlerExists(list.options[t].value);
count+=list.options[t].selected?1:0;
}
clearMessage(); displayMessage(cmi.countMsg.format([count]));
cmi.$('importStart').disabled=!count;
break;
case 'importSelectChanges': // select tiddlers that are updated from existing tiddlers
importReport(); // if an import was in progress, generate a report
for (var t=0,count=0; t < list.options.length; t++) {
list.options[t].selected=false;
if (list.options[t].value==''||!store.tiddlerExists(list.options[t].value)) continue;
for (var i=0; i<cmi.inbound.length; i++) // find matching inbound tiddler
{ var inbound=cmi.inbound[i]; if (inbound.title==list.options[t].value) break; }
list.options[t].selected=(inbound.modified-store.getTiddler(list.options[t].value).modified>0); // updated tiddler
count+=list.options[t].selected?1:0;
}
clearMessage(); displayMessage(cmi.countMsg.format([count]));
cmi.$('importStart').disabled=!count;
break;
case 'importSelectDifferences': // select tiddlers that are new or different from existing tiddlers
importReport(); // if an import was in progress, generate a report
for (var t=0,count=0; t < list.options.length; t++) {
list.options[t].selected=false;
if (list.options[t].value=='') continue;
if (!store.tiddlerExists(list.options[t].value)) { list.options[t].selected=true; count++; continue; }
for (var i=0; i<cmi.inbound.length; i++) // find matching inbound tiddler
{ var inbound=cmi.inbound[i]; if (inbound.title==list.options[t].value) break; }
list.options[t].selected=(inbound.modified-store.getTiddler(list.options[t].value).modified!=0); // changed tiddler
count+=list.options[t].selected?1:0;
}
clearMessage(); displayMessage(cmi.countMsg.format([count]));
cmi.$('importStart').disabled=!count;
break;
case 'importApplyFilter': // filter list to include only matching tiddlers
importReport(); // if an import was in progress, generate a report
clearMessage();
if (!cmi.all) // no tiddlers loaded = '0 selected'
{ displayMessage(cmi.countMsg.format([0])); return false; }
var hash=cmi.$('importLastFilter').value;
cmi.inbound=cmi.filterByHash('#'+hash,cmi.all);
refreshImportList(); // reset/resize the listbox
break;
case 'importStart': // initiate the import processing
importReport(); // if an import was in progress, generate a report
cmi.$('importApplyToAll').checked=false;
cmi.$('importStart').value=cmi.stopText;
if (cmi.index>0) cmi.index=-1; // stop processing
else cmi.index=importTiddlers(0); // or begin processing
importStopped();
break;
case 'importClose': // unload imported tiddlers or hide the import control panel
// if imported tiddlers not loaded, close the import control panel
if (!cmi.inbound) { thePanel.style.display='none'; break; }
importReport(); // if an import was in progress, generate a report
cmi.inbound=null; // clear the imported tiddler buffer
refreshImportList(); // reset/resize the listbox
break;
case 'importSkip': // don't import the tiddler
cmi.lastAction=which;
var theItem = list.options[cmi.index];
for (var j=0;j<cmi.inbound.length;j++)
if (cmi.inbound[j].title==theItem.value) break;
var theImported = cmi.inbound[j];
theImported.status='skipped after asking'; // mark item as skipped
theCollisionPanel.style.display='none';
cmi.index=importTiddlers(cmi.index+1); // resume with NEXT item
importStopped();
break;
case 'importRename': // change name of imported tiddler
cmi.lastAction=which;
var theItem = list.options[cmi.index];
for (var j=0;j<cmi.inbound.length;j++)
if (cmi.inbound[j].title==theItem.value) break;
var theImported = cmi.inbound[j];
theImported.status = 'renamed from '+theImported.title; // mark item as renamed
theImported.set(theNewTitle.value,null,null,null,null); // change the tiddler title
theItem.value = theNewTitle.value; // change the listbox item text
theItem.text = theNewTitle.value; // change the listbox item text
theCollisionPanel.style.display='none';
cmi.index=importTiddlers(cmi.index); // resume with THIS item
importStopped();
break;
case 'importMerge': // join existing and imported tiddler content
cmi.lastAction=which;
var theItem = list.options[cmi.index];
for (var j=0;j<cmi.inbound.length;j++)
if (cmi.inbound[j].title==theItem.value) break;
var theImported = cmi.inbound[j];
var theExisting = store.getTiddler(theItem.value);
var theText = theExisting.text+'\n----\n^^merged from: ';
theText +='[['+cmi.src+'#'+theItem.value+'|'+cmi.src+'#'+theItem.value+']]^^\n';
theText +='^^'+theImported.modified.toLocaleString()+' by '+theImported.modifier+'^^\n'+theImported.text;
var theDate = new Date();
var theTags = theExisting.getTags()+' '+theImported.getTags();
theImported.set(null,theText,null,theDate,theTags);
theImported.status = 'merged with '+theExisting.title; // mark item as merged
theImported.status += ' - '+theExisting.modified.formatString('MM/DD/YYYY 0hh:0mm:0ss');
theImported.status += ' by '+theExisting.modifier;
theCollisionPanel.style.display='none';
cmi.index=importTiddlers(cmi.index); // resume with this item
importStopped();
break;
case 'importReplace': // substitute imported tiddler for existing tiddler
cmi.lastAction=which;
var theItem = list.options[cmi.index];
for (var j=0;j<cmi.inbound.length;j++)
if (cmi.inbound[j].title==theItem.value) break;
var theImported = cmi.inbound[j];
var theExisting = store.getTiddler(theItem.value);
theImported.status = 'replaces '+theExisting.title; // mark item for replace
theImported.status += ' - '+theExisting.modified.formatString('MM/DD/YYYY 0hh:0mm:0ss');
theImported.status += ' by '+theExisting.modifier;
theCollisionPanel.style.display='none';
cmi.index=importTiddlers(cmi.index); // resume with THIS item
importStopped();
break;
case 'importListSmaller': // decrease current listbox size, minimum=5
if (list.options.length==1) break;
list.size-=(list.size>5)?1:0;
cmi.listsize=list.size;
break;
case 'importListLarger': // increase current listbox size, maximum=number of items in list
if (list.options.length==1) break;
list.size+=(list.size<list.options.length)?1:0;
cmi.listsize=list.size;
break;
case 'importListMaximize': // toggle listbox size between current and maximum
if (list.options.length==1) break;
list.size=(list.size==list.options.length)?cmi.listsize:list.options.length;
break;
}
}
//}}}
//{{{
config.macros.importTiddlers.showPanel=function(place,show,skipAnim) {
if (typeof place=='string') var place=document.getElementById(place);
if (!place||!place.style) return;
if(!skipAnim && anim && config.options.chkAnimate) anim.startAnimating(new Slider(place,show,false,'none'));
else place.style.display=show?'block':'none';
}
//}}}
//{{{
function refreshImportList(selectedIndex) {
var cmi=config.macros.importTiddlers; // abbrev
var list=cmi.$('importList'); if (!list) return;
// if nothing to show, reset list content and size
if (!cmi.inbound) {
while (list.length > 0) { list.options[0] = null; }
list.options[0]=new Option(cmi.loadText,'',false,false);
list.size=cmi.listsize;
cmi.$('importLoad').disabled=false;
cmi.$('importLoad').style.display='inline';
cmi.$('importStart').disabled=true;
cmi.$('importOptions').disabled=true;
cmi.$('importOptions').style.display='none';
cmi.$('fileImportSource').disabled=false;
cmi.$('importFromFile').disabled=false;
cmi.$('importFromWeb').disabled=false;
cmi.$('importStart').value=cmi.startText;
cmi.$('importClose').value=cmi.doneText;
cmi.$('importSelectPanel').style.display='none';
cmi.$('importOptionsPanel').style.display='none';
return;
}
// there are inbound tiddlers loaded...
cmi.$('importLoad').disabled=true;
cmi.$('importLoad').style.display='none';
cmi.$('importOptions').style.display='inline';
cmi.$('importOptions').disabled=false;
cmi.$('fileImportSource').disabled=true;
cmi.$('importFromFile').disabled=true;
cmi.$('importFromWeb').disabled=true;
cmi.$('importClose').value=cmi.closeText;
if (cmi.$('importSelectPanel').style.display=='none')
cmi.showPanel('importSelectPanel',true);
// get the sort order
if (!selectedIndex) selectedIndex=0;
if (selectedIndex==0) cmi.sort='title'; // heading
if (selectedIndex==1) cmi.sort='title';
if (selectedIndex==2) cmi.sort='modified';
if (selectedIndex==3) cmi.sort='tags';
if (selectedIndex>3) {
// display selected tiddler count
for (var t=0,count=0; t < list.options.length; t++) {
if (!list.options[t].selected) continue;
if (list.options[t].value!='')
count+=1;
else { // if heading is selected, deselect it, and then select and count all in section
list.options[t].selected=false;
for ( t++; t<list.options.length && list.options[t].value!=''; t++) {
list.options[t].selected=true;
count++;
}
}
}
clearMessage(); displayMessage(cmi.countMsg.format([count]));
}
cmi.$('importStart').disabled=!count;
if (selectedIndex>3) return; // no refresh needed
// get the alphasorted list of tiddlers
var tiddlers=cmi.inbound;
tiddlers.sort(function (a,b) {if(a['title'] == b['title']) return(0); else return (a['title'] < b['title']) ? -1 : +1; });
// clear current list contents
while (list.length > 0) { list.options[0] = null; }
// add heading and control items to list
var i=0;
var indent=String.fromCharCode(160)+String.fromCharCode(160);
if (cmi.all.length==tiddlers.length)
var summary=cmi.summaryMsg.format([tiddlers.length,(tiddlers.length!=1)?cmi.plural:cmi.single]);
else
var summary=cmi.summaryFilteredMsg.format([tiddlers.length,cmi.all.length,(cmi.all.length!=1)?cmi.plural:cmi.single]);
list.options[i++]=new Option(summary,'',false,false);
list.options[i++]=new Option(((cmi.sort=='title' )?'>':indent)+' [by title]','',false,false);
list.options[i++]=new Option(((cmi.sort=='modified')?'>':indent)+' [by date]','',false,false);
list.options[i++]=new Option(((cmi.sort=='tags')?'>':indent)+' [by tags]','',false,false);
// output the tiddler list
switch(cmi.sort) {
case 'title':
for(var t = 0; t < tiddlers.length; t++)
list.options[i++] = new Option(tiddlers[t].title,tiddlers[t].title,false,false);
break;
case 'modified':
// sort descending for newest date first
tiddlers.sort(function (a,b) {if(a['modified'] == b['modified']) return(0); else return (a['modified'] > b['modified']) ? -1 : +1; });
var lastSection = '';
for(var t = 0; t < tiddlers.length; t++) {
var tiddler = tiddlers[t];
var theSection = tiddler.modified.toLocaleDateString();
if (theSection != lastSection) {
list.options[i++] = new Option(theSection,'',false,false);
lastSection = theSection;
}
list.options[i++] = new Option(indent+indent+tiddler.title,tiddler.title,false,false);
}
break;
case 'tags':
var theTitles = {}; // all tiddler titles, hash indexed by tag value
var theTags = new Array();
for(var t=0; t<tiddlers.length; t++) {
var title=tiddlers[t].title;
var tags=tiddlers[t].tags;
if (!tags || !tags.length) {
if (theTitles['untagged']==undefined) { theTags.push('untagged'); theTitles['untagged']=new Array(); }
theTitles['untagged'].push(title);
}
else for(var s=0; s<tags.length; s++) {
if (theTitles[tags[s]]==undefined) { theTags.push(tags[s]); theTitles[tags[s]]=new Array(); }
theTitles[tags[s]].push(title);
}
}
theTags.sort();
for(var tagindex=0; tagindex<theTags.length; tagindex++) {
var theTag=theTags[tagindex];
list.options[i++]=new Option(theTag,'',false,false);
for(var t=0; t<theTitles[theTag].length; t++)
list.options[i++]=new Option(indent+indent+theTitles[theTag][t],theTitles[theTag][t],false,false);
}
break;
}
list.selectedIndex=selectedIndex; // select current control item
if (list.size<cmi.listsize) list.size=cmi.listsize;
if (list.size>list.options.length) list.size=list.options.length;
}
//}}}
//{{{
// re-entrant processing for handling import with interactive collision prompting
function importTiddlers(startIndex) {
var cmi=config.macros.importTiddlers; // abbrev
if (!cmi.inbound) return -1;
var list=cmi.$('importList'); if (!list) return;
var t;
// if starting new import, reset import status flags
if (startIndex==0)
for (var t=0;t<cmi.inbound.length;t++)
cmi.inbound[t].status='';
for (var i=startIndex; i<list.options.length; i++) {
// if list item is not selected or is a heading (i.e., has no value), skip it
if ((!list.options[i].selected) || ((t=list.options[i].value)==''))
continue;
for (var j=0;j<cmi.inbound.length;j++)
if (cmi.inbound[j].title==t) break;
var inbound = cmi.inbound[j];
var theExisting = store.getTiddler(inbound.title);
// avoid redundant import for tiddlers that are listed multiple times (when 'by tags')
if (inbound.status=='added')
continue;
// don't import the 'ImportedTiddlers' history from the other document...
if (inbound.title=='ImportedTiddlers')
continue;
// if tiddler exists and import not marked for replace or merge, stop importing
if (theExisting && (inbound.status.substr(0,7)!='replace') && (inbound.status.substr(0,5)!='merge'))
return i;
// assemble tags (remote + existing + added)
var newTags = '';
if (cmi.importTags)
newTags+=inbound.getTags() // import remote tags
if (cmi.keepTags && theExisting)
newTags+=' '+theExisting.getTags(); // keep existing tags
if (cmi.addTags && cmi.newTags.trim().length)
newTags+=' '+cmi.newTags; // add new tags
inbound.set(null,null,null,null,newTags.trim());
// set the status to 'added' (if not already set by the 'ask the user' UI)
inbound.status=(inbound.status=='')?'added':inbound.status;
// set sync fields
if (cmi.sync) {
if (!inbound.fields) inbound.fields={}; // for TW2.1.x backward-compatibility
inbound.fields['server.page.revision']=inbound.modified.convertToYYYYMMDDHHMM();
inbound.fields['server.type']='file';
inbound.fields['server.host']=(cmi.local?'file://':'')+cmi.src;
}
// do the import!
store.suspendNotifications();
store.saveTiddler(inbound.title, inbound.title, inbound.text, inbound.modifier, inbound.modified, inbound.tags, inbound.fields, true, inbound.created);
store.fetchTiddler(inbound.title).created = inbound.created; // force creation date to imported value (needed for TW2.1.x and earlier)
store.resumeNotifications();
}
return(-1); // signals that we really finished the entire list
}
function importStopped() {
var cmi=config.macros.importTiddlers; // abbrev
var list=cmi.$('importList'); if (!list) return;
var theNewTitle=cmi.$('importNewTitle');
if (cmi.index==-1){
cmi.$('importStart').value=cmi.startText;
importReport(); // import finished... generate the report
} else {
// import collision...
// show the collision panel and set the title edit field
cmi.$('importStart').value=cmi.stopText;
cmi.showPanel('importCollisionPanel',true);
theNewTitle.value=list.options[cmi.index].value;
if (cmi.$('importApplyToAll').checked && cmi.lastAction && cmi.lastAction.id!='importRename')
onClickImportButton(cmi.lastAction);
}
}
//}}}
//{{{
function importReport() {
var cmi=config.macros.importTiddlers; // abbrev
if (!cmi.inbound) return;
// if import was not completed, the collision panel will still be open... close it now.
var panel=cmi.$('importCollisionPanel'); if (panel) panel.style.display='none';
// get the alphasorted list of tiddlers
var tiddlers = cmi.inbound;
// gather the statistics
var count=0; var total=0;
for (var t=0; t<tiddlers.length; t++) {
if (!tiddlers[t].status || !tiddlers[t].status.trim().length) continue;
if (tiddlers[t].status.substr(0,7)!='skipped') count++;
total++;
}
// generate a report
if (total) displayMessage(cmi.processedMsg.format([total]));
if (count && config.options.chkImportReport) {
// get/create the report tiddler
var theReport = store.getTiddler('ImportedTiddlers');
if (!theReport) { theReport=new Tiddler(); theReport.title='ImportedTiddlers'; theReport.text=''; }
// format the report content
var now = new Date();
var newText = 'On '+now.toLocaleString()+', '+config.options.txtUserName
newText +=' imported '+count+' tiddler'+(count==1?'':'s')+' from\n[['+cmi.src+'|'+cmi.src+']]:\n';
if (cmi.addTags && cmi.newTags.trim().length)
newText += 'imported tiddlers were tagged with: "'+cmi.newTags+'"\n';
newText += '<<<\n';
for (var t=0; t<tiddlers.length; t++) if (tiddlers[t].status)
newText += '#[['+tiddlers[t].title+']] - '+tiddlers[t].status+'\n';
newText += '<<<\n';
// update the ImportedTiddlers content and show the tiddler
theReport.text = newText+((theReport.text!='')?'\n----\n':'')+theReport.text;
theReport.modifier = config.options.txtUserName;
theReport.modified = new Date();
store.saveTiddler(theReport.title, theReport.title, theReport.text, theReport.modifier, theReport.modified, theReport.tags, theReport.fields);
story.displayTiddler(null,theReport.title,1,null,null,false);
story.refreshTiddler(theReport.title,1,true);
}
// reset status flags
for (var t=0; t<cmi.inbound.length; t++) cmi.inbound[t].status='';
// mark document as dirty and let display update as needed
if (count) { store.setDirty(true); store.notifyAll(); }
// always show final message when tiddlers were actually loaded
if (count) displayMessage(cmi.importedMsg.format([count,tiddlers.length,cmi.src.replace(/%20/g,' ')]));
}
//}}}
//{{{
// // File and XMLHttpRequest I/O
config.macros.importTiddlers.askForFilename=function(here) {
var msg=here.title; // use tooltip as dialog box message
var path=getLocalPath(document.location.href);
var slashpos=path.lastIndexOf('/'); if (slashpos==-1) slashpos=path.lastIndexOf('\\');
if (slashpos!=-1) path = path.substr(0,slashpos+1); // remove filename from path, leave the trailing slash
var file='';
var result='';
if(window.Components) { // moz
try {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
picker.init(window, msg, nsIFilePicker.modeOpen);
var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
thispath.initWithPath(path);
picker.displayDirectory=thispath;
picker.defaultExtension='html';
picker.defaultString=file;
picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.persistentDescriptor;
}
catch(e) { alert('error during local file access: '+e.toString()) }
}
else { // IE
try { // XPSP2 IE only
var s = new ActiveXObject('UserAccounts.CommonDialog');
s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
s.FilterIndex=3; // default to HTML files;
s.InitialDir=path;
s.FileName=file;
if (s.showOpen()) var result=s.FileName;
}
catch(e) { // fallback
var result=prompt(msg,path+file);
}
}
return result;
}
config.macros.importTiddlers.loadRemoteFile = function(src,callback) {
if (src==undefined || !src.length) return null; // filename is required
var original=src; // URL as specified
var hashpos=src.indexOf('#'); if (hashpos!=-1) src=src.substr(0,hashpos); // URL with #... suffix removed (needed for IE)
clearMessage();
displayMessage(this.openMsg.format([src.replace(/%20/g,' ')]));
if (src.substr(0,5)!='http:' && src.substr(0,5)!='file:') { // if not a URL, read from local filesystem
var txt=loadFile(src);
if (!txt) { // file didn't load, might be relative path.. try fixup
var pathPrefix=document.location.href; // get current document path and trim off filename
var slashpos=pathPrefix.lastIndexOf('/'); if (slashpos==-1) slashpos=pathPrefix.lastIndexOf('\\');
if (slashpos!=-1 && slashpos!=pathPrefix.length-1) pathPrefix=pathPrefix.substr(0,slashpos+1);
src=pathPrefix+src;
if (pathPrefix.substr(0,5)!='http:') src=getLocalPath(src);
var txt=loadFile(src);
}
if (!txt) { // file still didn't load, report error
displayMessage(config.macros.importTiddlers.openErrMsg.format([src.replace(/%20/g,' '),'(filesystem error)']));
} else {
displayMessage(config.macros.importTiddlers.readMsg.format([txt.length,src.replace(/%20/g,' ')]));
if (callback) callback(true,original,convertUTF8ToUnicode(txt),src,null);
}
} else {
var name=config.options.txtRemoteUsername; var pass=config.options.txtRemotePassword;
var xhr=doHttp('GET',src,null,null,name,pass,callback,original,null)
if (!xhr) displayMessage(config.macros.importTiddlers.openErrMsg.format([src,'(XMLHTTPRequest error)']));
}
}
config.macros.importTiddlers.readTiddlersFromHTML=function(html)
{
var remoteStore=new TiddlyWiki();
remoteStore.importTiddlyWiki(html);
return remoteStore.getTiddlers('title');
}
config.macros.importTiddlers.filterTiddlerList=function(success,params,txt,src,xhr) {
var cmi=config.macros.importTiddlers; // abbreviation
var src=src.replace(/%20/g,' ');
if (!success) { displayMessage(cmi.openErrMsg.format([src,xhr.status])); return; }
cmi.all = cmi.readTiddlersFromHTML(txt);
var count=cmi.all?cmi.all.length:0;
var querypos=src.lastIndexOf('?'); if (querypos!=-1) src=src.substr(0,querypos);
displayMessage(cmi.foundMsg.format([count,src]));
cmi.inbound=cmi.filterByHash(params,cmi.all); // use full URL including hash (if any)
cmi.$('importLastFilter').value=cmi.lastFilter;
window.refreshImportList(0);
}
config.macros.importTiddlers.filterByHash=function(src,tiddlers)
{
var hashpos=src.lastIndexOf('#'); if (hashpos==-1) return tiddlers;
var hash=src.substr(hashpos+1); if (!hash.length) return tiddlers;
var tids=[];
var params=hash.parseParams('anon',null,true,false,false);
for (var p=1; p<params.length; p++) {
switch (params[p].name) {
case 'anon':
case 'open':
tids.pushUnique(params[p].value);
break;
case 'tag':
if (store.getMatchingTiddlers) { // for boolean expressions - see MatchTagsPlugin
var r=store.getMatchingTiddlers(params[p].value,null,tiddlers);
for (var t=0; t<r.length; t++) tids.pushUnique(r[t].title);
} else for (var t=0; t<tiddlers.length; t++)
if (tiddlers[t].isTagged(params[p].value))
tids.pushUnique(tiddlers[t].title);
break;
case 'story':
for (var t=0; t<tiddlers.length; t++)
if (tiddlers[t].title==params[p].value) {
tiddlers[t].changed();
for (var s=0; s<tiddlers[t].links.length; s++)
tids.pushUnique(tiddlers[t].links[s]);
break;
}
break;
case 'search':
for (var t=0; t<tiddlers.length; t++)
if (tiddlers[t].text.indexOf(params[p].value)!=-1)
tids.pushUnique(tiddlers[t].title);
break;
}
}
var matches=[];
for (var t=0; t<tiddlers.length; t++)
if (tids.contains(tiddlers[t].title))
matches.push(tiddlers[t]);
displayMessage(config.macros.importTiddlers.filterMsg.format([matches.length,hash]));
config.macros.importTiddlers.lastFilter=hash;
return matches;
}
//}}}
/***
|Name|ImportTiddlersPluginInfo|
|Source|http://www.TiddlyTools.com/#ImportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ImportTiddlersPluginInfo|
|Version|4.4.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for ImportTiddlersPlugin|
This plugin lets you selectively combine tiddlers from any two TiddlyWiki documents. An interactive control panel lets you pick a document to import from, and then select which tiddlers to import, with prompting for skip, rename, merge or replace actions when importing tiddlers that match existing titles. Automatically add tags to imported tiddlers so they are easy to find later on. Generates a detailed report of import 'history' in ImportedTiddlers.
!!!!!Usage
<<<
{{{<<importTiddlers>>}}} or {{{<<importTiddlers core>>}}}
invokes the built-in importTiddlers macro (TW2.1.x+). If installed in documents using TW2.0.x or earlier, fallback is to use 'link' display (see below)
{{{<<importTiddlers link label tooltip>>}}}
The ''link'' keyword creates an "import tiddlers" link that when clicked to show/hide import control panel. ''label'' and ''tooltip'' are optional text parameters (enclosed in quotes or {{{[[...]]}}}, and allow you to override the default display text for the link and the mouseover help text, respectively.
{{{<<importTiddlers inline>>}}}
creates import control panel directly in tiddler content
<<importTiddlers inline>>
Enter a document URL or press "..." to select a TiddlyWiki file to import, and then press ''[open]''. //Note: When loading a remote document, there may be some delay before the list of tiddlers appears.// Use the ''[-]'', ''[+]'', or ''[=]'' links to adjust the listbox size so you can view more (or less) tiddler titles at one time.
Select one or more titles from the listbox (hold CTRL or SHIFT while clicking to add/remove the highlight from individual list items). You can also click on ''all'', ''new'', ''changes'', or ''differences'' to automatically select a subset of tiddlers from the list. This makes it very quick and easy to find and import just the updated tiddlers you are interested in, based on a comparison of the two documents:
*''all'' selects ALL tiddlers from the import source document, even if they have not been changed.
*''new'' selects only tiddlers that are found in the import source document, but do not yet exist in the destination document
*''changes'' selects only tiddlers that exist in both documents but that are newer in the source document
*''differences'' selects all new and existing tiddlers that are different from the destination document (even if destination tiddler is newer)
When you have chosen the tiddlers you want, press ''[import]'' to begin copying them to the current TiddlyWiki document. When importing a tiddler whose title matches one that already exists, the import process pauses and the tiddler title is displayed in an input field, along with four push buttons: ''skip'', ''rename'', ''merge'' and ''replace''.
* ''skip'' bypasses importing the tiddler
* ''rename'' allows you to enter a new title in the input field to give the inbound tiddler a different name, so that both the old and new tiddlers will exist when the import is done.
* ''merge'' combines the content from both tiddlers into a single tiddler so you can then edit it to eliminate unwanted content.
* ''[replace]'' overwrites the existing tiddler with the imported one, discarding the previous tiddler content.
''Import Report History''
Whenever tiddlers are imported, a report is generated into a tiddler named [[ImportedTiddlers]], recording when the latest import was performed, the number of tiddlers successfully imported, from what location, and by whom, as well as a list of the tiddlers that were processed. When more tiddlers are imported at a later time, a new report is //added// to the existing [[ImportedTiddlers]], above the previous report (i.e., at the top of the tiddler), so that a reverse-chronological history of imports is maintained. If this cumulative record is not desired, you can delete [[ImportedTiddlers]] at any time.
Note: You can prevent a report from being generated for any given import activity by clearing the "create a report" checkbox before pressing the ''import'' button
<<<
!!!!!Revisions
<<<
2009.02.26 [4.4.1] use macro-specific definition of $() function abbreviation (avoids conflict with JQuery)
2008.09.30 [4.4.0] added fallback definition of merge() for use with TW2.0.x and TW1.2.x
2008.08.12 [4.3.3] rewrite backstage and shadow tiddler definitions for easier customization
2008.08.05 [4.3.2] rewrote loadRemoteFile() to eliminate use of platform-specific fileExists() function
2008.06.29 [4.3.1] More layout/animation work for simpler sequential interaction. Code reduction/cleanup
2008.06.28 [4.3.0] HTML and CSS cleanup and tweaks to layout. Added animation to panels
2008.06.22 [4.2.0] For FireFox, use HTML with separate text+button control instead of type='file' control
2008.06.05 [4.1.0] in filterByHash(), added support for boolean tag expressions using getMatchingTiddlers() (defined by MatchTagsPlugin)
2008.05.12 [4.0.2] automatically tweak the backstage "import" task to add the ImportTiddlers control panel as an optional alternative to the standard import wizard. (Moved from BackstageTweaks).
2008.04.30 [4.0.1] trim #... suffix for loading files/URLs in IE
2008.04.30 [4.0.0] added source filtering (using URL paramifiers). Also, abbreviations for code-size reduction.
2008.04.13 [3.9.0] added 'apply to all' checkbox for collision processing
2008.03.26 [3.8.0] added support for selecting pre-defined systemServer URLs
2008.03.25 [3.7.0] added support for setting 'server' fields on imported tiddlers (for later synchronizing of changes)
2008.01.03 [3.6.0] in loadRemoteFile(), use lower-level doHttp() instead of loadRemoteFile() in order to support username/password access to remote server
2007.10.30 [3.5.6] update [[ImportTiddlers]] shadow tiddler definition to include "inline" link, so the plugin control panel is displayed instead of the standard core interface.
2007.06.27 [3.5.5] added missing 'fields' params to saveTiddler() calls. Fixes problem where importing tiddlers would lose the custom fields. Also, moved functions for backward-compatibility with TW2.1.x to separate [[ImportTiddlersPluginPatch2.1.x]] tiddler, reducing the size of //this// plugin tiddler by a significant amount.
2007.06.25 [3.5.4] added calls to store.suspendNotifications() and store.resumeNotifications(). Eliminates redisplay processing overhead DURING import activities
2007.04.29 [3.5.3] if refreshImportList() when inbound tiddlers are loaded, change "close" button to "done", and disable certain controls to creates a modal condition, so that actions that reload tiddlers cannot be performed unless "done" is first pressed to end the mode..
2007.04.28 [3.5.2] in handler(), added param support for custom link label/prompt
2007.04.19 [3.5.1] in readTiddlersFromHTML(), for TW2.2 and above, use importTiddlyWiki() (new core functionality) to get tiddlers from remote file content. Also, copied updated TW21Loader.prototype.internalizeTiddler() definition from TW2.2b5 so plugin can read tiddlers from TW2.2+ even when running under TW2.1.x
2007.03.22 [3.5.0] in refreshImportList(), add handling for 'select section' when a heading is selected. Makes it really easy to import by tag or date!
2007.03.21 [3.4.0] split loadTiddlers functionality into separate plugin (see [[LoadTiddlersPlugin]])
2007.03.20 [3.3.1] tweak to previous change to allow relative file references via http: (bypasses getLocalPath() so remote URL will be used)
2007.03.20 [3.3.0] added support for local, relative file references: in loadRemoteFile(), check for fileExists(). If not found, prepend relative path location and try again. Allows use of simple "foo.html" file references with importTiddlers and/or loadTiddlers macros
2007.02.24 [3.2.1] re-labeled control panel "open" button to "load" to avoid confusion with "open" button in system-provided Browse... dialog. (i.e., "browse, open, open" becomes "browse, open, load")
2007.02.09 [3.2.0] loadTiddlers: added support for "noReload" tag (prevents overwriting existing tiddler, even if inbound tiddler is newer)
2007.02.08 [3.1.3] loadTiddlers: added missing code and documentation for "newTags" handling (a feature change from long, long ago that somehow got lost!)
2006.11.14 [3.1.2] fix macro handler parameter declaration (double-pasted param list corrupts IE)
2006.11.13 [3.1.1] use apply() method to invoke hijacked core handler
2006.11.13 [3.1.0] hijack TW2.1 built-in importTiddlers.handler() so it can co-exist with the plugin interface 'panel'. Use macro without params (or use 'core' keyword) to display built-in core interface. Use new "link" param to embed "import tiddlers" link that shows floating panel when clicked. Renamed a few plugin utility functions so they don't collide with core internal functions. More code restructuring to come.
2006.10.12 [3.0.8] in readTiddlersFromHTML(), fallback to find end of store area by matching "/body" when POST-BODY-START is not present (backward compatibility for older documents)
2006.09.10 [3.0.7] in readTiddlersFromHTML(), find end of store area by matching "POST-BODY-START" instead of "/body"
2006.08.16 [3.0.6] Use higher-level store.saveTiddler() instead of store.addTiddler() to avoid conflicts with ZW and other adaptations that hijack low-level tiddler handling. Also, in CreateImportPanel(), no longer register notify to "refresh listbox after every tiddler change" (left over from old 'auto-filtered' list handling). Thanks to Bob McElrath for report/solution.
2006.07.29 [3.0.5] added noChangeMsg to loadTiddlers processing. if not 'quiet' mode, reports skipped tiddlers.
2006.04.18 [3.0.4] in loadTiddlers.handler, fixed parsing of "prompt:" param. Also, corrected parameters mismatch in loadTiddlers() callback function definition (order of params was wrong, resulting in filters NOT being applied)
2006.04.12 [3.0.3] moved many display messages to macro properties for easier L10N translations via 'lingo' definitions.
2006.04.12 [3.0.2] additional refactoring of 'core candidate' code. Proposed API now defines "loadRemoteFile()" for XMLHttpRequest processing with built in fallback for handling local filesystem access, and readTiddlersFromHTML() to process the resulting source HTML content.
2006.04.04 [3.0.1] in refreshImportList(), when using [by tags], tiddlers without tags are now included in a new "untagged" psuedo-tag list section
2006.04.04 [3.0.0] Separate non-interactive {{{<<importTiddlers...>>}}} macro functionality for incorporation into TW2.1 core and renamed as {{{<<loadTiddlers>>}}} macro. New parameters for loadTiddlers: ''label:text'' and ''prompt:text'' for link creation, ''ask'' for filename/URL, ''tag:text'' for filtering, "confirm" for accept/reject of individual inbound tiddlers. Also, ImportedTiddlers report generator output has been simplified and "importReplace/importPublic" tags and associated "force" param (which were rarely, if ever, used) has been dropped.
2006.03.30 [2.9.1] when extracting store area from remote URL, look for "</body>" instead of "</body>\n</html>" so it will match even if the "\n" is absent from the source.
2006.03.30 [2.9.0] added optional 'force' macro param. When present, autoImportTiddlers() bypasses the checks for importPublic and importReplace. Based on a request from Tom Otvos.
2006.03.28 [2.8.1] in loadImportFile(), added checks to see if 'netscape' and 'x.overrideMimeType()' are defined (IE does *not* define these values, so we bypass this code)
Also, when extracting store area from remote URL, explicitly look for "</body>\n</html>" to exclude any extra content that may have been added to the end of the file by hosting environments such as GeoCities. Thanks to Tom Otvos for finding these bugs and suggesting some fixes.
2006.02.21 [2.8.0] added support for "tiddler:TiddlerName" filtering parameter in auto-import processing
2006.02.21 [2.7.1] Clean up layout problems with IE. (Use tables for alignment instead of SPANs styled with float:left and float:right)
2006.02.21 [2.7.0] Added "local file" and "web server" radio buttons for selecting dynamic import source controls in ImportPanel. Default file control is replaced with URL text input field when "web server" is selected. Default remote document URL is defined in SiteURL tiddler. Also, added option for prepending SiteProxy URL as prefix to remote URL to mask cross-domain document access (requires compatible server-side script)
2006.02.17 [2.6.0] Removed "differences only" listbox display mode, replaced with selection filter 'presets': all/new/changes/differences. Also fixed initialization handling for "add new tags" so that checkbox state is correctly tracked when panel is first displayed.
2006.02.16 [2.5.4] added checkbox options to control "import remote tags" and "keep existing tags" behavior, in addition to existing "add new tags" functionality.
2006.02.14 [2.5.3] FF1501 corrected unintended global 't' (loop index) in importReport() and autoImportTiddlers()
2006.02.10 [2.5.2] corrected unintended global variable in importReport().
2006.02.05 [2.5.1] moved globals from window.* to config.macros.importTiddlers.* to avoid FireFox 1.5.0.1 crash bug when referencing globals
2006.01.18 [2.5.0] added checkbox for "create a report". Default is to create/update the ImportedTiddlers report. Clear the checkbox to skip this step.
2006.01.15 [2.4.1] added "importPublic" tag and inverted default so that auto sharing is NOT done unless tagged with importPublic
2006.01.15 [2.4.0] Added support for tagging individual tiddlers with importSkip, importReplace, and/or importPrivate to control which tiddlers can be overwritten or shared with others when using auto-import macro syntax. Defaults are to SKIP overwriting existing tiddlers with imported tiddlers, and ALLOW your tiddlers to be auto-imported by others.
2006.01.15 [2.3.2] Added "ask" parameter to confirm each tiddler before importing (for use with auto-importing)
2006.01.15 [2.3.1] Strip TW core scripts from import source content and load just the storeArea into the hidden IFRAME. Makes loading more efficient by reducing the document size and by preventing the import document from executing its TW initialization (including plugins). Seems to resolve the "Found 0 tiddlers" problem. Also, when importing local documents, use convertUTF8ToUnicode() to convert the file contents so support international characters sets.
2006.01.12 [2.3.0] Reorganized code to use callback function for loading import files to support event-driven I/O via an ASYNCHRONOUS XMLHttpRequest. Let's processing continue while waiting for remote hosts to respond to URL requests. Added non-interactive 'batch' macro mode, using parameters to specify which tiddlers to import, and from what document source. Improved error messages and diagnostics, plus an optional 'quiet' switch for batch mode to eliminate //most// feedback.
2006.01.11 [2.2.0] Added "[by tags]" to list of tiddlers, based on code submitted by BradleyMeck
2006.01.09 [2.1.1] When a URL is typed in, and then the "open" button is pressed, it generates both an onChange event for the file input and a click event for open button. This results in multiple XMLHttpRequest()'s which seem to jam things up quite a bit. I removed the onChange handling for file input field. To open a file (local or URL), you must now explicitly press the "open" button in the control panel.
2006.01.08 [2.1.0] IMPORT FROM ANYWHERE!!! re-write getImportedTiddlers() logic to either read a local file (using local I/O), OR... read a remote file, using a combination of XML and an iframe to permit cross-domain reading of DOM elements. Adapted from example code and techniques courtesy of Jonny LeRoy.
2006.01.06 [2.0.2] When refreshing list contents, fixed check for tiddlerExists() when "show differences only" is selected, so that imported tiddlers that don't exist in the current file will be recognized as differences and included in the list.
2006.01.04 [2.0.1] When "show differences only" is NOT checked, import all tiddlers that have been selected even when they have a matching title and date.
2005.12.27 [2.0.0] Update for TW2.0
Defer initial panel creation and only register a notification function when panel first is created
2005.12.22 [1.3.1] tweak formatting in importReport() and add 'discard report' link to output
2005.12.03 [1.3.0] Dynamically create/remove importPanel as needed to ensure only one instance of interface elements exists, even if there are multiple instances of macro embedding. Also, dynamically create/recreate importFrame each time an external TW document is loaded for importation (reduces DOM overhead and ensures a 'fresh' frame for each document)
2005.11.29 [1.2.1] fixed formatting of 'detail info' in importReport()
2005.11.11 [1.2.0] added 'inline' param to embed controls in a tiddler
2005.11.09 [1.1.0] only load HTML and CSS the first time the macro handler is called. Allows for redundant placement of the macro without creating multiple instances of controls with the same ID's.
2005.10.25 [1.0.5] fixed typo in importReport() that prevented reports from being generated
2005.10.09 [1.0.4] combined documentation with plugin code instead of using separate tiddlers
2005.08.05 [1.0.3] moved CSS and HTML definitions into plugin code instead of using separate tiddlers
2005.07.27 [1.0.2] core update 1.2.29: custom overlayStyleSheet() replaced with new core setStylesheet()
2005.07.23 [1.0.1] added parameter checks and corrected addNotification() usage
2005.07.20 [1.0.0] Initial Release
<<<
On Friday, March 20, 2009 12:58:55 PM, PaulReiber imported 1 tiddler from
[[http://www.tiddlytools.com/insideTW/|http://www.tiddlytools.com/insideTW/]]:
<<<
#[[ShowObject]] - added
<<<
----
On Tuesday, March 03, 2009 5:36:26 PM, PaulReiber loaded 14 tiddlers from
[[http://www.tiddlytools.com|http://www.tiddlytools.com]]:
<<<
#[[CopyTiddlerPlugin]] - updated
#[[ExportTiddlersPlugin]] - updated
#[[ExportTiddlersPluginInfo]] - updated
#[[ImageSizePlugin]] - updated
#[[ImportTiddlersPlugin]] - updated
#[[ImportTiddlersPluginInfo]] - updated
#[[InlineJavascriptPlugin]] - updated
#[[InlineJavascriptPluginInfo]] - updated
#[[InstantBookmarklets]] - updated
#[[LoadRemotePlugin]] - updated
#[[OpenTaggedTiddlers]] - updated
#[[SplitTiddler]] - updated
#[[TagCloudPlugin]] - updated
#[[UnsavedChangesPlugin]] - updated
<<<
----
On Saturday, February 21, 2009 11:04:37 AM, PaulReiber loaded 1 tiddlers from
[[http://www.tiddlytools.com|http://www.tiddlytools.com]]:
<<<
#[[CopyTiddlerPlugin]] - updated
<<<
----
On Friday, February 20, 2009 4:41:02 PM, PaulReiber imported 1 tiddler from
[[C:\Users\Paul\Desktop\OpenSourceExplorations\RaphaelDemos.html|C:\Users\Paul\Desktop\OpenSourceExplorations\RaphaelDemos.html]]:
<<<
#[[AnimeJtest]] - added
<<<
----
On Friday, February 20, 2009 12:28:06 PM, PaulReiber imported 5 tiddlers from
[[C:\Users\Paul\Desktop\animate.html|C:\Users\Paul\Desktop\animate.html]]:
<<<
#[[AnimationEffectsPlugin]] - added
#[[AnimationEffectsPluginInfo]] - added
#[[AnimeJPlugin]] - added
#[[InlineJavascriptPlugin]] - replaces InlineJavascriptPlugin - 6/11/2008 07:15:00 by ELSDesignStudios
#[[RaphaelPlugin]] - replaces RaphaelPlugin - 1/20/2009 13:18:00 by ELSDesignStudios
<<<
----
On Monday, February 09, 2009 3:18:11 PM, PaulReiber loaded 4 tiddlers from
[[http://www.tiddlytools.com|http://www.tiddlytools.com]]:
<<<
#[[ClickifyPlugin]] - updated
#[[CopyTiddlerPlugin]] - updated
#[[CoreTweaks]] - updated
#[[TagCloudPlugin]] - updated
<<<
----
On Tuesday, January 27, 2009 6:20:37 PM, PaulReiber imported 1 tiddler from
[[http://www.tiddlytools.com/|http://www.tiddlytools.com/]]:
<<<
#[[MessageLogPlugin]] - added
<<<
----
On Tuesday, January 27, 2009 6:20:22 PM, PaulReiber imported 2 tiddlers from
[[http://www.tiddlytools.com/|http://www.tiddlytools.com/]]:
<<<
#[[MissingTiddlersList]] - added
#[[MissingTiddlersPlugin]] - added
<<<
----
On Tuesday, January 27, 2009 6:18:31 PM, PaulReiber imported 2 tiddlers from
[[http://www.tiddlytools.com/|http://www.tiddlytools.com/]]:
<<<
#[[ClickifyPlugin]] - added
#[[SectionLinksPlugin]] - added
<<<
----
On Tuesday, January 27, 2009 5:01:35 PM, PaulReiber loaded 1 tiddlers from
[[http://www.tiddlytools.com|http://www.tiddlytools.com]]:
<<<
#[[CoreTweaks]] - updated
<<<
----
On Tuesday, January 27, 2009 3:59:44 PM, PaulReiber imported 1 tiddler from
[[http://www.tiddlytools.com/|http://www.tiddlytools.com/]]:
<<<
#[[RaphaelPlugin]] - added
<<<
/***
|Name|InlineJavascriptPlugin|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.9.4|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Insert Javascript executable code directly into your tiddler content.|
''Call directly into TW core utility routines, define new functions, calculate values, add dynamically-generated TiddlyWiki-formatted output'' into tiddler content, or perform any other programmatic actions each time the tiddler is rendered.
!!!!!Documentation
>see [[InlineJavascriptPluginInfo]]
!!!!!Revisions
<<<
2009.02.26 [1.9.4] in $(), handle leading '#' on ID for compatibility with JQuery syntax
|please see [[InlineJavascriptPluginInfo]] for additional revision details|
2005.11.08 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.InlineJavascriptPlugin= {major: 1, minor: 9, revision: 3, date: new Date(2008,6,11)};
config.formatters.push( {
name: "inlineJavascript",
match: "\\<script",
lookahead: "\\<script(?: src=\\\"((?:.|\\n)*?)\\\")?(?: label=\\\"((?:.|\\n)*?)\\\")?(?: title=\\\"((?:.|\\n)*?)\\\")?(?: key=\\\"((?:.|\\n)*?)\\\")?( show)?\\>((?:.|\\n)*?)\\</script\\>",
handler: function(w) {
var lookaheadRegExp = new RegExp(this.lookahead,"mg");
lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var src=lookaheadMatch[1];
var label=lookaheadMatch[2];
var tip=lookaheadMatch[3];
var key=lookaheadMatch[4];
var show=lookaheadMatch[5];
var code=lookaheadMatch[6];
if (src) { // load a script library
// make script tag, set src, add to body to execute, then remove for cleanup
var script = document.createElement("script"); script.src = src;
document.body.appendChild(script); document.body.removeChild(script);
}
if (code) { // there is script code
if (show) // show inline script code in tiddler output
wikify("{{{\n"+lookaheadMatch[0]+"\n}}}\n",w.output);
if (label) { // create a link to an 'onclick' script
// add a link, define click handler, save code in link (pass 'place'), set link attributes
var link=createTiddlyElement(w.output,"a",null,"tiddlyLinkExisting",wikifyPlainText(label));
var fixup=code.replace(/document.write\s*\(/gi,'place.bufferedHTML+=(');
link.code="function _out(place){"+fixup+"\n};_out(this);"
link.tiddler=w.tiddler;
link.onclick=function(){
this.bufferedHTML="";
try{ var r=eval(this.code);
if(this.bufferedHTML.length || (typeof(r)==="string")&&r.length)
var s=this.parentNode.insertBefore(document.createElement("span"),this.nextSibling);
if(this.bufferedHTML.length)
s.innerHTML=this.bufferedHTML;
if((typeof(r)==="string")&&r.length) {
wikify(r,s,null,this.tiddler);
return false;
} else return r!==undefined?r:false;
} catch(e){alert(e.description||e.toString());return false;}
};
link.setAttribute("title",tip||"");
var URIcode='javascript:void(eval(decodeURIComponent(%22(function(){try{';
URIcode+=encodeURIComponent(encodeURIComponent(code.replace(/\n/g,' ')));
URIcode+='}catch(e){alert(e.description||e.toString())}})()%22)))';
link.setAttribute("href",URIcode);
link.style.cursor="pointer";
if (key) link.accessKey=key.substr(0,1); // single character only
}
else { // run inline script code
var fixup=code.replace(/document.write\s*\(/gi,'place.innerHTML+=(');
var c="function _out(place){"+fixup+"\n};_out(w.output);";
try { var out=eval(c); }
catch(e) { out=e.description?e.description:e.toString(); }
if (out && out.length) wikify(out,w.output,w.highlightRegExp,w.tiddler);
}
}
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
}
}
} )
//}}}
// // Backward-compatibility for TW2.1.x and earlier
//{{{
if (typeof(wikifyPlainText)=="undefined") window.wikifyPlainText=function(text,limit,tiddler) {
if(limit > 0) text = text.substr(0,limit);
var wikifier = new Wikifier(text,formatter,null,tiddler);
return wikifier.wikifyPlain();
}
//}}}
// // GLOBAL FUNCTION: $(...) -- 'shorthand' convenience syntax for document.getElementById()
//{{{
if (typeof($)=='undefined') { function $(id) { return document.getElementById(id.replace(/^#/,'')); } }
//}}}
/***
|Name|InlineJavascriptPluginInfo|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.9.4|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|Documentation for InlineJavascriptPlugin|
''Call directly into TW core utility routines, define new functions, calculate values, add dynamically-generated TiddlyWiki-formatted output'' into tiddler content, or perform any other programmatic actions each time the tiddler is rendered.
!!!!!Usage
<<<
This plugin adds wiki syntax for surrounding tiddler content with {{{<script>}}} and {{{</script>}}} markers, so that it can be recognized as embedded javascript code.
<script show>
/* javascript code goes here... */
</script>Every time the tiddler content is rendered, the javascript code is automatically evaluated, allowing you to invoke 'side-effect' processing and/or produce dynamically-generated content that is then inserted into the tiddler content, immediately following the script (see below). By including the optional ''show'' keyword as the final parameter in a {{{<script>}}} marker, the plugin will also include the script source code in the output that it displays in the tiddler. This is helpful when creating examples for documentation purposes (such as used in this tiddler!)
__''Deferred execution from an 'onClick' link''__
<script label="click here" title="mouseover tooltip text" key="X" show>
/* javascript code goes here... */
alert('you clicked on the link!');
</script>
By including a {{{label="..."}}} parameter in the initial {{{<script>}}} marker, the plugin will create a link to an 'onclick' script that will only be executed when that specific link is clicked, rather than running the script each time the tiddler is rendered. You may also include a {{{title="..."}}} parameter to specify the 'tooltip' text that will appear whenever the mouse is moved over the onClick link text, and a {{{key="X"}}} parameter to specify an //access key// (which must be a //single// letter or numeric digit only).
__''Loading scripts from external source files''__
<script src="URL" show>
/* optional javascript code goes here... */
</script>You can also load javascript directly from an external source URL, by including a src="..." parameter in the initial {{{<script>}}} marker (e.g., {{{<script src="demo.js"></script>}}}). This is particularly useful when incorporating third-party javascript libraries for use in custom extensions and plugins. The 'foreign' javascript code remains isolated in a separate file that can be easily replaced whenever an updated library file becomes available.
In addition to loading the javascript from the external file, you can also use this feature to invoke javascript code contained within the {{{<script>...</script>}}} markers. This code is invoked //after// the external script file has been processed, and can make immediate use of the functions and/or global variables defined by the external script file.
>Note: To ensure that your javascript functions are always available when needed, you should load the libraries from a tiddler that is rendered as soon as your TiddlyWiki document is opened, such as MainMenu. For example: put your {{{<script src="..."></script>}}} syntax into a separate 'library' tiddler (e.g., LoadScripts), and then add {{{<<tiddler LoadScripts>>}}} to MainMenu so that the library is loaded before any other tiddlers that rely upon the functions it defines.
>
>Normally, loading external javascript in this way does not produce any direct output, and should not have any impact on the appearance of your MainMenu. However, if your LoadScripts tiddler contains notes or other visible content, you can suppress this output by using 'inline CSS' in the MainMenu, like this: {{{@@display:none;<<tiddler LoadScripts>>@@}}}
<<<
!!!!!Creating dynamic tiddler content and accessing the ~TiddlyWiki DOM
<<<
An important difference between TiddlyWiki inline scripting and conventional embedded javascript techniques for web pages is the method used to produce output that is dynamically inserted into the document: in a typical web document, you use the {{{document.write()}}} (or {{{document.writeln()}}}) function to output text sequences (often containing HTML tags) that are then rendered when the entire document is first loaded into the browser window.
However, in a ~TiddlyWiki document, tiddlers (and other DOM elements) are created, deleted, and rendered "on-the-fly", so writing directly to the global 'document' object does not produce the results you want (i.e., replacing the embedded script within the tiddler content), and instead will //completely replace the entire ~TiddlyWiki document in your browser window (which is clearly not a good thing!)//. In order to allow scripts to use {{{document.write()}}}, the plugin automatically converts and buffers all HTML output so it can be safely inserted into your tiddler content, immediately following the script.
''Note that {{{document.write()}}} can only be used to output "pure HTML" syntax. To produce //wiki-formatted// output, your script should instead return a text value containing the desired wiki-syntax content'', which will then be automatically rendered immediately following the script. If returning a text value is not sufficient for your needs, the plugin also provides an automatically-defined variable, 'place', that gives the script code ''direct access to the //containing DOM element//'' into which the tiddler output is being rendered. You can use this variable to ''perform direct DOM manipulations'' that can, for example:
* generate wiki-formatted output using {{{wikify("...content...",place)}}}
* vary the script's actions based upon the DOM element in which it is embedded
* access 'tiddler-relative' DOM information using {{{story.findContainingTiddler(place)}}}
Note:
''When using an 'onclick' script, the 'place' element actually refers to the onclick //link text// itself, instead of the containing DOM element.'' This permits you to directly reference or modify the link text to reflect any 'stateful' conditions that might set by the script. To refer to the containing DOM element from within an 'onclick' script, you can use "place.parentNode" instead.
<<<
!!!!!Instant "bookmarklets"
<<<
You can also use an 'onclick' link to define a "bookmarklet": a small piece of javascript that can be ''invoked directly from the browser without having to be defined within the current document.'' This allows you to create 'stand-alone' commands that can be applied to virtually ANY TiddlyWiki document... even remotely-hosted documents that have been written by others!! To create a bookmarklet, simply define an 'onclick' script and then grab the resulting link text and drag-and-drop it onto your browser's toolbar (or right-click and use the 'bookmark this link' command to add it to the browser's menu).
Notes:
*When writing scripts intended for use as bookmarklets, due to the ~URI-encoding required by the browser, ''you cannot not use ANY double-quotes (") within the bookmarklet script code.''
*All comments embedded in the bookmarklet script must ''use the fully-delimited {{{/* ... */}}} comment syntax,'' rather than the shorter {{{//}}} comment syntax.
*Most importantly, because bookmarklets are invoked directly from the browser interface and are not embedded within the TiddlyWiki document, there is NO containing 'place' DOM element surrounding the script. As a result, ''you cannot use a bookmarklet to generate dynamic output in your document,'' and using {{{document.write()}}} or returning wiki-syntax text or making reference to the 'place' DOM element will halt the script and report a "Reference Error" when that bookmarklet is invoked.
Please see [[InstantBookmarklets]] for many examples of 'onclick' scripts that can also be used as bookmarklets.
<<<
!!!!!Special reserved function name
<<<
The plugin 'wraps' all inline javascript code inside a function, {{{_out()}}}, so that any return value you provide can be correctly handled by the plugin and inserted into the tiddler. To avoid unpredictable results (and possibly fatal execution errors), this function should never be redefined or called from ''within'' your script code.
<<<
!!!!!$(...) 'shorthand' function
<<<
As described by Dustin Diaz [[here|http://www.dustindiaz.com/top-ten-javascript/]], the plugin defines a 'shorthand' function that allows you to write:
{{{
$(id)
}}}
in place of the normal standard javascript syntax:
{{{
document.getElementById(id)
}}}
This function is provided merely as a convenience for javascript coders that may be familiar with this abbreviation, in order to allow them to save a few bytes when writing their own inline script code.
<<<
!!!!!Examples
<<<
simple dynamic output:
><script show>
document.write("The current date/time is: "+(new Date())+"<br>");
return "link to current user: [["+config.options.txtUserName+"]]\n";
</script>
dynamic output using 'place' to get size information for current tiddler:
><script show>
if (!window.story) window.story=window;
var title=story.findContainingTiddler(place).getAttribute("tiddler");
var size=store.getTiddlerText(title).length;
return title+" is using "+size+" bytes";
</script>
dynamic output from an 'onclick' script, using {{{document.write()}}} and/or {{{return "..."}}}
><script label="click here" show>
document.write("<br>The current date/time is: "+(new Date())+"<br>");
return "link to current user: [["+config.options.txtUserName+"]]\n";
</script>
creating an 'onclick' button/link that accesses the link text AND the containing tiddler:
><script label="click here" title="clicking this link will show an 'alert' box" key="H" show>
if (!window.story) window.story=window;
var txt=place.firstChild.data;
var tid=story.findContainingTiddler(place).getAttribute('tiddler');
alert('Hello World!\nlinktext='+txt+'\ntiddler='+tid);
</script>
dynamically setting onclick link text based on stateful information:
>{{block{
{{{
<script label="click here">
/* toggle "txtSomething" value */
var on=(config.txtSomething=="ON");
place.innerHTML=on?"enable":"disable";
config.txtSomething=on?"OFF":"ON";
return "\nThe current value is: "+config.txtSomething;
</script><script>
/* initialize onclick link text based on current "txtSomething" value */
var on=(config.txtSomething=="ON");
place.lastChild.previousSibling.innerHTML=on?"disable":"enable";
</script>
}}}
<script label="click here">
/* toggle "txtSomething" value */
var on=(config.txtSomething=="ON");
place.innerHTML=on?"enable":"disable";
config.txtSomething=on?"OFF":"ON";
return "\nThe current value is: "+config.txtSomething;
</script><script>
/* initialize onclick link text based on current "txtSomething" value */
var on=(config.txtSomething=="ON");
place.lastChild.innerHTML=on?"enable":"disable";
</script>
}}}
loading a script from a source url:
>http://www.TiddlyTools.com/demo.js contains:
>>{{{function inlineJavascriptDemo() { alert('Hello from demo.js!!') } }}}
>>{{{displayMessage('InlineJavascriptPlugin: demo.js has been loaded');}}}
>note: When using this example on your local system, you will need to download the external script file from the above URL and install it into the same directory as your document.
>
><script src="demo.js" show>
return "inlineJavascriptDemo() function has been defined"
</script>
><script label="click to invoke inlineJavascriptDemo()" key="D" show>
inlineJavascriptDemo();
</script>
<<<
!!!!!Revisions
<<<
2009.02.26 [1.9.4] in $(), handle leading '#' on ID for compatibility with JQuery syntax
2008.06.11 [1.9.3] added $(...) function as 'shorthand' for document.getElementById()
2008.03.03 [1.9.2] corrected fallback declaration of wikifyPlainText() (fixes Safari "parse error")
2008.02.23 [1.9.1] in onclick function, use string instead of array for 'bufferedHTML' (fixes IE errors)
2008.02.21 [1.9.0] output from 'onclick' scripts (return value or document.write() calls) are now buffered and rendered into into a span following the script. Also, added default 'return false' handling if no return value provided (prevents HREF from being triggered -- return TRUE to allow HREF to be processed). Thanks to Xavier Verges for suggestion and preliminary code.
2008.02.14 [1.8.1] added backward-compatibility for use of wikifyPlainText() in TW2.1.3 and earlier
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.28 [1.8.0] added support for key="X" syntax to specify custom access key definitions
2007.12.15 [1.7.0] autogenerate URI encoded HREF on links for onclick scripts. Drag links to browser toolbar to create bookmarklets. IMPORTANT NOTE: place is NOT defined when scripts are used as bookmarklets. In addition, double-quotes will cause syntax errors. Thanks to PaulReiber for debugging and brainstorming.
2007.11.26 [1.6.2] when converting "document.write()" function calls in inline code, allow whitespace between "write" and "(" so that "document.write ( foobar )" is properly converted.
2007.11.16 [1.6.1] when rendering "onclick scripts", pass label text through wikifyPlainText() to parse any embedded wiki-syntax to enable use of HTML entities or even TW macros to generate dynamic label text.
2007.02.19 [1.6.0] added support for title="..." to specify mouseover tooltip when using an onclick (label="...") script
2006.10.16 [1.5.2] add newline before closing '}' in 'function out_' wrapper. Fixes error caused when last line of script is a comment.
2006.06.01 [1.5.1] when calling wikify() on script return value, pass hightlightRegExp and tiddler params so macros that rely on these values can render properly
2006.04.19 [1.5.0] added 'show' parameter to force display of javascript source code in tiddler output
2006.01.05 [1.4.0] added support 'onclick' scripts. When label="..." param is present, a button/link is created using the indicated label text, and the script is only executed when the button/link is clicked. 'place' value is set to match the clicked button/link element.
2005.12.13 [1.3.1] when catching eval error in IE, e.description contains the error text, instead of e.toString(). Fixed error reporting so IE shows the correct response text. Based on a suggestion by UdoBorkowski
2005.11.09 [1.3.0] for 'inline' scripts (i.e., not scripts loaded with src="..."), automatically replace calls to 'document.write()' with 'place.innerHTML+=' so script output is directed into tiddler content. Based on a suggestion by BradleyMeck
2005.11.08 [1.2.0] handle loading of javascript from an external URL via src="..." syntax
2005.11.08 [1.1.0] pass 'place' param into scripts to provide direct DOM access
2005.11.08 [1.0.0] initial release
<<<
This package provides a set of TW-compatible "form input fields" for accessing and modifying custom tiddler fields, tags, options, etc. These input fields make it easier to build application-specific View/Edit templates as well as end-user-oriented "control panels" and "fill in forms".
/%
|Name|InstantBookmarklets|
|Source|http://www.TiddlyTools.com/#InstantBookmarklets|
|Version|2.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|instantly create bookmarklets by dragging onclick links to the browser toolbar|
See [[InlineJavascriptPluginInfo]] for bookmarklet authoring documentation
%/{{nowrap{
__[[InstantBookmarklets:|InstantBookmarklets]]__{{fine{
//drag these links to your browser toolbar!// <script label="(help...)">
alert("To create a bookmarklet, simply drag-and-drop any command link below directly onto your browser's toolbar or right-click and use 'bookmark this link' (or 'add to favorites') to add the bookmarklet to your browser's bookmarks menu. Once installed, you can use the bookmarklet with ANY TiddlyWiki document, even if the command script (and InlineJavascriptPlugin) has not been installed in that document!");
</script>}}}
//~TiddlyWiklets: {{fine{(TiddlyWiki "tear-off" utilities)}}}///%
========================== TOGGLE SITE TITLES %/
*<script label="▲ - Toggle site titles" title="show/hide SiteTitle and SiteSubtitle (header) content">
var c=document.getElementById('contentWrapper'); if (!c) return;
for (var i=0; i<c.childNodes.length; i++)
if (hasClass(c.childNodes[i],'header')) { var h=c.childNodes[i]; break; }
if (!h) return;
config.options.chkHideSiteTitles=h.style.display!='none';
h.style.display=config.options.chkHideSiteTitles?'none':'block';
saveOptionCookie('chkHideSiteTitles');
return false;
</script>/%
========================== TOGGLE LEFT SIDEBAR %/
*<<tiddler ToggleLeftSidebar with: "◄ - Toggle left sidebar">>/%
========================== TOGGLE RIGHT SIDEBAR %/
*<<tiddler ToggleRightSidebar with: "► - Toggle right sidebar">>/%
========================== TOGGLE ANIMATION EFFECTS %/
*<<tiddler ToggleAnimations with: "∞ - Toggle animation effects">>/%
========================== TOGGLE SINGLE PAGE MODE %/
*<<tiddler ToggleSinglePageMode with: "1 - Toggle single-page mode">>/%
========================== TOGGLE "FULLSCREEN" (SIDEBARS AND TITLES) %/
*<<tiddler ToggleFullScreen with: "◊ - Toggle fullscreen ON" "◊ - Toggle fullscreen OFF">>/%
========================== TOGGLE TIDDLER TITLES (and SUBTITLES) %/
*<<tiddler ToggleTiddlerTitles with: "T - Toggle tiddler titles">>/%
========================== TOGGLE TIDDLER TAGS %/
*<<tiddler ToggleTiddlerTags with: "# - Toggle tiddler tags">>/%
========================== RESTART WITHOUT RELOADING %/
*<script label="⌂ - Home" title="Restart initial page content WITHOUT RELOADING!">
story.closeAllTiddlers(); restart(); refreshPageTemplate();
return false;
</script>/%
========================== REFRESH WITHOUT RESTARTING %/
*<<tiddler RefreshPageDisplay with: "≈ - Refresh current display">>/%
========================== SHOW CURRENT VERSION, TIMESTAMP, and TIDDLER INFO %/
*<<tiddler ShowDocumentInfo>>/%
========================== RESET TIDDLYWIKI OPTION COOKIES (WITH CONFIRM) %/
*<<tiddler ResetOptionCookies>>/%
========================== CLEAR CHANGE COUNTERS %/
*<<tiddler ResetChangeCounters>>/%
========================== RESCUE STORE AREA (adapted from http://www.TiddlyWiki.com/#TiddlyBookmarklets) %/
*<<tiddler RescueStoreAreaCommand with: "∑ - Rescue current storeArea contents">>/%
========================== LOAD REMOTE PLUGINS... %/
//Load remote plugins: {{fine{(load on demand)}}}///%
========================== TiddlyTools (Eric Shulman)...%/
*[[TiddlyTools|http://www.TiddlyTools.com/]]{{block{/%
========================== LOAD IMPORT TIDDLERS PLUGIN
%/{{block{<<tiddler LoadRemotePlugin with:
[[ImportTiddlersPlugin]]
[[Load ImportTiddlersPlugin from svn.TiddlyWiki.org repository]]
[[http://svn.tiddlywiki.org/Trunk/contributors/EricShulman/plugins/ImportTiddlersPlugin.js]]
[[window.story.displayTiddler(null,"ImportTiddlers")]]
[[version.extensions.ImportTiddlersPlugin!=undefined]]
[[window.story.displayTiddler(null,"ImportTiddlers")]]
[[ImportTiddlersPluginConfig]]
>>}}}/%
========================== LOAD TIDDLER TWEAKER PLUGIN
%/{{block{<<tiddler LoadRemotePlugin with:
[[TiddlerTweakerPlugin]]
[[Load TiddlerTweakerPlugin from svn.TiddlyWiki.org repository]]
[[http://svn.tiddlywiki.org/Trunk/contributors/EricShulman/plugins/TiddlerTweakerPlugin.js]]
[[window.story.displayTiddler(null,'TiddlerTweaker')]]
[[version.extensions.TiddlerTweakerPlugin!=undefined]]
>>}}}/%
========================== LOAD REARRANGE TIDDLERS PLUGIN
%/{{block{<<tiddler LoadRemotePlugin with:
[[RearrangeTiddlersPlugin]]
[[Load RearrangeTiddlersPlugin from www.TiddlyTools.com]]
[[http://www.TiddlyTools.com/plugins/RearrangeTiddlersPlugin.js]]
[[window.story.forEachTiddler(function(t,e){window.story.refreshTiddler(t,null,true)}); window.refreshDisplay()]]
[[Story.prototype.rearrangeTiddlersHijack_refreshTiddler!=undefined]]
>>}}}/%
%/}}}/%
========================== Abego Software (Udo Borkowski)...%/
*[[Abego Software|http://tiddlywiki.abego-software.de/]]{{block{/%
========================== LOAD YOURSEARCH PLUGIN
%/{{block{<<tiddler LoadRemotePlugin with:
[[YourSearchPlugin]]
[[Load YourSearchPlugin from tiddlywiki.abego-software.de]]
[[http://tiddlywiki.abego-software.de/archive/YourSearchPlugin/Plugin-YourSearch-src.2.1.1.js]]
[[window.refreshPageTemplate()]]
[[version.extensions.YourSearchPlugin!=undefined]]
>>}}}/%
%/}}}/%
========================== Firefox Privileges (Xavier Vergés) %/
*[[FirefoxPrivileges.TiddlySpot.com|http://firefoxprivileges.tiddlyspot.com/]]{{block{/%
========================== LOAD AND DISPLAY FIREFOX PRIVILEGE MANAGER
%/{{block{<<tiddler LoadRemotePlugin with:
[[Firefox Privilege Manager]]
[[Load Firefox Privilege Manager from svn.TiddlyWiki.org repository]]
[[http://svn.tiddlywiki.org/Trunk/contributors/XavierVerges/plugins/FirefoxPrivilegesPlugin.js]]
[[config.macros.firefoxPrivileges.onload()]]
[[config.macros.firefoxPrivileges!=undefined]]
[[backstage.switchTab("firefoxPrivileges")]]
>>}}}/%
%/}}}/%
========================== Jash (Billy Reisinger) %/
*[[BillyReisinger.com:|http://www.billyreisinger.com/jash/]]{{block{/%
========================== LOAD AND DISPLAY JAVASCRIPT SHELL
%/{{block{<<tiddler LoadRemotePlugin with:
[[Jash (JAvascript SHell)]]
[[Load Jash (JAvascript SHell) from www.billyreisinger.com/jash]]
[[http://www.billyreisinger.com/jash/source/latest/Jash.js]]
[[window.jash.close()]]
[[window.jash!=undefined]]
>>}}}/%
%/}}}
}}}/% END NOWRAP %/
/*{{{*/
/**
* $Id: Jash.css,v 1.3 2007/11/16 03:06:33 billyreisinger Exp $
*
* Jash - JavaScript Shell
* Copyright: 2007, Billy Reisinger
* Documentation: http://www.billyreisinger.com/jash/
* License: GNU General Public License - http://www.gnu.org/licenses/gpl.html
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#JashParent {
width: 581px;
height: 450px;
border: 1px solid gray;
-moz-border-radius: 10px; /* ELS */
-webkit-border-radius: 10px; /* ELS */
color: black;
z-index: 10000;
overflow: hidden;
background: #ccc;
opacity: 0.90;
filter: alpha(opacity=90);
position: absolute;
left: 25%;
color: black;
font-family: monospace;
margin: 0;
}
#JashParent div {
margin: 0;
}
#JashParent a, #JashParent a:visited, #JashParent a:active, #JashParent a:hover {
text-decoration: none;
color: black;
}
.transparentMode {
opacity: 0.20 !important;
filter: alpha(opacity=20) !important;
}
#JashDragBar {
BACKGROUND: gray;
CURSOR: move;
COLOR: white;
font-family: arial,helvetica,sans-serif; /* ELS - changed from monospace to arial,helvetica,sans-serif */
font-weight: bold;
text-indent: 4px;
font-size: 14pt; /* ELS - changed from 14px to 14pt */
HEIGHT: 25px;
TEXT-ALIGN: left;
overflow: hidden;
border: 1px outset white;
-moz-border-radius-topleft: 10px; /* ELS */
-moz-border-radius-topright: 10px; /* ELS */
-webkit-border-top-left-radius: 10px; /* ELS */
-webkit-border-top-right-radius: 10px; /* ELS */
}
.JashXButton {
border: 1px solid white;
-moz-border-radius: 5px; /* ELS */
-webkit-border-radius: 5px; /* ELS */
color: white !important;
position: absolute;
background: #bbb;
width: 20px;
text-align: center;
display: block;
right: 3px; _right: 1px;
top: 4px; _top: 1px;
font-family: arial,helvetica,sans-serif; /* ELS - changed to arial,helvetica,sans-serif */
font-size: 8pt; /* ELS - changed from 18px to 8pt */
cursor: pointer;
}
a.JashXButton:hover {
background: #ddd;
}
#JashTextareaWrap {
width: 100%;
_height: 420px;
}
html>body #JashTextareaWrap {
height: 100%;
}
#JashOutput {
border: 2px inset white;
FONT-SIZE: 10px;
font-family: "Lucida Console", monaco, monospace;
BACKGROUND: black;
width: 99%;
COLOR: lightgreen;
PADDING: 2px;
height: 60%;
height: expression(parseInt(this.parentNode.parentNode.offsetHeight * (3/5)) + 'px');
}
#JashInput {
padding: 2px;
WIDTH: 99%;
border: 2px inset white;
-moz-border-radius-bottomleft: 10px; /* ELS */
-moz-border-radius-bottomright: 10px; /* ELS */
-webkit-border-bottom-left-radius: 10px; /* ELS */
-webkit-border-bottom-right-radius: 10px; /* ELS */
HEIGHT: 25%;
font-family: monospace;
font-size: 11px;
height: expression(parseInt(this.parentNode.parentNode.offsetHeight * (3/13)) + 'px');
}
#JashParent .cssEntry {
background: lightgreen;
font-size: 11px;
font-family: monospace;
}
#JashBottomBar {
BACKGROUND: #ccc;
POSITION: relative;
HEIGHT: 20px;
overflow: hidden;
margin-top: 2px;
}
#JashBottomBar a {
HEIGHT: 14px;
font-size: 9px;
font-weight: normal;
font-family: arial;
float: left;
padding: 4px;
background: #eee;
cursor: pointer;
border: 1px outset white;
margin-right: 1px;
}
#JashBottomBar a:hover {
padding-top: 3px;
padding-bottom: 5px;
background-color: white;
}
#JashBottomBar a:active, #JashBottomBar a:focus {
padding-top: 5px;
padding-bottom: 3px;
background-color: #ddd;
}
#JashResizeButton {
BORDER: 1px solid gray;
-moz-border-radius-bottomright: 10px; /* ELS */
-webkit-border-bottom-right-radius: 10px; /* ELS */
BACKGROUND: #eee;
WIDTH: 17px;
height: 17px;
line-height: 0;
CURSOR: move;
position: absolute;
bottom: -1px;
right: -1px;
z-index: 2000;
}
/*}}}*/
//{{{
// Jash - JavaScript Shell
// Copyright: 2007, Billy Reisinger
// Documentation: http://www.billyreisinger.com/jash/
// License: GNU General Public License - http://www.gnu.org/licenses/gpl.html
// MODIFIED BY ELS (www.TiddlyTools.com) on 12/11/2007 for embedded use within TiddlyWiki documents
// * disabled setting of stylesheet from remote URL - use internal CSS definitions instead (see [[jash.css]] tiddler)
// * disabled automatic display on startup (but initialize jash panel so ESC key will work)
window.Jash=function(){this.jashRoot="http://www.billyreisinger.com/jash/source/latest/";this.domGetElFunctions={id:new Array("document.getElementById","$"),className:new Array("getElementsByClassName","$C")};var line="-------------------------------------------------";var _null="nooutput";this.revision="$Revision: 1.14 $".replace(/(\$|[A-Za-z]|\s|:)/g,'');this.version="$Name: REL_1_35_7 $".replace(/\$|Name:|\s|REL_/g,'').replace(/_/g,'.');this.versionDate="$Date: 2007/11/16 03:24:54 $";this.main=function(){this.browser=this.returnBrowserType();this.lineNumber=0;this.mainBlock;this.output=document.getElementById("JashOutput");this.input;this.outputHistory=new Array();this.cssEvalFlag=false;this.innerHtmlInspection=false;this.accessKeyText=this.getAccessKeyText();this.defaultText="Jash, v"+this.version+"\nEnter \"jash.help()\" for a list of commands.\n";this.cls=this.clear;this.tabIndexIndex=0;this.currentNode={};this.tips=["Did you know?\nThe DOM Inspector will automatically put\n an element with an ID in the input field for you.","Did you know?\nYou can tie this script into your own to jash scripts. Use 'jash.methodName' anywhere\n in your scripts, and pull\n up this window before executing to see\n the results.","Did you know?\nUse jash.stopWatch.start() and jash.stopWatch.stop() to\n time execution speeds! Handy for optimization.","Did you know?\nPress TAB to complete a function, method, or property name.\n If more than one match is found, a list of possible\n matches will appear.","Did you know?\nYou can use jash.show() to show a list of the names\nand types of an object's members.\nOn the other hand, jash.dump will show names and\n_values_ of an object's members.","Whoa ---- you can now tab-complete HTML element ids after typing document.getElementsById(' (or the '$' shorthand if using Prototype). This also works with class names (i.e. document.getElementsByClassName)"]
this.defaultText+=line+"\n"+this.tips[(parseInt((Math.random()*10)%this.tips.length))]+"\n"+line+"\n";
/*
ELS: disable loading of remote stylesheet! (use styles from [[jash.css]] tiddler intead)
if(this.returnBrowserType()!="sa"){this.stylesheet=document.body.appendChild(document.createElement('link'));}else{this.stylesheet=document.getElementsByTagName("head")[0].appendChild(document.createElement("link"));}
this.stylesheet.type='text/css';this.stylesheet.rel='stylesheet';this.stylesheet.href=this.jashRoot+'Jash.css';
*/
this.create();Jash.TabComplete.prototype=this;this.tabComplete=new Jash.TabComplete();Jash.Evaluator.prototype=this;this.evaluation=new Jash.Evaluator();this.history=new Jash.History();var _self=this;window.setTimeout(function(){_self.input.focus();},500);if(typeof event!="undefined")delete event;}
this.returnBrowserType=function(){if(window.navigator.userAgent.toLowerCase().indexOf("opera")!=-1){return"op";}
if(window.navigator.userAgent.toLowerCase().indexOf("msie")!=-1){return"ie";}
if(window.navigator.userAgent.toLowerCase().indexOf("firefox")!=-1){return"ff";}
if(window.navigator.userAgent.toLowerCase().indexOf("safari")!=-1){return"sa";}}
this.returnOsType=function(){var ua=window.navigator.userAgent.toLowerCase();if(ua.indexOf("macintosh")!=-1){return"mac";}else if(ua.indexOf("windows")!=-1){return"win";}else if(ua.indexOf("linux i686")!=-1){return"linux";}}
this.getAccessKeyText=function(){var txt;var agt=this.returnOsType();switch(this.browser){case"ie":txt="Alt";break;case"ff":if(agt=="mac"){txt="Ctrl";}else if(agt=="linux"){txt="Alt";}else{txt="Alt-Shift";}
break;case"op":txt="Shift-Esc";break;case"sa":if(agt=="mac"){txt="Ctrl";}else{txt="Alt";}
break;default:txt="Alt";break;}
return txt;}
this.print=function(text,clear,suppressLineNumbers,autoscroll){clear=(typeof clear!="undefined")?clear:false;autoscroll=(typeof autoscroll!="undefined")?autoscroll:true;if(this.output==null||document.getElementById("JashParent")==null){this.create();this.output=document.getElementById("JashOutput");this.mainBlock=document.getElementById("JashParent");}
if(clear){this.clear();}
if(text!=""){if(typeof suppressLineNumbers!="undefined"&&!suppressLineNumbers){this.output.value+=this.lineNumber+". ";}
this.output.value+=text+"\n";if(autoscroll){this.output.scrollTop=this.output.scrollHeight;}
this.lineNumber++;}
return _null;}
this.show=function(obj){this.print(line,false,true);var out="";this.lineNumber=0;for(var p in obj){if(typeof obj[p]=="function"){var t=obj[p].toString();t=t.replace(/[\x0A\x0D]/g,"").replace(/\s+/g,"").replace(/\{.+\}/g,"{ ... }");t=t.replace(p,"");t=p+": "+t;}else{t=p+": "+typeof obj[p];}
out+=++this.lineNumber+". "+t+"\n";}
this.print(out,false,true);this.print(line,false,true);this.output.scrollTop=this.output.scrollHeight;return _null;}
this.dump=function(obj){if(typeof obj=="string"){this.print(obj);}else{this.print(line,false,true);var out=new Array();if(typeof obj.push=="undefined"){for(var th in obj){out.push(++this.lineNumber+". "+th+" = "+obj[th]);}}else{for(var i=0;i<obj.length;i++){out.push(++this.lineNumber+". "+obj[i]);}}
this.print(out.join("\n"),false,true);this.print(line,false,true);this.output.scrollTop=this.output.scrollHeight;}
return _null;}
this.clear=function(){this.outputHistory.push(this.output.value);this.output.value="";this.input.focus();return _null;}
this.showOutputHistory=function(){this.outputHistory.push(this.output.value);this.dump(this.outputHistory);}
this.assignInputKeyEvent=function(keyCode){if(keyCode==13){this.evaluation.evaluate(this.input.value);this.input.value="";return false;}else if(keyCode==38){if(this.browser!="op"){this.input.value=this.history.getPreviousInput();}
return false;}else if(keyCode==40){if(this.browser!="op"){this.input.value=this.history.getNextInput();}
return false;}else if(keyCode==9){this.tabComplete.tabComplete();return false;}}
this.getXBrowserYOffset=function(){var y;if(self.pageYOffset){y=self.pageYOffset;}else if(document.documentElement&&document.documentElement.scrollTop){y=document.documentElement.scrollTop;}else if(document.body){y=document.body.scrollTop;}
return y;}
this.getMouseXY=function(e){var tempX=0
var tempY=0
if(window.event){if(document.documentElement&&document.documentElement.scrollTop){tempX=window.event.clientX+document.documentElement.scrollLeft;tempY=window.event.clientY+document.documentElement.scrollTop;}else{tempX=window.event.clientX+document.body.scrollLeft;tempY=window.event.clientY+document.body.scrollTop;}}else{tempX=e.pageX;tempY=e.pageY;}
return{x:tempX,y:tempY};}
this.getDimensions=function(el){var dims={}
if(document.all){dims.x=el.offsetWidth;dims.y=el.offsetHeight;}else{dims.x=parseInt(document.defaultView.getComputedStyle(el,"").getPropertyValue("width"));dims.y=parseInt(document.defaultView.getComputedStyle(el,"").getPropertyValue("height"));}
return dims;}
this.addEvent=function(obj,eventName,func){if(obj.addEventListener)
return obj.addEventListener(eventName,func,true);else if(obj.attachEvent){obj.attachEvent("on"+eventName,func);return true;}
return false;}
this.findElementPosition=function(obj){var curleft=0;var curtop=0;if(obj.offsetParent){curleft=obj.offsetLeft
curtop=obj.offsetTop
while(obj=obj.offsetParent){curleft+=obj.offsetLeft
curtop+=obj.offsetTop}}
return[curleft,curtop];}
this.create=function(){if(document.getElementsByTagName("frameset").length>0){alert("Jash currently does not support pages with frames.");return;}
var self=this;var debugParent=document.createElement("div");var windowScrollY=0;if(document.documentElement&&document.documentElement.scrollTop){windowScrollY=document.documentElement.scrollTop;}else if(document.body){windowScrollY=document.body.scrollTop}else{windowScrollY=window.scrollY;}
debugParent.style.top=windowScrollY+50+"px";debugParent.id="JashParent";
/*
ELS: 12/12/2007 - REMOVED ESC HANDLER SO OTHER PAGE ELEMENTS GET THEM!... SEE BELOW FOR ALTERNATIVE SHIFT-ESC HANDLER
this.addEvent(document,"keydown",function(e){e=(typeof window.event!="undefined")?window.event:e;if(e.keyCode=="27"){if(typeof e.shiftKey=="undefined"||!e.shiftKey && (this.mainBlock.style.display!="none")){self.close();}}});
*/
var textareaWrap=document.createElement("div");textareaWrap.id="JashTextareaWrap";var debugOutput=document.createElement("textarea");debugOutput.id="JashOutput";debugOutput.wrap="off";debugOutput.readOnly="true";debugOutput.value=this.defaultText;var inp=document.createElement("textarea");inp.id="JashInput";var last="";inp.onkeydown=function(e){e=(typeof window.event!="undefined")?window.event:e;return self.assignInputKeyEvent(e.keyCode);}
inp.onkeypress=function(e){e=(typeof window.event!="undefined")?window.event:e;var k=e.keyCode;if(!self.evaluation.cssEvalFlag){if(k==9||k==13||k==38||k==40){if(k!=40&&this.browser!="ie"){return false;}}}else if(k==9){return false;}}
var dragBut=document.createElement("div");dragBut.innerHTML="Jash";dragBut.id="JashDragBar";dragBut.onmousedown=function(e){e=(typeof window.event!="undefined")?window.event:e;var xplus=(typeof e.layerX=="undefined")?e.offsetX:e.layerX;var yplus=(typeof e.layerY=="undefined")?e.offsetY:e.layerY;document.onmousemove=function(e){var coords=self.getMouseXY(e);document.getElementById("JashParent").style.top=coords.y-yplus+"px";document.getElementById("JashParent").style.left=coords.x-xplus+"px";}
return false;}
document.onmouseup=function(){document.onmousemove=null;};dragBut.onclick=function(){return false;}
var xBut=document.createElement("a");xBut.className="JashXButton";xBut.innerHTML="X";xBut.href="#";xBut.onclick=function(){self.close();return false;}
var clearBut=document.createElement("a");clearBut.innerHTML="Clear ("+this.accessKeyText+"-C)";clearBut.accessKey="C";clearBut.className="JashButton";clearBut.onclick=function(){self.clear();return false;}
this.setCrossBrowserAccessKeyFunctionForAnchor(clearBut);var evalBut=document.createElement("a");evalBut.value="Evaluate ("+this.accessKeyText+"-Z)";evalBut.innerHTML="Evaluate ("+this.accessKeyText+"-Z)";evalBut.accessKey="Z";evalBut.className="JashButton";evalBut.title="Evaluate current input ("+this.accessKeyText+"-Z)";evalBut.onclick=function(){self.evaluation.evaluate(inp.value);if(!self.evaluation.cssEvalFlag){inp.value="";}
inp.focus();return false;}
this.setCrossBrowserAccessKeyFunctionForAnchor(evalBut);var helpBut=document.createElement("a");helpBut.innerHTML="Help";helpBut.className="JashButton";helpBut.title="Help: show list of commands (or type jash.help(); )";helpBut.onclick=function(){self.help();}
var domBut=document.createElement("a");domBut.innerHTML="Mouseover DOM ("+this.accessKeyText+"-X)";domBut.title="Mouseover DOM: toggle to turn on/off inspection of document nodes ("+this.accessKeyText+"-X)";domBut.className="JashButton";domBut.accessKey="X";domBut.tabIndex="4";this.domActive=false;domBut.onclick=function(){if(!self.domActive){document.body.onmouseover=function(e){if(typeof e=="undefined"){e=window.event;}
self.showNodes(e);}
self.setButtonVisualActiveState(domBut,"on");self.domActive=true;}else{document.body.onmouseover=function(){}
self.domActive=false;self.setButtonVisualActiveState(domBut,"off");}
return _null;}
this.setCrossBrowserAccessKeyFunctionForAnchor(domBut);var innerHtmlInspectBut=document.createElement("a");innerHtmlInspectBut.innerHTML="innerHTML Dump ("+this.accessKeyText+"-A)";innerHtmlInspectBut.title="innerHTML Inspect: toggle to turn on/off innerHTML inspection of document nodes ("+this.accessKeyText+"-A)";innerHtmlInspectBut.className="JashButton";innerHtmlInspectBut.accessKey="A";innerHtmlInspectBut.tabIndex="5";this.innerHtmlInspection=false;innerHtmlInspectBut.onclick=function(){self.innerHtmlInspection=!self.innerHtmlInspection;self.setButtonVisualActiveState(innerHtmlInspectBut,self.innerHtmlInspection?"on":"off");return _null;}
this.setCrossBrowserAccessKeyFunctionForAnchor(innerHtmlInspectBut);var cssBut=document.createElement("a");cssBut.innerHTML="CSS Input ("+this.accessKeyText+"-S)";cssBut.title="CSS Input: turn on CSS input to enter arbitrary CSS ("+this.accessKeyText+"-S)";cssBut.className="JashButton";cssBut.accessKey="S";cssBut.onclick=function(){if(!self.evaluation.cssEvalFlag){self.setButtonVisualActiveState(cssBut,"on");self.evaluation.cssEvalFlag=true;inp.className="cssEntry";if(document.getElementById("JashStyleInput")!=null){self.evaluation.styleInputTag.disabled=false;}
inp.value="";}else{self.setButtonVisualActiveState(cssBut,"off");inp.className="";self.evaluation.cssEvalFlag=false;if(document.getElementById("JashStyleInput")!=null){self.evaluation.styleInputTag.disabled=true;}
inp.value="";}
inp.focus();return _null;}
this.setCrossBrowserAccessKeyFunctionForAnchor(cssBut);var resizeBut=document.createElement("div");resizeBut.id="JashResizeButton";this.minDims={x:100,y:100};resizeBut.onmousedown=function(e){e=(typeof window.event!="undefined")?window.event:e;var originalDims=self.getDimensions(textareaWrap);var originMouseDims=self.getMouseXY(e);document.onmousemove=function(e){var newMouseDims=self.getMouseXY(e);var newWidth=originalDims.x+(newMouseDims.x-originMouseDims.x);if(newWidth<self.minDims.x){newWidth=self.minDims.x;}
textareaWrap.style.width=newWidth+"px";debugParent.style.width=newWidth+"px";var newHeight=originalDims.y+(newMouseDims.y-originMouseDims.y);if(newHeight<self.minDims.y){newHeight=self.minDims.y;}
textareaWrap.style.height=newHeight+"px";debugParent.style.height=newHeight+"px";}
document.onmouseup=function(){document.onmousemove="";}}
var bottomBar=document.createElement("div");bottomBar.id="JashBottomBar";debugParent.appendChild(dragBut);debugParent.appendChild(xBut);bottomBar.appendChild(evalBut);bottomBar.appendChild(cssBut);bottomBar.appendChild(domBut);bottomBar.appendChild(innerHtmlInspectBut);bottomBar.appendChild(clearBut);bottomBar.appendChild(helpBut);debugParent.appendChild(bottomBar);debugParent.appendChild(resizeBut);document.body.appendChild(debugParent);textareaWrap.appendChild(debugOutput);textareaWrap.appendChild(inp);debugParent.appendChild(textareaWrap);this.bottomBar=document.getElementById("JashBottomBar");this.dragBar=document.getElementById("JashDragBar")
this.output=document.getElementById("JashOutput");this.input=document.getElementById("JashInput");this.mainBlock=debugParent;this.addEvent(window,'scroll',function(){debugParent.style.top=50+self.getXBrowserYOffset()+'px';});}
this.setButtonVisualActiveState=function(button,state){if(state=="on"){button.style.backgroundColor="lightgreen";}else{button.style.backgroundColor="";}}
this.help=function(){var out=new Array();out.push(line);out.push("Jash v"+this.version+" "+this.versionDate.replace(/\$/g,''),true);out.push("http://www.billyreisinger.com/jash/documentation.html");out.push(line);out.push("METHODS");out.push(line);out.push("this.cls() - clear console and terminal");out.push("jash.print(str,clear) - output str to console ~~ str = string ~~ clear = true|false: clear console before output");out.push("this.close() - close this console");out.push("this.dump(obj) - output object and members to console");out.push("this.show(obj) - print out the names and types (only) of all members of obj");out.push("this.stopWatch.start() - start timer");out.push("this.stopWatch.stop() - end timer and return result in ms");out.push("this.kill(HTML Element) - remove an element from the page.");out.push("this.getDimensions(HTML Element) - get width, height dimensions of an html element. Returns an object [x,y]");out.push(line);out.push("KEYSTROKES");out.push(line);out.push("press up arrow in input field to retrieve last input");out.push("press ESC to show/hide console");out.push("press "+this.accessKeyText+"-Q to turn on/off Transparent mode, so you can see through the Jash.");out.push("press ENTER in input field to enter a command");out.push("press TAB to auto-complete input");out.push("press "+this.accessKeyText+"-Z to evaluate input");out.push("press "+this.accessKeyText+"-X to activate/deactivate DOM inspector");out.push("press "+this.accessKeyText+"-A to activate/deactivate innerHTML dump (only works w/ DOM inspector)");out.push("press "+this.accessKeyText+"-C to clear output and input");out.push("press "+this.accessKeyText+"-S to turn on/off CSS input mode. In CSS input mode, you can enter arbitrary CSS selectors and rules, as you would normally do in a CSS stylesheet.");this.print(out.join("\n"));return _null;}
this.close=function(){if(this.mainBlock.style.display=="none"){this.mainBlock.style.display="block";this.input.focus();}else{this.mainBlock.style.display="none";}}
this.setCrossBrowserAccessKeyFunctionForAnchor=function(el){var self=this;el.tabIndex=++this.tabIndexIndex;if(this.browser=="ie"){el.onfocus=function(){if(window.event.altKey){el.onclick();}
self.input.focus();}}}
this.stopWatch={t_start:0,t_end:0,t_total:0,start:function(){t_start=new Date().getTime();return t_start;},stop:function(){t_end=new Date().getTime();t_total=t_end-t_start;return(t_total);}}
this.showNodes=function(e){if(typeof e=="undefined")e=window.event;var el=typeof e.target=="undefined"?e.srcElement:e.target;this.currentNode=el;var childMost=this.identifyNode(el,false);var out="";var childmostTxt="childmost..... "+childMost.txt+"\n";while(el=el.parentNode){if(el.nodeName.toLowerCase()=="html"){out="parentmost.... <html>\n"+out;break;}
out=this.identifyNode(el).txt+"\n"+out;}
out="**** PRESS "+this.accessKeyText+"-X TO PAUSE / UNPAUSE ****\n"+out;out+=childmostTxt;this.print(out,true,true,false);if(this.innerHtmlInspection){this.print("INNER HTML");if(this.currentNode.innerHTML.indexOf("<")!=-1){this.print(Jash.Indenter.indent(this.currentNode.innerHTML),false,true,false);}else{this.print(this.currentNode.innerHTML,false,true,false);}}
if(!this.evaluation.cssEvalFlag){if(childMost.id!=""){if(typeof $!="undefined"){this.input.value='$("'+childMost.id+'")';}else{this.input.value='document.getElementById("'+childMost.id+'")';}}else{this.input.value="this.currentNode";}}}
this.identifyNode=function(el,showDots){showDots=typeof showDots=="boolean"?showDots:true;var out={txt:"",id:""};if(showDots)out.txt+=".............. ";out.txt+="<"+el.nodeName.toLowerCase();for(var i=0;i<el.attributes.length;i++){if((this.browser=="ie"&&el.attributes[i].specified===true)||this.browser!="ie"){out.txt+=" "+el.attributes[i].name;out.txt+="=\""+el.attributes[i].value+"\"";}}
out.txt+=">";return out;}
this.kill=function(){this.currentNode.parentNode.removeChild(this.currentNode);}}
Jash.Evaluator=function(){this.cssEvalFlag=false;var _null="nooutput";this.evaluate=function(input){if(input=="")return false;this.history.add(input);if(this.cssEvalFlag){this.evalCss(input);this.print(input);}else{var output=this.evalJs(input);if(typeof output!="undefined"){this.print(">> "+input);this.print(output);}}}
this.evalJs=function(input){try{var result;if(this.browser=="ie"){result=eval(input);}else{result=window.eval(input);}
if(result!=null&&result.toString()!=_null){return(result.toString());}else{return"null"}}catch(e){return(e.message);}}
this.evalCss=function(input){try{this.insertStyleRule(input);}catch(e){}
return input;}
this.insertStyleRule=function(rule){var lastStyleSheetIndex=document.styleSheets.length-1;if(document.getElementById("JashStyleInput")==null){this.styleInputTag=document.createElement("style");this.styleInputTag.id="JashStyleInput";this.styleInputTag.type="text/css";document.body.appendChild(this.styleInputTag);}
if(this.browser=="ff"||this.browser=="op"){this.styleInputTag.innerHTML+=rule+"\n";}else if(this.browser=="ie"||this.browser=="sa"){if(this.browser=="ie"){var i=0;}else if(this.browser="sa"){var i=document.styleSheets.length-1;}
var rulesArray=rule.split("}");for(var t=0;t<rulesArray.length;t++){var ruleSplit=rulesArray[t].split("{");var selectors=ruleSplit[0].split(",");for(var k=0;k<selectors.length;k++){document.styleSheets[i].addRule(selectors[k],ruleSplit[1]);}}}
return"";}
return this;}
Jash.History=function(){this.entries=new Array('');this.position=0;}
Jash.History.prototype={add:function(input){this.entries.push(input);this.position=this.entries.length-1;},getPreviousInput:function(){if(this.position<0){return'';}
var entry=typeof this.entries[this.position]!="undefined"?this.entries[this.position]:'';if(this.position>0){this.position--;}
return entry;},getNextInput:function(){if(this.position+1<this.entries.length){return this.entries[++this.position];}else{return'';}}}
Jash.Indenter={indentChar:"\t",nodesCommonlyUnclosed:new Array("link ","img ","meta ","!DOCTYPE ","input ","param","hr","br"),stringRepeat:function(stringToRepeat,times){var string=new Array();for(var i=0;i<times;i++){string.push(stringToRepeat);}
return string.join('');},closeUnclosedNode:function(str){for(var k=0;k<this.nodesCommonlyUnclosed.length;k++){var reg=new RegExp("^"+this.nodesCommonlyUnclosed[k].toLowerCase());if(str.toLowerCase().match(reg)){return str.replace(">","/>");}}
return str;},indentAndAdd:function(level,string,arr){var indents=this.stringRepeat(this.indentChar,level);arr.push(indents+string);return arr;},indent:function(source){var source=source;var arr=new Array();source=source.replace(/[\n\r\t]/g,'');source=source.replace(/>\s+/g,">");source=source.replace(/\s+</g,"<");var splitsrc=source.split("<");for(i=0;i<splitsrc.length;i++){splitsrc[i]=this.closeUnclosedNode(splitsrc[i]);}
source=splitsrc.join("<");var level=0;var sourceLength=source.length;var position=0;while(position<sourceLength){if(source.charAt(position)=='<'){var startedAt=position;var tagLevel=1;if(source.charAt(position+1)=='/'){tagLevel=-1;}
if(source.charAt(position+1)=='!'){tagLevel=0;}
while(source.charAt(position)!='>'){position++;}
if(source.charAt(position-1)=='/'){tagLevel=0;}
var tagLength=position+1-startedAt;if(tagLevel===-1){level--;}
arr=this.indentAndAdd(level,source.substr(startedAt,tagLength),arr);if(tagLevel===1){level++;}}
if((position+1)<sourceLength){if(source.charAt(position+1)!=='<'){startedAt=position+1;while(source.charAt(position)!=='<'&&position<sourceLength){position++;}
if(source.charAt(position)==='<'){tagLength=position-startedAt;arr=this.indentAndAdd(level,source.substr(startedAt,tagLength),arr);}}else{position++;}}else{break;}}
return arr.join("\n");}}
Jash.Profiler=function(func,onFinish){this.func=func;this.time=0;this.defaultOnFinish=function(){};this.results=new Array();this.onFinish=typeof onFinish!="function"?this.defaultOnFinish:onFinish;var self=this;this.reverseWhile=function(reps){this.stopWatch.start();while(reps>0){this.func();reps--;}
return this.stopWatch.stop();}
this.forLoop=function(reps){this.stopWatch.start();for(i=0;i<reps;i++){this.func();}
return this.stopWatch.stop();}
this.loop=function(kind,reps){if(!this.results[kind]){this.results[kind]=new Array();}
var repsMemberName="r_"+reps;if(!this.results[kind][repsMemberName]){this.results[kind][repsMemberName]=new Array();}
var time=this[kind](reps);this.results[kind][repsMemberName].push(time);}
this.runOnce=function(){if(!this.results.runOnce){this.results.runOnce=new Array();}
this.stopWatch.start();func();this.results.runOnce.push(this.stopWatch.stop());}
this.stopWatch={t_start:0,t_end:0,t_total:0,start:function(){t_start=new Date().getTime();return t_start;},stop:function(){t_end=new Date().getTime();t_total=t_end-t_start;self.time=t_total;return t_total;}}
this.average=function(arr){var sum=0;for(i=0;i<arr.length;i++){sum+=arr[i];}
return sum/arr.length}
this.multiPass=function(passes,type,reps){if(typeof type=="undefined"){type="runOnce";}else if(typeof this[type]=="undefined"){jash.print("Error: the loop type '"+type+"' does not exist");return false;}
var self=this;if(type=="runOnce"){if(passes<1){self.reportProfile(Math.round(this.average(this.results.runOnce)),type,reps);}else{window.setTimeout(function(){self.runOnce();self.multiPass(--passes,type);},50);}}else{if(passes<1){var repsMemberName="r_"+reps;self.reportProfile(Math.round(this.average(this.results[type][repsMemberName])),type,reps);}else{window.setTimeout(function(){self.loop(type,reps);self.multiPass(--passes,type,reps);},50);}}}
this.reportProfile=function(avgMs,type,reps){var line="-------PROFILER----------------------------------------------";var str=line+"\n"+this.func+"\n"+line+"\n";str+="Type of profile: "+type+"\n";if(typeof reps!="undefined"){str+="Loop iterations: "+reps+"\n";}
str+="Average execution time: "+avgMs+"ms"+"\n";if(type=="runOnce"){howManyTimes=this.results.runOnce.length;}else{repsMemberName="r_"+reps;howManyTimes=this.results[type][repsMemberName].length;}
str+="Average calculated from "+howManyTimes+" pass(es)\n";str+=line+"\n";jash.print(str);}}
Jash.TabComplete=function(){this.tabComplete=function(e){e=(typeof window.event!="undefined")?window.event:e;var inputText=this.input.value;var match=null;if(match=this.searchInputForDomGetElFunctions(inputText)){this.tabCompleteIdOrClassInJavascript(match.match[0],match.type);this.focusCaretAtEndOfInput();return false;}else if(this.evaluation.cssEvalFlag){this.tabCompleteIdOrClassInCss(inputText);this.focusCaretAtEndOfInput();return false;}else{this.tabCompleteJavascript(e,inputText);this.focusCaretAtEndOfInput();}}
this.focusCaretAtEndOfInput=function(){this.input.selectionEnd=this.input.selectionStart=this.input.value.length;}
this.tabCompleteJavascript=function(e,inputText){var words=inputText.split(/\s+/);var lastWord=words[(words.length-1)];var numOpeningParens=lastWord.split("(").length-1;var numClosingParens=lastWord.split(")").length-1;var scope;var sentinel=0;var diff=numOpeningParens-numClosingParens;if(diff>0){numClosingParens=lastWord.split("(")[numOpeningParens].split(")").length-1;var numRealDanglers=numOpeningParens-numClosingParens;scope=lastWord.split("(").slice(numRealDanglers).join("(");}else if(diff<0){this.print("error: too many closing parentheses");return false;}else{scope=lastWord;}
scope=scope.split(".");var fragment=scope.pop();scope=scope.join(".");if(scope=="")scope="window";var members=this.getMembers(scope);var results=this.findTextMatchesInArray(members,fragment);if(results==false){}else if(typeof results!="string"){this.dump(results);var bestMatch=this.findBestStringMatch(fragment,results);if(fragment!=''){fragReg=new RegExp(fragment+"$");this.input.value=this.input.value.replace(fragReg,bestMatch);}else{this.input.value+=bestMatch;}}else{var reggie=new RegExp(fragment+"$");this.input.value=this.input.value.replace(reggie,results);}
return false;}
this.doAllStringsInArrayHaveSameCharacterAtIndex=function(index,arr){var matched=0;if(!arr[0].charAt(index))return false;var character=arr[0].charAt(index);for(var i=1;i<arr.length;i++){if(!arr[i].charAt(index)||arr[i].charAt(index)!=character){return false;}}
return true;}
this.findBestStringMatch=function(str,arr){var fragLength=str.length;var matches=this.doAllStringsInArrayHaveSameCharacterAtIndex(fragLength,arr);while(matches){fragLength++;matches=this.doAllStringsInArrayHaveSameCharacterAtIndex(fragLength,arr);}
return arr[0].substr(0,fragLength);}
this.tabCompleteIdOrClassInJavascript=function(inputText,type){var query=inputText.split("(");query=query[query.length-1].replace(/\W/g,'');var matches=new Array();var els=document.getElementsByTagName("*");if(type=="id"){for(var i=0;i<els.length;i++){if(els[i].id&&els[i].id.indexOf(query)==0){matches.push(els[i].id);}}}else if(type=="class"){for(var i=0;i<els.length;i++){if(els[i].className&&els[i].className!=''){var classes=els[i].className.split(/\s/);for(var ii=0;ii<classes.length;ii++){if(classes[ii].indexOf(query)==0||query==''){if(matches.join("***").indexOf(classes[ii])==-1){matches.push(classes[ii]);}}}}}}
if(matches.length==1){this.input.value+=matches[0].split(query)[1];}else if(matches.length==0){this.print("no match");}else{this.dump(matches.sort());var bestMatch=this.findBestStringMatch(query,matches);if(query!=''){var replacement=inputText.split("(");replacement[replacement.length-1]=replacement[replacement.length-1].replace(query,bestMatch);this.input.value=this.input.value.replace(inputText,replacement.join("("));}else{this.input.value+=bestMatch;}}}
this.tabCompleteIdOrClassInCss=function(inputText){var selectors=inputText.replace(/(\.|#)/g,' $1').split(/\s+/);var lastSelector=selectors[selectors.length-1];var els=document.getElementsByTagName("*");var matches=new Array();if(lastSelector.match(/^\./)){for(var i=0;i<els.length;i++){if(els[i].className&&els[i].className!=''){var classes=els[i].className.split(/\s/);for(var ii=0;ii<classes.length;ii++){if(classes[ii].indexOf(lastSelector.substr(1))==0||lastSelector=="."){if(matches.join("***").indexOf(classes[ii])==-1){matches.push("."+classes[ii]);}}}}}}else if(lastSelector.match(/^#/)){for(var i=0;i<els.length;i++){if(els[i].id&&els[i].id.indexOf(lastSelector.substr(1))==0){matches.push("#"+els[i].id);}}}
if(matches.length==1){this.input.value+=matches[0].split(lastSelector)[1];}else if(matches.length==0){this.print("no match");}else{this.dump(matches.sort());var bestMatch=this.findBestStringMatch(lastSelector,matches);if(lastSelector!=''){this.input.value=this.input.value.replace(lastSelector,bestMatch);}else{this.input.value+=bestMatch;}}}
this.searchInputForDomGetElFunctions=function(inputText){for(var i=0;i<this.domGetElFunctions.id.length;i++){var selfct=new RegExp(this.domGetElFunctions.id[i].replace("\$","\\\$")+"\\\(['\"]\\w*$");if(inputText.match(selfct)){return{match:inputText.match(selfct),type:"id"};}}
for(var i=0;i<this.domGetElFunctions.className.length;i++){var selfct=new RegExp(this.domGetElFunctions.className[i].replace("\$","\\\$")+"\\\(['\"]\\w*$");if(inputText.match(selfct)){return{match:inputText.match(selfct),type:"class"};}}}
this.findTextMatchesInArray=function(arrayToTest,findMe){var resultsArray=new Array();var tester=new RegExp("^"+findMe);for(var i=0;i<arrayToTest.length;i++){if(tester.test(arrayToTest[i])){resultsArray.push(arrayToTest[i]);}}
if(resultsArray.length>1){resultsArray.sort();return resultsArray;}else if(resultsArray.length==1){return resultsArray[0];}else{return false;}}
this.getMembers=function(context){var members=new Array();for(memberName in eval(context)){members.push(memberName);}
return members;}
return this;}
// ELS 12/12/2007: init is deferred until first time panel is shown
window.toggleJash=function() // show/hide panel...
{ if("jash" in window)window.jash.close();else{window.jash=new Jash();window.jash.main();} }
window.isJashVisible=function() // so scripts can find out the current display state
{ return window.jash?window.jash.mainBlock.style.display!="none":false; }
addEvent(document,"keydown",function(ev){ // SHIFT-ESC shows/hides panel, ESC hides panel
var e=(typeof window.event!="undefined")?window.event:ev;
if(e.keyCode=="27"&&(e.shiftKey||window.isJashVisible())) window.toggleJash(); });
//}}}
<html><hide linebreaks><a href="javascript:;" class="tiddlyLinkExisting"
title='JASH: Javascript Shell - view/modify internal run time variables and functions!'
onclick="if (window.toggleJash) toggleJash(); return false;"
onmouseover="this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
+encodeURIComponent(encodeURIComponent(this.onclick))
+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';">
$1
</a></html>
~JaSH is a Javascript Shell written by Billy Reisinger, and provides a cross-browser compatible interactive javascript development and debugging tool.
This package includes a whitespace-compressed version of the Jash source code ([[Jash.js]]), accompanied by the appropriate stylesheet definitions necessary to render the Jash interface ([[Jash.css]]). Additionally, [[JashCommand]] provides a simple ~HTML-based command link that toggles the display of the Jash interface with a single click.
/***
|Name|JustensPlayground|
|Source|early version of http://www.justenrobertson.com/rplay/rp2.js |
|Version|1.0.1|
|Author|Mashed into TiddlyWiki by Paul Reiber - Reiber Labs|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|InlineJavacriptPlugin, MooTools|
|Description|wrapper for Justen Robertsons flocking demo |
|Status|somewhat working - TiddlyWiki mashed together with MOOTOOLS behind the scenes to get it to fly|
This plugin implements an early version of Justens flocking demo in TiddlyWiki
!!!!!Documentation
<<<
Counts on MOOTOOLS being loaded in the MarkupPreHead
<<<
!!!!!Usage
<<<
Use [[InlineJavascriptPlugin]] to invoke/define the flocking functions from within tiddler content.
<<<
!!!!!Examples (requires InlineJavascriptPlugin)
<<<
<html><div id='paperBox' style='width:100%; height:100%;'></div></html>
<script show>
rp2.init();
</script>
<<<
!!!!!Revisions
<<<
2009.03.19 [1.0.0] initial release
2009.03.20 [1.0.1] found and eliminated initialization TypeError - addEventListener conflicting somehow
<<<
!!!!!Code
***/
//{{{
version.extensions.JustensPlayground ={major: 1, minor: 0, revision: 0, date: new Date(2009,3,19)};
//}}}
// // SNARFED LIBRARY FUNCTIONS
//{{{
/**
* rp2.js
* @version 0.1
* @author Justen Robertson
* @license Free (no restrictions, no rights reserved)
*
* This is bound to change a lot but feel free to pilfer what you want.
*/
/**
* function mkCurve
*
* Builds a curve string for use in a path. Useful for dynamically generating
* the string so we can pass it to an animation.
*/
function mkCurve(coords, type) {
var str = (type?type:"C");
coords.each(function(coord) {
if (typeof coord == 'string') str = str +" "+coord;
else str = str+" "+coord.x+","+coord.y;
});
return str;
}
/**
* function dec2hex
*
* Converts a decimal to hex value.
*/
function dec2hex(d) {return d.toString(16);}
/**
* function hex2dec
*
* Converts a hexadecimal to decimal value.
*/
function hex2dec(h) {return parseInt(h,16);}
/**
* function r2d
*
* Converts radian to degrees
*/
function r2d(deg) {
return deg*(360/(2*Math.PI));
}
/**
* function d2r
*
* Converts degrees to radians
*/
function d2r(rad) {
return rad*((2*Math.PI)/360);
}
function rndColor() {
var r = dec2hex(parseInt(255*Math.random()));
var g = dec2hex(parseInt(255*Math.random()));
var b = dec2hex(parseInt(255*Math.random()));
while (r.length<2) r = "0"+r; // pad it out to 2 places
while (g.length<2) g = "0"+g;
while (b.length<2) b = "0"+b;
return "#"+r+g+b;
}
/**
* class Coord
* @param p1 x coord, or hash of {x:x, y:y, z:z}
* @param p2 y coord
* @param p3 z coord
*
*/
function Coord(p1, p2, p3) {
this.x = (p1.x?p1.x:p1?p1:0);
this.y = (p1.y?p1.y:p2?p2:0);
this.z = (p1.z?p1.z:p3?p3:0);
/**
* @method str returns a string of "x,y" (z omitted)
* @param xadd an amount to add to x
* @param yadd an amount to add to y
*/
this.str = function(xadd, yadd) {return (this.x+(xadd?xadd:0))+","+(this.y+(yadd?yadd:0));};
/**
* @method rot rotates the coordinate around center and returns the result as a new Coord.
* @param angle angle of rotation in degrees
* @param cntr optional centerpoint, otherwise uses 0,0
* @return a new Coord at the new rotation point
*/
this.rot = function (angle, cntr) {
var xa = this.x;
var xb = cntr?cntr.x:0;
var ya = this.y;
var yb = cntr?cntr.y:0;
var b = xb-xa; // change in y from rotation center to coord
var a = yb-ya; // change in x from rotation center to coord
if (angle == 180) return new Coord(xa, ya+a*2); // no need to rotate, and it bugs anyway
var slope = b==0?90:a==0?0:r2d(a/b);
var leg = a==0?b:b==0?a:Math.sqrt(Math.pow(leg,2)+Math.pow(b,2)); // get the hypotenuse of xa,ya-xb,yb right triangle
var legAngle = 90 - (angle/2); // angle opposite legs
// law of sines states sinA/a = sinB/b = sinC/c so sin(legAngle)/leg = sin(angle)/base
var base = Math.sin(d2r(angle))*leg/Math.sin(d2r(legAngle)); // length of base
// Now we just calculate x & y translation and return it as a new coordinate
return new Coord(Math.cos(d2r(180-slope-legAngle))*base+xa, Math.sin(d2r(180-slope-legAngle))*base+ya);
}
/**
* @method diff returns a new Coord that is the difference between this and other
* @param other a coord to compare to
* @return Coord the difference between this and other
*/
this.diff = function (other) {
return new Coord(other.x-this.x, other.y-this.y, other.z-this.z);
}
/**
* @method add adds value of this to other and returns new Cood
* @param other a Coord to add to
* @return Coord the sum of this and other
*/
this.add = function(other) {
return new Coord(this.x+other.x, this.y+other.y, this.z+other.z);
}
/**
* @method times multiplies coordinates of this by coordinates of other
* @param other the set of coordinates to multiply by
* @return Coord the resultant coordinates
*/
this.times = function(other) {
return new Coord(this.x*other.x, this.y*other.y, this.z*other.z);
}
/**
* @method flip flips the coordinate around center
* @param center the center point to flip across
* @return Coord the flipped coordinates
*/
this.flip = function(center) {
var diff = this.diff(center);
var times = diff.times(new Coord(-1,-1,-1));
return center.add(diff);
}
}
// Revealing Module Pattern
// This pattern progressively enhances a page by hooking onto events transparently,
// and also by managing public and private access to methods and properties.
// All public methods and properties are returned as an object from the main
// function, which is executed at run time automatically; initialization should
// be bound to an appropriate load or domready event. The template is compatible
// with any javascript framework, or by itself - but a framework is a huge
// help in simplifying event binding.
var rp2 = function() {
var paper;
var field;
var view;
var circles = [];
var path;
var flocking = false;
var flockLast;
// Some simple spatial functions. x & y return the width & height of the
// box, and if param update is true, will update it to match the new window
// size. cx & cy return calculated center x & y of the view.
var x = function(update) {
if(update) {
var x = this.x();
this.paper.node.setProperty('width', x);
this.bg.attr('width', x-this.bg.attr('rx'));
}
return this.field.getSize().x-10;
}
var y = function(update){
if(update) {
$('paperBox').setStyle('height', $$('body')[0].getSize().y);
var y = this.y();
this.paper.node.setProperty('height', y);
this.bg.attr('height', y-this.bg.attr('ry'));
}
return this.field.getSize().y-10;
}
var cx = function(){return this.x()/2;}
var cy = function(){return this.y()/2;}
// center coordinates
var cc = function() {return new Coord(this.cx(), this.cy());}
var bindObservers = function() {
unbindObservers();
// following causes an odd error: TypeError: obj.addEventListener is not a function
// need to debug and understand but for now commenting it out helps a LOT
//window.addEvent('resize', function(){rp2.x(1); rp2.y(1);});
document.addEvent('mousemove', function(event) {rp2.flockTo(event)});
rp2.path.node.addEvent('click', function(event) {rp2.flip()});
}
// Unbind observers needs to exactly mirror bindObservers
var unbindObservers = function() {
window.removeEvents('resize');
}
var build = function() {
$('paperBox').setStyle('height', $$('body')[0].getSize().y);
rp2.field = $('paperBox');
rp2.paper = Raphael(rp2.field, rp2.x(), rp2.y());
// IE can't support thi