luci-app-mwan3: add dependecy to size option
[project/luci.git] / libs / luci-lib-nixio / axTLS / www / index.html
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
3 <head>
4 <script type="text/javascript">
5 //<![CDATA[
6 var version = {major: 2, minor: 1, revision: 3, date: new Date("Nov 3, 2006"), extensions: {}};
7 //]]>
8 </script>
9 <!--
10 TiddlyWiki 2.1.3 by Jeremy Ruston, (jeremy [at] osmosoft [dot] com)
11
12 Copyright (c) Osmosoft Limited 2004-2006
13
14 Redistribution and use in source and binary forms, with or without modification,
15 are permitted provided that the following conditions are met:
16
17 Redistributions of source code must retain the above copyright notice, this
18 list of conditions and the following disclaimer.
19
20 Redistributions in binary form must reproduce the above copyright notice, this
21 list of conditions and the following disclaimer in the documentation and/or other
22 materials provided with the distribution.
23
24 Neither the name of the Osmosoft Limited nor the names of its contributors may be
25 used to endorse or promote products derived from this software without specific
26 prior written permission.
27
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
29 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
30 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
31 SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
33 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
34 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
37 DAMAGE.
38 -->
39 <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
40 <!--PRE-HEAD-START-->
41 <!--{{{-->
42 <link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/>
43 <!--}}}-->
44 <!--PRE-HEAD-END-->
45 <title> axTLS Embedded SSL - changes, notes and errata </title>
46 <script type="text/javascript">
47 //<![CDATA[
48 // ---------------------------------------------------------------------------------
49 // Configuration repository
50 // ---------------------------------------------------------------------------------
51
52 // Miscellaneous options
53 var config = {
54         numRssItems: 20, // Number of items in the RSS feed
55         animFast: 0.12, // Speed for animations (lower == slower)
56         animSlow: 0.01, // Speed for EasterEgg animations
57         cascadeFast: 20, // Speed for cascade animations (higher == slower)
58         cascadeSlow: 60, // Speed for EasterEgg cascade animations
59         cascadeDepth: 5, // Depth of cascade animation
60         displayStartupTime: false // Whether to display startup time
61         };
62
63 // Messages
64 config.messages = {
65         messageClose: {},
66         dates: {}
67 };
68
69 // Options that can be set in the options panel and/or cookies
70 config.options = {
71         chkRegExpSearch: false,
72         chkCaseSensitiveSearch: false,
73         chkAnimate: true,
74         chkSaveBackups: true,
75         chkAutoSave: false,
76         chkGenerateAnRssFeed: false,
77         chkSaveEmptyTemplate: false,
78         chkOpenInNewWindow: true,
79         chkToggleLinks: false,
80         chkHttpReadOnly: true,
81         chkForceMinorUpdate: false,
82         chkConfirmDelete: true,
83         chkInsertTabs: false,
84         txtBackupFolder: "",
85         txtMainTab: "tabTimeline",
86         txtMoreTab: "moreTabAll",
87         txtMaxEditRows: "30"
88         };
89         
90 // List of notification functions to be called when certain tiddlers are changed or deleted
91 config.notifyTiddlers = [
92         {name: "StyleSheetLayout", notify: refreshStyles},
93         {name: "StyleSheetColors", notify: refreshStyles},
94         {name: "StyleSheet", notify: refreshStyles},
95         {name: "StyleSheetPrint", notify: refreshStyles},
96         {name: "PageTemplate", notify: refreshPageTemplate},
97         {name: "SiteTitle", notify: refreshPageTitle},
98         {name: "SiteSubtitle", notify: refreshPageTitle},
99         {name: "ColorPalette", notify: refreshColorPalette},
100         {name: null, notify: refreshDisplay}
101         ];
102
103 // Default tiddler templates
104 var DEFAULT_VIEW_TEMPLATE = 1;
105 var DEFAULT_EDIT_TEMPLATE = 2;
106 config.tiddlerTemplates = {
107         1: "ViewTemplate",
108         2: "EditTemplate"
109         };
110
111 // More messages (rather a legacy layout that shouldn't really be like this)
112 config.views = {
113         wikified: {
114                 tag: {}
115                 },
116         editor: {
117                 tagChooser: {}
118                 }
119         };
120
121 // Macros; each has a 'handler' member that is inserted later
122 config.macros = {
123         today: {},
124         version: {},
125         search: {sizeTextbox: 15},
126         tiddler: {},
127         tag: {},
128         tags: {},
129         tagging: {},
130         timeline: {},
131         allTags: {},
132         list: {
133                 all: {},
134                 missing: {},
135                 orphans: {},
136                 shadowed: {}
137                 },
138         closeAll: {},
139         permaview: {},
140         saveChanges: {},
141         slider: {},
142         option: {},
143         newTiddler: {},
144         newJournal: {},
145         sparkline: {},
146         tabs: {},
147         gradient: {},
148         message: {},
149         view: {},
150         edit: {},
151         tagChooser: {},
152         toolbar: {},
153         br: {},
154         plugins: {},
155         refreshDisplay: {},
156         importTiddlers: {}
157         };
158
159 // Commands supported by the toolbar macro
160 config.commands = {
161         closeTiddler: {},
162         closeOthers: {},
163         editTiddler: {},
164         saveTiddler: {hideReadOnly: true},
165         cancelTiddler: {},
166         deleteTiddler: {hideReadOnly: true},
167         permalink: {},
168         references: {},
169         jump: {}
170         };
171
172 // Browser detection... In a very few places, there's nothing else for it but to
173 // know what browser we're using.
174 config.userAgent = navigator.userAgent.toLowerCase();
175 config.browser = {
176         isIE: config.userAgent.indexOf("msie") != -1 && config.userAgent.indexOf("opera") == -1,
177         ieVersion: /MSIE (\d.\d)/i.exec(config.userAgent), // config.browser.ieVersion[1], if it exists, will be the IE version string, eg "6.0"
178         isSafari: config.userAgent.indexOf("applewebkit") != -1,
179         isBadSafari: !((new RegExp("[\u0150\u0170]","g")).test("\u0150")),
180         firefoxDate: /Gecko\/(\d{8})/i.exec(config.userAgent), // config.browser.firefoxDate[1], if it exists, will be Firefox release date as "YYYYMMDD"
181         isOpera: config.userAgent.indexOf("opera") != -1,
182         isLinux: config.userAgent.indexOf("linux") != -1,
183         isUnix: config.userAgent.indexOf("x11") != -1,
184         isMac: config.userAgent.indexOf("mac") != -1,
185         isWindows: config.userAgent.indexOf("win") != -1
186         };
187
188 // Basic regular expressions
189 config.textPrimitives = {
190         upperLetter: "[A-Z\u00c0-\u00de\u0150\u0170]",
191         lowerLetter: "[a-z0-9_\\-\u00df-\u00ff\u0151\u0171]",
192         anyLetter:   "[A-Za-z0-9_\\-\u00c0-\u00de\u00df-\u00ff\u0150\u0170\u0151\u0171]",
193         anyLetterStrict: "[A-Za-z0-9\u00c0-\u00de\u00df-\u00ff\u0150\u0170\u0151\u0171]"
194         };
195 if(config.browser.isBadSafari)
196         config.textPrimitives = {
197                 upperLetter: "[A-Z\u00c0-\u00de]",
198                 lowerLetter: "[a-z0-9_\\-\u00df-\u00ff]",
199                 anyLetter:   "[A-Za-z0-9_\\-\u00c0-\u00de\u00df-\u00ff]",
200                 anyLetterStrict: "[A-Za-z0-9\u00c0-\u00de\u00df-\u00ff]"
201                 }
202 config.textPrimitives.sliceSeparator = "::";
203 config.textPrimitives.urlPattern = "[a-z]{3,8}:[^\\s:'\"][^\\s'\"]*(?:/|\\b)";
204 config.textPrimitives.unWikiLink = "~";
205 config.textPrimitives.wikiLink = "(?:(?:" + config.textPrimitives.upperLetter + "+" +
206                                                                                                 config.textPrimitives.lowerLetter + "+" +
207                                                                                                 config.textPrimitives.upperLetter +
208                                                                                                 config.textPrimitives.anyLetter + "*)|(?:" +
209                                                                                                 config.textPrimitives.upperLetter + "{2,}" +
210                                                                                                 config.textPrimitives.lowerLetter + "+))";
211
212 config.textPrimitives.cssLookahead = "(?:(" + config.textPrimitives.anyLetter + "+)\\(([^\\)\\|\\n]+)(?:\\):))|(?:(" + config.textPrimitives.anyLetter + "+):([^;\\|\\n]+);)";
213 config.textPrimitives.cssLookaheadRegExp = new RegExp(config.textPrimitives.cssLookahead,"mg");
214
215 config.textPrimitives.brackettedLink = "\\[\\[([^\\]]+)\\]\\]";
216 config.textPrimitives.titledBrackettedLink = "\\[\\[([^\\[\\]\\|]+)\\|([^\\[\\]\\|]+)\\]\\]";
217 config.textPrimitives.tiddlerForcedLinkRegExp = new RegExp("(?:" + config.textPrimitives.titledBrackettedLink + ")|(?:" +
218         config.textPrimitives.brackettedLink + ")|(?:" + 
219         config.textPrimitives.urlPattern + ")","mg");
220 config.textPrimitives.tiddlerAnyLinkRegExp = new RegExp("("+ config.textPrimitives.wikiLink + ")|(?:" +
221         config.textPrimitives.titledBrackettedLink + ")|(?:" +
222         config.textPrimitives.brackettedLink + ")|(?:" +
223         config.textPrimitives.urlPattern + ")","mg");
224
225 // ---------------------------------------------------------------------------------
226 // Shadow tiddlers
227 // ---------------------------------------------------------------------------------
228
229 config.shadowTiddlers = {
230         ColorPalette: "Background: #fff\n" + 
231                                   "Foreground: #000\n" +
232                                   "PrimaryPale: #8cf\n" +
233                                   "PrimaryLight: #18f\n" +
234                                   "PrimaryMid: #04b\n" +
235                                   "PrimaryDark: #014\n" +
236                                   "SecondaryPale: #ffc\n" +
237                                   "SecondaryLight: #fe8\n" +
238                                   "SecondaryMid: #db4\n" +
239                                   "SecondaryDark: #841\n" +
240                                   "TertiaryPale: #eee\n" +
241                                   "TertiaryLight: #ccc\n" +
242                                   "TertiaryMid: #999\n" +
243                                   "TertiaryDark: #666\n" +
244                                   "Error: #f88\n",
245         StyleSheet: "",
246         StyleSheetColors: "/*{{{*/\nbody {\n    background: [[ColorPalette::Background]];\n     color: [[ColorPalette::Foreground]];\n}\n\na{\n color: [[ColorPalette::PrimaryMid]];\n}\n\na:hover{\n   background: [[ColorPalette::PrimaryMid]];\n     color: [[ColorPalette::Background]];\n}\n\na img{\n     border: 0;\n}\n\nh1,h2,h3,h4,h5 {\n     color: [[ColorPalette::SecondaryDark]];\n       background: [[ColorPalette::PrimaryPale]];\n}\n\n.button {\n    color: [[ColorPalette::PrimaryDark]];\n border: 1px solid [[ColorPalette::Background]];\n}\n\n.button:hover {\n color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::SecondaryLight]];\n border-color: [[ColorPalette::SecondaryMid]];\n}\n\n.button:active {\n  color: [[ColorPalette::Background]];\n  background: [[ColorPalette::SecondaryMid]];\n   border: 1px solid [[ColorPalette::SecondaryDark]];\n}\n\n.header {\n    background: [[ColorPalette::PrimaryMid]];\n}\n\n.headerShadow {\n       color: [[ColorPalette::Foreground]];\n}\n\n.headerShadow a {\n  font-weight: normal;\n  color: [[ColorPalette::Foreground]];\n}\n\n.headerForeground {\n        color: [[ColorPalette::Background]];\n}\n\n.headerForeground a {\n      font-weight: normal;\n  color: [[ColorPalette::PrimaryPale]];\n}\n\n.tabSelected{\n     color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::TertiaryPale]];\n   border-left: 1px solid [[ColorPalette::TertiaryLight]];\n       border-top: 1px solid [[ColorPalette::TertiaryLight]];\n        border-right: 1px solid [[ColorPalette::TertiaryLight]];\n}\n\n.tabUnselected {\n       color: [[ColorPalette::Background]];\n  background: [[ColorPalette::TertiaryMid]];\n}\n\n.tabContents {\n       color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::TertiaryPale]];\n   border: 1px solid [[ColorPalette::TertiaryLight]];\n}\n\n.tabContents .button {\n        border: 0;}\n\n#sidebar {\n}\n\n#sidebarOptions input {\n      border: 1px solid [[ColorPalette::PrimaryMid]];\n}\n\n#sidebarOptions .sliderPanel {\n  background: [[ColorPalette::PrimaryPale]];\n}\n\n#sidebarOptions .sliderPanel a {\n     border: none;\n color: [[ColorPalette::PrimaryMid]];\n}\n\n#sidebarOptions .sliderPanel a:hover {\n     color: [[ColorPalette::Background]];\n  background: [[ColorPalette::PrimaryMid]];\n}\n\n#sidebarOptions .sliderPanel a:active {\n       color: [[ColorPalette::PrimaryMid]];\n  background: [[ColorPalette::Background]];\n}\n\n.wizard {\n     background: [[ColorPalette::SecondaryLight]];\n border-top: 1px solid [[ColorPalette::SecondaryMid]];\n border-left: 1px solid [[ColorPalette::SecondaryMid]];\n}\n\n.wizard h1 {\n     color: [[ColorPalette::SecondaryDark]];\n}\n\n.wizard h2 {\n    color: [[ColorPalette::Foreground]];\n}\n\n.wizardStep {\n      background: [[ColorPalette::Background]];\n     border-top: 1px solid [[ColorPalette::SecondaryMid]];\n border-bottom: 1px solid [[ColorPalette::SecondaryMid]];\n      border-left: 1px solid [[ColorPalette::SecondaryMid]];\n}\n\n.wizard .button {\n        color: [[ColorPalette::Background]];\n  background: [[ColorPalette::PrimaryMid]];\n     border-top: 1px solid [[ColorPalette::PrimaryLight]];\n border-right: 1px solid [[ColorPalette::PrimaryDark]];\n        border-bottom: 1px solid [[ColorPalette::PrimaryDark]];\n       border-left: 1px solid [[ColorPalette::PrimaryLight]];\n}\n\n.wizard .button:hover {\n  color: [[ColorPalette::PrimaryLight]];\n        background: [[ColorPalette::PrimaryDark]];\n    border-color: [[ColorPalette::PrimaryLight]];\n}\n\n.wizard .button:active {\n  color: [[ColorPalette::Background]];\n  background: [[ColorPalette::PrimaryMid]];\n     border-top: 1px solid [[ColorPalette::PrimaryLight]];\n border-right: 1px solid [[ColorPalette::PrimaryDark]];\n        border-bottom: 1px solid [[ColorPalette::PrimaryDark]];\n       border-left: 1px solid [[ColorPalette::PrimaryLight]];\n}\n\n#messageArea {\n   border: 1px solid [[ColorPalette::SecondaryDark]];\n    background: [[ColorPalette::SecondaryMid]];\n   color: [[ColorPalette::PrimaryDark]];\n}\n\n#messageArea .button {\n    padding: 0.2em 0.2em 0.2em 0.2em;\n     color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::Background]];\n}\n\n.popup {\n      background: [[ColorPalette::PrimaryLight]];\n   border: 1px solid [[ColorPalette::PrimaryMid]];\n}\n\n.popup hr {\n     color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::PrimaryDark]];\n    border-bottom: 1px;\n}\n\n.listBreak div{\n     border-bottom: 1px solid [[ColorPalette::PrimaryDark]];\n}\n\n.popup li.disabled {\n    color: [[ColorPalette::PrimaryMid]];\n}\n\n.popup li a, .popup li a:visited {\n color: [[ColorPalette::TertiaryPale]];\n        border: none;\n}\n\n.popup li a:hover {\n       background: [[ColorPalette::PrimaryDark]];\n    color: [[ColorPalette::Background]];\n  border: none;\n}\n\n.tiddler .defaultCommand {\n font-weight: bold;\n}\n\n.shadow .title {\n    color: [[ColorPalette::TertiaryDark]];\n}\n\n.title {\n color: [[ColorPalette::SecondaryDark]];\n}\n\n.subtitle {\n     color: [[ColorPalette::TertiaryDark]];\n}\n\n.toolbar {\n       color: [[ColorPalette::PrimaryMid]];\n}\n\n.tagging, .tagged {\n        border: 1px solid [[ColorPalette::TertiaryPale]];\n     background-color: [[ColorPalette::TertiaryPale]];\n}\n\n.selected .tagging, .selected .tagged {\n       background-color: [[ColorPalette::TertiaryLight]];\n    border: 1px solid [[ColorPalette::TertiaryMid]];\n}\n\n.tagging .listTitle, .tagged .listTitle {\n      color: [[ColorPalette::PrimaryDark]];\n}\n\n.tagging .button, .tagged .button {\n               border: none;\n}\n\n.footer {\n color: [[ColorPalette::TertiaryLight]];\n}\n\n.selected .footer {\n     color: [[ColorPalette::TertiaryMid]];\n}\n\n.sparkline {\n      background: [[ColorPalette::PrimaryPale]];\n    border: 0;\n}\n\n.sparktick {\n background: [[ColorPalette::PrimaryDark]];\n}\n\n.error, .errorButton {\n       color: [[ColorPalette::Foreground]];\n  background: [[ColorPalette::Error]];\n}\n\n.warning {\n color: [[ColorPalette::Foreground]];\n  background: [[ColorPalette::SecondaryPale]];\n}\n\n.cascade {\n background: [[ColorPalette::TertiaryPale]];\n   color: [[ColorPalette::TertiaryMid]];\n border: 1px solid [[ColorPalette::TertiaryMid]];\n}\n\n.imageLink, #displayArea .imageLink {\n  background: transparent;\n}\n\n.viewer .listTitle {list-style-type: none; margin-left: -2em;}\n\n.viewer .button {\n    border: 1px solid [[ColorPalette::SecondaryMid]];\n}\n\n.viewer blockquote {\n  border-left: 3px solid [[ColorPalette::TertiaryDark]];\n}\n\n.viewer table {\n  border: 2px solid [[ColorPalette::TertiaryDark]];\n}\n\n.viewer th, thead td {\n        background: [[ColorPalette::SecondaryMid]];\n   border: 1px solid [[ColorPalette::TertiaryDark]];\n     color: [[ColorPalette::Background]];\n}\n\n.viewer td, .viewer tr {\n   border: 1px solid [[ColorPalette::TertiaryDark]];\n}\n\n.viewer pre {\n border: 1px solid [[ColorPalette::SecondaryLight]];\n   background: [[ColorPalette::SecondaryPale]];\n}\n\n.viewer code {\n     color: [[ColorPalette::SecondaryDark]];\n}\n\n.viewer hr {\n    border: 0;\n    border-top: dashed 1px [[ColorPalette::TertiaryDark]];\n        color: [[ColorPalette::TertiaryDark]];\n}\n\n.highlight, .marked {\n    background: [[ColorPalette::SecondaryLight]];\n}\n\n.editor input {\n   border: 1px solid [[ColorPalette::PrimaryMid]];\n}\n\n.editor textarea {\n      border: 1px solid [[ColorPalette::PrimaryMid]];\n       width: 100%;\n}\n\n.editorFooter {\n    color: [[ColorPalette::TertiaryMid]];\n}\n\n/*}}}*/",
247         StyleSheetLayout: "/*{{{*/\n* html .tiddler {\n    height: 1%;\n}\n\nbody {\n   font-size: .75em;\n     font-family: arial,helvetica;\n margin: 0;\n    padding: 0;\n}\n\nh1,h2,h3,h4,h5 {\n    font-weight: bold;\n    text-decoration: none;\n        padding-left: 0.4em;\n}\n\nh1 {font-size: 1.35em;}\nh2 {font-size: 1.25em;}\nh3 {font-size: 1.1em;}\nh4 {font-size: 1em;}\nh5 {font-size: .9em;}\n\nhr {\n      height: 1px;\n}\n\na{\n text-decoration: none;\n}\n\ndt {font-weight: bold;}\n\nol { list-style-type: decimal }\nol ol { list-style-type: lower-alpha }\nol ol ol { list-style-type: lower-roman }\nol ol ol ol { list-style-type: decimal }\nol ol ol ol ol { list-style-type: lower-alpha }\nol ol ol ol ol ol { list-style-type: lower-roman }\nol ol ol ol ol ol ol { list-style-type: decimal }\n\n.txtOptionInput {\n     width: 11em;\n}\n\n#contentWrapper .chkOptionInput {\n  border: 0;\n}\n\n.externalLink {\n      text-decoration: underline;\n}\n\n.indent {margin-left:3em;}\n.outdent {margin-left:3em; text-indent:-3em;}\ncode.escaped {white-space:nowrap;}\n\n.tiddlyLinkExisting {\n      font-weight: bold;\n}\n\n.tiddlyLinkNonExisting {\n     font-style: italic;\n}\n\n/* the 'a' is required for IE, otherwise it renders the whole tiddler a bold */\na.tiddlyLinkNonExisting.shadow {\n   font-weight: bold;\n}\n\n#mainMenu .tiddlyLinkExisting, \n#mainMenu .tiddlyLinkNonExisting,\n#sidebarTabs .tiddlyLinkNonExisting{\n font-weight: normal;\n font-style: normal;\n}\n\n#sidebarTabs .tiddlyLinkExisting {\n font-weight: bold;\n font-style: normal;\n}\n\n.header {\n            position: relative;\n}\n\n.header a:hover {\n   background: transparent;\n}\n\n.headerShadow {\n        position: relative;\n   padding: 4.5em 0em 1em 1em;\n   left: -1px;\n   top: -1px;\n}\n\n.headerForeground {\n  position: absolute;\n   padding: 4.5em 0em 1em 1em;\n   left: 0px;\n    top: 0px;\n}\n\n.siteTitle {\n  font-size: 3em;\n}\n\n.siteSubtitle {\n font-size: 1.2em;\n}\n\n#mainMenu {\n   position: absolute;\n   left: 0;\n      width: 10em;\n  text-align: right;\n    line-height: 1.6em;\n   padding: 1.5em 0.5em 0.5em 0.5em;\n     font-size: 1.1em;\n}\n\n#sidebar {\n    position: absolute;\n   right: 3px;\n   width: 16em;\n  font-size: .9em;\n}\n\n#sidebarOptions {\n      padding-top: 0.3em;\n}\n\n#sidebarOptions a {\n margin: 0em 0.2em;\n    padding: 0.2em 0.3em;\n display: block;\n}\n\n#sidebarOptions input {\n margin: 0.4em 0.5em;\n}\n\n#sidebarOptions .sliderPanel {\n     margin-left: 1em;\n     padding: 0.5em;\n       font-size: .85em;\n}\n\n#sidebarOptions .sliderPanel a {\n      font-weight: bold;\n    display: inline;\n      padding: 0;\n}\n\n#sidebarOptions .sliderPanel input {\n        margin: 0 0 .3em 0;\n}\n\n#sidebarTabs .tabContents {\n width: 15em;\n  overflow: hidden;\n}\n\n.wizard {\n     padding: 0.1em 0em 0em 2em;\n}\n\n.wizard h1 {\n        font-size: 2em;\n       font-weight: bold;\n    background: none;\n     padding: 0em 0em 0em 0em;\n     margin: 0.4em 0em 0.2em 0em;\n}\n\n.wizard h2 {\n       font-size: 1.2em;\n     font-weight: bold;\n    background: none;\n     padding: 0em 0em 0em 0em;\n     margin: 0.2em 0em 0.2em 0em;\n}\n\n.wizardStep {\n      padding: 1em 1em 1em 1em;\n}\n\n.wizard .button {\n     margin: 0.5em 0em 0em 0em;\n    font-size: 1.2em;\n}\n\n#messageArea {\nposition:absolute; top:0; right:0; margin: 0.5em; padding: 0.5em;\n}\n\n*[id='messageArea'] {\nposition:fixed !important; z-index:99;}\n\n.messageToolbar {\ndisplay: block;\ntext-align: right;\n}\n\n#messageArea a{\n        text-decoration: underline;\n}\n\n.popup {\n    font-size: .9em;\n      padding: 0.2em;\n       list-style: none;\n     margin: 0;\n}\n\n.popup hr {\n  display: block;\n       height: 1px;\n  width: auto;\n  padding: 0;\n   margin: 0.2em 0em;\n}\n\n.listBreak {\n font-size: 1px;\n       line-height: 1px;\n}\n\n.listBreak div {\n      margin: 2px 0;\n}\n\n.popup li.disabled {\n     padding: 0.2em;\n}\n\n.popup li a{\n    display: block;\n       padding: 0.2em;\n}\n\n.tabset {\n       padding: 1em 0em 0em 0.5em;\n}\n\n.tab {\n      margin: 0em 0em 0em 0.25em;\n   padding: 2px;\n}\n\n.tabContents {\n    padding: 0.5em;\n}\n\n.tabContents ul, .tabContents ol {\n      margin: 0;\n    padding: 0;\n}\n\n.txtMainTab .tabContents li {\n       list-style: none;\n}\n\n.tabContents li.listLink {\n     margin-left: .75em;\n}\n\n#displayArea {\n     margin: 1em 17em 0em 14em;\n}\n\n\n.toolbar {\n text-align: right;\n    font-size: .9em;\n      visibility: hidden;\n}\n\n.selected .toolbar {\n        visibility: visible;\n}\n\n.tiddler {\n padding: 1em 1em 0em 1em;\n}\n\n.missing .viewer,.missing .title {\n    font-style: italic;\n}\n\n.title {\n    font-size: 1.6em;\n     font-weight: bold;\n}\n\n.missing .subtitle {\n display: none;\n}\n\n.subtitle {\n      font-size: 1.1em;\n}\n\n.tiddler .button {\n    padding: 0.2em 0.4em;\n}\n\n.tagging {\nmargin: 0.5em 0.5em 0.5em 0;\nfloat: left;\ndisplay: none;\n}\n\n.isTag .tagging {\ndisplay: block;\n}\n\n.tagged {\nmargin: 0.5em;\nfloat: right;\n}\n\n.tagging, .tagged {\nfont-size: 0.9em;\npadding: 0.25em;\n}\n\n.tagging ul, .tagged ul {\nlist-style: none;margin: 0.25em;\npadding: 0;\n}\n\n.tagClear {\nclear: both;\n}\n\n.footer {\n      font-size: .9em;\n}\n\n.footer li {\ndisplay: inline;\n}\n\n* html .viewer pre {\n      width: 99%;\n   padding: 0 0 1em 0;\n}\n\n.viewer {\n   line-height: 1.4em;\n   padding-top: 0.5em;\n}\n\n.viewer .button {\n   margin: 0em 0.25em;\n   padding: 0em 0.25em;\n}\n\n.viewer blockquote {\n       line-height: 1.5em;\n   padding-left: 0.8em;\n  margin-left: 2.5em;\n}\n\n.viewer ul, .viewer ol{\n     margin-left: 0.5em;\n   padding-left: 1.5em;\n}\n\n.viewer table {\n    border-collapse: collapse;\n    margin: 0.8em 1.0em;\n}\n\n.viewer th, .viewer td, .viewer tr,.viewer caption{\n        padding: 3px;\n}\n\n.viewer table.listView {\n  font-size: 0.85em;\n    margin: 0.8em 1.0em;\n}\n\n.viewer table.listView th, .viewer table.listView td, .viewer table.listView tr {\n  padding: 0px 3px 0px 3px;\n}\n\n.viewer pre {\n padding: 0.5em;\n       margin-left: 0.5em;\n   font-size: 1.2em;\n     line-height: 1.4em;\n   overflow: auto;\n}\n\n.viewer code {\n  font-size: 1.2em;\n     line-height: 1.4em;\n}\n\n.editor {\nfont-size: 1.1em;\n}\n\n.editor input, .editor textarea {\n        display: block;\n       width: 100%;\n  font: inherit;\n}\n\n.editorFooter {\n  padding: 0.25em 0em;\n  font-size: .9em;\n}\n\n.editorFooter .button {\npadding-top: 0px; padding-bottom: 0px;}\n\n.fieldsetFix {border: 0;\npadding: 0;\nmargin: 1px 0px 1px 0px;\n}\n\n.sparkline {\n line-height: 1em;\n}\n\n.sparktick {\n  outline: 0;\n}\n\n.zoomer {\n   font-size: 1.1em;\n     position: absolute;\n   padding: 1em;\n}\n\n.cascade {\n        font-size: 1.1em;\n     position: absolute;\n   overflow: hidden;\n}\n/*}}}*/",
248         StyleSheetPrint: "/*{{{*/\n@media print {\n#mainMenu, #sidebar, #messageArea, .toolbar {display: none ! important;}\n#displayArea {margin: 1em 1em 0em 1em;}\n/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */\nnoscript {display:none;}\n}\n/*}}}*/",
249         PageTemplate: "<!--{{{-->\n<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>\n<div class='headerShadow'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;\n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n<div class='headerForeground'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;\n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n</div>\n<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>\n<div id='sidebar'>\n<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>\n<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>\n</div>\n<div id='displayArea'>\n<div id='messageArea'></div>\n<div id='tiddlerDisplay'></div>\n</div>\n<!--}}}-->",
250         ViewTemplate: "<!--{{{-->\n<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler permalink references jump'></div>\n<div class='title' macro='view title'></div>\n<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date [[DD MMM YYYY]]'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date [[DD MMM YYYY]]'></span>)</div>\n<div class='tagging' macro='tagging'></div>\n<div class='tagged' macro='tags'></div>\n<div class='viewer' macro='view text wikified'></div>\n<div class='tagClear'></div>\n<!--}}}-->",
251         EditTemplate: "<!--{{{-->\n<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'></div>\n<div class='title' macro='view title'></div>\n<div class='editor' macro='edit title'></div>\n<div class='editor' macro='edit text'></div>\n<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>\n<!--}}}-->",
252         MarkupPreHead: "<!--{{{-->\n<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/>\n<!--}}}-->",
253         MarkupPostHead: "",
254         MarkupPreBody: "",
255         MarkupPostBody: ""
256         };
257
258 // ---------------------------------------------------------------------------------
259 // Translateable strings
260 // ---------------------------------------------------------------------------------
261
262 // Strings in "double quotes" should be translated; strings in 'single quotes' should be left alone
263
264 merge(config.options,{
265         txtUserName: "YourName"});
266
267 merge(config.messages,{
268         customConfigError: "Problems were encountered loading plugins. See PluginManager for details",
269         pluginError: "Error: %0",
270         pluginDisabled: "Not executed because disabled via 'systemConfigDisable' tag",
271         pluginForced: "Executed because forced via 'systemConfigForce' tag",
272         pluginVersionError: "Not executed because this plugin needs a newer version of TiddlyWiki",
273         nothingSelected: "Nothing is selected. You must select one or more items first",
274         savedSnapshotError: "It appears that this TiddlyWiki has been incorrectly saved. Please see http://www.tiddlywiki.com/#DownloadSoftware for details",
275         subtitleUnknown: "(unknown)",
276         undefinedTiddlerToolTip: "The tiddler '%0' doesn't yet exist",
277         shadowedTiddlerToolTip: "The tiddler '%0' doesn't yet exist, but has a pre-defined shadow value",
278         tiddlerLinkTooltip: "%0 - %1, %2",
279         externalLinkTooltip: "External link to %0",
280         noTags: "There are no tagged tiddlers",
281         notFileUrlError: "You need to save this TiddlyWiki to a file before you can save changes",
282         cantSaveError: "It's not possible to save changes. This could be because your browser doesn't support saving (instead, use FireFox if you can), or because the pathname to your TiddlyWiki file contains illegal characters",
283         invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki",
284         backupSaved: "Backup saved",
285         backupFailed: "Failed to save backup file",
286         rssSaved: "RSS feed saved",
287         rssFailed: "Failed to save RSS feed file",
288         emptySaved: "Empty template saved",
289         emptyFailed: "Failed to save empty template file",
290         mainSaved: "Main TiddlyWiki file saved",
291         mainFailed: "Failed to save main TiddlyWiki file. Your changes have not been saved",
292         macroError: "Error in macro <<%0>>",
293         macroErrorDetails: "Error while executing macro <<%0>>:\n%1",
294         missingMacro: "No such macro",
295         overwriteWarning: "A tiddler named '%0' already exists. Choose OK to overwrite it",
296         unsavedChangesWarning: "WARNING! There are unsaved changes in TiddlyWiki\n\nChoose OK to save\nChoose CANCEL to discard",
297         confirmExit: "--------------------------------\n\nThere are unsaved changes in TiddlyWiki. If you continue you will lose those changes\n\n--------------------------------",
298         saveInstructions: "SaveChanges",
299         unsupportedTWFormat: "Unsupported TiddlyWiki format '%0'",
300         tiddlerSaveError: "Error when saving tiddler '%0'",
301         tiddlerLoadError: "Error when loading tiddler '%0'",
302         wrongSaveFormat: "Cannot save with storage format '%0'. Using standard format for save.",
303         invalidFieldName: "Invalid field name %0",
304         fieldCannotBeChanged: "Field '%0' cannot be changed"});
305
306 merge(config.messages.messageClose,{
307         text: "close",
308         tooltip: "close this message area"});
309
310 config.messages.dates.months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November","December"];
311 config.messages.dates.days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
312 config.messages.dates.shortMonths = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
313 config.messages.dates.shortDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
314
315 merge(config.views.wikified.tag,{
316         labelNoTags: "no tags",
317         labelTags: "tags: ",
318         openTag: "Open tag '%0'",
319         tooltip: "Show tiddlers tagged with '%0'",
320         openAllText: "Open all",
321         openAllTooltip: "Open all of these tiddlers",
322         popupNone: "No other tiddlers tagged with '%0'"});
323
324 merge(config.views.wikified,{
325         defaultText: "The tiddler '%0' doesn't yet exist. Double-click to create it",
326         defaultModifier: "(missing)",
327         shadowModifier: "(built-in shadow tiddler)",
328         createdPrompt: "created"});
329
330 merge(config.views.editor,{
331         tagPrompt: "Type tags separated with spaces, [[use double square brackets]] if necessary, or add existing",
332         defaultText: "Type the text for '%0'"});
333
334 merge(config.views.editor.tagChooser,{
335         text: "tags",
336         tooltip: "Choose existing tags to add to this tiddler",
337         popupNone: "There are no tags defined",
338         tagTooltip: "Add the tag '%0'"});
339
340 merge(config.macros.search,{
341         label: "search",
342         prompt: "Search this TiddlyWiki",
343         accessKey: "F",
344         successMsg: "%0 tiddlers found matching %1",
345         failureMsg: "No tiddlers found matching %0"});
346
347 merge(config.macros.tagging,{
348         label: "tagging: ",
349         labelNotTag: "not tagging",
350         tooltip: "List of tiddlers tagged with '%0'"});
351
352 merge(config.macros.timeline,{
353         dateFormat: "DD MMM YYYY"});
354
355 merge(config.macros.allTags,{
356         tooltip: "Show tiddlers tagged with '%0'",
357         noTags: "There are no tagged tiddlers"});
358
359 config.macros.list.all.prompt = "All tiddlers in alphabetical order";
360 config.macros.list.missing.prompt = "Tiddlers that have links to them but are not defined";
361 config.macros.list.orphans.prompt = "Tiddlers that are not linked to from any other tiddlers";
362 config.macros.list.shadowed.prompt = "Tiddlers shadowed with default contents";
363
364 merge(config.macros.closeAll,{
365         label: "close all",
366         prompt: "Close all displayed tiddlers (except any that are being edited)"});
367
368 merge(config.macros.permaview,{
369         label: "permaview",
370         prompt: "Link to an URL that retrieves all the currently displayed tiddlers"});
371
372 merge(config.macros.saveChanges,{
373         label: "save changes",
374         prompt: "Save all tiddlers to create a new TiddlyWiki",
375         accessKey: "S"});
376
377 merge(config.macros.newTiddler,{
378         label: "new tiddler",
379         prompt: "Create a new tiddler",
380         title: "New Tiddler",
381         accessKey: "N"});
382
383 merge(config.macros.newJournal,{
384         label: "new journal",
385         prompt: "Create a new tiddler from the current date and time",
386         accessKey: "J"});
387
388 merge(config.macros.plugins,{
389         skippedText: "(This plugin has not been executed because it was added since startup)",
390         noPluginText: "There are no plugins installed",
391         confirmDeleteText: "Are you sure you want to delete these tiddlers:\n\n%0",
392         listViewTemplate : {
393                 columns: [
394                         {name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
395                         {name: 'Title', field: 'title', tiddlerLink: 'title', title: "Title", type: 'TiddlerLink'},
396                         {name: 'Forced', field: 'forced', title: "Forced", tag: 'systemConfigForce', type: 'TagCheckbox'},
397                         {name: 'Disabled', field: 'disabled', title: "Disabled", tag: 'systemConfigDisable', type: 'TagCheckbox'},
398                         {name: 'Executed', field: 'executed', title: "Loaded", type: 'Boolean', trueText: "Yes", falseText: "No"},
399                         {name: 'Error', field: 'error', title: "Status", type: 'Boolean', trueText: "Error", falseText: "OK"},
400                         {name: 'Log', field: 'log', title: "Log", type: 'StringList'}
401                         ],
402                 rowClasses: [
403                         {className: 'error', field: 'error'},
404                         {className: 'warning', field: 'warning'}
405                         ],
406                 actions: [
407                         {caption: "More actions...", name: ''},
408                         {caption: "Remove systemConfig tag", name: 'remove'},
409                         {caption: "Delete these tiddlers forever", name: 'delete'}
410                         ]}
411         });
412
413 merge(config.macros.refreshDisplay,{
414         label: "refresh",
415         prompt: "Redraw the entire TiddlyWiki display"
416         });
417
418 merge(config.macros.importTiddlers,{
419         readOnlyWarning: "You cannot import tiddlers into a read-only TiddlyWiki. Try opening the TiddlyWiki file from a file:// URL",
420         defaultPath: "http://www.tiddlywiki.com/index.html",
421         fetchLabel: "fetch",
422         fetchPrompt: "Fetch the tiddlywiki file",
423         fetchError: "There were problems fetching the tiddlywiki file",
424         confirmOverwriteText: "Are you sure you want to overwrite these tiddlers:\n\n%0",
425         wizardTitle: "Import tiddlers from another TiddlyWiki file",
426         step1: "Step 1: Locate the TiddlyWiki file",
427         step1prompt: "Enter the URL or pathname here: ",
428         step1promptFile: "...or browse for a file: ",
429         step1promptFeeds: "...or select a pre-defined feed: ",
430         step1feedPrompt: "Choose...",
431         step2: "Step 2: Loading TiddlyWiki file",
432         step2Text: "Please wait while the file is loaded from: %0",
433         step3: "Step 3: Choose the tiddlers to import",
434         step4: "%0 tiddler(s) imported",
435         step5: "Done",
436         listViewTemplate: {
437                 columns: [
438                         {name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
439                         {name: 'Title', field: 'title', title: "Title", type: 'String'},
440                         {name: 'Snippet', field: 'text', title: "Snippet", type: 'String'},
441                         {name: 'Tags', field: 'tags', title: "Tags", type: 'Tags'}
442                         ],
443                 rowClasses: [
444                         ],
445                 actions: [
446                         {caption: "More actions...", name: ''},
447                         {caption: "Import these tiddlers", name: 'import'}
448                         ]}
449         });
450
451 merge(config.commands.closeTiddler,{
452         text: "close",
453         tooltip: "Close this tiddler"});
454
455 merge(config.commands.closeOthers,{
456         text: "close others",
457         tooltip: "Close all other tiddlers"});
458
459 merge(config.commands.editTiddler,{
460         text: "edit",
461         tooltip: "Edit this tiddler",
462         readOnlyText: "view",
463         readOnlyTooltip: "View the source of this tiddler"});
464
465 merge(config.commands.saveTiddler,{
466         text: "done",
467         tooltip: "Save changes to this tiddler"});
468
469 merge(config.commands.cancelTiddler,{
470         text: "cancel",
471         tooltip: "Undo changes to this tiddler",
472         warning: "Are you sure you want to abandon your changes to '%0'?",
473         readOnlyText: "done",
474         readOnlyTooltip: "View this tiddler normally"});
475
476 merge(config.commands.deleteTiddler,{
477         text: "delete",
478         tooltip: "Delete this tiddler",
479         warning: "Are you sure you want to delete '%0'?"});
480
481 merge(config.commands.permalink,{
482         text: "permalink",
483         tooltip: "Permalink for this tiddler"});
484
485 merge(config.commands.references,{
486         text: "references",
487         tooltip: "Show tiddlers that link to this one",
488         popupNone: "No references"});
489
490 merge(config.commands.jump,{
491         text: "jump",
492         tooltip: "Jump to another open tiddler"});
493
494 merge(config.shadowTiddlers,{
495         DefaultTiddlers: "GettingStarted",
496         MainMenu: "GettingStarted",
497         SiteTitle: "My TiddlyWiki",
498         SiteSubtitle: "a reusable non-linear personal web notebook",
499         SiteUrl: "http://www.tiddlywiki.com/",
500         GettingStarted: "To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:\n* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)\n* MainMenu: The menu (usually on the left)\n* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened\nYou'll also need to enter your username for signing your edits: <<option txtUserName>>",
501         SideBarOptions: "<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal 'DD MMM YYYY'>><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel 'options ยป' 'Change TiddlyWiki advanced options'>>",
502         OptionsPanel: "These InterfaceOptions for customising TiddlyWiki are saved in your browser\n\nYour username for signing your edits. Write it as a WikiWord (eg JoeBloggs)\n\n<<option txtUserName>>\n<<option chkSaveBackups>> SaveBackups\n<<option chkAutoSave>> AutoSave\n<<option chkRegExpSearch>> RegExpSearch\n<<option chkCaseSensitiveSearch>> CaseSensitiveSearch\n<<option chkAnimate>> EnableAnimations\n\n----\nAdvancedOptions\nPluginManager\nImportTiddlers",
503         AdvancedOptions: "<<option chkGenerateAnRssFeed>> GenerateAnRssFeed\n<<option chkOpenInNewWindow>> OpenLinksInNewWindow\n<<option chkSaveEmptyTemplate>> SaveEmptyTemplate\n<<option chkToggleLinks>> Clicking on links to tiddlers that are already open causes them to close\n^^(override with Control or other modifier key)^^\n<<option chkHttpReadOnly>> HideEditingFeatures when viewed over HTTP\n<<option chkForceMinorUpdate>> Treat edits as MinorChanges by preserving date and time\n^^(override with Shift key when clicking 'done' or by pressing Ctrl-Shift-Enter^^\n<<option chkConfirmDelete>> ConfirmBeforeDeleting\nMaximum number of lines in a tiddler edit box: <<option txtMaxEditRows>>\nFolder name for backup files: <<option txtBackupFolder>>\n<<option chkInsertTabs>> Use tab key to insert tab characters instead of jumping to next field",
504         SideBarTabs: "<<tabs txtMainTab Timeline Timeline TabTimeline All 'All tiddlers' TabAll Tags 'All tags' TabTags More 'More lists' TabMore>>",
505         TabTimeline: "<<timeline>>",
506         TabAll: "<<list all>>",
507         TabTags: "<<allTags>>",
508         TabMore: "<<tabs txtMoreTab Missing 'Missing tiddlers' TabMoreMissing Orphans 'Orphaned tiddlers' TabMoreOrphans Shadowed 'Shadowed tiddlers' TabMoreShadowed>>",
509         TabMoreMissing: "<<list missing>>",
510         TabMoreOrphans: "<<list orphans>>",
511         TabMoreShadowed: "<<list shadowed>>",
512         PluginManager: "<<plugins>>",
513         ImportTiddlers: "<<importTiddlers>>"});
514
515 // ---------------------------------------------------------------------------------
516 // Main
517 // ---------------------------------------------------------------------------------
518
519 var params = null; // Command line parameters
520 var store = null; // TiddlyWiki storage
521 var story = null; // Main story
522 var formatter = null; // Default formatters for the wikifier
523 config.parsers = {}; // Hashmap of alternative parsers for the wikifier
524 var anim = new Animator(); // Animation engine
525 var readOnly = false; // Whether we're in readonly mode
526 var highlightHack = null; // Embarrassing hack department...
527 var hadConfirmExit = false; // Don't warn more than once
528 var safeMode = false; // Disable all plugins and cookies
529 var installedPlugins = []; // Information filled in when plugins are executed
530 var startingUp = false; // Whether we're in the process of starting up
531 var pluginInfo,tiddler; // Used to pass information to plugins in loadPlugins()
532
533 // Whether to use the JavaSaver applet
534 var useJavaSaver = config.browser.isSafari || config.browser.isOpera;
535
536 // Starting up
537 function main()
538 {
539         var now, then = new Date();
540         startingUp = true;
541         window.onbeforeunload = function(e) {if(window.confirmExit) return confirmExit();};
542         params = getParameters();
543         if(params)
544                 params = params.parseParams("open",null,false);
545         store = new TiddlyWiki();
546         invokeParamifier(params,"oninit");
547         story = new Story("tiddlerDisplay","tiddler");
548         addEvent(document,"click",Popup.onDocumentClick);
549         saveTest();
550         loadOptionsCookie();
551         for(var s=0; s<config.notifyTiddlers.length; s++)
552                 store.addNotification(config.notifyTiddlers[s].name,config.notifyTiddlers[s].notify);
553         store.loadFromDiv("storeArea","store",true);
554         invokeParamifier(params,"onload");
555         var pluginProblem = loadPlugins();
556         formatter = new Formatter(config.formatters);
557         readOnly = (window.location.protocol == "file:") ? false : config.options.chkHttpReadOnly;
558         invokeParamifier(params,"onconfig");
559         store.notifyAll();
560         restart();
561         if(pluginProblem)
562                 {
563                 story.displayTiddler(null,"PluginManager");
564                 displayMessage(config.messages.customConfigError);
565                 }
566         now = new Date();
567         if(config.displayStartupTime)
568                 displayMessage("TiddlyWiki startup in " + (now-then)/1000 + " seconds");
569         startingUp = false;
570 }
571
572 // Restarting
573 function restart()
574 {
575         invokeParamifier(params,"onstart");
576         if(story.isEmpty())
577                 {
578                 var defaultParams = store.getTiddlerText("DefaultTiddlers").parseParams("open",null,false);
579                 invokeParamifier(defaultParams,"onstart");
580                 }
581         window.scrollTo(0,0);
582 }
583
584 function saveTest()
585 {
586         var saveTest = document.getElementById("saveTest");
587         if(saveTest.hasChildNodes())
588                 alert(config.messages.savedSnapshotError);
589         saveTest.appendChild(document.createTextNode("savetest"));
590 }
591
592 function loadPlugins()
593 {
594         if(safeMode)
595                 return false;
596         var configTiddlers = store.getTaggedTiddlers("systemConfig");
597         installedPlugins = [];
598         var hadProblem = false;
599         for(var t=0; t<configTiddlers.length; t++)
600                 {
601                 tiddler = configTiddlers[t];
602                 pluginInfo = getPluginInfo(tiddler);
603                 if(isPluginExecutable(pluginInfo))
604                         {
605                         pluginInfo.executed = true;
606                         pluginInfo.error = false;
607                         try
608                                 {
609                                 if(tiddler.text && tiddler.text != "")
610                                         window.eval(tiddler.text);
611                                 }
612                         catch(e)
613                                 {
614                                 pluginInfo.log.push(config.messages.pluginError.format([exceptionText(e)]));
615                                 pluginInfo.error = true;
616                                 hadProblem = true;
617                                 }
618                         }
619                 else
620                         pluginInfo.warning = true;
621                 installedPlugins.push(pluginInfo);
622                 }
623         return hadProblem;
624 }
625
626 function getPluginInfo(tiddler)
627 {
628         var p = store.getTiddlerSlices(tiddler.title,["Name","Description","Version","CoreVersion","Date","Source","Author","License","Browsers"]);
629         p.tiddler = tiddler;
630         p.title = tiddler.title;
631         p.log = [];
632         return p;
633 }
634
635 // Check that a particular plugin is valid for execution
636 function isPluginExecutable(plugin)
637 {
638         if(plugin.tiddler.isTagged("systemConfigDisable"))
639                 return verifyTail(plugin,false,config.messages.pluginDisabled);
640         if(plugin.tiddler.isTagged("systemConfigForce"))
641                 return verifyTail(plugin,true,config.messages.pluginForced);
642         if(plugin["CoreVersion"])
643                 {
644                 var coreVersion = plugin["CoreVersion"].split(".");
645                 var w = parseInt(coreVersion[0]) - version.major;
646                 if(w == 0 && coreVersion[1])
647                         w = parseInt(coreVersion[1]) - version.minor;
648                 if(w == 0 && coreVersion[2])
649                         w = parseInt(coreVersion[2]) - version.revision;
650                 if(w > 0)
651                         return verifyTail(plugin,false,config.messages.pluginVersionError);
652                 }
653         return true;
654 }
655
656 function verifyTail(plugin,result,message)
657 {
658         plugin.log.push(message);
659         return result;
660 }
661
662 function invokeMacro(place,macro,params,wikifier,tiddler)
663 {
664         try
665                 {
666                 var m = config.macros[macro];
667                 if(m && m.handler)
668                         m.handler(place,macro,params.readMacroParams(),wikifier,params,tiddler);
669                 else
670                         createTiddlyError(place,config.messages.macroError.format([macro]),config.messages.macroErrorDetails.format([macro,config.messages.missingMacro]));
671                 }
672         catch(ex)
673                 {
674                 createTiddlyError(place,config.messages.macroError.format([macro]),config.messages.macroErrorDetails.format([macro,ex.toString()]));
675                 }
676 }
677
678 // ---------------------------------------------------------------------------------
679 // Paramifiers
680 // ---------------------------------------------------------------------------------
681
682 function getParameters()
683 {
684         var p = null;
685         if(window.location.hash)
686                 {
687                 p = decodeURI(window.location.hash.substr(1));
688                 if(config.browser.firefoxDate != null && config.browser.firefoxDate[1] < "20051111")
689                         p = convertUTF8ToUnicode(p);
690                 }
691         return p;
692 }
693
694 function invokeParamifier(params,handler)
695 {
696         if(!params || params.length == undefined || params.length <= 1)
697                 return;
698         for(var t=1; t<params.length; t++)
699                 {
700                 var p = config.paramifiers[params[t].name];
701                 if(p && p[handler] instanceof Function)
702                         p[handler](params[t].value);
703                 }
704 }
705
706 config.paramifiers = {};
707
708 config.paramifiers.start = {
709         oninit: function(v) {
710                 safeMode = v.toLowerCase() == "safe";
711                 }
712 };
713
714 config.paramifiers.open = {
715         onstart: function(v) {
716                 story.displayTiddler("bottom",v,null,false,false);
717                 }
718 };
719
720 config.paramifiers.story = {
721         onstart: function(v) {
722                 var list = store.getTiddlerText(v,"").parseParams("open",null,false);
723                 invokeParamifier(list,"onstart");
724                 }
725 };
726
727 config.paramifiers.search = {
728         onstart: function(v) {
729                 story.search(v,false,false);
730                 }
731 };
732
733 config.paramifiers.searchRegExp = {
734         onstart: function(v) {
735                 story.prototype.search(v,false,true);
736                 }
737 };
738
739 config.paramifiers.tag = {
740         onstart: function(v) {
741                 var tagged = store.getTaggedTiddlers(v,"title");
742                 for(var t=0; t<tagged.length; t++)
743                         story.displayTiddler("bottom",tagged[t].title,null,false,false);
744                 }
745 };
746
747 config.paramifiers.newTiddler = {
748         onstart: function(v) {
749                 if(!readOnly)
750                         {
751                         story.displayTiddler(null,v,DEFAULT_EDIT_TEMPLATE);
752                         story.focusTiddler(v,"text");
753                         }
754                 }
755 };
756
757 config.paramifiers.newJournal = {
758         onstart: function(v) {
759                 if(!readOnly)
760                         {
761                         var now = new Date();
762                         var title = now.formatString(v.trim());
763                         story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE);
764                         story.focusTiddler(title,"text");
765                         }
766                 }
767 };
768
769 // ---------------------------------------------------------------------------------
770 // Formatter helpers
771 // ---------------------------------------------------------------------------------
772
773 function Formatter(formatters)
774 {
775         this.formatters = [];
776         var pattern = [];
777         for(var n=0; n<formatters.length; n++)
778                 {
779                 pattern.push("(" + formatters[n].match + ")");
780                 this.formatters.push(formatters[n]);
781                 }
782         this.formatterRegExp = new RegExp(pattern.join("|"),"mg");
783 }
784
785 config.formatterHelpers = {
786
787         createElementAndWikify: function(w)
788         {
789                 w.subWikifyTerm(createTiddlyElement(w.output,this.element),this.termRegExp);
790         },
791         
792         inlineCssHelper: function(w)
793         {
794                 var styles = [];
795                 config.textPrimitives.cssLookaheadRegExp.lastIndex = w.nextMatch;
796                 var lookaheadMatch = config.textPrimitives.cssLookaheadRegExp.exec(w.source);
797                 while(lookaheadMatch && lookaheadMatch.index == w.nextMatch)
798                         {
799                         var s,v;
800                         if(lookaheadMatch[1])
801                                 {
802                                 s = lookaheadMatch[1].unDash();
803                                 v = lookaheadMatch[2];
804                                 }
805                         else
806                                 {
807                                 s = lookaheadMatch[3].unDash();
808                                 v = lookaheadMatch[4];
809                                 }
810                         if (s=="bgcolor")
811                                 s = "backgroundColor";
812                         styles.push({style: s, value: v});
813                         w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
814                         config.textPrimitives.cssLookaheadRegExp.lastIndex = w.nextMatch;
815                         lookaheadMatch = config.textPrimitives.cssLookaheadRegExp.exec(w.source);
816                         }
817                 return styles;
818         },
819
820         applyCssHelper: function(e,styles)
821         {
822                 for(var t=0; t< styles.length; t++)
823                         {
824                         try
825                                 {
826                                 e.style[styles[t].style] = styles[t].value;
827                                 }
828                         catch (ex)
829                                 {
830                                 }
831                         }
832         },
833
834         enclosedTextHelper: function(w)
835         {
836                 this.lookaheadRegExp.lastIndex = w.matchStart;
837                 var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
838                 if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
839                         {
840                         var text = lookaheadMatch[1];
841                         if(config.browser.isIE)
842                                 text = text.replace(/\n/g,"\r");
843                         createTiddlyElement(w.output,this.element,null,null,text);
844                         w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
845                         }
846         },
847
848         isExternalLink: function(link)
849         {
850                 if(store.tiddlerExists(link) || store.isShadowTiddler(link))
851                         {
852                         //# Definitely not an external link
853                         return false;
854                         }
855                 var urlRegExp = new RegExp(config.textPrimitives.urlPattern,"mg");
856                 if(urlRegExp.exec(link))
857                         {
858                         // Definitely an external link
859                         return true;
860                         }
861                 if (link.indexOf(".")!=-1 || link.indexOf("\\")!=-1 || link.indexOf("/")!=-1)
862                         {
863                         //# Link contains . / or \ so is probably an external link
864                         return true;
865                         }
866                 //# Otherwise assume it is not an external link
867                 return false;
868         }
869
870 };
871
872 // ---------------------------------------------------------------------------------
873 // Standard formatters
874 // ---------------------------------------------------------------------------------
875
876 config.formatters = [
877 {
878         name: "table",
879         match: "^\\|(?:[^\\n]*)\\|(?:[fhck]?)$",
880         lookaheadRegExp: /^\|([^\n]*)\|([fhck]?)$/mg,
881         rowTermRegExp: /(\|(?:[fhck]?)$\n?)/mg,
882         cellRegExp: /(?:\|([^\n\|]*)\|)|(\|[fhck]?$\n?)/mg,
883         cellTermRegExp: /((?:\x20*)\|)/mg,
884         rowTypes: {"c":"caption", "h":"thead", "":"tbody", "f":"tfoot"},
885
886         handler: function(w)
887         {
888                 var table = createTiddlyElement(w.output,"table");
889                 var prevColumns = [];
890                 var currRowType = null;
891                 var rowContainer;
892                 var rowCount = 0;
893                 w.nextMatch = w.matchStart;
894                 this.lookaheadRegExp.lastIndex = w.nextMatch;
895                 var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
896                 while(lookaheadMatch && lookaheadMatch.index == w.nextMatch)
897                         {
898                         var nextRowType = lookaheadMatch[2];
899                         if(nextRowType == "k")
900                                 {
901                                 table.className = lookaheadMatch[1];
902                                 w.nextMatch += lookaheadMatch[0].length+1;
903                                 }
904                         else
905                                 {
906                                 if(nextRowType != currRowType)
907                                         {
908                                         rowContainer = createTiddlyElement(table,this.rowTypes[nextRowType]);
909                                         currRowType = nextRowType;
910                                         }
911                                 if(currRowType == "c")
912                                         {
913                                         // Caption
914                                         w.nextMatch++;
915                                         if(rowContainer != table.firstChild)
916                                                 table.insertBefore(rowContainer,table.firstChild);
917                                         rowContainer.setAttribute("align",rowCount == 0?"top":"bottom");
918                                         w.subWikifyTerm(rowContainer,this.rowTermRegExp);
919                                         }
920                                 else
921                                         {
922                                         this.rowHandler(w,createTiddlyElement(rowContainer,"tr",null,(rowCount&1)?"oddRow":"evenRow"),prevColumns);
923                                         rowCount++;
924                                         }
925                                 }
926                         this.lookaheadRegExp.lastIndex = w.nextMatch;
927                         lookaheadMatch = this.lookaheadRegExp.exec(w.source);
928                         }
929         },
930         rowHandler: function(w,e,prevColumns)
931         {
932                 var col = 0;
933                 var colSpanCount = 1;
934                 var prevCell = null;
935                 this.cellRegExp.lastIndex = w.nextMatch;
936                 var cellMatch = this.cellRegExp.exec(w.source);
937                 while(cellMatch && cellMatch.index == w.nextMatch)
938                         {
939                         if(cellMatch[1] == "~")
940                                 {
941                                 // Rowspan
942                                 var last = prevColumns[col];
943                                 if(last)
944                                         {
945                                         last.rowSpanCount++;
946                                         last.element.setAttribute("rowspan",last.rowSpanCount);
947                                         last.element.setAttribute("rowSpan",last.rowSpanCount); // Needed for IE
948                                         last.element.valign = "center";
949                                         }
950                                 w.nextMatch = this.cellRegExp.lastIndex-1;
951                                 }
952                         else if(cellMatch[1] == ">")
953                                 {
954                                 // Colspan
955                                 colSpanCount++;
956                                 w.nextMatch = this.cellRegExp.lastIndex-1;
957                                 }
958                         else if(cellMatch[2])
959                                 {
960                                 // End of row
961                                 if(prevCell && colSpanCount > 1)
962                                         {
963                                         prevCell.setAttribute("colspan",colSpanCount);
964                                         prevCell.setAttribute("colSpan",colSpanCount); // Needed for IE
965                                         }
966                                 w.nextMatch = this.cellRegExp.lastIndex;
967                                 break;
968                                 }
969                         else
970                                 {
971                                 // Cell
972                                 w.nextMatch++;
973                                 var styles = config.formatterHelpers.inlineCssHelper(w);
974                                 var spaceLeft = false;
975                                 var chr = w.source.substr(w.nextMatch,1);
976                                 while(chr == " ")
977                                         {
978                                         spaceLeft = true;
979                                         w.nextMatch++;
980                                         chr = w.source.substr(w.nextMatch,1);
981                                         }
982                                 var cell;
983                                 if(chr == "!")
984                                         {
985                                         cell = createTiddlyElement(e,"th");
986                                         w.nextMatch++;
987                                         }
988                                 else
989                                         cell = createTiddlyElement(e,"td");
990                                 prevCell = cell;
991                                 prevColumns[col] = {rowSpanCount:1, element:cell};
992                                 if(colSpanCount > 1)
993                                         {
994                                         cell.setAttribute("colspan",colSpanCount);
995                                         cell.setAttribute("colSpan",colSpanCount); // Needed for IE
996                                         colSpanCount = 1;
997                                         }
998                                 config.formatterHelpers.applyCssHelper(cell,styles);
999                                 w.subWikifyTerm(cell,this.cellTermRegExp);
1000                                 if(w.matchText.substr(w.matchText.length-2,1) == " ") // spaceRight
1001                                         cell.align = spaceLeft ? "center" : "left";
1002                                 else if(spaceLeft)
1003                                         cell.align = "right";
1004                                 w.nextMatch--;
1005                                 }
1006                         col++;
1007                         this.cellRegExp.lastIndex = w.nextMatch;
1008                         cellMatch = this.cellRegExp.exec(w.source);
1009                         }
1010         }
1011 },
1012
1013 {
1014         name: "heading",
1015         match: "^!{1,5}",
1016         termRegExp: /(\n)/mg,
1017         handler: function(w)
1018         {
1019                 w.subWikifyTerm(createTiddlyElement(w.output,"h" + w.matchLength),this.termRegExp);
1020         }
1021 },
1022
1023 {
1024         name: "list",
1025         match: "^(?:(?:(?:\\*)|(?:#)|(?:;)|(?::))+)",
1026         lookaheadRegExp: /^(?:(?:(\*)|(#)|(;)|(:))+)/mg,
1027         termRegExp: /(\n)/mg,
1028         handler: function(w)
1029         {
1030                 var placeStack = [w.output];
1031                 var currLevel = 0, currType = null;
1032                 var listLevel, listType, itemType;
1033                 w.nextMatch = w.matchStart;
1034                 this.lookaheadRegExp.lastIndex = w.nextMatch;
1035                 var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
1036                 while(lookaheadMatch && lookaheadMatch.index == w.nextMatch)
1037                         {
1038                         if(lookaheadMatch[1])
1039                                 {
1040                                 listType = "ul";
1041                                 itemType = "li";
1042                                 }
1043                         else if(lookaheadMatch[2])
1044                                 {
1045                                 listType = "ol";
1046                                 itemType = "li";
1047                                 }
1048                         else if(lookaheadMatch[3])
1049                                 {
1050                                 listType = "dl";
1051                                 itemType = "dt";
1052                                 }
1053                         else if(lookaheadMatch[4])
1054                                 {
1055                                 listType = "dl";
1056                                 itemType = "dd";
1057                                 }
1058                         listLevel = lookaheadMatch[0].length;
1059                         w.nextMatch += lookaheadMatch[0].length;
1060                         if(listLevel > currLevel)
1061                                 {
1062                                 for(var t=currLevel; t<listLevel; t++)
1063                                         placeStack.push(createTiddlyElement(placeStack[placeStack.length-1],listType));
1064                                 }
1065                         else if(listLevel < currLevel)
1066                                 {
1067                                 for(var t=currLevel; t>listLevel; t--)
1068                                         placeStack.pop();
1069                                 }
1070                         else if(listLevel == currLevel && listType != currType)
1071                                 {
1072                                 placeStack.pop();
1073                                 placeStack.push(createTiddlyElement(placeStack[placeStack.length-1],listType));
1074                                 }
1075                         currLevel = listLevel;
1076                         currType = listType;
1077                         var e = createTiddlyElement(placeStack[placeStack.length-1],itemType);
1078                         w.subWikifyTerm(e,this.termRegExp);
1079                         this.lookaheadRegExp.lastIndex = w.nextMatch;
1080                         lookaheadMatch = this.lookaheadRegExp.exec(w.source);
1081                 }
1082         }
1083 },
1084
1085 {
1086         name: "quoteByBlock",
1087         match: "^<<<\\n",
1088         termRegExp: /(^<<<(\n|$))/mg,
1089         element: "blockquote",
1090         handler: config.formatterHelpers.createElementAndWikify
1091 },
1092
1093 {
1094         name: "quoteByLine",
1095         match: "^>+",
1096         lookaheadRegExp: /^>+/mg,
1097         termRegExp: /(\n)/mg,
1098         element: "blockquote",
1099         handler: function(w)
1100         {
1101                 var placeStack = [w.output];
1102                 var currLevel = 0;
1103                 var newLevel = w.matchLength;
1104                 var t;
1105                 do {
1106                         if(newLevel > currLevel)
1107                                 {
1108                                 for(t=currLevel; t<newLevel; t++)
1109                                         placeStack.push(createTiddlyElement(placeStack[placeStack.length-1],this.element));
1110                                 }
1111                         else if(newLevel < currLevel)
1112                                 {
1113                                 for(t=currLevel; t>newLevel; t--)
1114                                         placeStack.pop();
1115                                 }
1116                         currLevel = newLevel;
1117                         w.subWikifyTerm(placeStack[placeStack.length-1],this.termRegExp);
1118                         createTiddlyElement(placeStack[placeStack.length-1],"br");
1119                         this.lookaheadRegExp.lastIndex = w.nextMatch;
1120                         var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
1121                         var matched = lookaheadMatch && lookaheadMatch.index == w.nextMatch;
1122                         if(matched)
1123                                 {
1124                                 newLevel = lookaheadMatch[0].length;
1125                                 w.nextMatch += lookaheadMatch[0].length;
1126                                 }
1127                 } while(matched);
1128         }
1129 },
1130
1131 {
1132         name: "rule",
1133         match: "^----+$\\n?",
1134         handler: function(w)
1135         {
1136                 createTiddlyElement(w.output,"hr");
1137         }
1138 },
1139
1140 {
1141         name: "monospacedByLine",
1142         match: "^\\{\\{\\{\\n",
1143         lookaheadRegExp: /^\{\{\{\n((?:^[^\n]*\n)+?)(^\}\}\}$\n?)/mg,
1144         element: "pre",
1145         handler: config.formatterHelpers.enclosedTextHelper
1146 },
1147
1148 {
1149         name: "monospacedByLineForCSS",
1150         match: "^/\\*[\\{]{3}\\*/\\n",
1151         lookaheadRegExp: /\/\*[\{]{3}\*\/\n*((?:^[^\n]*\n)+?)(\n*^\/\*[\}]{3}\*\/$\n?)/mg,
1152         element: "pre",
1153         handler: config.formatterHelpers.enclosedTextHelper
1154 },
1155
1156 {
1157         name: "monospacedByLineForPlugin",
1158         match: "^//\\{\\{\\{\\n",
1159         lookaheadRegExp: /^\/\/\{\{\{\n\n*((?:^[^\n]*\n)+?)(\n*^\/\/\}\}\}$\n?)/mg,
1160         element: "pre",
1161         handler: config.formatterHelpers.enclosedTextHelper
1162 },
1163
1164 {
1165         name: "monospacedByLineForTemplate",
1166         match: "^<!--[\\{]{3}-->\\n",
1167         lookaheadRegExp: /<!--[\{]{3}-->\n*((?:^[^\n]*\n)+?)(\n*^<!--[\}]{3}-->$\n?)/mg, 
1168         element: "pre",
1169         handler: config.formatterHelpers.enclosedTextHelper
1170 },
1171
1172 {
1173         name: "wikifyCommentForPlugin", 
1174         match: "^/\\*\\*\\*\\n",
1175         termRegExp: /(^\*\*\*\/\n)/mg,
1176         handler: function(w)
1177         {
1178                 w.subWikifyTerm(w.output,this.termRegExp);
1179         }
1180 },
1181
1182 {
1183         name: "wikifyCommentForTemplate", 
1184         match: "^<!---\\n",
1185         termRegExp: /(^--->\n)/mg,
1186         handler: function(w) 
1187         {
1188                 w.subWikifyTerm(w.output,this.termRegExp);
1189         }
1190 },
1191
1192 {
1193         name: "macro",
1194         match: "<<",
1195         lookaheadRegExp: /<<([^>\s]+)(?:\s*)((?:[^>]|(?:>(?!>)))*)>>/mg,
1196         handler: function(w)
1197         {
1198                 this.lookaheadRegExp.lastIndex = w.matchStart;
1199                 var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
1200                 if(lookaheadMatch && lookaheadMatch.index == w.matchStart && lookaheadMatch[1])
1201                         {
1202                         w.nextMatch = this.lookaheadRegExp.lastIndex;
1203                         invokeMacro(w.output,lookaheadMatch[1],lookaheadMatch[2],w,w.tiddler);
1204                         }
1205         }
1206 },
1207
1208 {
1209         name: "prettyLink",
1210         match: "\\[\\[",
1211         lookaheadRegExp: /\[\[(.*?)(?:\|(~)?(.*?))?\]\]/mg,
1212         handler: function(w)
1213         {
1214                 this.lookaheadRegExp.lastIndex = w.matchStart;
1215                 var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
1216                 if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
1217                         {
1218                         var e;
1219                         var text = lookaheadMatch[1];
1220                         if(lookaheadMatch[3])
1221                                 {
1222                                 // Pretty bracketted link
1223                                 var link = lookaheadMatch[3];
1224                                 e = (!lookaheadMatch[2] && config.formatterHelpers.isExternalLink(link))
1225                                                 ? createExternalLink(w.output,link)
1226                                                 : createTiddlyLink(w.output,link,false,null,w.isStatic);
1227                                 }
1228                         else
1229                                 {
1230                                 // Simple bracketted link
1231                                 e = createTiddlyLink(w.output,text,false,null,w.isStatic);
1232                                 }
1233                         createTiddlyText(e,text);
1234                         w.nextMatch = this.lookaheadRegExp.lastIndex;
1235                         }
1236         }
1237 },
1238
1239 {
1240         name: "unWikiLink",
1241         match: config.textPrimitives.unWikiLink+config.textPrimitives.wikiLink,
1242         handler: function(w)
1243         {
1244                 w.outputText(w.output,w.matchStart+1,w.nextMatch);
1245         }
1246 },
1247
1248 {
1249         name: "wikiLink",
1250         match: config.textPrimitives.wikiLink,
1251         handler: function(w)
1252         {
1253                 if(w.matchStart > 0)
1254                         {
1255                         var preRegExp = new RegExp(config.textPrimitives.anyLetterStrict,"mg");
1256                         preRegExp.lastIndex = w.matchStart-1;
1257                         var preMatch = preRegExp.exec(w.source);
1258                         if(preMatch.index == w.matchStart-1)
1259                                 {
1260                                 w.outputText(w.output,w.matchStart,w.nextMatch);
1261                                 return;
1262                                 }
1263                         }
1264                 if(w.autoLinkWikiWords == true || store.isShadowTiddler(w.matchText))
1265                         {
1266                         var link = createTiddlyLink(w.output,w.matchText,false,null,w.isStatic);
1267                         w.outputText(link,w.matchStart,w.nextMatch);
1268                         }
1269                 else
1270                         {
1271                         w.outputText(w.output,w.matchStart,w.nextMatch);
1272                         }
1273         }
1274 },
1275
1276 {
1277         name: "urlLink",
1278         match: config.textPrimitives.urlPattern,
1279         handler: function(w)
1280         {
1281                 w.outputText(createExternalLink(w.output,w.matchText),w.matchStart,w.nextMatch);
1282         }
1283 },
1284
1285 {
1286         name: "image",
1287         match: "\\[[<>]?[Ii][Mm][Gg]\\[",
1288         lookaheadRegExp: /\[(<?)(>?)[Ii][Mm][Gg]\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg,
1289         handler: function(w)
1290         {
1291                 this.lookaheadRegExp.lastIndex = w.matchStart;
1292                 var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
1293                 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) // Simple bracketted link
1294                         {
1295                         var e = w.output;
1296                         if(lookaheadMatch[5])
1297                                 {
1298                                 var link = lookaheadMatch[5];
1299                                 e = config.formatterHelpers.isExternalLink(link) ? createExternalLink(w.output,link) : createTiddlyLink(w.output,link,false,null,w.isStatic);
1300                                 addClass(e,"imageLink");
1301                                 }
1302                         var img = createTiddlyElement(e,"img");
1303                         if(lookaheadMatch[1])
1304                                 img.align = "left";
1305                         else if(lookaheadMatch[2])
1306                                 img.align = "right";
1307                         if(lookaheadMatch[3])
1308                                 img.title = lookaheadMatch[3];
1309                         img.src = lookaheadMatch[4];
1310                         w.nextMatch = this.lookaheadRegExp.lastIndex;
1311                         }
1312         }
1313 },
1314
1315 {
1316         name: "html",
1317         match: "<[Hh][Tt][Mm][Ll]>",
1318         lookaheadRegExp: /<[Hh][Tt][Mm][Ll]>((?:.|\n)*?)<\/[Hh][Tt][Mm][Ll]>/mg,
1319         handler: function(w)
1320         {
1321                 this.lookaheadRegExp.lastIndex = w.matchStart;
1322                 var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
1323                 if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
1324                         {
1325                         createTiddlyElement(w.output,"span").innerHTML = lookaheadMatch[1];
1326                         w.nextMatch = this.lookaheadRegExp.lastIndex;
1327                         }
1328         }
1329 },
1330
1331 {
1332         name: "commentByBlock",
1333         match: "/%",
1334         lookaheadRegExp: /\/%((?:.|\n)*?)%\//mg,
1335         handler: function(w)
1336         {
1337                 this.lookaheadRegExp.lastIndex = w.matchStart;
1338                 var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
1339                 if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
1340                         w.nextMatch = this.lookaheadRegExp.lastIndex;
1341         }
1342 },
1343
1344 {
1345         name: "boldByChar",
1346         match: "''",
1347         termRegExp: /('')/mg,
1348         element: "strong",
1349         handler: config.formatterHelpers.createElementAndWikify
1350 },
1351
1352 {
1353         name: "italicByChar",
1354         match: "//",
1355         termRegExp: /(\/\/)/mg,
1356         element: "em",
1357         handler: config.formatterHelpers.createElementAndWikify
1358 },
1359
1360 {
1361         name: "underlineByChar",
1362         match: "__",
1363         termRegExp: /(__)/mg,
1364         element: "u",
1365         handler: config.formatterHelpers.createElementAndWikify
1366 },
1367
1368 {
1369         name: "strikeByChar",
1370         match: "--(?!\\s|$)",
1371         termRegExp: /((?!\s)--|(?=\n\n))/mg,
1372         element: "strike",
1373         handler: config.formatterHelpers.createElementAndWikify
1374 },
1375
1376 {
1377         name: "superscriptByChar",
1378         match: "\\^\\^",
1379         termRegExp: /(\^\^)/mg,
1380         element: "sup",
1381         handler: config.formatterHelpers.createElementAndWikify
1382 },
1383
1384 {
1385         name: "subscriptByChar",
1386         match: "~~",
1387         termRegExp: /(~~)/mg,
1388         element: "sub",
1389         handler: config.formatterHelpers.createElementAndWikify
1390 },
1391
1392 {
1393         name: "monospacedByChar",
1394         match: "\\{\\{\\{",
1395         lookaheadRegExp: /\{\{\{((?:.|\n)*?)\}\}\}/mg,
1396         handler: function(w)
1397         {
1398                 this.lookaheadRegExp.lastIndex = w.matchStart;
1399                 var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
1400                 if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
1401                         {
1402                         createTiddlyElement(w.output,"code",null,null,lookaheadMatch[1]);
1403                         w.nextMatch = this.lookaheadRegExp.lastIndex;
1404                         }
1405         }
1406 },
1407
1408 {
1409         name: "styleByChar",
1410         match: "@@",
1411         termRegExp: /(@@)/mg,
1412         handler:  function(w)
1413         {
1414                 var e = createTiddlyElement(w.output,"span");
1415                 var styles = config.formatterHelpers.inlineCssHelper(w);
1416                 if(styles.length == 0)
1417                         e.className = "marked";
1418                 else
1419                         config.formatterHelpers.applyCssHelper(e,styles);
1420                 w.subWikifyTerm(e,this.termRegExp);
1421         }
1422 },
1423
1424 {
1425         name: "lineBreak",
1426         match: "\\n|<br ?/?>",
1427         handler: function(w)
1428         {
1429                 createTiddlyElement(w.output,"br");
1430         }
1431 },
1432
1433 {
1434         name: "rawText",
1435         match: "\\\"{3}|<nowiki>",
1436         lookaheadRegExp: /(?:\"{3}|<nowiki>)((?:.|\n)*?)(?:\"{3}|<\/nowiki>)/mg,
1437         handler: function(w)
1438         {
1439                 this.lookaheadRegExp.lastIndex = w.matchStart;
1440                 var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
1441                 if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
1442                         {
1443                         createTiddlyElement(w.output,"span",null,null,lookaheadMatch[1]);
1444                         w.nextMatch = this.lookaheadRegExp.lastIndex;
1445                         }
1446         }
1447 },
1448
1449 {
1450         name: "mdash",
1451         match: "--",
1452         handler: function(w)
1453                 {
1454                 createTiddlyElement(w.output,"span").innerHTML = "&mdash;";
1455                 }
1456 },
1457
1458 {
1459         name: "htmlEntitiesEncoding",
1460         match: "(?:(?:&#?[a-zA-Z0-9]{2,8};|.)(?:&#?(?:x0*(?:3[0-6][0-9a-fA-F]|1D[c-fC-F][0-9a-fA-F]|20[d-fD-F][0-9a-fA-F]|FE2[0-9a-fA-F])|0*(?:76[89]|7[7-9][0-9]|8[0-7][0-9]|761[6-9]|76[2-7][0-9]|84[0-3][0-9]|844[0-7]|6505[6-9]|6506[0-9]|6507[0-1]));)+|&#?[a-zA-Z0-9]{2,8};)",
1461         handler: function(w)
1462                 {
1463                 createTiddlyElement(w.output,"span").innerHTML = w.matchText;
1464                 }
1465 },
1466
1467 {
1468         name: "customClasses",
1469         match: "\\{\\{",
1470         termRegExp: /(\}\}\})/mg,
1471         lookaheadRegExp: /\{\{[\s]*([\w]+[\s\w]*)[\s]*\{(\n?)/mg,
1472         handler: function(w)
1473         {
1474                 this.lookaheadRegExp.lastIndex = w.matchStart;
1475                 var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
1476                 if(lookaheadMatch)
1477                         {
1478                         var e = createTiddlyElement(w.output,lookaheadMatch[2] == "\n" ? "div" : "span",null,lookaheadMatch[1]);
1479                         w.nextMatch = this.lookaheadRegExp.lastIndex;
1480                         w.subWikifyTerm(e,this.termRegExp);
1481                         }
1482         }
1483 }
1484
1485 ];
1486
1487 // ---------------------------------------------------------------------------------
1488 // Wikifier
1489 // ---------------------------------------------------------------------------------
1490
1491 function getParser(tiddler)
1492 {
1493         var f = formatter;
1494         if(tiddler!=null)
1495                 {
1496                 for(var i in config.parsers)
1497                         {
1498                         if(tiddler.isTagged(config.parsers[i].formatTag))
1499                                 {
1500                                 f = config.parsers[i];
1501                                 break;
1502                                 }
1503                         }
1504                 }
1505         return f;
1506 }
1507
1508 function wikify(source,output,highlightRegExp,tiddler)
1509 {
1510         if(source && source != "")
1511                 {
1512                 var wikifier = new Wikifier(source,getParser(tiddler),highlightRegExp,tiddler);
1513                 wikifier.subWikifyUnterm(output);
1514                 }
1515 }
1516
1517 function wikifyStatic(source,highlightRegExp,tiddler)
1518 {
1519         var e = createTiddlyElement(document.body,"div");
1520         e.style.display = "none";
1521         var html = "";
1522         if(source && source != "")
1523                 {
1524                 var wikifier = new Wikifier(source,getParser(tiddler),highlightRegExp,tiddler);
1525                 wikifier.isStatic = true;
1526                 wikifier.subWikifyUnterm(e);
1527                 html = e.innerHTML;
1528                 e.parentNode.removeChild(e);
1529                 }
1530         return html;
1531 }
1532
1533 // Wikify a named tiddler to plain text
1534 function wikifyPlain(title)
1535 {
1536         if(store.tiddlerExists(title) || store.isShadowTiddler(title))
1537                 {
1538                 var wikifier = new Wikifier(store.getTiddlerText(title),formatter,null,store.getTiddler(title));
1539                 return wikifier.wikifyPlain();
1540                 }
1541         else
1542                 return "";
1543 }
1544
1545 // Highlight plain text into an element
1546 function highlightify(source,output,highlightRegExp)
1547 {
1548         if(source && source != "")
1549                 {
1550                 var wikifier = new Wikifier(source,formatter,highlightRegExp);
1551                 wikifier.outputText(output,0,source.length);
1552                 }
1553 }
1554
1555 // Construct a wikifier object
1556 // source - source string that's going to be wikified
1557 // formatter - Formatter() object containing the list of formatters to be used
1558 // highlightRegExp - regular expression of the text string to highlight
1559 // tiddler - reference to the tiddler that's taken to be the container for this wikification
1560 function Wikifier(source,formatter,highlightRegExp,tiddler)
1561 {
1562         this.source = source;
1563         this.output = null;
1564         this.formatter = formatter;
1565         this.nextMatch = 0;
1566         this.autoLinkWikiWords = tiddler && tiddler.autoLinkWikiWords() == false ? false : true;
1567         this.highlightRegExp = highlightRegExp;
1568         this.highlightMatch = null;
1569         this.isStatic = false;
1570         if(highlightRegExp)
1571                 {
1572                 highlightRegExp.lastIndex = 0;
1573                 this.highlightMatch = highlightRegExp.exec(source);
1574                 }
1575         this.tiddler = tiddler;
1576 }
1577
1578 Wikifier.prototype.wikifyPlain = function()
1579 {
1580         var e = createTiddlyElement(document.body,"div");
1581         e.style.display = "none";
1582         this.subWikify(e);
1583         var text = getPlainText(e);
1584         e.parentNode.removeChild(e);
1585         return text;
1586 }
1587
1588 Wikifier.prototype.subWikify = function(output,terminator)
1589 {
1590         // Handle the terminated and unterminated cases separately
1591         if (terminator)
1592                 this.subWikifyTerm(output,new RegExp("(" + terminator + ")","mg"));
1593         else
1594                 this.subWikifyUnterm(output);
1595 }
1596
1597 Wikifier.prototype.subWikifyUnterm = function(output)
1598 {
1599         // subWikify() can be indirectly recursive, so we need to save the old output pointer
1600         var oldOutput = this.output;
1601         this.output = output;
1602         // Get the first match
1603         this.formatter.formatterRegExp.lastIndex = this.nextMatch;
1604         var formatterMatch = this.formatter.formatterRegExp.exec(this.source);
1605         while(formatterMatch)
1606                 {
1607                 // Output any text before the match
1608                 if(formatterMatch.index > this.nextMatch)
1609                         this.outputText(this.output,this.nextMatch,formatterMatch.index);
1610                 // Set the match parameters for the handler
1611                 this.matchStart = formatterMatch.index;
1612                 this.matchLength = formatterMatch[0].length;
1613                 this.matchText = formatterMatch[0];
1614                 this.nextMatch = this.formatter.formatterRegExp.lastIndex;
1615                 // Figure out which formatter matched and call its handler
1616                 for(var t=1; t<formatterMatch.length; t++)
1617                         {
1618                         if(formatterMatch[t])
1619                                 {
1620                                 this.formatter.formatters[t-1].handler(this);
1621                                 this.formatter.formatterRegExp.lastIndex = this.nextMatch;
1622                                 break;
1623                                 }
1624                         }
1625                 // Get the next match
1626                 formatterMatch = this.formatter.formatterRegExp.exec(this.source);
1627                 }
1628         // Output any text after the last match
1629         if(this.nextMatch < this.source.length)
1630                 {
1631                 this.outputText(this.output,this.nextMatch,this.source.length);
1632                 this.nextMatch = this.source.length;
1633                 }
1634         // Restore the output pointer
1635         this.output = oldOutput;
1636 }
1637
1638 Wikifier.prototype.subWikifyTerm = function(output,terminatorRegExp)
1639 {
1640         // subWikify() can be indirectly recursive, so we need to save the old output pointer
1641         var oldOutput = this.output;
1642         this.output = output;
1643         // Get the first matches for the formatter and terminator RegExps
1644         terminatorRegExp.lastIndex = this.nextMatch;
1645         var terminatorMatch = terminatorRegExp.exec(this.source);
1646         this.formatter.formatterRegExp.lastIndex = this.nextMatch;
1647         var formatterMatch = this.formatter.formatterRegExp.exec(terminatorMatch ? this.source.substr(0,terminatorMatch.index) : this.source);
1648         while(terminatorMatch || formatterMatch)
1649                 {
1650                 // Check for a terminator match  before the next formatter match
1651                 if(terminatorMatch && (!formatterMatch || terminatorMatch.index <= formatterMatch.index))
1652                         {
1653                         // Output any text before the match
1654                         if(terminatorMatch.index > this.nextMatch)
1655                                 this.outputText(this.output,this.nextMatch,terminatorMatch.index);
1656                         // Set the match parameters
1657                         this.matchText = terminatorMatch[1];
1658                         this.matchLength = terminatorMatch[1].length;
1659                         this.matchStart = terminatorMatch.index;
1660                         this.nextMatch = this.matchStart + this.matchLength;
1661                         // Restore the output pointer
1662                         this.output = oldOutput;
1663                         return;
1664                         }
1665                 // It must be a formatter match; output any text before the match
1666                 if(formatterMatch.index > this.nextMatch)
1667                         this.outputText(this.output,this.nextMatch,formatterMatch.index);
1668                 // Set the match parameters
1669                 this.matchStart = formatterMatch.index;
1670                 this.matchLength = formatterMatch[0].length;
1671                 this.matchText = formatterMatch[0];
1672                 this.nextMatch = this.formatter.formatterRegExp.lastIndex;
1673                 // Figure out which formatter matched and call its handler
1674                 for(var t=1; t<formatterMatch.length; t++)
1675                         {
1676                         if(formatterMatch[t])
1677                                 {
1678                                 this.formatter.formatters[t-1].handler(this);
1679                                 this.formatter.formatterRegExp.lastIndex = this.nextMatch;
1680                                 break;
1681                                 }
1682                         }
1683                 // Get the next match
1684                 terminatorRegExp.lastIndex = this.nextMatch;
1685                 terminatorMatch = terminatorRegExp.exec(this.source);
1686                 formatterMatch = this.formatter.formatterRegExp.exec(terminatorMatch ? this.source.substr(0,terminatorMatch.index) : this.source);
1687                 }
1688         // Output any text after the last match
1689         if(this.nextMatch < this.source.length)
1690                 {
1691                 this.outputText(this.output,this.nextMatch,this.source.length);
1692                 this.nextMatch = this.source.length;
1693                 }
1694         // Restore the output pointer
1695         this.output = oldOutput;
1696 }
1697
1698 Wikifier.prototype.outputText = function(place,startPos,endPos)
1699 {
1700         // Check for highlights
1701         while(this.highlightMatch && (this.highlightRegExp.lastIndex > startPos) && (this.highlightMatch.index < endPos) && (startPos < endPos))
1702                 {
1703                 // Deal with any plain text before the highlight
1704                 if(this.highlightMatch.index > startPos)
1705                         {
1706                         createTiddlyText(place,this.source.substring(startPos,this.highlightMatch.index));
1707                         startPos = this.highlightMatch.index;
1708                         }
1709                 // Deal with the highlight
1710                 var highlightEnd = Math.min(this.highlightRegExp.lastIndex,endPos);
1711                 var theHighlight = createTiddlyElement(place,"span",null,"highlight",this.source.substring(startPos,highlightEnd));
1712                 startPos = highlightEnd;
1713                 // Nudge along to the next highlight if we're done with this one
1714                 if(startPos >= this.highlightRegExp.lastIndex)
1715                         this.highlightMatch = this.highlightRegExp.exec(this.source);
1716                 }
1717         // Do the unhighlighted text left over
1718         if(startPos < endPos)
1719                 {
1720                 createTiddlyText(place,this.source.substring(startPos,endPos));
1721                 }
1722 }
1723
1724 // ---------------------------------------------------------------------------------
1725 // Macro definitions
1726 // ---------------------------------------------------------------------------------
1727
1728 config.macros.today.handler = function(place,macroName,params)
1729 {
1730         var now = new Date();
1731         var text;
1732         if(params[0])
1733                 text = now.formatString(params[0].trim());
1734         else
1735                 text = now.toLocaleString();
1736         createTiddlyElement(place,"span",null,null,text);
1737 }
1738
1739 config.macros.version.handler = function(place)
1740 {
1741         createTiddlyElement(place,"span",null,null,version.major + "." + version.minor + "." + version.revision + (version.beta ? " (beta " + version.beta + ")" : ""));
1742 }
1743
1744 config.macros.list.handler = function(place,macroName,params)
1745 {
1746         var type = params[0] ? params[0] : "all";
1747         var theList = document.createElement("ul");
1748         place.appendChild(theList);
1749         if(this[type].prompt)
1750                 createTiddlyElement(theList,"li",null,"listTitle",this[type].prompt);
1751         var results;
1752         if(this[type].handler)
1753                 results = this[type].handler(params);
1754         for(var t = 0; t < results.length; t++)
1755                 {
1756                 var theListItem = document.createElement("li")
1757                 theList.appendChild(theListItem);
1758                 if(typeof results[t] == "string")
1759                         createTiddlyLink(theListItem,results[t],true);
1760                 else
1761                         createTiddlyLink(theListItem,results[t].title,true);
1762                 }
1763 }
1764
1765 config.macros.list.all.handler = function(params)
1766 {
1767         return store.reverseLookup("tags","excludeLists",false,"title");
1768 }
1769
1770 config.macros.list.missing.handler = function(params)
1771 {
1772         return store.getMissingLinks();
1773 }
1774
1775 config.macros.list.orphans.handler = function(params)
1776 {
1777         return store.getOrphans();
1778 }
1779
1780 config.macros.list.shadowed.handler = function(params)
1781 {
1782         return store.getShadowed();
1783 }
1784
1785 config.macros.allTags.handler = function(place,macroName,params)
1786 {
1787         var tags = store.getTags();
1788         var theDateList = createTiddlyElement(place,"ul");
1789         if(tags.length == 0)
1790                 createTiddlyElement(theDateList,"li",null,"listTitle",this.noTags);
1791         for(var t=0; t<tags.length; t++)
1792                 {
1793                 var theListItem =createTiddlyElement(theDateList,"li");
1794                 var theTag = createTiddlyButton(theListItem,tags[t][0] + " (" + tags[t][1] + ")",this.tooltip.format([tags[t][0]]),onClickTag);
1795                 theTag.setAttribute("tag",tags[t][0]);
1796                 }
1797 }
1798
1799 config.macros.timeline.handler = function(place,macroName,params)
1800 {
1801         var field = params[0] ? params[0] : "modified";
1802         var tiddlers = store.reverseLookup("tags","excludeLists",false,field);
1803         var lastDay = "";
1804         var last = params[1] ? tiddlers.length-Math.min(tiddlers.length,parseInt(params[1])) : 0;
1805         for(var t=tiddlers.length-1; t>=last; t--)
1806                 {
1807                 var tiddler = tiddlers[t];
1808                 var theDay = tiddler[field].convertToLocalYYYYMMDDHHMM().substr(0,8);
1809                 if(theDay != lastDay)
1810                         {
1811                         var theDateList = document.createElement("ul");
1812                         place.appendChild(theDateList);
1813                         createTiddlyElement(theDateList,"li",null,"listTitle",tiddler[field].formatString(this.dateFormat));
1814                         lastDay = theDay;
1815                         }
1816                 var theDateListItem = createTiddlyElement(theDateList,"li",null,"listLink");
1817                 theDateListItem.appendChild(createTiddlyLink(place,tiddler.title,true));
1818                 }
1819 }
1820
1821 config.macros.search.handler = function(place,macroName,params)
1822 {
1823         var searchTimeout = null;
1824         var btn = createTiddlyButton(place,this.label,this.prompt,this.onClick);
1825         var txt = createTiddlyElement(place,"input",null,"txtOptionInput");
1826         if(params[0])
1827                 txt.value = params[0];
1828         txt.onkeyup = this.onKeyPress;
1829         txt.onfocus = this.onFocus;
1830         txt.setAttribute("size",this.sizeTextbox);
1831         txt.setAttribute("accessKey",this.accessKey);
1832         txt.setAttribute("autocomplete","off");
1833         txt.setAttribute("lastSearchText","");
1834         if(config.browser.isSafari)
1835                 {
1836                 txt.setAttribute("type","search");
1837                 txt.setAttribute("results","5");
1838                 }
1839         else
1840                 txt.setAttribute("type","text");
1841 }
1842
1843 // Global because there's only ever one outstanding incremental search timer
1844 config.macros.search.timeout = null;
1845
1846 config.macros.search.doSearch = function(txt)
1847 {
1848         if(txt.value.length > 0)
1849                 {
1850                 story.search(txt.value,config.options.chkCaseSensitiveSearch,config.options.chkRegExpSearch);
1851                 txt.setAttribute("lastSearchText",txt.value);
1852                 }
1853 }
1854
1855 config.macros.search.onClick = function(e)
1856 {
1857         config.macros.search.doSearch(this.nextSibling);
1858         return false;
1859 }
1860
1861 config.macros.search.onKeyPress = function(e)
1862 {
1863         if(!e) var e = window.event;
1864         switch(e.keyCode)
1865                 {
1866                 case 13: // Ctrl-Enter
1867                 case 10: // Ctrl-Enter on IE PC
1868                         config.macros.search.doSearch(this);
1869                         break;
1870                 case 27: // Escape
1871                         this.value = "";
1872                         clearMessage();
1873                         break;
1874                 }
1875         if(this.value.length > 2)
1876                 {
1877                 if(this.value != this.getAttribute("lastSearchText"))
1878                         {
1879                         if(config.macros.search.timeout)
1880                                 clearTimeout(config.macros.search.timeout);
1881                         var txt = this;
1882                         config.macros.search.timeout = setTimeout(function() {config.macros.search.doSearch(txt);},500);
1883                         }
1884                 }
1885         else
1886                 {
1887                 if(config.macros.search.timeout)
1888                         clearTimeout(config.macros.search.timeout);
1889                 }
1890 }
1891
1892 config.macros.search.onFocus = function(e)
1893 {
1894         this.select();
1895 }
1896
1897 config.macros.tiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler)
1898 {
1899         params = paramString.parseParams("name",null,true,false,true);
1900         var names = params[0]["name"];
1901         var tiddlerName = names[0];
1902         var className = names[1] ? names[1] : null;
1903         var args = params[0]["with"];
1904         var wrapper = createTiddlyElement(place,"span",null,className);
1905         if(!args)
1906                 {
1907                 wrapper.setAttribute("refresh","content");
1908                 wrapper.setAttribute("tiddler",tiddlerName);
1909                 }
1910         var text = store.getTiddlerText(tiddlerName);
1911         if(text)
1912                 {
1913                 var stack = config.macros.tiddler.tiddlerStack;
1914                 if(stack.indexOf(tiddlerName) !== -1)
1915                         return;
1916                 stack.push(tiddlerName);
1917                 try
1918                         {
1919                         var n = args ? Math.min(args.length,9) : 0;
1920                         for(var i=0; i<n; i++) 
1921                                 {
1922                                 var placeholderRE = new RegExp("\\$" + (i + 1),"mg");
1923                                 text = text.replace(placeholderRE,args[i]);
1924                                 }
1925                         config.macros.tiddler.renderText(wrapper,text,tiddlerName,params);
1926                         }
1927                 finally
1928                         {
1929                         stack.pop();
1930                         }
1931                 }
1932 }
1933
1934 config.macros.tiddler.renderText = function(place,text,tiddlerName,params) 
1935 {
1936         wikify(text,place,null,store.getTiddler(tiddlerName));
1937 }
1938
1939 config.macros.tiddler.tiddlerStack = [];
1940
1941 config.macros.tag.handler = function(place,macroName,params)
1942 {
1943         createTagButton(place,params[0]);
1944 }
1945
1946 config.macros.tags.handler = function(place,macroName,params,wikifier,paramString,tiddler)
1947 {
1948         params = paramString.parseParams("anon",null,true,false,false);
1949         var theList = createTiddlyElement(place,"ul");
1950         var title = getParam(params,"anon","");
1951         if(title && store.tiddlerExists(title))
1952                 tiddler = store.getTiddler(title);
1953         var sep = getParam(params,"sep"," ");
1954         var lingo = config.views.wikified.tag;
1955         var prompt = tiddler.tags.length == 0 ? lingo.labelNoTags : lingo.labelTags;
1956         createTiddlyElement(theList,"li",null,"listTitle",prompt.format([tiddler.title]));
1957         for(var t=0; t<tiddler.tags.length; t++)
1958                 {
1959                 createTagButton(createTiddlyElement(theList,"li"),tiddler.tags[t],tiddler.title);
1960                 if(t<tiddler.tags.length-1)
1961                         createTiddlyText(theList,sep);
1962                 }
1963 }
1964
1965 config.macros.tagging.handler = function(place,macroName,params,wikifier,paramString,tiddler)
1966 {
1967         params = paramString.parseParams("anon",null,true,false,false);
1968         var theList = createTiddlyElement(place,"ul");
1969         var title = getParam(params,"anon","");
1970         if(title == "" && tiddler instanceof Tiddler)
1971                 title = tiddler.title;
1972         var sep = getParam(params,"sep"," ");
1973         theList.setAttribute("title",this.tooltip.format([title]));
1974         var tagged = store.getTaggedTiddlers(title);
1975         var prompt = tagged.length == 0 ? this.labelNotTag : this.label;
1976         createTiddlyElement(theList,"li",null,"listTitle",prompt.format([title,tagged.length]));
1977         for(var t=0; t<tagged.length; t++)
1978                 {
1979                 createTiddlyLink(createTiddlyElement(theList,"li"),tagged[t].title,true);
1980                 if(t<tagged.length-1)
1981                         createTiddlyText(theList,sep);
1982                 }
1983 }
1984
1985 config.macros.closeAll.handler = function(place)
1986 {
1987         createTiddlyButton(place,this.label,this.prompt,this.onClick);
1988 }
1989
1990 config.macros.closeAll.onClick = function(e)
1991 {
1992         story.closeAllTiddlers();
1993         return false;
1994 }
1995
1996 config.macros.permaview.handler = function(place)
1997 {
1998         createTiddlyButton(place,this.label,this.prompt,this.onClick);
1999 }
2000
2001 config.macros.permaview.onClick = function(e)
2002 {
2003         story.permaView();
2004         return false;
2005 }
2006
2007 config.macros.saveChanges.handler = function(place)
2008 {
2009         if(!readOnly)
2010                 createTiddlyButton(place,this.label,this.prompt,this.onClick,null,null,this.accessKey);
2011 }
2012
2013 config.macros.saveChanges.onClick = function(e)
2014 {
2015         saveChanges();
2016         return false;
2017 }
2018
2019 config.macros.slider.onClickSlider = function(e)
2020 {
2021         if(!e) var e = window.event;
2022         var n = this.nextSibling;
2023         var cookie = n.getAttribute("cookie");
2024         var isOpen = n.style.display != "none";
2025         if(anim && config.options.chkAnimate)
2026                 anim.startAnimating(new Slider(n,!isOpen,e.shiftKey || e.altKey,"none"));
2027         else
2028                 n.style.display = isOpen ? "none" : "block";
2029         config.options[cookie] = !isOpen;
2030         saveOptionCookie(cookie);
2031         return false;
2032 }
2033
2034 config.macros.slider.createSlider = function(place,cookie,title,tooltip)
2035 {
2036         var cookie = cookie ? cookie : "";
2037         var btn = createTiddlyButton(place,title,tooltip,this.onClickSlider);
2038         var panel = createTiddlyElement(null,"div",null,"sliderPanel");
2039         panel.setAttribute("cookie",cookie);
2040         panel.style.display = config.options[cookie] ? "block" : "none";
2041         place.appendChild(panel);
2042         return panel;
2043 }
2044
2045 config.macros.slider.handler = function(place,macroName,params)
2046 {
2047         var panel = this.createSlider(place,params[0],params[2],params[3]);
2048         var text = store.getTiddlerText(params[1]);
2049         panel.setAttribute("refresh", "content");
2050         panel.setAttribute("tiddler", params[1]);
2051         if(text)
2052                 wikify(text,panel,null,store.getTiddler(params[1]));
2053 }
2054
2055 config.macros.option.onChangeOption = function(e)
2056 {
2057         var opt = this.getAttribute("option");
2058         var elementType,valueField;
2059         if(opt)
2060                 {
2061                 switch(opt.substr(0,3))
2062                         {
2063                         case "txt":
2064                                 elementType = "input";
2065                                 valueField = "value";
2066                                 break;
2067                         case "chk":
2068                                 elementType = "input";
2069                                 valueField = "checked";
2070                                 break;
2071                         }
2072                 config.options[opt] = this[valueField];
2073                 saveOptionCookie(opt);
2074                 var nodes = document.getElementsByTagName(elementType);
2075                 for(var t=0; t<nodes.length; t++)
2076                         {
2077                         var optNode = nodes[t].getAttribute("option");
2078                         if(opt == optNode)
2079                                 nodes[t][valueField] = this[valueField];
2080                         }
2081                 }
2082         return(true);
2083 }
2084
2085 config.macros.option.handler = function(place,macroName,params)
2086 {
2087         var opt = params[0];
2088         if(config.options[opt] == undefined)
2089                 return;
2090         var c;
2091         switch(opt.substr(0,3))
2092                 {
2093                 case "txt":
2094                         c = document.createElement("input");
2095                         c.onkeyup = this.onChangeOption;
2096                         c.setAttribute("option",opt);
2097                         c.className = "txtOptionInput";
2098                         place.appendChild(c);
2099                         c.value = config.options[opt];
2100                         break;
2101                 case "chk":
2102                         c = document.createElement("input");
2103                         c.setAttribute("type","checkbox");
2104                         c.onclick = this.onChangeOption;
2105                         c.setAttribute("option",opt);
2106                         c.className = "chkOptionInput";
2107                         place.appendChild(c);
2108                         c.checked = config.options[opt];
2109                         break;
2110                 }
2111 }
2112
2113
2114
2115 config.macros.newTiddler.createNewTiddlerButton = function(place,title,params,label,prompt,accessKey,newFocus,isJournal)
2116 {
2117         var tags = [];
2118         for(var t=1; t<params.length; t++)
2119                 if((params[t].name == "anon" && t != 1) || (params[t].name == "tag"))
2120                         tags.push(params[t].value);
2121         label = getParam(params,"label",label);
2122         prompt = getParam(params,"prompt",prompt);
2123         accessKey = getParam(params,"accessKey",accessKey);
2124         newFocus = getParam(params,"focus",newFocus);
2125         var btn = createTiddlyButton(place,label,prompt,this.onClickNewTiddler,null,null,accessKey);
2126         btn.setAttribute("newTitle",title);
2127         btn.setAttribute("isJournal",isJournal);
2128         btn.setAttribute("params",tags.join("|"));
2129         btn.setAttribute("newFocus",newFocus);
2130         btn.setAttribute("newTemplate",getParam(params,"template",DEFAULT_EDIT_TEMPLATE));
2131         var text = getParam(params,"text");
2132         if(text !== undefined) 
2133                 btn.setAttribute("newText",text);
2134         return btn;
2135 }
2136
2137 config.macros.newTiddler.onClickNewTiddler = function()
2138 {
2139         var title = this.getAttribute("newTitle");
2140         if(this.getAttribute("isJournal"))
2141                 {
2142                 var now = new Date();
2143                 title = now.formatString(title.trim());
2144                 }
2145         var params = this.getAttribute("params").split("|");
2146         var focus = this.getAttribute("newFocus");
2147         var template = this.getAttribute("newTemplate");
2148         story.displayTiddler(null,title,template);
2149         var text = this.getAttribute("newText");
2150         if(typeof text == "string")
2151                 story.getTiddlerField(title,"text").value = text.format([title]);
2152         for(var t=0;t<params.length;t++)
2153                 story.setTiddlerTag(title,params[t],+1);
2154         story.focusTiddler(title,focus);
2155         return false;
2156 }
2157
2158 config.macros.newTiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler)
2159 {
2160         if(!readOnly)
2161                 {
2162                 params = paramString.parseParams("anon",null,true,false,false);
2163                 var title = params[1] && params[1].name == "anon" ? params[1].value : this.title;
2164                 title = getParam(params,"title",title);
2165                 this.createNewTiddlerButton(place,title,params,this.label,this.prompt,this.accessKey,"title",false);
2166                 }
2167 }
2168
2169 config.macros.newJournal.handler = function(place,macroName,params,wikifier,paramString,tiddler)
2170 {
2171         if(!readOnly)
2172                 {
2173                 params = paramString.parseParams("anon",null,true,false,false);
2174                 var title = params[1] && params[1].name == "anon" ? params[1].value : "";
2175                 title = getParam(params,"title",title);
2176                 config.macros.newTiddler.createNewTiddlerButton(place,title,params,this.label,this.prompt,this.accessKey,"text",true);
2177                 }
2178 }
2179
2180 config.macros.sparkline.handler = function(place,macroName,params)
2181 {
2182         var data = [];
2183         var min = 0;
2184         var max = 0;
2185         for(var t=0; t<params.length; t++)
2186                 {
2187                 var v = parseInt(params[t]);
2188                 if(v < min)
2189                         min = v;
2190                 if(v > max)
2191                         max = v;
2192                 data.push(v);
2193                 }
2194         if(data.length < 1)
2195                 return;
2196         var box = createTiddlyElement(place,"span",null,"sparkline",String.fromCharCode(160));
2197         box.title = data.join(",");
2198         var w = box.offsetWidth;
2199         var h = box.offsetHeight;
2200         box.style.paddingRight = (data.length * 2 - w) + "px";
2201         box.style.position = "relative";
2202         for(var d=0; d<data.length; d++)
2203                 {
2204                 var tick = document.createElement("img");
2205                 tick.border = 0;
2206                 tick.className = "sparktick";
2207                 tick.style.position = "absolute";
2208                 tick.src = "data:image/gif,GIF89a%01%00%01%00%91%FF%00%FF%FF%FF%00%00%00%C0%C0%C0%00%00%00!%F9%04%01%00%00%02%00%2C%00%00%00%00%01%00%01%00%40%02%02T%01%00%3B";
2209                 tick.style.left = d*2 + "px";
2210                 tick.style.width = "2px";
2211                 var v = Math.floor(((data[d] - min)/(max-min)) * h);
2212                 tick.style.top = (h-v) + "px";
2213                 tick.style.height = v + "px";
2214                 box.appendChild(tick);
2215                 }
2216 }
2217
2218 config.macros.tabs.handler = function(place,macroName,params)
2219 {
2220         var cookie = params[0];
2221         var numTabs = (params.length-1)/3;
2222         var wrapper = createTiddlyElement(null,"div",null,cookie);
2223         var tabset = createTiddlyElement(wrapper,"div",null,"tabset");
2224         tabset.setAttribute("cookie",cookie);
2225         var validTab = false;
2226         for(var t=0; t<numTabs; t++)
2227                 {
2228                 var label = params[t*3+1];
2229                 var prompt = params[t*3+2];
2230                 var content = params[t*3+3];
2231                 var tab = createTiddlyButton(tabset,label,prompt,this.onClickTab,"tab tabUnselected");
2232                 tab.setAttribute("tab",label);
2233                 tab.setAttribute("content",content);
2234                 tab.title = prompt;
2235                 if(config.options[cookie] == label)
2236                         validTab = true;
2237                 }
2238         if(!validTab)
2239                 config.options[cookie] = params[1];
2240         place.appendChild(wrapper);
2241         this.switchTab(tabset,config.options[cookie]);
2242 }
2243
2244 config.macros.tabs.onClickTab = function(e)
2245 {
2246         config.macros.tabs.switchTab(this.parentNode,this.getAttribute("tab"));
2247         return false;
2248 }
2249
2250 config.macros.tabs.switchTab = function(tabset,tab)
2251 {
2252         var cookie = tabset.getAttribute("cookie");
2253         var theTab = null
2254         var nodes = tabset.childNodes;
2255         for(var t=0; t<nodes.length; t++)
2256                 if(nodes[t].getAttribute && nodes[t].getAttribute("tab") == tab)
2257                         {
2258                         theTab = nodes[t];
2259                         theTab.className = "tab tabSelected";
2260                         }
2261                 else
2262                         nodes[t].className = "tab tabUnselected"
2263         if(theTab)
2264                 {
2265                 if(tabset.nextSibling && tabset.nextSibling.className == "tabContents")
2266                         tabset.parentNode.removeChild(tabset.nextSibling);
2267                 var tabContent = createTiddlyElement(null,"div",null,"tabContents");
2268                 tabset.parentNode.insertBefore(tabContent,tabset.nextSibling);
2269                 var contentTitle = theTab.getAttribute("content");
2270                 wikify(store.getTiddlerText(contentTitle),tabContent,null,store.getTiddler(contentTitle));
2271                 if(cookie)
2272                         {
2273                         config.options[cookie] = tab;
2274                         saveOptionCookie(cookie);
2275                         }
2276                 }
2277 }
2278
2279 // <<gradient [[tiddler name]] vert|horiz rgb rgb rgb rgb... >>
2280 config.macros.gradient.handler = function(place,macroName,params,wikifier)
2281 {
2282         var terminator = ">>";
2283         var panel;
2284         if(wikifier)
2285                 panel = createTiddlyElement(place,"div",null,"gradient");
2286         else
2287                 panel = place;
2288         panel.style.position = "relative";
2289         panel.style.overflow = "hidden";
2290         panel.style.zIndex = "0";
2291         var t;
2292         if(wikifier)
2293                 {
2294                 var styles = config.formatterHelpers.inlineCssHelper(wikifier);
2295                 config.formatterHelpers.applyCssHelper(panel,styles);
2296                 }
2297         var colours = [];
2298         for(t=1; t<params.length; t++)
2299                 {
2300                 var c = new RGB(params[t]);
2301                 if(c)
2302                         colours.push(c);
2303                 }
2304         drawGradient(panel,params[0] != "vert",colours);
2305         if(wikifier)
2306                 wikifier.subWikify(panel,terminator);
2307         if(document.all)
2308                 {
2309                 panel.style.height = "100%";
2310                 panel.style.width = "100%";
2311                 }
2312 }
2313
2314 config.macros.message.handler = function(place,macroName,params)
2315 {
2316         if(params[0])
2317                 {
2318                 var m = config;
2319                 var p = params[0].split(".");
2320                 for(var t=0; t<p.length; t++)
2321                         {
2322                         if(p[t] in m)
2323                                 m = m[p[t]];
2324                         else
2325                                 break;
2326                         }
2327                 createTiddlyText(place,m.toString().format(params.splice(1)));
2328                 }
2329 }
2330
2331 config.macros.view.handler = function(place,macroName,params,wikifier,paramString,tiddler)
2332 {
2333         if((tiddler instanceof Tiddler) && params[0])
2334                 {
2335                 var value = store.getValue(tiddler,params[0]);
2336                 if(value != undefined)
2337                         switch(params[1])
2338                                 {
2339                                 case undefined:
2340                                         highlightify(value,place,highlightHack);
2341                                         break;
2342                                 case "link":
2343                                         createTiddlyLink(place,value,true);
2344                                         break;
2345                                 case "wikified":
2346                                         wikify(value,place,highlightHack,tiddler);
2347                                         break;
2348                                 case "date":
2349                                         value = Date.convertFromYYYYMMDDHHMM(value);
2350                                         if(params[2])
2351                                                 createTiddlyText(place,value.formatString(params[2]));
2352                                         else
2353                                                 createTiddlyText(place,value);
2354                                         break;
2355                                 }
2356                 }
2357 }
2358
2359 config.macros.edit.handler = function(place,macroName,params,wikifier,paramString,tiddler)
2360 {
2361         var field = params[0];
2362         if((tiddler instanceof Tiddler) && field)
2363                 {
2364                 story.setDirty(tiddler.title,true);
2365                 if(field != "text")
2366                         {
2367                                 var e = createTiddlyElement(null,"input");
2368                                 if(tiddler.isReadOnly())
2369                                         e.setAttribute("readOnly","readOnly");
2370                                 e.setAttribute("edit",field);
2371                                 e.setAttribute("type","text");
2372                                 var v = store.getValue(tiddler,field);
2373                                 if(!v) 
2374                                         v = "";
2375                                 e.value = v;
2376                                 e.setAttribute("size","40");
2377                                 e.setAttribute("autocomplete","off");
2378                                 place.appendChild(e);
2379                         }
2380                 else
2381                         {
2382                                 var wrapper1 = createTiddlyElement(null,"fieldset",null,"fieldsetFix");
2383                                 var wrapper2 = createTiddlyElement(wrapper1,"div");
2384                                 var e = createTiddlyElement(wrapper2,"textarea");
2385                                 if(tiddler.isReadOnly())
2386                                         e.setAttribute("readOnly","readOnly");
2387                                 var v = store.getValue(tiddler,field);
2388                                 if(!v) 
2389                                         v = "";
2390                                 e.value = v;
2391                                 var rows = 10;
2392                                 var lines = v.match(/\n/mg);
2393                                 var maxLines = Math.max(parseInt(config.options.txtMaxEditRows),5);
2394                                 if(lines != null && lines.length > rows)
2395                                         rows = lines.length + 5;
2396                                 rows = Math.min(rows,maxLines);
2397                                 e.setAttribute("rows",rows);
2398                                 e.setAttribute("edit",field);
2399                                 place.appendChild(wrapper1);
2400                         }
2401                 }
2402 }
2403
2404 config.macros.tagChooser.onClick = function(e)
2405 {
2406         if(!e) var e = window.event;
2407         var lingo = config.views.editor.tagChooser;
2408         var popup = Popup.create(this);
2409         var tags = store.getTags();
2410         if(tags.length == 0)
2411                 createTiddlyText(createTiddlyElement(popup,"li"),lingo.popupNone);
2412         for(var t=0; t<tags.length; t++)
2413                 {
2414                 var theTag = createTiddlyButton(createTiddlyElement(popup,"li"),tags[t][0],lingo.tagTooltip.format([tags[t][0]]),config.macros.tagChooser.onTagClick);
2415                 theTag.setAttribute("tag",tags[t][0]);
2416                 theTag.setAttribute("tiddler", this.getAttribute("tiddler"));
2417                 }
2418         Popup.show(popup,false);
2419         e.cancelBubble = true;
2420         if(e.stopPropagation) e.stopPropagation();
2421         return(false);
2422 }
2423
2424 config.macros.tagChooser.onTagClick = function(e)
2425 {
2426         if(!e) var e = window.event;
2427         var tag = this.getAttribute("tag");
2428         var title = this.getAttribute("tiddler");
2429         if(!readOnly)
2430                 story.setTiddlerTag(title,tag,0);
2431         return(false);
2432 }
2433
2434 config.macros.tagChooser.handler = function(place,macroName,params,wikifier,paramString,tiddler)
2435 {
2436         if(tiddler instanceof Tiddler)
2437                 {
2438                 var title = tiddler.title;
2439                 var lingo = config.views.editor.tagChooser;
2440                 var btn = createTiddlyButton(place,lingo.text,lingo.tooltip,this.onClick);
2441                 btn.setAttribute("tiddler", title);
2442                 }
2443 }
2444
2445 // Create a toolbar command button
2446 // place - parent DOM element
2447 // command - reference to config.commands[] member -or- name of member
2448 // tiddler - reference to tiddler that toolbar applies to
2449 // theClass - the class to give the button
2450 config.macros.toolbar.createCommand = function(place,commandName,tiddler,theClass)
2451 {
2452         if(typeof commandName != "string")
2453                 {
2454                 var c = null;
2455                 for(var t in config.commands)
2456                         if(config.commands[t] == commandName)
2457                                 c = t;
2458                 commandName = c;
2459                 }
2460         if((tiddler instanceof Tiddler) && (typeof commandName == "string"))
2461                 {
2462                 var title = tiddler.title;
2463                 var command = config.commands[commandName];
2464                 var ro = tiddler.isReadOnly();
2465                 var shadow = store.isShadowTiddler(title) && !store.tiddlerExists(title);
2466                 var text = ro && command.readOnlyText ? command.readOnlyText : command.text;
2467                 var tooltip = ro && command.readOnlyTooltip ? command.readOnlyTooltip : command.tooltip;
2468                 if((!ro || (ro && !command.hideReadOnly)) && !(shadow && command.hideShadow))
2469
2470                         {
2471                         var btn = createTiddlyButton(null,text,tooltip,this.onClickCommand);
2472                         btn.setAttribute("commandName", commandName);
2473                         btn.setAttribute("tiddler", title);
2474                         if(theClass)
2475                                 addClass(btn,theClass);
2476                         place.appendChild(btn);
2477                         }
2478                 }
2479 }
2480
2481 config.macros.toolbar.onClickCommand = function(e)
2482 {
2483         if(!e) var e = window.event;
2484         var command = config.commands[this.getAttribute("commandName")];
2485         return command.handler(e,this,this.getAttribute("tiddler"));
2486 }
2487
2488 // Invoke the first command encountered from a given place that is tagged with a specified class
2489 config.macros.toolbar.invokeCommand = function(place,theClass,event)
2490 {
2491         var children = place.getElementsByTagName("a")
2492         for(var t=0; t<children.length; t++)
2493                 {
2494                 var c = children[t];
2495                 if(hasClass(c,theClass) && c.getAttribute && c.getAttribute("commandName"))
2496                         {
2497                         if(c.onclick instanceof Function)
2498                                 c.onclick.call(c,event);
2499                         break;
2500                         }
2501                 }
2502 }
2503
2504 config.macros.toolbar.handler = function(place,macroName,params,wikifier,paramString,tiddler)
2505 {
2506         for(var t=0; t<params.length; t++)
2507                 {
2508                 var c = params[t];
2509                 var theClass = "";
2510                 switch(c.substr(0,1))
2511                         {
2512                         case "+":
2513                                 theClass = "defaultCommand";
2514                                 c = c.substr(1);
2515                                 break;
2516                         case "-":
2517                                 theClass = "cancelCommand";
2518                                 c = c.substr(1);
2519                                 break;
2520                         }
2521                 if(c in config.commands)
2522                         this.createCommand(place,c,tiddler,theClass);
2523                 }
2524 }
2525
2526 config.macros.plugins.handler = function(place,macroName,params,wikifier,paramString,tiddler)
2527 {
2528         var e = createTiddlyElement(place,"div");
2529         e.setAttribute("refresh","macro");
2530         e.setAttribute("macroName","plugins");
2531         e.setAttribute("params",paramString);
2532         this.refresh(e,paramString);
2533 }
2534
2535 config.macros.plugins.refresh = function(place,params)
2536 {
2537         var selectedRows = [];
2538         ListView.forEachSelector(place,function(e,rowName) {
2539                         if(e.checked)
2540                                 selectedRows.push(e.getAttribute("rowName"));
2541                 });
2542         removeChildren(place);
2543         params = params.parseParams("anon");
2544         var plugins = installedPlugins.slice(0);
2545         var t,tiddler,p;
2546         var configTiddlers = store.getTaggedTiddlers("systemConfig");
2547         for(t=0; t<configTiddlers.length; t++)
2548                 {
2549                 tiddler = configTiddlers[t];
2550                 if(plugins.findByField("title",tiddler.title) == null)
2551                         {
2552                         p = getPluginInfo(tiddler);
2553                         p.executed = false;
2554                         p.log.splice(0,0,this.skippedText);
2555                         plugins.push(p);
2556                         }
2557                 }
2558         for(t=0; t<plugins.length; t++)
2559                 {
2560                 var p = plugins[t];
2561                 p.forced = p.tiddler.isTagged("systemConfigForce");
2562                 p.disabled = p.tiddler.isTagged("systemConfigDisable");
2563                 p.Selected = selectedRows.indexOf(plugins[t].title) != -1;
2564                 }
2565         if(plugins.length == 0)
2566                 createTiddlyElement(place,"em",null,null,this.noPluginText);
2567         else
2568                 ListView.create(place,plugins,this.listViewTemplate,this.onSelectCommand);
2569 }
2570
2571 config.macros.plugins.onSelectCommand = function(command,rowNames)
2572 {
2573         var t;
2574         switch(command)
2575                 {
2576                 case "remove":
2577                         for(t=0; t<rowNames.length; t++)
2578                                 store.setTiddlerTag(rowNames[t],false,"systemConfig");
2579                         break;
2580                 case "delete":
2581                         if(rowNames.length > 0 && confirm(config.macros.plugins.confirmDeleteText.format([rowNames.join(", ")])))
2582                                 {
2583                                 for(t=0; t<rowNames.length; t++)
2584                                         {
2585                                         store.removeTiddler(rowNames[t]);
2586                                         story.closeTiddler(rowNames[t],true,false);
2587                                         }
2588                                 }
2589                         break;
2590                 }
2591         if(config.options.chkAutoSave)
2592                 saveChanges(true);
2593 }
2594
2595 config.macros.refreshDisplay.handler = function(place)
2596 {
2597         createTiddlyButton(place,this.label,this.prompt,this.onClick);
2598 }
2599
2600 config.macros.refreshDisplay.onClick = function(e)
2601 {
2602         refreshAll();
2603         return false;
2604 }
2605
2606 config.macros.importTiddlers.handler = function(place,macroName,params,wikifier,paramString,tiddler)
2607 {
2608         if(readOnly)
2609                 {
2610                 createTiddlyElement(place,"div",null,"marked",this.readOnlyWarning);
2611                 return;
2612                 }
2613         var importer = createTiddlyElement(null,"div",null,"importTiddler wizard");
2614         createTiddlyElement(importer,"h1",null,null,this.wizardTitle);
2615         createTiddlyElement(importer,"h2",null,"step1",this.step1);
2616         var step = createTiddlyElement(importer,"div",null,"wizardStep");
2617         createTiddlyText(step,this.step1prompt);
2618         var input = createTiddlyElement(null,"input",null,"txtOptionInput");
2619         input.type = "text";
2620         input.size = 50;
2621         step.appendChild(input);
2622         importer.inputBox = input;
2623         createTiddlyElement(step,"br");
2624         createTiddlyText(step,this.step1promptFile);
2625         var fileInput = createTiddlyElement(null,"input",null,"txtOptionInput");
2626         fileInput.type = "file";
2627         fileInput.size = 50;
2628         fileInput.onchange = this.onBrowseChange;
2629         fileInput.onkeyup = this.onBrowseChange;
2630         step.appendChild(fileInput);
2631         createTiddlyElement(step,"br");
2632         createTiddlyText(step,this.step1promptFeeds);
2633         var feeds = this.getFeeds([{caption: this.step1feedPrompt, name: ""}]);
2634         createTiddlyDropDown(step,this.onFeedChange,feeds);
2635         createTiddlyElement(step,"br");
2636         createTiddlyButton(step,this.fetchLabel,this.fetchPrompt,this.onFetch,null,null,null);
2637         place.appendChild(importer);
2638 }
2639
2640 config.macros.importTiddlers.getFeeds = function(feeds)
2641 {
2642         var tagged = store.getTaggedTiddlers("contentPublisher","title");
2643         for(var t=0; t<tagged.length; t++)
2644                 feeds.push({caption: tagged[t].title, name: store.getTiddlerSlice(tagged[t].title,"URL")});
2645         return feeds;
2646 }
2647
2648 config.macros.importTiddlers.onFeedChange = function(e)
2649 {
2650         var importer = findRelated(this,"importTiddler","className","parentNode");
2651         importer.inputBox.value = this.value;
2652         this.selectedIndex = 0;
2653 }
2654
2655 config.macros.importTiddlers.onBrowseChange = function(e)
2656 {
2657         var importer = findRelated(this,"importTiddler","className","parentNode");
2658         importer.inputBox.value = "file://" + this.value;
2659 }
2660
2661 config.macros.importTiddlers.onFetch = function(e)
2662 {
2663         var importer = findRelated(this,"importTiddler","className","parentNode");
2664         var url = importer.inputBox.value;
2665         var cutoff = findRelated(importer.firstChild,"step2","className","nextSibling");
2666         while(cutoff)
2667                 {
2668                 var temp = cutoff.nextSibling;
2669                 cutoff.parentNode.removeChild(cutoff);
2670                 cutoff = temp;
2671                 }
2672         createTiddlyElement(importer,"h2",null,"step2",config.macros.importTiddlers.step2);
2673         var step = createTiddlyElement(importer,"div",null,"wizardStep",config.macros.importTiddlers.step2Text.format([url]));
2674         loadRemoteFile(url,config.macros.importTiddlers.onLoad,importer);
2675 }
2676
2677 config.macros.importTiddlers.onLoad = function(status,params,responseText,url,xhr)
2678 {
2679         if(!status)
2680                 {
2681                 displayMessage(this.fetchError);
2682                 return;
2683                 }
2684         var importer = params;
2685         // Check that the tiddler we're in hasn't been closed - doesn't work on IE
2686 //      var p = importer;
2687 //      while(p.parentNode)
2688 //              p = p.parentNode;
2689 //      if(!(p instanceof HTMLDocument))
2690 //              return;
2691         // Crack out the content - (should be refactored)
2692         var posOpeningDiv = responseText.indexOf(startSaveArea);
2693         var limitClosingDiv = responseText.indexOf("<!--POST-BODY-START--"+">");
2694         var posClosingDiv = responseText.lastIndexOf(endSaveArea,limitClosingDiv == -1 ? responseText.length : limitClosingDiv);
2695         if((posOpeningDiv == -1) || (posClosingDiv == -1))
2696                 {
2697                 alert(config.messages.invalidFileError.format([url]));
2698                 return;
2699                 }
2700         var content = "<html><body>" + responseText.substring(posOpeningDiv,posClosingDiv + endSaveArea.length) + "</body></html>";
2701         // Create the iframe
2702         var iframe = document.createElement("iframe");
2703         iframe.style.display = "none";
2704         importer.insertBefore(iframe,importer.firstChild);
2705         var doc = iframe.document;
2706         if(iframe.contentDocument)
2707                 doc = iframe.contentDocument; // For NS6
2708         else if(iframe.contentWindow)
2709                 doc = iframe.contentWindow.document; // For IE5.5 and IE6
2710         // Put the content in the iframe
2711         doc.open();
2712         doc.writeln(content);
2713         doc.close();
2714         // Load the content into a TiddlyWiki() object
2715         var storeArea = doc.getElementById("storeArea");
2716         var importStore = new TiddlyWiki();
2717         importStore.loadFromDiv(storeArea,"store");
2718         // Get rid of the iframe
2719         iframe.parentNode.removeChild(iframe);
2720         // Extract data for the listview
2721         var tiddlers = [];
2722         importStore.forEachTiddler(function(title,tiddler)
2723                 {
2724                 var t = {};
2725                 t.title = title;
2726                 t.modified = tiddler.modified;
2727                 t.modifier = tiddler.modifier;
2728                 t.text = tiddler.text.substr(0,50);
2729                 t.tags = tiddler.tags;
2730                 tiddlers.push(t);
2731                 });
2732         // Display the listview
2733         createTiddlyElement(importer,"h2",null,"step3",config.macros.importTiddlers.step3);
2734         var step = createTiddlyElement(importer,"div",null,"wizardStep");
2735         ListView.create(step,tiddlers,config.macros.importTiddlers.listViewTemplate,config.macros.importTiddlers.onSelectCommand);
2736         // Save the importer
2737         importer.store = importStore;
2738 }
2739
2740 config.macros.importTiddlers.onSelectCommand = function(listView,command,rowNames)
2741 {
2742         var importer = findRelated(listView,"importTiddler","className","parentNode");
2743         switch(command)
2744                 {
2745                 case "import":
2746                         config.macros.importTiddlers.doImport(importer,rowNames);
2747                         break;
2748                 }
2749         if(config.options.chkAutoSave)
2750                 saveChanges(true);
2751 }
2752
2753 config.macros.importTiddlers.doImport = function(importer,rowNames)
2754 {
2755         var theStore = importer.store;
2756         var overwrite = new Array();
2757         var t;
2758         for(t=0; t<rowNames.length; t++)
2759                 {
2760                 if(store.tiddlerExists(rowNames[t]))
2761                         overwrite.push(rowNames[t]);
2762         }
2763         if(overwrite.length > 0)
2764                 if(!confirm(this.confirmOverwriteText.format([overwrite.join(", ")])))
2765                         return;
2766         for(t=0; t<rowNames.length; t++)
2767                 {
2768                 var inbound = theStore.fetchTiddler(rowNames[t]);
2769                 store.saveTiddler(inbound.title, inbound.title, inbound.text, inbound.modifier, inbound.modified, inbound.tags);
2770                 store.fetchTiddler(inbound.title).created = inbound.created;
2771                 store.notify(rowNames[t],false);
2772                 }
2773         store.notifyAll();
2774         store.setDirty(true);
2775         createTiddlyElement(importer,"h2",null,"step4",this.step4.format([rowNames.length]));
2776         var step = createTiddlyElement(importer,"div",null,"wizardStep");
2777         for(t=0; t<rowNames.length; t++)
2778                 {
2779                 createTiddlyLink(step,rowNames[t],true);
2780                 createTiddlyElement(step,"br");
2781                 }
2782         createTiddlyElement(importer,"h2",null,"step5",this.step5);
2783 }
2784 // ---------------------------------------------------------------------------------
2785 // Menu and toolbar commands
2786 // ---------------------------------------------------------------------------------
2787
2788 config.commands.closeTiddler.handler = function(event,src,title)
2789 {
2790         story.closeTiddler(title,true,event.shiftKey || event.altKey);
2791         return false;
2792 }
2793
2794 config.commands.closeOthers.handler = function(event,src,title)
2795 {
2796         story.closeAllTiddlers(title);
2797         return false;
2798 }
2799
2800 config.commands.editTiddler.handler = function(event,src,title)
2801 {
2802         clearMessage();
2803         story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE);
2804         story.focusTiddler(title,"text");
2805         return false;
2806 }
2807
2808 config.commands.saveTiddler.handler = function(event,src,title)
2809 {
2810         var newTitle = story.saveTiddler(title,event.shiftKey);
2811         if(newTitle)
2812            story.displayTiddler(null,newTitle);
2813         return false;
2814 }
2815
2816 config.commands.cancelTiddler.handler = function(event,src,title)
2817 {
2818         if(story.hasChanges(title) && !readOnly)
2819                 if(!confirm(this.warning.format([title])))
2820                         return false;
2821         story.setDirty(title,false);
2822         story.displayTiddler(null,title);
2823         return false;
2824 }
2825
2826 config.commands.deleteTiddler.handler = function(event,src,title)
2827 {
2828         var deleteIt = true;
2829         if (config.options.chkConfirmDelete)
2830                 deleteIt = confirm(this.warning.format([title]));
2831         if (deleteIt)
2832                 {
2833                 store.removeTiddler(title);
2834                 story.closeTiddler(title,true,event.shiftKey || event.altKey);
2835                 if(config.options.chkAutoSave)
2836                         saveChanges();
2837                 }
2838         return false;
2839 }
2840
2841 config.commands.permalink.handler = function(event,src,title)
2842 {
2843         var t = encodeURIComponent(String.encodeTiddlyLink(title));
2844         if(window.location.hash != t)
2845                 window.location.hash = t;
2846         return false;
2847 }
2848
2849 config.commands.references.handler = function(event,src,title)
2850 {
2851         var popup = Popup.create(src);
2852         if(popup)
2853                 {
2854                 var references = store.getReferringTiddlers(title);
2855                 var c = false;
2856                 for(var r=0; r<references.length; r++)
2857                         if(references[r].title != title && !references[r].isTagged("excludeLists"))
2858                                 {
2859                                 createTiddlyLink(createTiddlyElement(popup,"li"),references[r].title,true);
2860                                 c = true;
2861                                 }
2862                 if(!c)
2863                         createTiddlyText(createTiddlyElement(popup,"li",null,"disabled"),this.popupNone);
2864                 }
2865         Popup.show(popup,false);
2866         event.cancelBubble = true;
2867         if (event.stopPropagation) event.stopPropagation();
2868         return false;
2869 }
2870
2871 config.commands.jump.handler = function(event,src,title)
2872 {
2873         var popup = Popup.create(src);
2874         if(popup)
2875                 {
2876                 story.forEachTiddler(function(title,element) {
2877                         createTiddlyLink(createTiddlyElement(popup,"li"),title,true);
2878                         });
2879                 }
2880         Popup.show(popup,false);
2881         event.cancelBubble = true;
2882         if (event.stopPropagation) event.stopPropagation();
2883         return false;
2884 }
2885
2886 // ---------------------------------------------------------------------------------
2887 // Tiddler() object
2888 // ---------------------------------------------------------------------------------
2889
2890 function Tiddler()
2891 {
2892         this.title = null;
2893         this.text = null;
2894         this.modifier = null;
2895         this.modified = new Date();
2896         this.created = new Date();
2897         this.links = [];
2898         this.linksUpdated = false;
2899         this.tags = [];
2900         return this;
2901 }
2902
2903 Tiddler.prototype.getLinks = function()
2904 {
2905         if(this.linksUpdated==false)
2906                 this.changed();
2907         return this.links;
2908 }
2909
2910 // Format the text for storage in an RSS item
2911 Tiddler.prototype.saveToRss = function(url)
2912 {
2913         var s = [];
2914         s.push("<item>");
2915         s.push("<title" + ">" + this.title.htmlEncode() + "</title" + ">");
2916         s.push("<description>" + wikifyStatic(this.text,null,this).htmlEncode() + "</description>");
2917         for(var t=0; t<this.tags.length; t++)
2918                 s.push("<category>" + this.tags[t] + "</category>");
2919         s.push("<link>" + url + "#" + encodeURIComponent(String.encodeTiddlyLink(this.title)) + "</link>");
2920         s.push("<pubDate>" + this.modified.toGMTString() + "</pubDate>");
2921         s.push("</item>");
2922         return(s.join("\n"));
2923 }
2924
2925 // Change the text and other attributes of a tiddler
2926 Tiddler.prototype.set = function(title,text,modifier,modified,tags,created,fields)
2927 {
2928         this.assign(title,text,modifier,modified,tags,created,fields);
2929         this.changed();
2930         return this;
2931 }
2932
2933 // Change the text and other attributes of a tiddler without triggered a tiddler.changed() call
2934 Tiddler.prototype.assign = function(title,text,modifier,modified,tags,created,fields)
2935 {
2936         if(title != undefined)
2937                 this.title = title;
2938         if(text != undefined)
2939                 this.text = text;
2940         if(modifier != undefined)
2941                 this.modifier = modifier;
2942         if(modified != undefined)
2943                 this.modified = modified;
2944         if(created != undefined)
2945                 this.created = created;
2946         if(fields != undefined)
2947                 this.fields = fields;
2948         if(tags != undefined)
2949                 this.tags = (typeof tags == "string") ? tags.readBracketedList() : tags;
2950         else if(this.tags == undefined)
2951                 this.tags = [];
2952         return this;
2953 }
2954
2955 // Get the tags for a tiddler as a string (space delimited, using [[brackets]] for tags containing spaces)
2956 Tiddler.prototype.getTags = function()
2957 {
2958         return String.encodeTiddlyLinkList(this.tags);
2959 }
2960
2961 // Test if a tiddler carries a tag
2962 Tiddler.prototype.isTagged = function(tag)
2963 {
2964         return this.tags.indexOf(tag) != -1;
2965 }
2966