raybooks is loading ...

Requires Javascript.
raybooks - book reviews on a Tiddlywiki
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected{color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}
	
.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.sparkline {background:[[ColorPalette::PrimaryPale]]; border:0;}
.sparktick {background:[[ColorPalette::PrimaryDark]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity:60)';}
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0em 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0em 1em 1em; left:0px; top:0px;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0em 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 .3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0em 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0em 0em 0em; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0em;}
.wizardFooter .status {padding:0em 0.4em 0em 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em 0.1em 0.2em;}

#messageArea {position:fixed; top:2em; right:0em; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em 0.2em 0.2em 0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em 0.2em 0.2em 0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em 1em 1em 1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0em;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0em 0em 0.5em;}
.tab {margin:0em 0em 0em 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0em 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0em 1em;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0em 0.25em; padding:0em 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0em; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}

.fieldsetFix {border:0; padding:0; margin:1px 0px 1px 0px;}

.sparkline {line-height:1em;}
.sparktick {outline:0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0em; right:0em;}
#backstageButton a {padding:0.1em 0.4em 0.1em 0.4em; margin:0.1em 0.1em 0.1em 0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin:0em 3em 0em 3em; padding:1em 1em 1em 1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em 0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none ! important;}
#displayArea {margin: 1em 1em 0em 1em;}
/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

Your username for signing your edits. Write it as a WikiWord (eg JoeBloggs)

<<option txtUserName>>
<<option chkSaveBackups>> SaveBackups
<<option chkAutoSave>> AutoSave
<<option chkRegExpSearch>> RegExpSearch
<<option chkCaseSensitiveSearch>> CaseSensitiveSearch
<<option chkAnimate>> EnableAnimations

----
Also see AdvancedOptions
<<importTiddlers>>
To add a new book or article, just click 'new book' or 'new article' in the right-hand sidebar. A tiddler will open up in edit mode. 

While in edit mode, give the tiddler a title based on your book or article's author and title. if you have a link to an image of your book's cover, feel free to add it following the instructions. Then click done.

Your tiddler will go into viewing mode. Here is where you can add the appropriate author, title, publisher and other information about your book or article. Only type in the information you think you will need.

A word about topics: there is a field called primary topic where you can put the primary topic that your book is about. But you may wish to add other topics. No problem! Just double-click inside the tiddler to go back to edit mode. You will see a thin field at the bottom for tags. For tags with more than one word, either use WikiWords with alternating upper and lowercase letters, or use double square brackets {{{[[these]]}}} to enclose multiple word phrases.

In edit mode you can also add any notes you want to take on your book or article: summary, evaluation, quotes, etc. Do this near the bottom under the Notes headline. For information on how to format text, see [[How to Format Text]].

<<formTiddler NewBookTemplate>><data>{"author":"Warren Adler","booktitle":"Cult","pubinfo":"Three Ponds Press","mine":true,"medium":"eBook (eReader)","genre":"Drama","primtopic":"Murder"}</data>Not read yet.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Mitch Albom","booktitle":"Tuesdays with Morrie","pubinfo":"Time Warner (1997)","mine":true,"medium":"Paperback","genre":"Non-fiction","primtopic":"Philosphy","rating":"75","synopsis":"Author spends time with mentor just before mentor dies"}</data>
<<notes heading:'Rays Notes'>>
!!!Comments:
<<comment>>
Best-seller in the "self help" vein. it is a good book, and has a good message, but is a bit inclined to "weepie" and "moralising" at times...I guess that is what sells.
Ray20080912
<<forEachTiddler where 'tiddler.tags.contains("article")' sortBy 'tiddler.data("author")' 
write 
'"{{justfine{"+tiddler.data("author")+",  }}} {{justfine{"+tiddler.data("articletitle")+".}}} {{italic{"+tiddler.data("journalinfo")+".}}}  {{justfine{"+tiddler.data("pagenumbers")+".}}} [[here|"+tiddler.title+"]]<br>\n"' 
>>
After saving the file to your computer and opening the new file, go to the right-hand menu and in the window type a username for yourself. This will allow you to edit this file. The username should be a WikiWord, a word that alternates between upper and lowercase letters (JoeBloggs, TexMex, etc).

<<formTiddler NewBookTemplate>><data>{"author":"David Baldacci","booktitle":"Absolute Power","pubinfo":"Warner Books (1996)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Thriller","primtopic":"Murder ","synopsis":"Drunken president gets involved in the death of his girlfriend.","rating":"70"}</data>The President of the USA is drunk. He is getting a leg over the wife of one of his supporters when she resists and he smacks her...the bodyguards show up and kill her. A Cat Burgler has seen it all, and now he must run for his life. Ho Hum! A bit over-the-top. The pages turn easily, but the brain never gets into gear.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"David Baldacci","booktitle":"Stone Cold","pubinfo":"McMillan (2007)","mine":true,"medium":"Paperback","genre":"Thriller","primtopic":"Confidence tricks","synopsis":"Cold blooded casino boss seeks revenge","rating":"65"}</data>A group of friends try to assist one of their group after she plays a confidence trick on a Casino Owner, and he decides to have his revenge. There are several counter-plos and the whole thing gets confusing.
!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"James Barclay","booktitle":"Dawnthief","pubinfo":"Gollancz (1999)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Fantasy","primtopic":"Epic adventure","rating":"0"}</data>Not read yet.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Greg Bear","booktitle":"Darwin's Radio","pubinfo":"Ballantine Book (1999)","mine":true,"medium":"Paperback [2nd hand]","genre":"Science Fiction","primtopic":"Evolution","rating":"80","synopsis":"Evolution gets a hand"}</data>Greg Bear postulates that Evolution is not a smooth progression across thousands of lifecycles, but goes along in fits and starts courtesy of infestation of cells by viruses. This book introduces the concept by recounting a situation where humans have developed dramatically within a single generation, causing great trauma for the Olds and the News.
This author is very accomplished in the skills of plausibly explaining the science that could support this happening, and there is adventure and drama in a clever plot.
!!!Comments 
<<comment>>
BibblyWiki is an adaptation of TiddlyWiki software designed to create bibliographies, personal library inventories and notes on books.
<<forEachTiddler 
where 
'tiddler.tags.contains("bibentry") && tiddler.data("booktitle")' 
sortBy
'tiddler.title'
write 
 '"{{justfine{"+tiddler.data("author")+",  }}} {{italic{ "+tiddler.data("booktitle")+".}}} "+tiddler.data("pubinfo")+" [[here|"+tiddler.title+"]]<br>\n"' 
>>

<<formTiddler NewBookTemplate>><data>{"author":"John Birmingham","booktitle":"Weapons of Choice","pubinfo":"Ballantine Books (2004)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Science Fiction","primtopic":"Space meets WW2","synopsis":"Spaceships crashes into WW@ destroyer..mayhem ensues.","rating":"65"}</data>First book in a series...a blend of SciFi and WW2 saga, but it doesn't work very well. His writing is quite richly descriptive, but the plot is lacking in any plausibility. i won't bother with part2.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Judy Blume","booktitle":"Summer Sisters","pubinfo":"Dell (1998)","mine":true,"medium":"Paperback (2nd hand)","genre":"Drama","synopsis":"School girls growing up, and sometimes behaving badly.","primtopic":"Family life","rating":"75"}</data>20 years or so of the life of 2 best friends, starting out as girfriends in Junior Highschool, then on an island (Martha's Vineyard?). A very fine wordsmith, but not enough seems to happen to keep the pages turning continually.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Gerry Boyle","booktitle":"Home Body","pubinfo":"berkely Books (2004)","mine":true,"keep":true,"medium":"Paperback","genre":"Thriller","primtopic":"Murder","synopsis":"A strange young boy appears on the scene, and things happen.","rating":"75"}</data>Better than average thriller, and bits stick in the mind even after months. Well developed characters, and a complex plot assist here.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Bill Bryson","booktitle":"A Short History of Nearly Everything","pubinfo":"Black Swan (2003)","mine":true,"medium":"Paperback","genre":"Reference","primtopic":"Everything scientific","synopsis":"Reference work","rating":"0"}</data>Not read yet.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"John Burdett","booktitle":"Bangkok Haunts","pubinfo":"Corgi (2007)","mine":true,"primtopic":"Culture","medium":"Paperback","genre":"Thriller","rating":"75","synopsis":"Further adventures of the only honest cop in Bangkok"}</data>Third in a series of Crime books,featuring Khun Sonchai, the only honest cop in Bangkok. 
The Author evidently knows Bangkok well, and is well researched in the unique culture of Thailand; it is good see he reports, rather than judges, deeply believed concepts like witchcraft, Ghosts, and other paranormal events.
The plot is quite shallow, serving really as little more than a frame on which to display all manner of seedy aspects of crime, drugs, prostitution in Bangkok, while continuing to develop some characters who have evidently been with us from previous installments.
!!!Comments
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Jan Burke","booktitle":"Nine","pubinfo":"Pocket Books (2002)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Thriller","primtopic":"Murder","synopsis":"Someone is killing of the most-wanted criminals.","rating":"70"}</data>Fast paced, interesting plot...a better than average page-turner of the bloody kind.
!!!Comments:
<<comment>>
I am still working on this function. It will sort topics alphabetically but will include both the primary topic and extra topics that you add as tags.

<<forEachTiddler 
where 
'tiddler.tags.contains("bibentry") && tiddler.data("primtopic")'
sortBy
'tiddler.data("primtopic")+"."+tiddler.getTags()'
script '
function excludeSomeTags(tags) {
    var result = [];
    for (var i = 0; i < tags.length; i++)
        if (tags[i] != "bibentry")
if (tags[i] != "article")
            result.push(tags[i])
    return result;}' 
write
'"{{bold{"+tiddler.data("primtopic")+"."+excludeSomeTags(tiddler.tags).join(".")+"}}}<br>{{indent{"+tiddler.data("author") +",  {{italic{"+tiddler.data("booktitle")+"}}} [[here|"+tiddler.title+"]]}}}<br>\n"'
>>
<<forEachTiddler
where
'tiddler.tags.contains("bibentry") && tiddler.data("callnumber")'
sortBy 'tiddler.data("callnumber")'
write
'"{{bold{"+tiddler.data("callnumber")+"}}}{{indent{"+tiddler.data("author")+",  {{italic{"+tiddler.data("booktitle")+"}}} [[here|"+tiddler.title+"]]\n"'>>
<<forEachTiddler 
where 'tiddler.tags.contains("bibentry") && tiddler.data("genre")' 
sortBy 'tiddler.data("genre"); ascending'
write
'"{{bold{"+tiddler.data("genre")+"}}}<br>{{indent{"+tiddler.data("author")+",}}}{{italic{ "+tiddler.data("booktitle")+".}}} [[here|"+tiddler.title+"]]<br>\n"' 
>>
<<forEachTiddler 
where 'tiddler.tags.contains("bibentry") && tiddler.data("medium")' 
sortBy 'tiddler.data("medium"); ascending'
write
'"{{bold{"+tiddler.data("medium")+"}}}{{indent{"+tiddler.data("author")+",}}}{{italic{ "+tiddler.data("booktitle")+".}}} [[here|"+tiddler.title+"]]<br>\n"' 
>>
<<forEachTiddler 
where 'tiddler.tags.contains("bibentry") && tiddler.data("primtopic") && tiddler.data("pubinfo")' 
sortBy 'tiddler.data("primtopic") && tiddler.data("author") && tiddler.data("booktitle")'
write
'"{{bold{"+tiddler.data("primtopic")+"}}}<br>{{indent{"+tiddler.data("author")+",}}}{{italic{ "+tiddler.data("booktitle")+".}}} [[here|"+tiddler.title+"]]<br>\n"' 
>>
<<forEachTiddler
where
'tiddler.tags.contains("bibentry") && tiddler.data("rating")'
sortBy 'tiddler.data("rating")' descending
write
'"|[["+tiddler.data("rating")+"]]|"+tiddler.data("genre")+"|"+tiddler.data("medium")+"|[["+tiddler.title+"]]|\n"'
>>
<<forEachTiddler 
where 'tiddler.tags.contains("bibentry") && tiddler.data("synopsis")' 
sortBy 'tiddler.data("synopsis"); ascending'
write
'"{{bold{"+tiddler.data("synopsis")+"}}}<br>{{indent{"+tiddler.data("author")+",}}}{{italic{ "+tiddler.data("booktitle")+".}}} [[here|"+tiddler.title+"]]<br>\n"' 
>>
<<forEachTiddler
where
'tiddler.tags.contains("bibentry") && tiddler.data("booktitle")'
sortBy 'tiddler.data("booktitle")'
write
'"{{italic bold{"+tiddler.data("booktitle")+".}}}  {{justfine{"+tiddler.data("author")+",}}}  "+tiddler.data("pubinfo")+" [[here|"+tiddler.title+"]]<br>\n"' 
>>
<<forEachTiddler 
where 'tiddler.tags.contains("bibentry") && tiddler.data("primtopic")' 
sortBy 'tiddler.data("primtopic"); ascending'
write
'"{{bold{"+tiddler.data("primtopic")+"}}}{{indent{"+tiddler.data("author")+",}}}{{italic{ "+tiddler.data("booktitle")+".}}} [[here|"+tiddler.title+"]]<br>\n"' 
>>
Background: #eeddaa
Foreground: #000
PrimaryPale: #ddcc99
PrimaryLight: #bb8833
PrimaryMid: #553322
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #cccccc
SecondaryDark: #553322
TertiaryPale: #ddcc99
TertiaryLight: #EEC591
TertiaryMid: #553322
TertiaryDark: #8B7355
/***
|Name|CommentPlugin|
|Source|http://www.TiddlyTools.com/#CommentPlugin|
|Documentation|http://www.TiddlyTools.com/#CommentPluginInfo|
|Version|2.9.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|automatically insert formatted comments into tiddler content|
!!!!!Documentation
>see [[CommentPluginInfo]]
!!!!!Configuration
>see [[CommentPluginInfo]]
!!!!!Revisions
<<<
2008.05.17 [2.9.0] optional 'overwrite' param replaces existing comment when stored as separate tiddler
| please see [[CommentPluginInfo]] for previous revision details |
2006.04.20 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.CommentPlugin= {major: 2, minor: 9, revision: 0, date: new Date(2008,5,17)};

config.macros.comment= {
	marker: "/%"+"comment"+"%/",
	fmt: "__''%subject%''__\n^^posted by %who% on %when%^^\n<<<\n%message%\n<<<\n",
	datefmt: "DDD, MMM DDth, YYYY at hh12:0mm:0ss am",
	tags: "",
	reverse: false,
	handler: function(place,macroName,params,wikifier,paramstring,tiddler) {
		var span=createTiddlyElement(place,"span");
		var here=story.findContainingTiddler(place);
		if (here) var tid=here.getAttribute("tiddler");  // containing tiddler title
		span.setAttribute("here",tid);
		var target=(params[0]&&params[0].length&&params[0]!="here")?params[0]:tid;  // target title
		span.setAttribute("target",target);
		var overwrite=(params[1]&&params[1].toLowerCase()=="overwrite"); if (overwrite) params.shift();
		span.setAttribute("overwrite",overwrite?"true":"false");
		var reverse=(params[1]&&params[1].toLowerCase()=="reverse"); if (reverse) params.shift();
		span.setAttribute("reverse",(reverse||this.reverse)?"true":"false");
		var tags=(params[1]&&params[1].length)?params[1]:this.tags; // target tags
		span.setAttribute("tags",tags);
		var fmt=(params[2]&&params[2].length)?params[2]:this.fmt; // output format
		span.setAttribute("fmt",fmt.unescapeLineBreaks());
		var datefmt=(params[3]&&params[3].length)?params[3]:this.datefmt; // date format
		span.setAttribute("datefmt",datefmt.unescapeLineBreaks());
		var html=this.html;
		html=html.replace(/%nosubject%/g,(this.fmt.indexOf("%subject%")==-1)?"none":"block");
		html=html.replace(/%nomessage%/g,(this.fmt.indexOf("%message%")==-1)?"none":"block");
		var subjtxt=""; var msgtxt="";
		/*********** TBD: set previous subj/msg into form (for DiscussionPlugin "edit")
		if (overwrite) {
			var txt=store.getTiddlerText(target,"");
			// TBD: get subject text
			// TBD: get msg txt
		}
		************/
		html=html.replace(/%subjtxt%/g,subjtxt);
		html=html.replace(/%msgtxt%/g,msgtxt);
		span.innerHTML=html; // append comment form to content
	},
	html: "<form style='display:inline;margin:0;padding:0;'>\
		<div style='display:%nosubject%'>\
		subject:<br>\
		<input type='text' name='subject' title='enter subject text' style='width:100%' value='%subjtxt%'>\
		</div>\
		<div style='display:%nomessage%'>\
		message:<br>\
		<textarea name='message' rows='7' title='enter message text' \
			style='width:100%'>%msgtxt%</textarea>\
		</div>\
		<center>\
		<i>Please enter your information and then press</i>\
		<input type='button' value='post' onclick='\
			var s=this.form.subject; var m=this.form.message;\
			if (\"%nosubject%\"!=\"none\" && !s.value.length)\
				{ alert(\"Please enter a subject\"); s.focus(); return false; }\
			if (\"%nomessage%\"!=\"none\" && !m.value.length)\
				{ alert(\"Please enter a message\"); m.focus(); return false; }\
			var here=this.form.parentNode.getAttribute(\"here\");\
			var reverse=this.form.parentNode.getAttribute(\"reverse\")==\"true\";\
			var target=this.form.parentNode.getAttribute(\"target\");\
			var tags=this.form.parentNode.getAttribute(\"tags\").readBracketedList();\
			var fmt=this.form.parentNode.getAttribute(\"fmt\");\
			var datefmt=this.form.parentNode.getAttribute(\"datefmt\");\
			var overwrite=this.form.parentNode.getAttribute(\"overwrite\")==\"true\";\
			config.macros.comment.addComment(here,reverse,target,tags,fmt,datefmt,s.value,m.value,overwrite);'>\
		</center>\
		</form>",
	addComment: function(here,reverse,target,newtags,fmt,datefmt,subject,message,overwrite) {
		var UTC=new Date().convertToYYYYMMDDHHMMSSMMM();
		var rand=Math.random().toString();
		var who=config.options.txtUserName;
		var when=new Date().formatString(datefmt);
		target=target.replace(/%tiddler%/g,here);
		target=target.replace(/%UTC%/g,UTC);
		target=target.replace(/%random%/g,rand);
		target=target.replace(/%who%/g,who);
		target=target.replace(/%when%/g,when);
		target=target.replace(/%subject%/g,subject);
		var t=store.getTiddler(target);
		var text=t?t.text:"";
		var modifier=t?t.modifier:config.options.txtUserName;
		var modified=t?t.modified:new Date();
		var tags=t?t.tags:[];
		for(var i=0; i<newtags.length; i++) tags.pushUnique(newtags[i]);
		var fields=t?t.fields:{};
		var out=fmt;
		out=out.replace(/%tiddler%/g,here);
		out=out.replace(/%UTC%/g,UTC);
		out=out.replace(/%when%/g,when);
		out=out.replace(/%who%/g,who);
		out=out.replace(/%subject%/g,subject);
		out=out.replace(/%message%/g,message);
		var pos=text.indexOf(this.marker);
		if (pos==-1) pos=text.length; // no marker - insert at end
		else if (reverse) pos+=this.marker.length; // reverse order by inserting AFTER marker
		var newtxt=overwrite?out:(text.substr(0,pos)+out+text.substr(pos));
		store.saveTiddler(target,target,newtxt,modifier,modified,tags,fields);
		if (document.getElementById(story.idPrefix+target))
			story.refreshTiddler(target,DEFAULT_VIEW_TEMPLATE,true);
		if (here!=target && document.getElementById(story.idPrefix+here))
			story.refreshTiddler(here,DEFAULT_VIEW_TEMPLATE,true);
	}
};
//}}}
/***
|Name|CommentPluginInfo|
|Source|http://www.TiddlyTools.com/#CommentPlugin|
|Documentation|http://www.TiddlyTools.com/#CommentPluginInfo|
|Version|2.9.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|Documentation|
|Requires||
|Overrides||
|Description|Documentation for CommentPlugin|
!!!!!Usage
<<<
syntax:
{{{
<<comment TiddlerName overwrite reverse tags format dateformat>>
}}}
where:
*''~TiddlerName'' //(optional)//<br>specifies the 'target' tiddler into which the comments should be written.  If omitted, the tiddler in which the {{{<<comment>>}}} macro is contained is used by default.  //Note: when specifying additional macro parameters, you can use a blank ~TiddlerName (e.g., {{{""}}}) or the keyword //{{{"here"}}}// as a 'placeholder' to allow the current 'containing tiddler' to be used by default.//  The specified target can also include special //named substitution markers// to automatically generate a unique title for each target tiddler by dynamically inserting  values to construct the target ~TiddlerName, where:
**%tiddler%=containing tiddler title,
**%UTC%=UTC timestamp (YYYYMMMDD.HHMMSSMMM),
**%random%=random decimal number (.123456789),
**%who%=current TiddlyWiki username,
**%subject%=comment subject text.
*''overwrite'' //(optional)//<br>By default, comments are added to the current content of a tiddler (if it already exists).  When the ''overwrite'' keyword parameter is present, the comment text completely replaces the previous contents of an existing tiddler.  ''Warning: extreme caution should always be applied when using the overwrite option, as all existing content of a tiddler will be discarded whenever a comment is written to that tiddler''. 
*''reverse'' //(optional)//<br>specifies the order in which new comments are added to the target tiddler.  By default, new comments are added //following// existing comments (if any).  When this parameter is present, new comments will be inserted //before// existing comments, resulting in a reverse-chronological display (i.e, newest comment shown first).
*''tags'' //(optional)//<br>specifies one or more space-separated tags to add to the target tiddler whenever a comment is written.  Note that the list of tags should be enclosed in "..." so that it is processed as a single parameter.  Also, to specify tags when writing comments to the current tiddler, use a blank placeholder for the TiddlerName (e.g., "")
*''format'' //(optional)//<br>specifies a custom output format that overrides the default output format defined via {{{config.macros.comment.fmt}}} and is used when inserting comments into the target tiddler.  The format uses //named substitution markers//, where:
**%tiddler%=containing tiddler title,
**%UTC%=UTC timestamp (YYYYMMMDD.HHMMSSMMM),
**%when%=formatted date/time,
**%who%=username,
**%subject%=subject,
**%message%=comment body text.
*''dateformat'' //(optional)//<br>specifies a custom date/timestamp output used within the comment format above.  When present, this parameter overrides the default date/timestamp format defined via {{{config.macros.comment.datefmt}}}.  See the ''Configuration'' section below for additional details.

To indicate the location within the target tiddler where new comments are to be saved, embed a marker: {{{/%comment%/}}}, in the tiddler source.  Each new comment is inserted immediately preceding the marker, resulting in a time-ordered sequence of comments.  If no comment marker is present in the target tiddler, new comments are automatically appended to the end of that tiddler's content.
<<<
!!!!!Configuration
<<<
To configure the behavior and formats used by [[CommentPlugin]], place one or more of the following javascript statements in a tiddler tagged with <<tag systemConfig>>: //(note: the default values for each setting are shown)//
{{{
config.macros.comment.reverse=false;
}}}
>when set to {{{true}}}, all new comments to be inserted //following// the comment marker instead of preceding it, resulting in a reverse chronological display order.  If no comment marker is present in the target tiddler source, the 'reverse' option is ignored and new comments are always appended to the end of the target tiddler.
{{{
config.macros.comment.fmt="__''%subject%''__\n^^posted by %who% on %when%^^\n<<<\n%message%\n<<<\n";
}}}
>defines the comment output format to be inserted into the tiddler, where: %when%=date/time, %who%=username, %subject%=subject, and %message% is the body of the comment.  //Note: if you omit %subject% from the output format, the subject input field on the comment form will be automatically suppressed.  Similarly, omitting %message% from the output format suppresses the message input field.  This can be useful when using the {{{<<comment>>}}} macro to create simple activity logs that only require a short, one-line subject rather than entering extended message content.//
{{{
config.macros.comment.datefmt="DDD, MMM DDth, YYYY at hh12:0mm:0ss am";
}}}
>defines the date/timestamp output used within the comment format above.
{{{
config.macros.comment.tags="";
}}}
>defines an optional space-separated, list of tags to be added to the target tiddler whenever a comment is written.  This is most useful when the target tiddler is different from the tiddler containing the {{{<<comment>>}}} macro, to make it easy to locate that tiddler later on.

Note: as of revision 2.0.0, dependencies on [[NestedSlidersPlugin]], [[MoveablePanelPlugin]], [[InlineJavascriptPlugin]] and [[ExpandSlidersScript]] have been eliminated.  As a result, the comment form and generated comment output are no longer automatically contained within sliders and the "view all/close all" command is not automatically included.  To recreate the previous output format and comment interface, use the following syntax in the tiddler in which you want to place your comments:
{{{
+++^40em^[add a note]...
<<moveablePanel>>add a note
----
<<comment here "" "+++!!!!![%when% (%who%): %subject%]>...\n%message%\n===\n">>===
 | <<tiddler ExpandSlidersScript with: here "view all" "close all">>
}}}
<<<
!!!!!Revisions
<<<
2008.05.17 [2.9.0] added support for optional 'overwrite' macro param to replace existing comment (for use when comment is stored as separate tiddler)
2008.04.21 [2.8.0] replaced use of %n markers with special 'named' markers: %tiddler%, %UTC%, %random%, %who%, %when%, %subject% and %message% to avoid conflict with TW core processing of tiddler content.  Also, added support for 'reverse' macro param.
2008.04.17 [2.7.0] added support for constructing target by inserting UTC timestamp, random number, username and/or subject text into target tiddler title
2008.04.15 [2.6.0] added support for custom format and dateformat parameters to override global default formats
2008.04.15 [2.5.1] make sure tiddlers are displayed before attempting to refresh them
2008.04.15 [2.5.0] refresh tiddler containing comment macro after adding new comment to target tiddler (if different)
2008.04.14 [2.4.0] added optional tag list parameter for tagging the target tiddler when comments are written
2008.04.14 [2.3.0] if %2 (subject) or %3 (message) are omitted from format string, suppress display and validation of corresponding form elements.
2008.04.13 [2.2.0] added optional ~TiddlerName param to specify target tiddler for writing comments
2008.04.10 [2.1.0] converted from inline script to plugin
2008.04.05 [2.0.0] removed dependencies on NestedSlidersPlugin, MoveablePanelPlugin, ExpandSlidersScript
2007.10.24 [1.2.0] added config.options.txtCommentDateFormat
2007.07.05 [1.1.0] added 'view all/close all' toolbar item plus code cleanup
2007.06.28 [1.0.2] added tiddler.fields to saveTiddler() call (preserves custom fields)
2007.05.26 [1.0.1] added support for optional 'reverse' keyword.
2006.04.20 [1.0.0] initial release
<<<
config.macros.comment.reverse=false;
config.macros.comment.fmt="__''%subject%''__\n^^posted by %who% on %when%^^\n<<<\n%message%\n<<<\n";
config.macros.comment.datefmt="DDD, MMM DDth, YYYY at hh12:0mm:0ss am";

config.options.chkSideMenu = false;

config.options.chkSliderOptionsPanel = false; 
<<formTiddler NewBookTemplate>><data>{"author":"Robin Cook","booktitle":"Chromosome6","pubinfo":"Berkely (1997)","mine":true,"keep":true,"rating":"65","medium":"Paperback [2nd hand]","genre":"Science Fiction","primtopic":"Bio-weapons","synopsis":"Someone has done a bit of tinkering with cloning."}</data>Secretive biotech company sets up shop in deepest Africa, and starts mixing Ape with Man to produce super soldiers. Something must be done about it. Nice descriptions of the science of cloning, especially for when it was written. poorly realised plot, shallow comic-book characters, and unimaginative wordsmithing leave the potential in the typewriter.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Robin Cook","booktitle":"Coma","pubinfo":"Signet (1978)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Science Fiction","primtopic":"bad doctors","synopsis":"Patients are being farmed.","rating":"70"}</data>Plausible medial science applied to an incredible plot does not quite produce a memorable book. Cook specialises in medicine-related novels and his obvious knowledge works up to a point. However...stilted writing and shallow characters let him down.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Robin Cook","booktitle":"Mutation","pubinfo":"Berkely (1989)","mine":true,"medium":"Paperback [2nd hand]","genre":"Science Fiction","rating":"70","primtopic":"Ethics","synopsis":"Don't trust doctors and hospitals"}</data>Nearly believable tale of medical weirdness...basically what this author specialises in. The science is interesting, but the character development is a bit under-done.
!!!Comments
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Robin Cook","booktitle":"Vector","pubinfo":"berkley Book (2000)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Science Fiction","primtopic":"Bio-terrorism","synopsis":"Unhappy Russian immigrant to USA is unhappy","rating":"70"}</data>Medical plausibility is infuded in all Cook's novels, as he is a medical doctor and can readily turn his specialist knowledge to advantage. While his books are always interesting, they are ultimately a little disappointing due to his rather halting word-smithing and his somewhat shallow characters. This one is no exception.
!!!Comments:
<<comment>>
/***
|Name|CoreTweaks|
|Source|http://www.TiddlyTools.com/#CoreTweaks|
|Version|none|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <<br>>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.closeTiddler, Story.prototype.closeAllTiddlers, window.wikify, confirmExit, Slider.prototype.tick|
|Description|a small collection of overrides to TW core functions|

This tiddler contains some quick tweaks and modifications to TW core functions to provide minor changes in standard features or behavior.  It is hoped that some of these tweaks may be incorporated into later versions of the TW core, so that these adjustements will be available without needing these add-on definitions.
----
***/

// // {{groupbox small{
// // fix for bug#301, in which FireFox doesn't properly re-display textarea contents when other elements are removed from the DOM, causing the textarea to shift position but leave the textarea contents behind (overlapping other content)

// // This fix adds an optional 'allowAsync' param to closeAll() and closeAllTiddlers().   When TRUE, asynch redisplay handling is used after closing one or more tiddlers, permitting FireFox the opportunity to properly re-render contents of textareas.  Various core handlers are also revised so they can use the #301 fix, while still allowing existing plugins functions that require on synchronous handling  (e.g., BreadcrumbsPlugin restartHome()) to operate correctly.

// // This fix also includes a small tweak to ensure that when a tiddler in the story column is closed, the previous tiddler is scrolled into view, as suggested by DaveGifford (http://www.giffmex.org)
//{{{
Story.prototype.coreTweaks_closeTiddler = Story.prototype.closeTiddler;
Story.prototype.closeTiddler = function(title,animate,slowly,allowAsync)
{
	var tiddlerElem = document.getElementById(this.idPrefix + title);
	if(tiddlerElem != null) {
		// make sure previous tiddler is in view
		if (tiddlerElem.previousSibling) window.scrollTo(0,ensureVisible(tiddlerElem.previousSibling));
		clearMessage();
		this.scrubTiddler(tiddlerElem);
		if(anim && config.options.chkAnimate && animate)
			anim.startAnimating(new Slider(tiddlerElem,false,slowly,"all"));
		else {
			// bug #301 fix... set overflow=hidden and use asynch redraw (if allowed)
			tiddlerElem.style.overflow = "hidden";
			if (allowAsync)
				setTimeout(function(){tiddlerElem.parentNode.removeChild(tiddlerElem)},0);
			else
				tiddlerElem.parentNode.removeChild(tiddlerElem);
		}
	}
}
// bug #301 fix...  optional param, allowAsync, for pass-thru to closeTiddlers()
Story.prototype.closeAllTiddlers = function(exclude,allowAsync)
{
	clearMessage();
	this.forEachTiddler(function(title,element) {
		if((title != exclude) && element.getAttribute("dirty") != "true")
			this.closeTiddler(title,false,false,allowAsync); // no animation
		});
	window.scrollTo(0,0);
}
config.commands.closeTiddler.handler = function(event,src,title)
{
	story.closeTiddler(title,true,event.shiftKey || event.altKey,true); // bug #301 fix...  "close" uses allowAsync
	return false;
}
config.commands.closeOthers.handler = function(event,src,title)
{
	story.closeAllTiddlers(title,true); // bug #301 fix...  "close others" uses allowAsync
	return false;
}
config.macros.closeAll.onClick = function(e)
{
	story.closeAllTiddlers(null,true); // bug #301 fix... "close all" uses allowAsync
	return false;
}
//}}}
// // }}}
// // {{groupbox small{
// // This tweak adds URL paramifier handlers for "hide:elementID" and "show:elementID".  This is useful for forcing the display state of specific TW page elements, without requiring StyleSheet changes.  For example, if your customized StyleSheet hides the sidebar (useful for 'read only' published documents), you can force it to display when you need to edit the document by adding {{{#show:sidebar}}} to the document URL.  Alternatively, you might want to supress non-tiddler content when printing by hiding the sidebars and header (e.g., {{{#hide:mainMenu hide:sidebar hide:header}}})
//{{{
if (config.paramifiers) { // check for backward-compatibility
	config.paramifiers.hide = { onstart: function(id) { var e=document.getElementById(id); if (e) e.style.display="none"; } };
	config.paramifiers.show = { onstart: function(id) { var e=document.getElementById(id); if (e) e.style.display="block"; } };
}
//}}}
// // }}}
// // {{groupbox small{
// // This HIJACK tweak pre-processes source content to convert "backslash-newline" into {{{<<br>>>}}} before wikify(), so that literal newlines can be embedded in line-mode wiki syntax (e.g., tables, bullets, etc.).  Based on a suggestion from Sitaram Chamarty.
//{{{
window.coreWikify = wikify;
window.wikify = function(source,output,highlightRegExp,tiddler)
{
	if (source) source=source.replace(/\\\n\s*/mg,"<<br>>");
	coreWikify(source,output,highlightRegExp,tiddler)
}
//}}}
// // }}}
// // {{groupbox small{
// // This tweak adds a check for any tiddlers that are being actively edited, so that accidental page transitions don't discard tiddler content that has been entered but not yet saved to the 'store' (i.e., by pressing 'done').
//{{{
config.messages.editing_confirmExit ="There are currently open tiddler editors that may contain unsaved changes.\nIf you continue you will lose those changes";
function confirmExit()
{
	hadConfirmExit = true;
	if(store && store.isDirty && store.isDirty())
		return config.messages.confirmExit;
	// added by ELS
	var editing=false;
	story.forEachTiddler(function(title,element) { if(element.getAttribute("dirty")=="true") editing=true; });
	if (editing) return config.messages.editing_confirmExit;
}
//}}}
// // }}}
// // {{groupbox small{
// // When a slider is opened/closed with animation enabled, the opacity/alphafilter styles are incrementally adjusted to create a "fade-in/fade-out" effect.  However, this effect seems to render incredibly slowly on FireFox, and even slower when the background image is a complex JPG photo image, making animation impractical to use.  This tweak provides an option to disable the opacity/alphafilter handling, while leaving the 'incremental height' animation intact.  The resulting increase in performance makes it possible to leave the animation enabled so that you can benefit from the visual cues it provides.
//{{{
if (!config.options.chkEnableFade) config.options.chkEnableFade=false; // ELS: added conditional option for fade-in/fade-out
Slider.prototype.tick = function()
{
	this.progress += this.step;
	if(this.progress < 0 || this.progress > 1)
		{
		this.stop();
		return false;
		}
	else
		{
		var f = Animator.slowInSlowOut(this.progress);
		var h = this.realHeight * f;
		this.element.style.height = h + "px";
		if (config.options.chkEnableFade) // ELS: added conditional option for fade-in/fade-out
			{
			this.element.style.opacity = f;
			this.element.style.filter = "alpha(opacity:" + f * 100 +")";
			}
		return true;
		}
}
//}}}
// // }}}
<<formTiddler NewBookTemplate>><data>{"author":"Patricia Cornwell","booktitle":"The Body farm","pubinfo":"Berkely Books (1995)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Thriller","primtopic":"multiple murders","synopsis":"Forensic scientist uncovers the work of a serial killer.","rating":"70"}</data>Entertaining page-turner of the bloody kind. The main character is just a bit too smooth and unruffled to be believable.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Patricia Cornwell","booktitle":"Trace","pubinfo":"Berkely (2005)","mine":true,"medium":"Paperback [2nd hand]","genre":"Thriller","primtopic":"Deduction","rating":"70","synopsis":"Another family-related crime for Dr Kay Scarpetta to solve."}</data>I have read a couple of these Scarpetta crime thrillers now and, while they keep one's interest till the end, there is not much left in the memory banks a few days after the book has been closed.
!!!Comments 
<<comment>>
TiddlyWiki is © 2006 [[osmosoft|http://www.osmosoft.com]]. 

TiddlyWiki is a free, Open Source program created by Jeremy Ruston. (see at http://tiddlywiki.com)

BibblyWiki is an adaptation of TiddlyWiki by DaveGifford.

/***
|''Name:''|CreoleFormatterPlugin|
|''Description:''|Extension of TiddlyWiki syntax to support [[Creole|http://www.wikicreole.org/]] text formatting|
|''Author:''|Martin Budden (mjbudden (at) gmail (dot) com)|
|''Source:''|http://www.martinswiki.com/#CreoleFormatterPlugin |
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/MartinBudden/formatters/CreoleFormatterPlugin.js |
|''Version:''|0.1.8|
|''Date:''|May 7, 2007|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]] |
|''~CoreVersion:''|2.1.0|

This is an early release of the CreoleFormatterPlugin, which extends the TiddlyWiki syntax to support Creole
text formatting. See [[testCreoleFormat]] for an example.

The Creole formatter is different from the other formatters in that Tiddlers are not required to be
tagged: instead the Creole format adds formatting that augments TiddlyWiki's format.

The Creole formatter adds the following:
# {{{**}}} for bold
# {{{=Heading 1=}}} with 1 to 6 equals signs for headings
# {{{[[link|title]]}}} format for links (rather than TW's {{{[[title|link]]}}}).

Since Creole augments rather than replaces TW's formatting there is a problem of how to resolve a prettyLink:
the formatter has some intelligence to determine if whether a link is a TW style link or a Creole style link.
Additionally a tiddler can be tagged 'titleThenLinkFormat' or 'linkThenTitleFormat' to force resolution one
way or the other.

See: http://www.wikicreole.org/wiki/Home

Please report any defects you find at http://groups.google.co.uk/group/TiddlyWikiDev

This is an early alpha release, with (at least) the following known issues:
# Creole image format not yet supported

***/

//{{{
// Ensure that the CreoleFormatterPlugin is only installed once.
if(!version.extensions.CreoleFormatterPlugin) {
version.extensions.CreoleFormatterPlugin = {installed:true};

if(version.major < 2 || (version.major == 2 && version.minor < 1)) {
	alertAndThrow('CreoleFormatterPlugin requires TiddlyWiki 2.1 or later.');
}

creoleFormatter = {}; // 'namespace' for local functions

creoleFormatter.heading = {
	name: 'creoleHeading',
	match: '^={1,6}(?!=)',
	termRegExp: /(={0,6}\n+)/mg,
	handler: function(w) {w.subWikifyTerm(createTiddlyElement(w.output,'h' + w.matchLength),this.termRegExp);}
};

creoleFormatter.bold = {
	name: 'creoleBold',
	match: '\\*\\*',
	termRegExp: /(\*\*|(?=\n\n))/mg,
	element: 'strong',
	handler: config.formatterHelpers.createElementAndWikify
};

creoleFormatter.explicitLink = {
	name: 'creoleExplicitLink',
	match: '\\[\\[',
	lookaheadRegExp: /\[\[(.*?)(?:\|(.*?))?\]\]/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var e;
			var link = lookaheadMatch[1];
			var text = lookaheadMatch[2];
			if(text) {
				// both text and link defined, so try and workout which is which
				var wlRegExp = new RegExp(config.textPrimitives.wikiLink,'mg');
				wlRegExp.lastIndex = 0;
				if(w.tiddler.isTagged('titleThenLinkFormat')) {
					// format is [[text|link]]
					link = text;
					text = lookaheadMatch[1];
					e = config.formatterHelpers.isExternalLink(link) ? createExternalLink(w.output,link) : createTiddlyLink(w.output,link,false,null,w.isStatic);
				} else if(w.tiddler.isTagged('linkThenTitleFormat')) {
					// standard format is [[link|text]]
					e = config.formatterHelpers.isExternalLink(link) ? createExternalLink(w.output,link) : createTiddlyLink(w.output,link,false,null,w.isStatic);
				} else if(config.formatterHelpers.isExternalLink(link)) {
					e = createExternalLink(w.output,link);
				} else if(config.formatterHelpers.isExternalLink(text)) {
					link = text;
					text = lookaheadMatch[1];
					e = createExternalLink(w.output,link);
				} else if(store.tiddlerExists(link)) {
					e = createTiddlyLink(w.output,link,false,null,w.isStatic);
				} else if(store.tiddlerExists(text)) {
					link = text;
					text = lookaheadMatch[1];
					e = createTiddlyLink(w.output,link,false,null,w.isStatic);
				} else if(wlRegExp.exec(text)) {
					//text is a WikiWord, so assume its a tiddler link
					link = text;
					text = lookaheadMatch[1];
					e = createTiddlyLink(w.output,link,false,null,w.isStatic);
				} else {
					// assume standard link format
					e = config.formatterHelpers.isExternalLink(link) ? createExternalLink(w.output,link) : createTiddlyLink(w.output,link,false,null,w.isStatic);
				}
			} else {
				text = link;
				e = config.formatterHelpers.isExternalLink(link) ? createExternalLink(w.output,link) : createTiddlyLink(w.output,link,false,null,w.isStatic);
			}
			createTiddlyText(e,text);
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}//# end handler
};

creoleFormatter.replaceFormatters = function()
{
	// replace formatters where necessary
	for(var i=0; i<config.formatters.length; i++) {
		// replace formatters as required
		var name = config.formatters[i].name;
		if(name == 'prettyLink') {
			config.formatters[i] = creoleFormatter.explicitLink;
		} else if(name == 'italicByChar') {
			config.formatters[i].termRegExp = /(\/\/|(?=\n\n))/mg;
		} else if(name == 'list') {
			// require a space after the list character (required for '*' which otherwise clashes with bold
			config.formatters[i].match = '^[\\*#;:]+ ';
		}
	}
};
creoleFormatter.replaceFormatters();

// add new formatters
config.formatters.push(creoleFormatter.heading);
config.formatters.push(creoleFormatter.bold);

}// end of 'install only once'
//}}}
<<formTiddler NewBookTemplate>><data>{"author":"Michael Crichton","booktitle":"Next","pubinfo":"Harper Colling (2006)","mine":true,"medium":"Paperback","genre":"Science Fiction","primtopic":"Biogenetics","synopsis":"Science out of control","rating":"70"}</data>There is something about Crichton's writing style that makes his books a bit of a slog...I am sure it is more about word-smithing than subject matter, and it is ultimately disappointing.
Biogenetic research gets out of control when good scientists are compromised by the profit incentive of their employers...pretty soon there is a crisis.
!!!Comments:
<<comment>>
/***
|''Name:''|DataTiddlerPlugin|
|''Version:''|1.0.6 (2006-08-26)|
|''Source:''|http://tiddlywiki.abego-software.de/#DataTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license]]|
|''TiddlyWiki:''|1.2.38+, 2.0|
|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|
!Description
Enhance your tiddlers with structured data (such as strings, booleans, numbers, or even arrays and compound objects) that can be easily accessed and modified through named fields (in JavaScript code).

Such tiddler data can be used in various applications. E.g. you may create tables that collect data from various tiddlers. 

''//Example: "Table with all December Expenses"//''
{{{
<<forEachTiddler
    where
        'tiddler.tags.contains("expense") && tiddler.data("month") == "Dec"'
    write
        '"|[["+tiddler.title+"]]|"+tiddler.data("descr")+"| "+tiddler.data("amount")+"|\n"'
>>
}}}
//(This assumes that expenses are stored in tiddlers tagged with "expense".)//
<<forEachTiddler
    where
        'tiddler.tags.contains("expense") && tiddler.data("month") == "Dec"'
    write
        '"|[["+tiddler.title+"]]|"+tiddler.data("descr")+"| "+tiddler.data("amount")+"|\n"'
>>
For other examples see DataTiddlerExamples.




''Access and Modify Tiddler Data''

You can "attach" data to every tiddler by assigning a JavaScript value (such as a string, boolean, number, or even arrays and compound objects) to named fields. 

These values can be accessed and modified through the following Tiddler methods:
|!Method|!Example|!Description|
|{{{data(field)}}}|{{{t.data("age")}}}|Returns the value of the given data field of the tiddler. When no such field is defined or its value is undefined {{{undefined}}} is returned.|
|{{{data(field,defaultValue)}}}|{{{t.data("isVIP",false)}}}|Returns the value of the given data field of the tiddler. When no such field is defined or its value is undefined the defaultValue is returned.|
|{{{data()}}}|{{{t.data()}}}|Returns the data object of the tiddler, with a property for every field. The properties of the returned data object may only be read and not be modified. To modify the data use DataTiddler.setData(...) or the corresponding Tiddler method.|
|{{{setData(field,value)}}}|{{{t.setData("age",42)}}}|Sets the value of the given data field of the tiddler to the value. When the value is {{{undefined}}} the field is removed.|
|{{{setData(field,value,defaultValue)}}}|{{{t.setData("isVIP",flag,false)}}}|Sets the value of the given data field of the tiddler to the value. When the value is equal to the defaultValue no value is set (and the field is removed).|

Alternatively you may use the following functions to access and modify the data. In this case the tiddler argument is either a tiddler or the name of a tiddler.
|!Method|!Description|
|{{{DataTiddler.getData(tiddler,field)}}}|Returns the value of the given data field of the tiddler. When no such field is defined or its value is undefined {{{undefined}}} is returned.|
|{{{DataTiddler.getData(tiddler,field,defaultValue)}}}|Returns the value of the given data field of the tiddler. When no such field is defined or its value is undefined the defaultValue is returned.|
|{{{DataTiddler.getDataObject(tiddler)}}}|Returns the data object of the tiddler, with a property for every field. The properties of the returned data object may only be read and not be modified. To modify the data use DataTiddler.setData(...) or the corresponding Tiddler method.|
|{{{DataTiddler.setData(tiddler,field,value)}}}|Sets the value of the given data field of the tiddler to the value. When the value is {{{undefined}}} the field is removed.|
|{{{DataTiddler.setData(tiddler,field,value,defaultValue)}}}|Sets the value of the given data field of the tiddler to the value. When the value is equal to the defaultValue no value is set (and the field is removed).|
//(For details on the various functions see the detailed comments in the source code.)//


''Data Representation in a Tiddler''

The data of a tiddler is stored as plain text in the tiddler's content/text, inside a "data" section that is framed by a {{{<data>...</data>}}} block. Inside the data section the information is stored in the [[JSON format|http://www.crockford.com/JSON/index.html]]. 

//''Data Section Example:''//
{{{
<data>{"isVIP":true,"user":"John Brown","age":34}</data>
}}}

The data section is not displayed when viewing the tiddler (see also "The showData Macro").

Beside the data section a tiddler may have all kind of other content.

Typically you will not access the data section text directly but use the methods given above. Nevertheless you may retrieve the text of the data section's content through the {{{DataTiddler.getDataText(tiddler)}}} function.


''Saving Changes''

The "setData" methods respect the "ForceMinorUpdate" and "AutoSave" configuration values. I.e. when "ForceMinorUpdate" is true changing a value using setData will not affect the "modifier" and "modified" attributes. With "AutoSave" set to true every setData will directly save the changes after a setData.


''Notifications''

No notifications are sent when a tiddler's data value is changed through the "setData" methods. 

''Escape Data Section''
In case that you want to use the text {{{<data>}}} or {{{</data>}}} in a tiddler text you must prefix the text with a tilde ('~'). Otherwise it may be wrongly considered as the data section. The tiddler text {{{~<data>}}} is displayed as {{{<data>}}}.


''The showData Macro''

By default the data of a tiddler (that is stored in the {{{<data>...</data>}}} section of the tiddler) is not displayed. If you want to display this data you may used the {{{<<showData ...>>}}} macro:

''Syntax:'' 
|>|{{{<<}}}''showData '' [''JSON''] [//tiddlerName//] {{{>>}}}|
|''JSON''|By default the data is rendered as a table with a "Name" and "Value" column. When defining ''JSON'' the data is rendered in JSON format|
|//tiddlerName//|Defines the tiddler holding the data to be displayed. When no tiddler is given the tiddler containing the showData macro is used. When the tiddler name contains spaces you must quote the name (or use the {{{[[...]]}}} syntax.)|
|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|


!Revision history
* v1.0.6 (2006-08-26) 
** Removed misleading comment
* v1.0.5 (2006-02-27) (Internal Release Only)
** Internal
*** Make "JSLint" conform
* v1.0.4 (2006-02-05)
** Bugfix: showData fails in TiddlyWiki 2.0
* v1.0.3 (2006-01-06)
** Support TiddlyWiki 2.0
* v1.0.2 (2005-12-22)
** Enhancements:
*** Handle texts "<data>" or "</data>" more robust when used in a tiddler text or as a field value.
*** Improved (JSON) error messages.
** Bugs fixed: 
*** References are not updated when using the DataTiddler.
*** Changes to compound objects are not always saved.
*** "~</data>" is not rendered correctly (expected "</data>")
* v1.0.1 (2005-12-13)
** Features: 
*** The showData macro supports an optional "tiddlername" argument to specify the tiddler containing the data to be displayed
** Bugs fixed: 
*** A script immediately following a data section is deleted when the data is changed. (Thanks to GeoffS for reporting.)
* v1.0.0 (2005-12-12)
** initial version

!Code
***/
//{{{
//============================================================================
//============================================================================
//                           DataTiddlerPlugin
//============================================================================
//============================================================================

// Ensure that the DataTiddler Plugin is only installed once.
//
if (!version.extensions.DataTiddlerPlugin) {



version.extensions.DataTiddlerPlugin = {
    major: 1, minor: 0, revision: 6,
    date: new Date(2006, 7, 26), 
    type: 'plugin',
    source: "http://tiddlywiki.abego-software.de/#DataTiddlerPlugin"
};

// For backward compatibility with v1.2.x
//
if (!window.story) window.story=window; 
if (!TiddlyWiki.prototype.getTiddler) {
	TiddlyWiki.prototype.getTiddler = function(title) { 
		var t = this.tiddlers[title]; 
		return (t !== undefined && t instanceof Tiddler) ? t : null; 
	};
}

//============================================================================
// DataTiddler Class
//============================================================================

// ---------------------------------------------------------------------------
// Configurations and constants 
// ---------------------------------------------------------------------------

function DataTiddler() {
}

DataTiddler = {
    // Function to stringify a JavaScript value, producing the text for the data section content.
    // (Must match the implementation of DataTiddler.parse.)
    //
    stringify : null,
    

    // Function to parse the text for the data section content, producing a JavaScript value.
    // (Must match the implementation of DataTiddler.stringify.)
    //
    parse : null
};

// Ensure access for IE
window.DataTiddler = DataTiddler;

// ---------------------------------------------------------------------------
// Data Accessor and Mutator
// ---------------------------------------------------------------------------


// Returns the value of the given data field of the tiddler.
// When no such field is defined or its value is undefined
// the defaultValue is returned.
// 
// @param tiddler either a tiddler name or a tiddler
//
DataTiddler.getData = function(tiddler, field, defaultValue) {
    var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;
    if (!(t instanceof Tiddler)) {
        throw "Tiddler expected. Got "+tiddler;
    }

    return DataTiddler.getTiddlerDataValue(t, field, defaultValue);
};


// Sets the value of the given data field of the tiddler to
// the value. When the value is equal to the defaultValue
// no value is set (and the field is removed)
//
// Changing data of a tiddler will not trigger notifications.
// 
// @param tiddler either a tiddler name or a tiddler
//
DataTiddler.setData = function(tiddler, field, value, defaultValue) {
    var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;
    if (!(t instanceof Tiddler)) {
        throw "Tiddler expected. Got "+tiddler+ "("+t+")";
    }

    DataTiddler.setTiddlerDataValue(t, field, value, defaultValue);
};


// Returns the data object of the tiddler, with a property for every field.
//
// The properties of the returned data object may only be read and
// not be modified. To modify the data use DataTiddler.setData(...) 
// or the corresponding Tiddler method.
//
// If no data section is defined a new (empty) object is returned.
//
// @param tiddler either a tiddler name or a Tiddler
//
DataTiddler.getDataObject = function(tiddler) {
    var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;
    if (!(t instanceof Tiddler)) {
        throw "Tiddler expected. Got "+tiddler;
    }

    return DataTiddler.getTiddlerDataObject(t);
};

// Returns the text of the content of the data section of the tiddler.
//
// When no data section is defined for the tiddler null is returned 
//
// @param tiddler either a tiddler name or a Tiddler
// @return [may be null]
//
DataTiddler.getDataText = function(tiddler) {
    var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;
    if (!(t instanceof Tiddler)) {
        throw "Tiddler expected. Got "+tiddler;
    }

    return DataTiddler.readDataSectionText(t);
};


// ---------------------------------------------------------------------------
// Internal helper methods (must not be used by code from outside this plugin)
// ---------------------------------------------------------------------------

// Internal.
//
// The original JSONError is not very user friendly, 
// especially it does not define a toString() method
// Therefore we extend it here.
//
DataTiddler.extendJSONError = function(ex) {
	if (ex.name == 'JSONError') {
        ex.toString = function() {
			return ex.name + ": "+ex.message+" ("+ex.text+")";
		};
	}
	return ex;
};

// Internal.
//
// @param t a Tiddler
//
DataTiddler.getTiddlerDataObject = function(t) {
    if (t.dataObject === undefined) {
        var data = DataTiddler.readData(t);
        t.dataObject = (data) ? data : {};
    }
    
    return t.dataObject;
};


// Internal.
//
// @param tiddler a Tiddler
//
DataTiddler.getTiddlerDataValue = function(tiddler, field, defaultValue) {
    var value = DataTiddler.getTiddlerDataObject(tiddler)[field];
    return (value === undefined) ? defaultValue : value;
};


// Internal.
//
// @param tiddler a Tiddler
//
DataTiddler.setTiddlerDataValue = function(tiddler, field, value, defaultValue) {
    var data = DataTiddler.getTiddlerDataObject(tiddler);
    var oldValue = data[field];
	
    if (value == defaultValue) {
        if (oldValue !== undefined) {
            delete data[field];
            DataTiddler.save(tiddler);
        }
        return;
    }
    data[field] = value;
    DataTiddler.save(tiddler);
};

// Internal.
//
// Reads the data section from the tiddler's content and returns its text
// (as a String).
//
// Returns null when no data is defined.
//
// @param tiddler a Tiddler
// @return [may be null]
//
DataTiddler.readDataSectionText = function(tiddler) {
    var matches = DataTiddler.getDataTiddlerMatches(tiddler);
    if (matches === null || !matches[2]) {
        return null;
    }
    return matches[2];
};

// Internal.
//
// Reads the data section from the tiddler's content and returns it
// (as an internalized object).
//
// Returns null when no data is defined.
//
// @param tiddler a Tiddler
// @return [may be null]
//
DataTiddler.readData = function(tiddler) {
    var text = DataTiddler.readDataSectionText(tiddler);
	try {
	    return text ? DataTiddler.parse(text) : null;
	} catch(ex) {
		throw DataTiddler.extendJSONError(ex);
	}
};

// Internal.
// 
// Returns the serialized text of the data of the given tiddler, as it
// should be stored in the data section.
//
// @param tiddler a Tiddler
//
DataTiddler.getDataTextOfTiddler = function(tiddler) {
    var data = DataTiddler.getTiddlerDataObject(tiddler);
    return DataTiddler.stringify(data);
};


// Internal.
// 
DataTiddler.indexOfNonEscapedText = function(s, subString, startIndex) {
	var index = s.indexOf(subString, startIndex);
	while ((index > 0) && (s[index-1] == '~')) { 
		index = s.indexOf(subString, index+1);
	}
	return index;
};

// Internal.
//
DataTiddler.getDataSectionInfo = function(text) {
	// Special care must be taken to handle "<data>" and "</data>" texts inside
	// a data section. 
	// Also take care not to use an escaped <data> (i.e. "~<data>") as the start 
	// of a data section. (Same for </data>)

    // NOTE: we are explicitly searching for a data section that contains a JSON
    // string, i.e. framed with braces. This way we are little bit more robust in
    // case the tiddler contains unescaped texts "<data>" or "</data>". This must
    // be changed when using a different stringifier.

	var startTagText = "<data>{";
	var endTagText = "}</data>";

	var startPos = 0;

	// Find the first not escaped "<data>".
	var startDataTagIndex = DataTiddler.indexOfNonEscapedText(text, startTagText, 0);
	if (startDataTagIndex < 0) {
		return null;
	}

	// Find the *last* not escaped "</data>".
	var endDataTagIndex = text.indexOf(endTagText, startDataTagIndex);
	if (endDataTagIndex < 0) {
		return null;
	}
	var nextEndDataTagIndex;
	while ((nextEndDataTagIndex = text.indexOf(endTagText, endDataTagIndex+1)) >= 0) {
		endDataTagIndex = nextEndDataTagIndex;
	}

	return {
		prefixEnd: startDataTagIndex, 
		dataStart: startDataTagIndex+(startTagText.length)-1, 
		dataEnd: endDataTagIndex, 
		suffixStart: endDataTagIndex+(endTagText.length)
	};
};

// Internal.
// 
// Returns the "matches" of a content of a DataTiddler on the
// "data" regular expression. Return null when no data is defined
// in the tiddler content.
//
// Group 1: text before data section (prefix)
// Group 2: content of data section
// Group 3: text behind data section (suffix)
//
// @param tiddler a Tiddler
// @return [may be null] null when the tiddler contains no data section, otherwise see above.
//
DataTiddler.getDataTiddlerMatches = function(tiddler) {
	var text = tiddler.text;
	var info = DataTiddler.getDataSectionInfo(text);
	if (!info) {
		return null;
	}

	var prefix = text.substr(0,info.prefixEnd);
	var data = text.substr(info.dataStart, info.dataEnd-info.dataStart+1);
	var suffix = text.substr(info.suffixStart);
	
	return [text, prefix, data, suffix];
};


// Internal.
//
// Saves the data in a <data> block of the given tiddler (as a minor change). 
//
// The "chkAutoSave" and "chkForceMinorUpdate" options are respected. 
// I.e. the TiddlyWiki *file* is only saved when AutoSave is on.
//
// Notifications are not send. 
//
// This method should only be called when the data really has changed. 
//
// @param tiddler
//             the tiddler to be saved.
//
DataTiddler.save = function(tiddler) {

    var matches = DataTiddler.getDataTiddlerMatches(tiddler);

    var prefix;
    var suffix;
    if (matches === null) {
        prefix = tiddler.text;
        suffix = "";
    } else {
        prefix = matches[1];
        suffix = matches[3];
    }

    var dataText = DataTiddler.getDataTextOfTiddler(tiddler);
    var newText = 
            (dataText !== null) 
                ? prefix + "<data>" + dataText + "</data>" + suffix
                : prefix + suffix;
    if (newText != tiddler.text) {
        // make the change in the tiddlers text
        
        // ... see DataTiddler.MyTiddlerChangedFunction
        tiddler.isDataTiddlerChange = true;
        
        // ... do the action change
        tiddler.set(
                tiddler.title,
                newText,
                config.options.txtUserName, 
                config.options.chkForceMinorUpdate? undefined : new Date(),
                tiddler.tags);

        // ... see DataTiddler.MyTiddlerChangedFunction
        delete tiddler.isDataTiddlerChange;

        // Mark the store as dirty.
        store.dirty = true;
 
        // AutoSave if option is selected
        if(config.options.chkAutoSave) {
           saveChanges();
        }
    }
};

// Internal.
//
DataTiddler.MyTiddlerChangedFunction = function() {
    // Remove the data object from the tiddler when the tiddler is changed
    // by code other than DataTiddler code. 
    //
    // This is necessary since the data object is just a "cached version" 
    // of the data defined in the data section of the tiddler and the 
    // "external" change may have changed the content of the data section.
    // Thus we are not sure if the data object reflects the data section 
    // contents. 
    // 
    // By deleting the data object we ensure that the data object is 
    // reconstructed the next time it is needed, with the data defined by
    // the data section in the tiddler's text.
    
    // To indicate that a change is a "DataTiddler change" a temporary
    // property "isDataTiddlerChange" is added to the tiddler.
    if (this.dataObject && !this.isDataTiddlerChange) {
        delete this.dataObject;
    }
    
    // call the original code.
	DataTiddler.originalTiddlerChangedFunction.apply(this, arguments);
};


//============================================================================
// Formatters
//============================================================================

// This formatter ensures that "~<data>" is rendered as "<data>". This is used to 
// escape the "<data>" of a data section, just in case someone really wants to use
// "<data>" as a text in a tiddler and not start a data section.
//
// Same for </data>.
//
config.formatters.push( {
    name: "data-escape",
    match: "~<\\/?data>",

    handler: function(w) {
            w.outputText(w.output,w.matchStart + 1,w.nextMatch);
    }
} );


// This formatter ensures that <data>...</data> sections are not rendered.
//
config.formatters.push( {
    name: "data",
    match: "<data>",

    handler: function(w) {
		var info = DataTiddler.getDataSectionInfo(w.source);
		if (info && info.prefixEnd == w.matchStart) {
            w.nextMatch = info.suffixStart;
		} else {
			w.outputText(w.output,w.matchStart,w.nextMatch);
		}
    }
} );


//============================================================================
// Tiddler Class Extension
//============================================================================

// "Hijack" the changed method ---------------------------------------------------

DataTiddler.originalTiddlerChangedFunction = Tiddler.prototype.changed;
Tiddler.prototype.changed = DataTiddler.MyTiddlerChangedFunction;

// Define accessor methods -------------------------------------------------------

// Returns the value of the given data field of the tiddler. When no such field 
// is defined or its value is undefined the defaultValue is returned.
//
// When field is undefined (or null) the data object is returned. (See 
// DataTiddler.getDataObject.)
//
// @param field [may be null, undefined]
// @param defaultValue [may be null, undefined]
// @return [may be null, undefined]
//
Tiddler.prototype.data = function(field, defaultValue) {
    return (field) 
         ? DataTiddler.getTiddlerDataValue(this, field, defaultValue)
         : DataTiddler.getTiddlerDataObject(this);
};

// Sets the value of the given data field of the tiddler to the value. When the 
// value is equal to the defaultValue no value is set (and the field is removed).
//
// @param value [may be null, undefined]
// @param defaultValue [may be null, undefined]
//
Tiddler.prototype.setData = function(field, value, defaultValue) {
    DataTiddler.setTiddlerDataValue(this, field, value, defaultValue);
};


//============================================================================
// showData Macro
//============================================================================

config.macros.showData = {
     // Standard Properties
     label: "showData",
     prompt: "Display the values stored in the data section of the tiddler"
};

config.macros.showData.handler = function(place,macroName,params) {
    // --- Parsing ------------------------------------------

    var i = 0; // index running over the params
    // Parse the optional "JSON"
    var showInJSONFormat = false;
    if ((i < params.length) && params[i] == "JSON") {
        i++;
        showInJSONFormat = true;
    }
    
    var tiddlerName = story.findContainingTiddler(place).id.substr(7);
    if (i < params.length) {
        tiddlerName = params[i];
        i++;
    }

    // --- Processing ------------------------------------------
    try {
        if (showInJSONFormat) {
            this.renderDataInJSONFormat(place, tiddlerName);
        } else {
            this.renderDataAsTable(place, tiddlerName);
        }
    } catch (e) {
        this.createErrorElement(place, e);
    }
};

config.macros.showData.renderDataInJSONFormat = function(place,tiddlerName) {
    var text = DataTiddler.getDataText(tiddlerName);
    if (text) {
        createTiddlyElement(place,"pre",null,null,text);
    }
};

config.macros.showData.renderDataAsTable = function(place,tiddlerName) {
    var text = "|!Name|!Value|\n";
    var data = DataTiddler.getDataObject(tiddlerName);
    if (data) {
        for (var i in data) {
            var value = data[i];
            text += "|"+i+"|"+DataTiddler.stringify(value)+"|\n";
        }
    }
    
    wikify(text, place);
};


// Internal.
//
// Creates an element that holds an error message
// 
config.macros.showData.createErrorElement = function(place, exception) {
    var message = (exception.description) ? exception.description : exception.toString();
    return createTiddlyElement(place,"span",null,"showDataError","<<showData ...>>: "+message);
};

// ---------------------------------------------------------------------------
// Stylesheet Extensions (may be overridden by local StyleSheet)
// ---------------------------------------------------------------------------
//
setStylesheet(
    ".showDataError{color: #ffffff;background-color: #880000;}",
    "showData");


} // of "install only once"
// Used Globals (for JSLint) ==============

// ... TiddlyWiki Core
/*global 	createTiddlyElement, saveChanges, store, story, wikify */
// ... DataTiddler
/*global 	DataTiddler */
// ... JSON
/*global 	JSON */
			

/***
!JSON Code, used to serialize the data
***/
/*
Copyright (c) 2005 JSON.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The Software shall be used for Good, not Evil.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/*
    The global object JSON contains two methods.

    JSON.stringify(value) takes a JavaScript value and produces a JSON text.
    The value must not be cyclical.

    JSON.parse(text) takes a JSON text and produces a JavaScript value. It will
    throw a 'JSONError' exception if there is an error.
*/
var JSON = {
    copyright: '(c)2005 JSON.org',
    license: 'http://www.crockford.com/JSON/license.html',
/*
    Stringify a JavaScript value, producing a JSON text.
*/
    stringify: function (v) {
        var a = [];

/*
    Emit a string.
*/
        function e(s) {
            a[a.length] = s;
        }

/*
    Convert a value.
*/
        function g(x) {
            var c, i, l, v;

            switch (typeof x) {
            case 'object':
                if (x) {
                    if (x instanceof Array) {
                        e('[');
                        l = a.length;
                        for (i = 0; i < x.length; i += 1) {
                            v = x[i];
                            if (typeof v != 'undefined' &&
                                    typeof v != 'function') {
                                if (l < a.length) {
                                    e(',');
                                }
                                g(v);
                            }
                        }
                        e(']');
                        return;
                    } else if (typeof x.toString != 'undefined') {
                        e('{');
                        l = a.length;
                        for (i in x) {
                            v = x[i];
                            if (x.hasOwnProperty(i) &&
                                    typeof v != 'undefined' &&
                                    typeof v != 'function') {
                                if (l < a.length) {
                                    e(',');
                                }
                                g(i);
                                e(':');
                                g(v);
                            }
                        }
                        return e('}');
                    }
                }
                e('null');
                return;
            case 'number':
                e(isFinite(x) ? +x : 'null');
                return;
            case 'string':
                l = x.length;
                e('"');
                for (i = 0; i < l; i += 1) {
                    c = x.charAt(i);
                    if (c >= ' ') {
                        if (c == '\\' || c == '"') {
                            e('\\');
                        }
                        e(c);
                    } else {
                        switch (c) {
                            case '\b':
                                e('\\b');
                                break;
                            case '\f':
                                e('\\f');
                                break;
                            case '\n':
                                e('\\n');
                                break;
                            case '\r':
                                e('\\r');
                                break;
                            case '\t':
                                e('\\t');
                                break;
                            default:
                                c = c.charCodeAt();
                                e('\\u00' + Math.floor(c / 16).toString(16) +
                                    (c % 16).toString(16));
                        }
                    }
                }
                e('"');
                return;
            case 'boolean':
                e(String(x));
                return;
            default:
                e('null');
                return;
            }
        }
        g(v);
        return a.join('');
    },
/*
    Parse a JSON text, producing a JavaScript value.
*/
    parse: function (text) {
        var p = /^\s*(([,:{}\[\]])|"(\\.|[^\x00-\x1f"\\])*"|-?\d+(\.\d*)?([eE][+-]?\d+)?|true|false|null)\s*/,
            token,
            operator;

        function error(m, t) {
            throw {
                name: 'JSONError',
                message: m,
                text: t || operator || token
            };
        }

        function next(b) {
            if (b && b != operator) {
                error("Expected '" + b + "'");
            }
            if (text) {
                var t = p.exec(text);
                if (t) {
                    if (t[2]) {
                        token = null;
                        operator = t[2];
                    } else {
                        operator = null;
                        try {
                            token = eval(t[1]);
                        } catch (e) {
                            error("Bad token", t[1]);
                        }
                    }
                    text = text.substring(t[0].length);
                } else {
                    error("Unrecognized token", text);
                }
            } else {
                token = operator = undefined;
            }
        }


        function val() {
            var k, o;
            switch (operator) {
            case '{':
                next('{');
                o = {};
                if (operator != '}') {
                    for (;;) {
                        if (operator || typeof token != 'string') {
                            error("Missing key");
                        }
                        k = token;
                        next();
                        next(':');
                        o[k] = val();
                        if (operator != ',') {
                            break;
                        }
                        next(',');
                    }
                }
                next('}');
                return o;
            case '[':
                next('[');
                o = [];
                if (operator != ']') {
                    for (;;) {
                        o.push(val());
                        if (operator != ',') {
                            break;
                        }
                        next(',');
                    }
                }
                next(']');
                return o;
            default:
                if (operator !== null) {
                    error("Missing value");
                }
                k = token;
                next();
                return k;
            }
        }
        next();
        return val();
    }
};

/***
!Setup the data serialization
***/

DataTiddler.format = "JSON";
DataTiddler.stringify = JSON.stringify;
DataTiddler.parse = JSON.parse;

//}}}

I am a missionary with the Christian Reformed Church in Mexico City. I use TiddlyWiki primarily to create Spanish Bible resources. If you want to know more about me, visit my website [[link here|http://www.giffmex.org/bloghome.html]], which has personal info, articles, links to our photos on Flickr, links to my other TiddlyWiki resources, links to my Spanish resources, etc.

If you have questions about TiddlyWiki, you should first consult my TiddlyWiki tutorial (http://www.giffmex.org/twfortherestofus.html), and if you still have questions, contact the TiddlyWiki group at Google [[link here|http://groups-beta.google.com/group/TiddlyWiki]] rather than contact me. 

But if you must contact me, my e-mail is contacto (at) giffmex (dot) org. Please, no spam. My thoughts on spam can be found [[here|http://www.giffmex.org/gniknow.html]].

In the right-hand Interface options panel, there are several options with check boxes beside them, and two of them are {{{SaveBackups}}} and {{{AutoSave}}}. When {{{SaveBackups}}} is checked, TiddlyWiki automatically makes an entire backup copy of itself in the folder where it is located or in a folder designated by you in AdvancedOptions whenever changes are saved.  When {{{AutoSave}}} is checked, TiddlyWiki saves changes immediately after they are made.

Below is a chart on the pros and cons of checking and unchecking these items.

|! ''SaveBackups'' |! ''AutoSave'' |! Description |!  ''Use these options together...'' |
|vertical-align:top;[X]<<br>>(checked)|vertical-align:top;[X]<<br>>(checked)|vertical-align:top;TiddlyWiki saves every change immediately to the current file, and also creates an entire backup copy of itself with every change.<<br>><<br>>If you make a mistake, just go to the backup of the previously saved version and rename it to the original file's name. |vertical-align:top;...if you really need a backup copy for every change you make, as a safety net so that you don't lose valuable information because of mistakes.<<br>><<br>>...if you don't want to hit "save changes" yourself but you need to save your data at every step.<<br>><<br>>...if you don't mind the delay in automatic saves and backups as your file gets larger.<<br>><<br>>...if you are willing to manually delete all those backup files (they add up fast!)<<br>><<br>>|
|bgcolor(#eeeeee):vertical-align:top;[_]<<br>>(unchecked)|bgcolor(#eeeeee):vertical-align:top;[_]<<br>>(unchecked)|bgcolor(#eeeeee):vertical-align:top;TiddlyWiki saves nothing until you click "save changes" in the right-hand sidebar. Changes are saved to the current file. |bgcolor(#eeeeee):vertical-align:top;...if you don't need the safety net of backup copies in case of mistakes, and would prefer changes to be saved to the current file.<<br>><<br>>...if you prefer to save changes manually at regular intervals rather than wait while TiddlyWiki saves your changes for you.<<br>><<br>>...if you don't have the hard drive space for multiple backup copes or don't like deleting them.<<br>><<br>>...if you are confident that your computer won't crash between your manual saves.<<br>><<br>>|
|vertical-align:top;[X]<<br>>(checked)|vertical-align:top;[_]<<br>>(unchecked)|vertical-align:top;TiddlyWiki saves an entire backup copy of itself, but only when you save changes manually.|vertical-align:top;...if you want the safety net of backup copies in case of mistakes, but you don't want one for every single change you make. <<br>><<br>>...if you prefer to save changes manually at regular intervals rather than have TiddlyWiki save changes at every step.<<br>><<br>>...if you are willing to manually delete backup files later.<<br>><<br>>...if you are confident that your computer won't crash between your manual saves.<<br>><<br>>|
|vertical-align:top;bgcolor(#eeeeee):[_]<<br>>(unchecked)|bgcolor(#eeeeee):vertical-align:top;[X]<<br>>(checked)|bgcolor(#eeeeee):vertical-align:top;TiddlyWiki saves every change immediately to the current file, but does not create a backup copy of itself.|bgcolor(#eeeeee):vertical-align:top;...if you prefer changes to be saved to the current file rather than have the safety net of backup copies.<<br>><<br>>...if you prefer TiddlyWiki to save your changes automatically rather than have to hit 'save changes' every now and then.<<br>><<br>>...if you don't have the hard drive space for multiple backup copes or don't like deleting them.<<br>><<br>>...if you don't mind waiting for TiddlyWiki to save every change, because you want to make sure your changes are saved at every step.<<br>><<br>>...if you are confident that you won't irretrievably lose valuable information by making a mistake.<<br>><<br>>|


<<formTiddler NewBookTemplate>><data>{"author":"Kiran Desai","booktitle":"The inheritance of loss","pubinfo":"Grove (2006) ","mine":true,"medium":"Paperback","genre":"Drama","primtopic":"Culture","rating":"85","synopsis":"Life in India, then USA, then India"}</data>Winner of the 2006 Man Booker prize.
Wonderfully written, tragic and funny, account of the period of growing up of a child of up-country India, who moves to USA for fortune, and returns to his home village at a difficult time. 
!!!Comments:
<<comment>>
By default, the [[First things first]] tiddler appears when you open this file. Obviously you won't need that anymore after you go through these steps. Click on DefaultTiddlers and doubleclick the tiddler that appears. Remove [[First things first]] and add whatever tiddlers you want to appear at startup, if anything. Tiddler titles need either to be WikiWords or surrounded by double brackets. {{{[[like this]]}}}

<<formTiddler NewBookTemplate>><data>{"author":"Jared Diamond","booktitle":"Collapse","pubinfo":"Penguin (2005)","mine":true,"keep":true,"medium":"Paperback","genre":"Non-fiction - Reference","primtopic":"History","synopsis":"How societies choose to fail or survive.","rating":"0"}</data>Not read yet.
!!!Comments
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Jared Diamond","booktitle":"Guns, germs and Steel","pubinfo":"Vintage (1997)","mine":true,"keep":true,"medium":"Paperback","genre":"Non-fiction - Reference","primtopic":"Human History","rating":"0"}</data>Not read yet.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Michael Dibdin","booktitle":"End games","pubinfo":"Faber & Faber (2007)","mine":true,"medium":"PaperBack","genre":"Thriller","primtopic":"Murder","synopsis":"policeman investigates a Sicilian murder","rating":"70"}</data>Inspector Aurelio Zen investigates a bizarre murder in Sicily...hampered all along the way by local superstition, and Mafia intrigue.
!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Andre Dubus III","booktitle":"The House of Sand and Fog","pubinfo":"Vintage (2004)","mine":true,"medium":"Paperback","genre":"Drama","primtopic":"Fight for a House","synopsis":"Clash of cultures, leading to unfortunate events.","rating":"85","keep":true}</data>An exceptionally well-told tale of the unfortunate outcomes resulting from mis-understandings due to cultural differences. Great story, excellent character development, complex and interesting scenes...not surprisingly, the book was snapped up and quickly converted into a very high quality movie.
!!!Comments:
<comment>>
<!--{{{-->
<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<div class='editor' macro='edit text'></div>

<!--}}}-->

<<formTiddler NewBookTemplate>><data>{"author":"Ben Elton","booktitle":"Blind Faith","pubinfo":"Black Swan  Paperback (2007)","mine":true,"primtopic":"Society","medium":"Paperback","genre":"Satire","rating":"75","keep":true,"synopsis":"Mankind is drugged on sugar & porn, and controlled by religion."}</data>
<<notes heading:'Rays Notes'>> 
!!!Comments:
<<comment>>
So...here is another satirical novel by Ben Elton.

This one has shades of George Orwell's //1984//  and of Ray Bradbury's //Fahrenheit 541// throughout, but updated to include the Internet and //Global Warming//.

There is a sort of comic influence to the whole book, but Elton is constantly pushing the reader to consider the fine edge between humour and nightmare.

Despite the gory ending, wherein the hero is burned alive on a pile of books, Elton manages to give the whole thing a last minute twist and finish on a hopeful note.

If Elton is giving us a cautionary tale, then it has got to be on the basis that we are already addicted to:
* sugar
* internet porn, and
* Blind Faith.

I had some difficulty getting into the swing of the first 30 pages of the book [not unusual with Ben Elton's books, due to his unusual non-flowing style] but finally got taken hold of by the compelling story and dark humour.
Ray20080916
*Figure out how to do "All topics" integration
*Figure out how to do "My library" indexes
*Create a form for webpage articles
*Add 'This is digital' to book template
*Spanish version of BibblyWiki
*Beef up credits to include plugin authors
*Add tag cloud, or is this thing too bloated as it is?

Any ideas for other features? Contact me at giff (at) giffmex (dot) org. 
This is a personal organizer based on TiddlyWiki software. Feel free to browse through the options in the topmenu. But when you feel convinced that you want to save and use this organizer for yourself, you will find below the first things you will need to do. Click any instruction below to open its "tiddler".

[[Save BibblyWiki to your computer]]
[[Assign yourself a username]]
[[Personalize the title and subtitle in the header]]
[[Determine what you want to appear when you first open the file]]
[[Decide on saving options]]

<<formTiddler NewBookTemplate>><data>{"author":"Fannie Flagg","booktitle":"Welcome to the World, Baby Girl","pubinfo":"Ballantine Books (1998)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Fiction, general","primtopic":"Drama","synopsis":"Forty years in the life of a country girl who makes good in the city.","rating":"70"}</data>Light weight, light hearted romp through the lives of a family of characters, most of whom are country bumpkins. Flagg paints word pictures quite well.
!!!Comments:
<<comment>>
/***
|Name|FontSizePlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#FontSizePlugin|
|Version|1.0|
|Requires|~TW2.x|
!Description:
Resize tiddler text on the fly. The text size is remembered between sessions by use of a cookie.
You can customize the maximum and minimum allowed sizes.
(only affects tiddler content text, not any other text)

Also, you can load a TW file with a font-size specified in the url.
Eg: http://tw.lewcid.org/#font:110

!Demo:
Try using the font-size buttons in the sidebar, or in the MainMenu above.

!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.
Then put {{{<<fontSize "font-size:">>}}} in your SideBarOptions tiddler, or anywhere else that you might like.

!Usage
{{{<<fontSize>>}}} results in <<fontSize>>
{{{<<fontSize font-size: >>}}} results in <<fontSize font-size:>>

!Customizing:
The buttons and prefix text are wrapped in a span with class fontResizer, for easy css styling.
To change the default font-size, and the maximum and minimum font-size allowed, edit the config.fontSize.settings section of the code below.

!Notes:
This plugin assumes that the initial font-size is 100% and then increases or decreases the size by 10%. This stepsize of 10% can also be customized.

!History:
*27-07-06, version 1.0 : prevented double clicks from triggering editing of containing tiddler.
*25-07-06,  version 0.9

!Code
***/

//{{{
config.fontSize={};

//configuration settings
config.fontSize.settings =
{
            defaultSize : 100,  // all sizes in %
            maxSize : 200,
            minSize : 40,
            stepSize : 10
};

//startup code
var fontSettings = config.fontSize.settings;

if (!config.options.txtFontSize)
            {config.options.txtFontSize = fontSettings.defaultSize;
            saveOptionCookie("txtFontSize");}
setStylesheet(".tiddler .viewer {font-size:"+config.options.txtFontSize+"%;}\n","fontResizerStyles");
setStylesheet("#contentWrapper .fontResizer .button {display:inline;font-size:105%; font-weight:bold; margin:0 1px; padding: 0 3px; text-align:center !important;}\n .fontResizer {margin:0 0.5em;}","fontResizerButtonStyles");

//macro
config.macros.fontSize={};
config.macros.fontSize.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{

               var sp = createTiddlyElement(place,"span",null,"fontResizer");
               sp.ondblclick=this.onDblClick;
               if (params[0])
                           createTiddlyText(sp,params[0]);
               createTiddlyButton(sp,"+","increase font-size",this.incFont);
               createTiddlyButton(sp,"=","reset font-size",this.resetFont);
               createTiddlyButton(sp,"–","decrease font-size",this.decFont);
}

config.macros.fontSize.onDblClick = function (e)
{
             if (!e) var e = window.event;
             e.cancelBubble = true;
             if (e.stopPropagation) e.stopPropagation();
             return false;
}

config.macros.fontSize.setFont = function ()
{
               saveOptionCookie("txtFontSize");
               setStylesheet(".tiddler .viewer {font-size:"+config.options.txtFontSize+"%;}\n","fontResizerStyles");
}

config.macros.fontSize.incFont=function()
{
               if (config.options.txtFontSize < fontSettings.maxSize)
                  config.options.txtFontSize = (config.options.txtFontSize*1)+fontSettings.stepSize;
               config.macros.fontSize.setFont();
}

config.macros.fontSize.decFont=function()
{

               if (config.options.txtFontSize > fontSettings.minSize)
                  config.options.txtFontSize = (config.options.txtFontSize*1) - fontSettings.stepSize;
               config.macros.fontSize.setFont();
}

config.macros.fontSize.resetFont=function()
{

               config.options.txtFontSize=fontSettings.defaultSize;
               config.macros.fontSize.setFont();
}

config.paramifiers.font =
{
               onstart: function(v)
                  {
                   config.options.txtFontSize = v;
                   config.macros.fontSize.setFont();
                  }
};
//}}}
FontSizePlugin ver 1.0

FontSizePlugin has been updated to prevent double clicks of the button from triggering editing of the containing tiddler.

Type tags separated with spaces, [[use double square brackets]] if necessary, or add existingtagsTags: ▼closeclose others ↕ viewpermalinkreferencesjump
FontSizePlugin
27 July 2006(created 25 July 2006)
Name FontSizePlugin 
Created by SaqImtiaz 
Location http://tw.lewcid.org/#FontSizePlugin 
Version 1.0 
Requires TW2.x 

Description:
Resize tiddler text on the fly. The text size is remembered between sessions by use of a cookie.
You can customize the maximum and minimum allowed sizes.
(only affects tiddler content text, not any other text)

Also, you can load a TW file with a font-size specified in the url.
Eg: http://tw.lewcid.org/#font:110


Demo:
Try using the font-size buttons in the sidebar, or in the MainMenu above.


Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.
Then put <<fontSize "font-size:">> in your SideBarOptions tiddler, or anywhere else that you might like.


Usage
<<fontSize>> results in +=–
<<fontSize font-size: >> results in font-size:+=–


Customizing:
The buttons and prefix text are wrapped in a span with class fontResizer, for easy css styling.
To change the default font-size, and the maximum and minimum font-size allowed, edit the config.fontSize.settings section of the code below.


Notes:
This plugin assumes that the initial font-size is 100% and then increases or decreases the size by 10%. This stepsize of 10% can also be customized.


History:
27-07-06, version 1.0 : prevented double clicks from triggering editing of containing tiddler.
25-07-06,  version 0.9


Code

config.fontSize={};

//configuration settings
config.fontSize.settings =
{
            defaultSize : 100,  // all sizes in %
            maxSize : 200,
            minSize : 40,
            stepSize : 10
};

//startup code
var fontSettings = config.fontSize.settings;

if (!config.options.txtFontSize)
            {config.options.txtFontSize = fontSettings.defaultSize;
            saveOptionCookie("txtFontSize");}
setStylesheet(".tiddler .viewer {font-size:"+config.options.txtFontSize+"%;}\n","fontResizerStyles");
setStylesheet("#contentWrapper .fontResizer .button {display:inline;font-size:105%; font-weight:bold; margin:0 1px; padding: 0 3px; text-align:center !important;}\n .fontResizer {margin:0 0.5em;}","fontResizerButtonStyles");

//macro
config.macros.fontSize={};
config.macros.fontSize.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{

               var sp = createTiddlyElement(place,"span",null,"fontResizer");
               sp.ondblclick=this.onDblClick;
               if (params[0])
                           createTiddlyText(sp,params[0]);
               createTiddlyButton(sp,"+","increase font-size",this.incFont);
               createTiddlyButton(sp,"=","reset font-size",this.resetFont);
               createTiddlyButton(sp,"–","decrease font-size",this.decFont);
}

config.macros.fontSize.onDblClick = function (e)
{
             if (!e) var e = window.event;
             e.cancelBubble = true;
             if (e.stopPropagation) e.stopPropagation();
             return false;
}

config.macros.fontSize.setFont = function ()
{
               saveOptionCookie("txtFontSize");
               setStylesheet(".tiddler .viewer {font-size:"+config.options.txtFontSize+"%;}\n","fontResizerStyles");
}

config.macros.fontSize.incFont=function()
{
               if (config.options.txtFontSize < fontSettings.maxSize)
                  config.options.txtFontSize = (config.options.txtFontSize*1)+fontSettings.stepSize;
               config.macros.fontSize.setFont();
}

config.macros.fontSize.decFont=function()
{

               if (config.options.txtFontSize > fontSettings.minSize)
                  config.options.txtFontSize = (config.options.txtFontSize*1) - fontSettings.stepSize;
               config.macros.fontSize.setFont();
}

config.macros.fontSize.resetFont=function()
{

               config.options.txtFontSize=fontSettings.defaultSize;
               config.macros.fontSize.setFont();
}

config.paramifiers.font =
{
               onstart: function(v)
                  {
                   config.options.txtFontSize = v;
                   config.macros.fontSize.setFont();
                  }
};
/***
|''Name:''|ForEachTiddlerPlugin|
|''Version:''|1.0.5 (2006-02-05)|
|''Source:''|http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license]]|
|''Macros:''|[[ForEachTiddlerMacro]] v1.0.5|
|''TiddlyWiki:''|1.2.38+, 2.0|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|
!Description

Create customizable lists, tables etc. for your selections of tiddlers. Specify the tiddlers to include and their order through a powerful language.

''Syntax:'' 
|>|{{{<<}}}''forEachTiddler'' [''in'' //tiddlyWikiPath//] [''where'' //whereCondition//] [''sortBy'' //sortExpression// [''ascending'' //or// ''descending'']] [''script'' //scriptText//] [//action// [//actionParameters//]]{{{>>}}}|
|//tiddlyWikiPath//|The filepath to the TiddlyWiki the macro should work on. When missing the current TiddlyWiki is used.|
|//whereCondition//|(quoted) JavaScript boolean expression. May refer to the build-in variables {{{tiddler}}} and {{{context}}}.|
|//sortExpression//|(quoted) JavaScript expression returning "comparable" objects (using '{{{<}}}','{{{>}}}','{{{==}}}'. May refer to the build-in variables {{{tiddler}}} and {{{context}}}.|
|//scriptText//|(quoted) JavaScript text. Typically defines JavaScript functions that are called by the various JavaScript expressions (whereClause, sortClause, action arguments,...)|
|//action//|The action that should be performed on every selected tiddler, in the given order. By default the actions [[addToList|AddToListAction]] and [[write|WriteAction]] are supported. When no action is specified [[addToList|AddToListAction]] is used.|
|//actionParameters//|(action specific) parameters the action may refer while processing the tiddlers (see action descriptions for details). <<tiddler [[JavaScript in actionParameters]]>>|
|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|

See details see [[ForEachTiddlerMacro]] and [[ForEachTiddlerExamples]].

!Revision history
* v1.0.5
** Pass tiddler containing the macro with wikify, context object also holds reference to tiddler containing the macro ("inTiddler"). Thanks to SimonBaird.
** Support Firefox 1.5.0.1
** Internal
*** Make "JSLint" conform
*** "Only install once"
* v1.0.4 (2006-01-06)
** Support TiddlyWiki 2.0
* v1.0.3 (2005-12-22)
** Features: 
*** Write output to a file supports multi-byte environments (Thanks to Bram Chen) 
*** Provide API to access the forEachTiddler functionality directly through JavaScript (see getTiddlers and performMacro)
** Enhancements:
*** Improved error messages on InternetExplorer.
* v1.0.2 (2005-12-10)
** Features: 
*** context object also holds reference to store (TiddlyWiki)
** Fixed Bugs: 
*** ForEachTiddler 1.0.1 has broken support on win32 Opera 8.51 (Thanks to BrunoSabin for reporting)
* v1.0.1 (2005-12-08)
** Features: 
*** Access tiddlers stored in separated TiddlyWikis through the "in" option. I.e. you are no longer limited to only work on the "current TiddlyWiki".
*** Write output to an external file using the "toFile" option of the "write" action. With this option you may write your customized tiddler exports.
*** Use the "script" section to define "helper" JavaScript functions etc. to be used in the various JavaScript expressions (whereClause, sortClause, action arguments,...).
*** Access and store context information for the current forEachTiddler invocation (through the build-in "context" object) .
*** Improved script evaluation (for where/sort clause and write scripts).
* v1.0.0 (2005-11-20)
** initial version

!Code
***/
//{{{

 
//============================================================================
//============================================================================
// ForEachTiddlerPlugin
//============================================================================
//============================================================================

// Only install once
if (!version.extensions.ForEachTiddlerPlugin) {

version.extensions.ForEachTiddlerPlugin = {major: 1, minor: 0, revision: 5, date: new Date(2006,2,5), source: "http://tiddlywiki.abego-software.de/#ForEachTiddlergPlugin"};

// For backward compatibility with TW 1.2.x
//
if (!TiddlyWiki.prototype.forEachTiddler) {
 TiddlyWiki.prototype.forEachTiddler = function(callback) {
 for(var t in this.tiddlers) {
 callback.call(this,t,this.tiddlers[t]);
 }
 };
}

//============================================================================
// forEachTiddler Macro
//============================================================================

version.extensions.forEachTiddler = {major: 1, minor: 0, revision: 5, date: new Date(2006,2,5), provider: "http://tiddlywiki.abego-software.de"};

// ---------------------------------------------------------------------------
// Configurations and constants 
// ---------------------------------------------------------------------------

config.macros.forEachTiddler = {
 // Standard Properties
 label: "forEachTiddler",
 prompt: "Perform actions on a (sorted) selection of tiddlers",

 // actions
 actions: {
 addToList: {},
 write: {}
 }
};

// ---------------------------------------------------------------------------
// The forEachTiddler Macro Handler 
// ---------------------------------------------------------------------------

config.macros.forEachTiddler.getContainingTiddler = function(e) {
 while(e && !hasClass(e,"tiddler"))
 e = e.parentNode;
 var title = e ? e.getAttribute("tiddler") : null; 
 return title ? store.getTiddler(title) : null;
};

config.macros.forEachTiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
 // config.macros.forEachTiddler.traceMacroCall(place,macroName,params,wikifier,paramString,tiddler);

 if (!tiddler) tiddler = config.macros.forEachTiddler.getContainingTiddler(place);
 // --- Parsing ------------------------------------------

 var i = 0; // index running over the params
 // Parse the "in" clause
 var tiddlyWikiPath = undefined;
 if ((i < params.length) && params[i] == "in") {
 i++;
 if (i >= params.length) {
 this.handleError(place, "TiddlyWiki path expected behind 'in'.");
 return;
 }
 tiddlyWikiPath = this.paramEncode((i < params.length) ? params[i] : "");
 i++;
 }

 // Parse the where clause
 var whereClause ="true";
 if ((i < params.length) && params[i] == "where") {
 i++;
 whereClause = this.paramEncode((i < params.length) ? params[i] : "");
 i++;
 }

 // Parse the sort stuff
 var sortClause = null;
 var sortAscending = true; 
 if ((i < params.length) && params[i] == "sortBy") {
 i++;
 if (i >= params.length) {
 this.handleError(place, "sortClause missing behind 'sortBy'.");
 return;
 }
 sortClause = this.paramEncode(params[i]);
 i++;

 if ((i < params.length) && (params[i] == "ascending" || params[i] == "descending")) {
 sortAscending = params[i] == "ascending";
 i++;
 }
 }

 // Parse the script
 var scriptText = null;
 if ((i < params.length) && params[i] == "script") {
 i++;
 scriptText = this.paramEncode((i < params.length) ? params[i] : "");
 i++;
 }

 // Parse the action. 
 // When we are already at the end use the default action
 var actionName = "addToList";
 if (i < params.length) {
 if (!config.macros.forEachTiddler.actions[params[i]]) {
 this.handleError(place, "Unknown action '"+params[i]+"'.");
 return;
 } else {
 actionName = params[i]; 
 i++;
 }
 } 
 
 // Get the action parameter
 // (the parsing is done inside the individual action implementation.)
 var actionParameter = params.slice(i);


 // --- Processing ------------------------------------------
 try {
 this.performMacro({
 place: place, 
 inTiddler: tiddler,
 whereClause: whereClause, 
 sortClause: sortClause, 
 sortAscending: sortAscending, 
 actionName: actionName, 
 actionParameter: actionParameter, 
 scriptText: scriptText, 
 tiddlyWikiPath: tiddlyWikiPath});

 } catch (e) {
 this.handleError(place, e);
 }
};

// Returns an object with properties "tiddlers" and "context".
// tiddlers holds the (sorted) tiddlers selected by the parameter,
// context the context of the execution of the macro.
//
// The action is not yet performed.
//
// @parameter see performMacro
//
config.macros.forEachTiddler.getTiddlersAndContext = function(parameter) {

 var context = config.macros.forEachTiddler.createContext(parameter.place, parameter.whereClause, parameter.sortClause, parameter.sortAscending, parameter.actionName, parameter.actionParameter, parameter.scriptText, parameter.tiddlyWikiPath, parameter.inTiddler);

 var tiddlyWiki = parameter.tiddlyWikiPath ? this.loadTiddlyWiki(parameter.tiddlyWikiPath) : store;
 context["tiddlyWiki"] = tiddlyWiki;
 
 // Get the tiddlers, as defined by the whereClause
 var tiddlers = this.findTiddlers(parameter.whereClause, context, tiddlyWiki);
 context["tiddlers"] = tiddlers;

 // Sort the tiddlers, when sorting is required.
 if (parameter.sortClause) {
 this.sortTiddlers(tiddlers, parameter.sortClause, parameter.sortAscending, context);
 }

 return {tiddlers: tiddlers, context: context};
};

// Returns the (sorted) tiddlers selected by the parameter.
//
// The action is not yet performed.
//
// @parameter see performMacro
//
config.macros.forEachTiddler.getTiddlers = function(parameter) {
 return this.getTiddlersAndContext(parameter).tiddlers;
};

// Performs the macros with the given parameter.
//
// @param parameter holds the parameter of the macro as separate properties.
// The following properties are supported:
//
// place
// whereClause
// sortClause
// sortAscending
// actionName
// actionParameter
// scriptText
// tiddlyWikiPath
//
// All properties are optional. 
// For most actions the place property must be defined.
//
config.macros.forEachTiddler.performMacro = function(parameter) {
 var tiddlersAndContext = this.getTiddlersAndContext(parameter);

 // Perform the action
 var actionName = parameter.actionName ? parameter.actionName : "addToList";
 var action = config.macros.forEachTiddler.actions[actionName];
 if (!action) {
 this.handleError(parameter.place, "Unknown action '"+actionName+"'.");
 return;
 }

 var actionHandler = action.handler;
 actionHandler(parameter.place, tiddlersAndContext.tiddlers, parameter.actionParameter, tiddlersAndContext.context);
};

// ---------------------------------------------------------------------------
// The actions 
// ---------------------------------------------------------------------------

// Internal.
//
// --- The addToList Action -----------------------------------------------
//
config.macros.forEachTiddler.actions.addToList.handler = function(place, tiddlers, parameter, context) {
 // Parse the parameter
 var p = 0;

 // Check for extra parameters
 if (parameter.length > p) {
 config.macros.forEachTiddler.createExtraParameterErrorElement(place, "addToList", parameter, p);
 return;
 }

 // Perform the action.
 var list = document.createElement("ul");
 place.appendChild(list);
 for (var i = 0; i < tiddlers.length; i++) {
 var tiddler = tiddlers[i];
 var listItem = document.createElement("li");
 list.appendChild(listItem);
 createTiddlyLink(listItem, tiddler.title, true);
 }
};

// Internal.
//
// --- The write Action ---------------------------------------------------
//
config.macros.forEachTiddler.actions.write.handler = function(place, tiddlers, parameter, context) {
 // Parse the parameter
 var p = 0;
 if (p >= parameter.length) {
 this.handleError(place, "Missing expression behind 'write'.");
 return;
 }

 var textExpression = config.macros.forEachTiddler.paramEncode(parameter[p]);
 p++;

 // Parse the "toFile" option
 var filename = null;
 var lineSeparator = undefined;
 if ((p < parameter.length) && parameter[p] == "toFile") {
 p++;
 if (p >= parameter.length) {
 this.handleError(place, "Filename expected behind 'toFile' of 'write' action.");
 return;
 }
 
 filename = config.macros.forEachTiddler.getLocalPath(config.macros.forEachTiddler.paramEncode(parameter[p]));
 p++;
 if ((p < parameter.length) && parameter[p] == "withLineSeparator") {
 p++;
 if (p >= parameter.length) {
 this.handleError(place, "Line separator text expected behind 'withLineSeparator' of 'write' action.");
 return;
 }
 lineSeparator = config.macros.forEachTiddler.paramEncode(parameter[p]);
 p++;
 }
 }
 
 // Check for extra parameters
 if (parameter.length > p) {
 config.macros.forEachTiddler.createExtraParameterErrorElement(place, "write", parameter, p);
 return;
 }

 // Perform the action.
 var func = config.macros.forEachTiddler.getEvalTiddlerFunction(textExpression, context);
 var count = tiddlers.length;
 var text = "";
 for (var i = 0; i < count; i++) {
 var tiddler = tiddlers[i];
 text += func(tiddler, context, count, i);
 }
 
 if (filename) {
 if (lineSeparator !== undefined) {
 lineSeparator = lineSeparator.replace(/\\n/mg, "\n").replace(/\\r/mg, "\r");
 text = text.replace(/\n/mg,lineSeparator);
 }
 saveFile(filename, convertUnicodeToUTF8(text));
 } else {
 var wrapper = createTiddlyElement(place, "span");
 wikify(text, wrapper, null/* highlightRegExp */, context.inTiddler);
 }
};


// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

// Internal.
//
config.macros.forEachTiddler.createContext = function(placeParam, whereClauseParam, sortClauseParam, sortAscendingParam, actionNameParam, actionParameterParam, scriptText, tiddlyWikiPathParam, inTiddlerParam) {
 return {
 place : placeParam, 
 whereClause : whereClauseParam, 
 sortClause : sortClauseParam, 
 sortAscending : sortAscendingParam, 
 script : scriptText,
 actionName : actionNameParam, 
 actionParameter : actionParameterParam,
 tiddlyWikiPath : tiddlyWikiPathParam,
 inTiddler : inTiddlerParam
 };
};

// Internal.
//
// Returns a TiddlyWiki with the tiddlers loaded from the TiddlyWiki of 
// the given path.
//
config.macros.forEachTiddler.loadTiddlyWiki = function(path, idPrefix) {
 if (!idPrefix) {
 idPrefix = "store";
 }
 var lenPrefix = idPrefix.length;
 
 // Read the content of the given file
 var content = loadFile(this.getLocalPath(path));
 if(content === null) {
 throw "TiddlyWiki '"+path+"' not found.";
 }
 
 // Locate the storeArea div's
 var posOpeningDiv = content.indexOf(startSaveArea);
 var posClosingDiv = content.lastIndexOf(endSaveArea);
 if((posOpeningDiv == -1) || (posClosingDiv == -1)) {
 throw "File '"+path+"' is not a TiddlyWiki.";
 }
 var storageText = content.substr(posOpeningDiv + startSaveArea.length, posClosingDiv);
 
 // Create a "div" element that contains the storage text
 var myStorageDiv = document.createElement("div");
 myStorageDiv.innerHTML = storageText;
 myStorageDiv.normalize();
 
 // Create all tiddlers in a new TiddlyWiki
 // (following code is modified copy of TiddlyWiki.prototype.loadFromDiv)
 var tiddlyWiki = new TiddlyWiki();
 var store = myStorageDiv.childNodes;
 for(var t = 0; t < store.length; t++) {
 var e = store[t];
 var title = null;
 if(e.getAttribute)
 title = e.getAttribute("tiddler");
 if(!title && e.id && e.id.substr(0,lenPrefix) == idPrefix)
 title = e.id.substr(lenPrefix);
 if(title && title !== "") {
 var tiddler = tiddlyWiki.createTiddler(title);
 tiddler.loadFromDiv(e,title);
 }
 }
 tiddlyWiki.dirty = false;

 return tiddlyWiki;
};


 
// Internal.
//
// Returns a function that has a function body returning the given javaScriptExpression.
// The function has the parameters:
// 
// (tiddler, context, count, index)
//
config.macros.forEachTiddler.getEvalTiddlerFunction = function (javaScriptExpression, context) {
 var script = context["script"];
 var functionText = "var theFunction = function(tiddler, context, count, index) { return "+javaScriptExpression+"}";
 var fullText = (script ? script+";" : "")+functionText+";theFunction;";
 return eval(fullText);
};

// Internal.
//
config.macros.forEachTiddler.findTiddlers = function(whereClause, context, tiddlyWiki) {
 var result = [];
 var func = config.macros.forEachTiddler.getEvalTiddlerFunction(whereClause, context);
 tiddlyWiki.forEachTiddler(function(title,tiddler) {
 if (func(tiddler, context, undefined, undefined)) {
 result.push(tiddler);
 }
 });
 return result;
};

// Internal.
//
config.macros.forEachTiddler.createExtraParameterErrorElement = function(place, actionName, parameter, firstUnusedIndex) {
 var message = "Extra parameter behind '"+actionName+"':";
 for (var i = firstUnusedIndex; i < parameter.length; i++) {
 message += " "+parameter[i];
 }
 this.handleError(place, message);
};

// Internal.
//
config.macros.forEachTiddler.sortAscending = function(tiddlerA, tiddlerB) {
 var result = 
 (tiddlerA.forEachTiddlerSortValue == tiddlerB.forEachTiddlerSortValue) 
 ? 0
 : (tiddlerA.forEachTiddlerSortValue < tiddlerB.forEachTiddlerSortValue)
 ? -1 
 : +1; 
 return result;
};

// Internal.
//
config.macros.forEachTiddler.sortDescending = function(tiddlerA, tiddlerB) {
 var result = 
 (tiddlerA.forEachTiddlerSortValue == tiddlerB.forEachTiddlerSortValue) 
 ? 0
 : (tiddlerA.forEachTiddlerSortValue < tiddlerB.forEachTiddlerSortValue)
 ? +1 
 : -1; 
 return result;
};

// Internal.
//
config.macros.forEachTiddler.sortTiddlers = function(tiddlers, sortClause, ascending, context) {
 // To avoid evaluating the sortClause whenever two items are compared 
 // we pre-calculate the sortValue for every item in the array and store it in a 
 // temporary property ("forEachTiddlerSortValue") of the tiddlers.
 var func = config.macros.forEachTiddler.getEvalTiddlerFunction(sortClause, context);
 var count = tiddlers.length;
 var i;
 for (i = 0; i < count; i++) {
 var tiddler = tiddlers[i];
 tiddler.forEachTiddlerSortValue = func(tiddler,context, undefined, undefined);
 }

 // Do the sorting
 tiddlers.sort(ascending ? this.sortAscending : this.sortDescending);

 // Delete the temporary property that holds the sortValue. 
 for (i = 0; i < tiddlers.length; i++) {
 delete tiddlers[i].forEachTiddlerSortValue;
 }
};


// Internal.
//
config.macros.forEachTiddler.trace = function(message) {
 displayMessage(message);
};

// Internal.
//
config.macros.forEachTiddler.traceMacroCall = function(place,macroName,params) {
 var message ="<<"+macroName;
 for (var i = 0; i < params.length; i++) {
 message += " "+params[i];
 }
 message += ">>";
 displayMessage(message);
};


// Internal.
//
// Creates an element that holds an error message
// 
config.macros.forEachTiddler.createErrorElement = function(place, exception) {
 var message = (exception.description) ? exception.description : exception.toString();
 return createTiddlyElement(place,"span",null,"forEachTiddlerError","<<forEachTiddler ...>>: "+message);
};

// Internal.
//
// @param place [may be null]
//
config.macros.forEachTiddler.handleError = function(place, exception) {
 if (place) {
 this.createErrorElement(place, exception);
 } else {
 throw exception;
 }
};

// Internal.
//
// Encodes the given string.
//
// Replaces 
// "$))" to ">>"
// "$)" to ">"
//
config.macros.forEachTiddler.paramEncode = function(s) {
 var reGTGT = new RegExp("\\$\\)\\)","mg");
 var reGT = new RegExp("\\$\\)","mg");
 return s.replace(reGTGT, ">>").replace(reGT, ">");
};

// Internal.
//
// Returns the given original path (that is a file path, starting with "file:")
// as a path to a local file, in the systems native file format.
//
// Location information in the originalPath (i.e. the "#" and stuff following)
// is stripped.
// 
config.macros.forEachTiddler.getLocalPath = function(originalPath) {
 // Remove any location part of the URL
 var hashPos = originalPath.indexOf("#");
 if(hashPos != -1)
 originalPath = originalPath.substr(0,hashPos);
 // Convert to a native file format assuming
 // "file:///x:/path/path/path..." - pc local file --> "x:\path\path\path..."
 // "file://///server/share/path/path/path..." - FireFox pc network file --> "\\server\share\path\path\path..."
 // "file:///path/path/path..." - mac/unix local file --> "/path/path/path..."
 // "file://server/share/path/path/path..." - pc network file --> "\\server\share\path\path\path..."
 var localPath;
 if(originalPath.charAt(9) == ":") // pc local file
 localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\\");
 else if(originalPath.indexOf("file://///") === 0) // FireFox pc network file
 localPath = "\\\\" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\\");
 else if(originalPath.indexOf("file:///") === 0) // mac/unix local file
 localPath = unescape(originalPath.substr(7));
 else if(originalPath.indexOf("file:/") === 0) // mac/unix local file
 localPath = unescape(originalPath.substr(5));
 else // pc network file
 localPath = "\\\\" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\\"); 
 return localPath;
};

// ---------------------------------------------------------------------------
// Stylesheet Extensions (may be overridden by local StyleSheet)
// ---------------------------------------------------------------------------
//
setStylesheet(
 ".forEachTiddlerError{color: #ffffff;background-color: #880000;}",
 "forEachTiddler");

//============================================================================
// End of forEachTiddler Macro
//============================================================================


//============================================================================
// String.startsWith Function
//============================================================================
//
// Returns true if the string starts with the given prefix, false otherwise.
//
version.extensions["String.startsWith"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.startsWith = function(prefix) {
 var n = prefix.length;
 return (this.length >= n) && (this.slice(0, n) == prefix);
};



//============================================================================
// String.endsWith Function
//============================================================================
//
// Returns true if the string ends with the given suffix, false otherwise.
//
version.extensions["String.endsWith"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.endsWith = function(suffix) {
 var n = suffix.length;
 return (this.length >= n) && (this.right(n) == suffix);
};


//============================================================================
// String.contains Function
//============================================================================
//
// Returns true when the string contains the given substring, false otherwise.
//
version.extensions["String.contains"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.contains = function(substring) {
 return this.indexOf(substring) >= 0;
};

//============================================================================
// Array.indexOf Function
//============================================================================
//
// Returns the index of the first occurance of the given item in the array or 
// -1 when no such item exists.
//
// @param item [may be null]
//
version.extensions["Array.indexOf"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.indexOf = function(item) {
 for (var i = 0; i < this.length; i++) {
 if (this[i] == item) {
 return i;
 }
 }
 return -1;
};

//============================================================================
// Array.contains Function
//============================================================================
//
// Returns true when the array contains the given item, otherwise false. 
//
// @param item [may be null]
//
version.extensions["Array.contains"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.contains = function(item) {
 return (this.indexOf(item) >= 0);
};

//============================================================================
// Array.containsAny Function
//============================================================================
//
// Returns true when the array contains at least one of the elements 
// of the item. Otherwise (or when items contains no elements) false is returned.
//
version.extensions["Array.containsAny"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.containsAny = function(items) {
 for(var i = 0; i < items.length; i++) {
 if (this.contains(items[i])) {
 return true;
 }
 }
 return false;
};


//============================================================================
// Array.containsAll Function
//============================================================================
//
// Returns true when the array contains all the items, otherwise false.
// 
// When items is null false is returned (even if the array contains a null).
//
// @param items [may be null] 
//
version.extensions["Array.containsAll"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.containsAll = function(items) {
 for(var i = 0; i < items.length; i++) {
 if (!this.contains(items[i])) {
 return false;
 }
 }
 return true;
};


} // of "install only once"

// Used Globals (for JSLint) ==============
// ... DOM
/*global document */
// ... TiddlyWiki Core
/*global convertUnicodeToUTF8, createTiddlyElement, createTiddlyLink, 
 displayMessage, endSaveArea, hasClass, loadFile, saveFile, 
 startSaveArea, store, wikify */
//}}}


/***
!Licence and Copyright
Copyright (c) abego Software ~GmbH, 2005 ([[www.abego-software.de|http://www.abego-software.de]])

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.

Neither the name of abego Software nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
***/

The [[FormTiddlerPlugin]] allows you to enter your data in a form and store the form's data in your tiddlers.

(For more information on tiddler data see the [[DataTiddlerPlugin]].)

//''Define ~FormTemplate''//

When you want to enter data in a form you first have to define a [[FormTemplate]] tiddler. A FormTemplate tiddler is a tiddler that contains named HTML INPUT elements (such as textfields, password fields, lists etc.) that define the stuff that should be edited in the form. E.g. you may have a FormTemplate that looks like this:

<html>
 <b>Name:</b><br/>
 <input name=userName type=text /><br/>
 <b>Password:</b><br/>
 <input name=pwd type=password /><br/>
</html>

The correspond HTML text looks like this
{{{
<html>
 <b>Name:</b><br/>
 <input name=userName type=text /><br/>
 <b>Password:</b><br/>
 <input name=pwd type=password /><br/>
</html>
}}}

The name of the INPUT element is also the name of the data field it is editing. E.g. a text field defined like this: 
{{{
<input name=userName type=text />
}}}
will edit the data field "userName" of the tiddler.


You are free to layout the INPUT elements as you like, but don't add a "form" element around them and don't define 'onchange' handlers, since this will be done automatically by the {{{<<formTiddler ...>>}}} macro.


//''Use ~FormTemplates (through the {{{<<formTiddler ...>>}}} macro)''//

In a second step you add the {{{<<formTiddler ...>>}}} macro to tiddlers that should be edited. In the macro you are referencing the [[FormTemplate]] that should be used to edit the tiddler's data. You may refer to the same FormTemplate tiddler in as many tiddlers as you like. Every such tiddler displays the same INPUT elements as the FormTemplate, but with the "data" of each individual tiddler.

In addition you may more than one {{{<<formTiddler...>>}}} macro call in one tiddler. Just make sure that the names of the elements in the referenced FormTemplate tiddlers do not collide. This feature may be useful if you want to construct a larger input form from a set of smaller FormTemplates.

You can easily create tiddlers with an embedded {{{<<formTiddler...>>}}} macro call using the [[<<newTiddlerWithForm...>>|NewTiddlerWithFormMacro]] macro. The macro shows a button similar to the "new tiddler" button and creates the requested tiddler, ready to enter data. For details see NewTiddlerWithFormMacro.


//''"Structured" and "Free" Data''//

Typically you will edit a tiddler that uses the {{{<<formTiddler...>>}}} macro through the form. But you are free to also edit the tiddler "as usual", through the build-in edit feature. I.e. you may mix "structured data" (as entered through the form) with "free data". I.e. on a "Contact" tiddler you may add an image to the tiddler, or add extra links to related persons. Or you add more tags. Just make sure that you don't modify the {{{<data>...</data>}}} section of the tiddler, since this contains the data maintained by the form.

Also notice that since the data entered in the forms is stored in the tiddler's text (in the {{{<data>...</data>}}} section) using the "search" feature will also find the texts you entered in the forms (even though it will not hilite the texts in the fields).


//''Applications''//

Using the [[FormTiddlerPlugin]] it is easy to manage things like:
* [[Contacts]]
* [[Bugreports]]
* ~ToDo Lists
* and many more.

Since a FormTemplate is typically used for many tiddlers of the same kind you may also consider using the ForEachTiddlerMacro to collect data across multiple tiddlers (e.g. to get a list of all contacts, a summary page for the bug reports etc.)

(See also [[FormTiddler Examples]])


//''HTML Elements''//

For those not that familiar with the HTML INPUT elements here a short overview with HTML snippets. 
|!Type|!HTML Example|!Comment|
|button|{{{<input name=btn type=button value="Just a button" />}}}|no data|
|checkbox|{{{<input name=isVIP type=checkbox />is VIP}}}||
|file|{{{<input name=attachment type=file />}}}|The "file" input element typically does not restore the path of the previously selected file. Nevertheless the path of the file is stored in the tiddler.|
|hidden|{{{<input name=hiddenValue type=hidden value="This is a hidden value" />}}}||
|password|{{{<input name=pwd type=password />}}}|The data entered in a "password" field is stored as clear text in the tiddler.|
|radio|{{{<input name=level type=radio value="Beginner" />Beginner<input name=level type=radio value="Expert" />Expert<input name=level type=radio value="Guru" />Guru}}}||
|reset|{{{<input name=btnReset type=reset />}}}|no data|
|select-one|{{{<select name=browser ><option>Firefox<option>Internet Explorer<option>Opera<option>Other</select >}}}||
|select-multiple|{{{<select name=music MULTIPLE ><option> R&B <option> Jazz <option> Blues <option> New Age</select >}}}||
|submit|{{{<input name=btnSubmit type=submit />}}}|no data|
|text|{{{<input name=userName type=text/>}}}||
|textarea|{{{<TEXTAREA name=notes rows=4 cols=80 ></TEXTAREA>}}}||

For details consult the Web or a textbook on HTML editing.
The {{{<<formTiddler ...>>}}} macro defined by the FormTiddlerPlugin. 

When a tiddler T1 references the (FormTemplate) tiddler T2 in the FormTiddlerMacro, the data of T1 can be edited through the INPUT elements defined by T2.
/***
<<checkForDataTiddlerPlugin>>
|''Name:''|FormTiddlerPlugin|
|''Version:''|1.0.5 (2006-02-24)|
|''Source:''|http://tiddlywiki.abego-software.de/#FormTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license]]|
|''Macros:''|formTiddler, checkForDataTiddlerPlugin, newTiddlerWithForm|
|''Requires:''|DataTiddlerPlugin|
|''TiddlyWiki:''|1.2.38+, 2.0|
|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|
!Description
Use form-based tiddlers to enter your tiddler data using text fields, listboxes, checkboxes etc. (All standard HTML Form input elements supported).

''Syntax:'' 
|>|{{{<<}}}''formTiddler'' //tiddlerName//{{{>>}}}|
|//tiddlerName//|The name of the FormTemplate tiddler to be used to edit the data of the tiddler containing the macro.|

|>|{{{<<}}}''newTiddlerWithForm'' //formTemplateName// //buttonLabel// [//titleExpression// [''askUser'']] {{{>>}}}|
|//formTemplateName//|The name of the tiddler that defines the form the new tiddler should use.|
|//buttonLabel//|The label of the button|
|//titleExpression//|A (quoted) JavaScript String expression that defines the title (/name) of the new tiddler.|
|''askUser''|Typically the user is not asked for the title when a title is specified (and not yet used). When ''askUser'' is given the user will be asked in any case. This may be used when the calculated title is just a suggestion that must be confirmed by the user|
|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|

For details and how to use the macros see the [[introduction|FormTiddler Introduction]] and the [[examples|FormTiddler Examples]].

!Revision history
* v1.0.5 (2006-02-24)
** Removed "debugger;" instruction
* v1.0.4 (2006-02-07)
** Bug: On IE no data is written to data section when field values changed (thanks to KenGirard for reporting)
* v1.0.3 (2006-02-05)
** Bug: {{{"No form template specified in <<formTiddler>>"}}} when using formTiddler macro on InternetExplorer (thanks to KenGirard for reporting)
* v1.0.2 (2006-01-06)
** Support TiddlyWiki 2.0
* v1.0.1 (2005-12-22)
** Features: 
*** Support InternetExplorer
*** Added newTiddlerWithForm Macro
* v1.0.0 (2005-12-14)
** initial version

!Code
***/
//{{{

//============================================================================
//============================================================================
// FormTiddlerPlugin
//============================================================================
//============================================================================


version.extensions.FormTiddlerPlugin = {
 major: 1, minor: 0, revision: 5,
 date: new Date(2006, 2, 24), 
 type: 'plugin',
 source: "http://tiddlywiki.abego-software.de/#FormTiddlerPlugin"
};

// For backward compatibility with v1.2.x
//
if (!window.story) window.story=window; 
if (!TiddlyWiki.prototype.getTiddler) TiddlyWiki.prototype.getTiddler = function(title) { return t = this.tiddlers[title]; return (t != undefined && t instanceof Tiddler) ? t : null; } 

//============================================================================
// formTiddler Macro
//============================================================================

// -------------------------------------------------------------------------------
// Configurations and constants 
// -------------------------------------------------------------------------------

config.macros.formTiddler = {
 // Standard Properties
 label: "formTiddler",
 version: {major: 1, minor: 0, revision: 4, date: new Date(2006, 2, 7)},
 prompt: "Edit tiddler data using forms",

 // Define the "setters" that set the values of INPUT elements of a given type
 // (must match the corresponding "getter")
 setter: { 
 button: function(e, value) {/*contains no data */ },
 checkbox: function(e, value) {e.checked = value;},
 file: function(e, value) {try {e.value = value;} catch(e) {/* ignore, possibly security error*/}},
 hidden: function(e, value) {e.value = value;},
 password: function(e, value) {e.value = value;},
 radio: function(e, value) {e.checked = (e.value == value);},
 reset: function(e, value) {/*contains no data */ },
 "select-one": function(e, value) {config.macros.formTiddler.setSelectOneValue(e,value);},
 "select-multiple": function(e, value) {config.macros.formTiddler.setSelectMultipleValue(e,value);},
 submit: function(e, value) {/*contains no data */},
 text: function(e, value) {e.value = value;},
 textarea: function(e, value) {e.value = value;}
 },

 // Define the "getters" that return the value of INPUT elements of a given type
 // Return undefined to not store any data.
 getter: { 
 button: function(e, value) {return undefined;},
 checkbox: function(e, value) {return e.checked;},
 file: function(e, value) {return e.value;},
 hidden: function(e, value) {return e.value;},
 password: function(e, value) {return e.value;},
 radio: function(e, value) {return e.checked ? e.value : undefined;},
 reset: function(e, value) {return undefined;},
 "select-one": function(e, value) {return config.macros.formTiddler.getSelectOneValue(e);},
 "select-multiple": function(e, value) {return config.macros.formTiddler.getSelectMultipleValue(e);},
 submit: function(e, value) {return undefined;},
 text: function(e, value) {return e.value;},
 textarea: function(e, value) {return e.value;}
 }
};


// -------------------------------------------------------------------------------
// The formTiddler Macro Handler 
// -------------------------------------------------------------------------------

config.macros.formTiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
 if (!config.macros.formTiddler.checkForExtensions(place, macroName)) {
 return;
 }
 
 // --- Parsing ------------------------------------------

 var i = 0; // index running over the params

 // get the name of the form template tiddler
 var formTemplateName = undefined;
 if (i < params.length) {
 formTemplateName = params[i];
 i++;
 }

 if (!formTemplateName) {
 config.macros.formTiddler.createErrorElement(place, "No form template specified in <<" + macroName + ">>.");
 return;
 }


 // --- Processing ------------------------------------------

 // Get the form template text. 
 // (This contains the INPUT elements for the form.)
 var formTemplateTiddler = store.getTiddler(formTemplateName);
 if (!formTemplateTiddler) {
 config.macros.formTiddler.createErrorElement(place, "Form template '" + formTemplateName + "' not found.");
 return;
 }
 var templateText = formTemplateTiddler.text;
 if(!templateText) {
 // Shortcut: when template text is empty we do nothing.
 return;
 }

 // Get the name of the tiddler containing this "formTiddler" macro
 // (i.e. the tiddler, that will be edited and that contains the data)
 var tiddlerName = config.macros.formTiddler.getContainingTiddlerName(place);

 // Append a "form" element. 
 var formName = "form"+formTemplateName+"__"+tiddlerName;
 var e = document.createElement("form");
 e.setAttribute("name", formName);
 place.appendChild(e);

 // "Embed" the elements defined by the templateText (i.e. the INPUT elements) 
 // into the "form" element we just created
 wikify(templateText, e);

 // Initialize the INPUT elements.
 config.macros.formTiddler.initValuesAndHandlersInFormElements(formName, DataTiddler.getDataObject(tiddlerName));
}


// -------------------------------------------------------------------------------
// Form Data Access 
// -------------------------------------------------------------------------------

// Internal.
//
// Initialize the INPUT elements of the form with the values of their "matching"
// data fields in the tiddler. Also setup the onChange handler to ensure that
// changes in the INPUT elements are stored in the tiddler's data.
//
config.macros.formTiddler.initValuesAndHandlersInFormElements = function(formName, data) {
 // config.macros.formTiddler.trace("initValuesAndHandlersInFormElements(formName="+formName+", data="+data+")");

 // find the form
 var form = config.macros.formTiddler.findForm(formName);
 if (!form) {
 return;
 }

 try {
 var elems = form.elements;
 for (var i = 0; i < elems.length; i++) {
 var c = elems[i];
 
 var setter = config.macros.formTiddler.setter[c.type];
 if (setter) {
 var value = data[c.name];
 if (value != null) {
 setter(c, value);
 }
 c.onchange = onFormTiddlerChange;
 } else {
 config.macros.formTiddler.displayFormTiddlerError("No setter defined for INPUT element of type '"+c.type+"'. (Element '"+c.name+"' in form '"+formName+"')");
 }
 }
 } catch(e) {
 config.macros.formTiddler.displayFormTiddlerError("Error when updating elements with new formData. "+e);
 }
}


// Internal.
//
// @return [may be null]
//
config.macros.formTiddler.findForm = function(formName) {
 // We must manually iterate through the document's forms, since
 // IE does not support the "document[formName]" approach

 var forms = window.document.forms;
 for (var i = 0; i < forms.length; i++) {
 var form = forms[i];
 if (form.name == formName) {
 return form;
 }
 }

 return null;
}


// Internal.
//
config.macros.formTiddler.setSelectOneValue = function(element,value) {
 var n = element.options.length;
 for (var i = 0; i < n; i++) {
 element.options[i].selected = element.options[i].value == value;
 }
}

// Internal.
//
config.macros.formTiddler.setSelectMultipleValue = function(element,value) {
 var values = {};
 for (var i = 0; i < value.length; i++) {
 values[value[i]] = true;
 }
 
 var n = element.length;
 for (var i = 0; i < n; i++) {
 element.options[i].selected = !(!values[element.options[i].value]);
 }
}

// Internal.
//
config.macros.formTiddler.getSelectOneValue = function(element) {
 var i = element.selectedIndex;
 return (i >= 0) ? element.options[i].value : null;
}

// Internal.
//
config.macros.formTiddler.getSelectMultipleValue = function(element) {
 var values = [];
 var n = element.length;
 for (var i = 0; i < n; i++) {
 if (element.options[i].selected) {
 values.push(element.options[i].value);
 }
 }
 return values;
}



// -------------------------------------------------------------------------------
// Helpers 
// -------------------------------------------------------------------------------

// Internal.
//
config.macros.formTiddler.checkForExtensions = function(place,macroName) {
 if (!version.extensions.DataTiddlerPlugin) {
 config.macros.formTiddler.createErrorElement(place, "<<" + macroName + ">> requires the DataTiddlerPlugin. (You can get it from http://tiddlywiki.abego-software.de/#DataTiddlerPlugin)");
 return false;
 }
 return true;
}

// Internal.
//
// Displays a trace message in the "TiddlyWiki" message pane.
// (used for debugging)
//
config.macros.formTiddler.trace = function(s) {
 displayMessage("Trace: "+s);
}

// Internal.
//
// Display some error message in the "TiddlyWiki" message pane.
//
config.macros.formTiddler.displayFormTiddlerError = function(s) {
 alert("FormTiddlerPlugin Error: "+s);
}

// Internal.
//
// Creates an element that holds an error message
// 
config.macros.formTiddler.createErrorElement = function(place, message) {
 return createTiddlyElement(place,"span",null,"formTiddlerError",message);
}

// Internal.
//
// Returns the name of the tiddler containing the given element.
// 
config.macros.formTiddler.getContainingTiddlerName = function(element) {
 return story.findContainingTiddler(element).id.substr(7);
}

// -------------------------------------------------------------------------------
// Event Handlers 
// -------------------------------------------------------------------------------

// This function must be called by the INPUT elements whenever their
// data changes. Typically this is done through an "onChange" handler.
//
function onFormTiddlerChange (e) {
 // config.macros.formTiddler.trace("onFormTiddlerChange "+e);

 if (!e) var e = window.event;

 var target = resolveTarget(e);
 var tiddlerName = config.macros.formTiddler.getContainingTiddlerName(target);
 var getter = config.macros.formTiddler.getter[target.type];
 if (getter) {
 var value = getter(target);
 DataTiddler.setData(tiddlerName, target.name, value);
 } else {
 config.macros.formTiddler.displayFormTiddlerError("No getter defined for INPUT element of type '"+target.type+"'. (Element '"+target.name+"' used in tiddler '"+tiddlerName+"')");
 }
}

// ensure that the function can be used in HTML event handler
window.onFormTiddlerChange = onFormTiddlerChange;


// -------------------------------------------------------------------------------
// Stylesheet Extensions (may be overridden by local StyleSheet)
// -------------------------------------------------------------------------------

setStylesheet(
 ".formTiddlerError{color: #ffffff;background-color: #880000;}",
 "formTiddler");


//============================================================================
// checkForDataTiddlerPlugin Macro
//============================================================================

config.macros.checkForDataTiddlerPlugin = {
 // Standard Properties
 label: "checkForDataTiddlerPlugin",
 version: {major: 1, minor: 0, revision: 0, date: new Date(2005, 12, 14)},
 prompt: "Check if the DataTiddlerPlugin exists"
}

config.macros.checkForDataTiddlerPlugin.handler = function(place,macroName,params) {
 config.macros.formTiddler.checkForExtensions(place, config.macros.formTiddler.label);
}



//============================================================================
// newTiddlerWithForm Macro
//============================================================================

config.macros.newTiddlerWithForm = {
 // Standard Properties
 label: "newTiddlerWithForm",
 version: {major: 1, minor: 0, revision: 1, date: new Date(2006, 1, 6)},
 prompt: "Creates a new Tiddler with a <<formTiddler ...>> macro"
}

config.macros.newTiddlerWithForm.handler = function(place,macroName,params) {
 // --- Parsing ------------------------------------------

 var i = 0; // index running over the params

 // get the name of the form template tiddler
 var formTemplateName = undefined;
 if (i < params.length) {
 formTemplateName = params[i];
 i++;
 }

 if (!formTemplateName) {
 config.macros.formTiddler.createErrorElement(place, "No form template specified in <<" + macroName + ">>.");
 return;
 }

 // get the button label
 var buttonLabel = undefined;
 if (i < params.length) {
 buttonLabel = params[i];
 i++;
 }

 if (!buttonLabel) {
 config.macros.formTiddler.createErrorElement(place, "No button label specified in <<" + macroName + ">>.");
 return;
 }

 // get the (optional) tiddlerName script and "askUser"
 var tiddlerNameScript = undefined;
 var askUser = false;
 if (i < params.length) {
 tiddlerNameScript = params[i];
 i++;

 if (i < params.length && params[i] == "askUser") {
 askUser = true;
 i++;
 }
 }

 // --- Processing ------------------------------------------

 if(!readOnly) {
 var onClick = function() {
 var tiddlerName;
 if (tiddlerNameScript) {
 try {
 tiddlerName = eval(tiddlerNameScript);
 } catch (ex) {
 }
 }
 if (!tiddlerName || askUser) {
 tiddlerName = prompt("Please specify a tiddler name.", askUser ? tiddlerName : "");
 }
 while (tiddlerName && store.getTiddler(tiddlerName)) {
 tiddlerName = prompt("A tiddler named '"+tiddlerName+"' already exists.\n\n"+"Please specify a tiddler name.", tiddlerName);
 }

 // tiddlerName is either null (user canceled) or a name that is not yet in the store.
 if (tiddlerName) {
 var body = "<<formTiddler [["+formTemplateName+"]]>>";
 var tags = [];
 store.saveTiddler(tiddlerName,tiddlerName,body,config.options.txtUserName,new Date(),tags);
 story.displayTiddler(null,tiddlerName,1);
 }
 }

 createTiddlyButton(place,buttonLabel,buttonLabel,onClick);
 }
}

//}}}


/***
!Licence and Copyright
Copyright (c) abego Software ~GmbH, 2005 ([[www.abego-software.de|http://www.abego-software.de]])

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.

Neither the name of abego Software nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
***/
<<formTiddler NewBookTemplate>><data>{"author":"E. M. Forster","booktitle":"A Room with a View","pubinfo":"Project Gutenberg","mine":true,"medium":"eBook (eReader)","genre":"Fiction, general","primtopic":"Satire","synopsis":"Young Lady struggles to make her own decisions","rating":"75"}</data>We follow a young  Lady, in 19th century Italy and England, as she struggles to find the strength to make her own decisions about Life.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Tim Gautreaux","booktitle":"The Next Step InThe Dance","pubinfo":"Sceptre (1998)","mine":true,"medium":"Paperback","genre":"Fiction, general","primtopic":"Love","rating":"85","synopsis":"Small town drama in Central USA","keep":true}</data>Masterly First Novel by an author who is capable of making each sentence a work of art. The story is interesting an involving and dramatic. The characters and relationships are complex and richly drawn.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Tim Gautreaux","booktitle":"The Clearing","pubinfo":"Sceptre (2003)","mine":true,"medium":"Paperback","genre":"Fiction, general","primtopic":"1920s life in the Swamp","synopsis":"murerous goings on in a small water-logged logging village.","rating":"85","keep":true}</data>Superbly written. imaginative novel set in the 1920's in frontierland in the swamps of southern USA. Every sentence is a delight to read.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Jon Hassler","booktitle":"North of Hope","pubinfo":"Ballantine Book (1990)","mine":true,"medium":"Paperback [2nd hand]","genre":"Drama","primtopic":"Tragedy","synopsis":"People on Crisis","rating":"70"}</data>Somewhat turgid 30 year spread in the lives of a number of people living in a remote community in the north of USA. It involves Priests, and loss of faith. Character development is good, as is plot...it is just that there are layers and relentless layers of bad situations covering all the characters.
!!!Comments:
<<comment>>
/***
| Name:|HideWhenPlugin|
| Description:|Allows conditional inclusion/exclusion in templates|
| Version:|6.9.3|
| Date:|30-Sep-2006|
| Source:|http://mptw.tiddlyspot.com/#HideWhenPlugin|
| Author:|Simon Baird <simon.baird@gmail.com>|
For use in ViewTemplate and EditTemplate. Eg
{{{<div macro="showWhen tiddler.tags.contains('Task')">[[TaskToolbar]]</div>}}}
{{{<div macro="showWhen tiddler.modifier == 'BartSimpson'"><img src="bart.gif"/></div>}}}
***/
//{{{
merge(config.macros,{

 hideWhen: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
 if (eval(paramString)) {
 removeChildren(place);
 place.parentNode.removeChild(place);
 }
 }},

 showWhen: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
 config.macros.hideWhen.handler(place,macroName,params,wikifier,'!('+paramString+')',tiddler);
 }}

});

//}}}

<<formTiddler NewBookTemplate>><data>{"author":"Tami Hoag","booktitle":"Dust to Dust","pubinfo":"Bantam Books (2000)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Thriller","primtopic":"Murder","synopsis":"Crooked cops are everywhere.","rating":"70"}</data>Did the young cop kill his girlfriend, and then hang himself...or...?  The pages turn...time passes...not much lingers...
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Janette Turner Hospital","booktitle":"Charades","mine":true,"medium":"Paperback","genre":"Fiction, general","primtopic":"Life","rating":"80","pubinfo":"UQP [University of Queensland Press] (1988)","synopsis":"Girl's journey of discovery about her Life"}</data>Young woman seeks to know her history.
!!!Comments 
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Janette Turner Hospital","booktitle":"Due preparations for the Plague","pubinfo":"Harper Perennial (2004)","mine":true,"medium":"Paperback","genre":"Fiction, general","primtopic":"Disaster","rating":"0","keep":true}</data>not read yet.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Khaled Hosseini","booktitle":"A Thousand Splendid Suns","mine":true,"keep":true,"medium":"Paperback","genre":"Fiction, general","primtopic":"Life in Afganistan","rating":"0"}</data>Not read yet.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Khaled Hosseini","booktitle":"The Kite Runner","mine":true,"keep":true,"rating":"80","genre":"Fiction, general"}</data>
TiddlyWiki uses Wiki style markup, a way of lightly "tagging" plain text so it can be transformed into HTML. Go into edit mode by double-clicking this tiddler or pressing the 'edit' button in the hidden menu above to see the code for the following formatting samples.

! Header Samples
!Header 1
!!Header 2
!!!Header 3
!!!!Header 4
!!!!!Header 5

! Unordered Lists:
* Lists are where it's at
* Just use an asterisk and you're set
** To nest lists just add more asterisks...
***...like this
* The circle makes a great bullet because once you've printed a list you can mark off completed items
* You can also nest mixed list types
## Like this

! Ordered Lists
# Ordered lists are pretty neat too
# If you're handy with HTML and CSS you could customize the [[numbering scheme|http://www.w3schools.com/css/pr_list-style-type.asp]]
## To nest, just add more octothorpes (pound signs)...
### Like this
* You can also
** Mix list types
*** like this
# Pretty neat don't you think?

! Tiddler links
To create a Tiddler link, just use mixed-case WikiWord, or use [[brackets]] for NonWikiWordLinks. This is how the GTD style [[@Action]] lists are created. 

Note that existing Tiddlers are in bold and empty Tiddlers are in italics. See CreatingTiddlers for details.

! External Links
You can link to [[external sites|http://google.com]] with brackets. You can also LinkToFolders on your machine or network shares.

! Images
Edit this tiddler to see how it's done.
[img[http://img110.echo.cx/img110/139/gorilla8nw.jpg]]

!Tables
|!th1111111111|!th2222222222|
|>| colspan |
| rowspan |left|
|~| right|
|colored| center |
|caption|c

For a complex table example, see PeriodicTable.

! Horizontal Rules
You can divide a tiddler into
----
sections by typing four dashes on a line by themselves.

! Blockquotes
<<<
This is how you do an extended, wrapped blockquote so you don't have to put angle quotes on every line.
<<<
>level 1
>level 1
>>level 2
>>level 2
>>>level 3
>>>level 3
>>level 2
>level 1

! Other Formatting
''Bold''
==Strike==
__Underline__
//Italic//
Superscript: 2^^3^^=8
Subscript: a~~ij~~ = -a~~ji~~
@@highlight@@
@@color(green):green colored@@
@@bgcolor(#ff0000):color(#ffffff):red colored@@
~BibblyWiki was designed for three specific but overlapping needs that students have:
{{indent{1. To create bibliographies.
{{indent{2. To organize their personal libraries of books and articles.
{{indent{3. To take notes on books and articles. 

With ~BibblyWiki, you add your book data, and ~BibblyWiki automatically adds your book to a pre-formatted bibliography and several indexes. It doesn't get much easier than that - and best of all, it's free! Below are links to instructions for various ~BibblyWiki tasks:

[[Save BibblyWiki to your computer]]
[[Add a new book or article to my library / bibliography]]
[[Click here to see an example book entry|Wright, N.T., Jesus and the Victory of God]]
[[Search for a book or article in my library / bibliography]]
[[View sorted indexes of my library / bibliography]]
[[Features yet to come]]

For further instructions on TiddlyWiki, see our tutorial [[here|http://www.giffmex.org/twfortherestofus.html]].

If you found ~BibblyWiki helpful, would you consider helping me buy books via an Amazon gift certificate?<br><br><html><a href="https://www.amazon.com/gp/registry/wishlist/1OTJM9IE7SPVS/ref=wl_web/"><img src="https://images-na.ssl-images-amazon.com/images/G/01/gifts/registries/wishlist/v2/web/wl-btn-74-b._V46774601_.gif" width="74" alt="My Amazon.com Wish List" height="42" border="0" /></a></html>

Click <<slideShow style:'MySSStyleSheet' repeat>> to start slideshow, then use Ctrl+ or Ctrl- to fit comfortably on your screen. You can discover simple controls near the bottom of the screen with your mouse.

-s-
!Ray has a lot of viewable content published on the web


-s-

!Ray welcomes interaction:
# eMail at raycastorey@gmail.com
# or, leave comments wherever you are viewing a page with a "comments" facility.

-s-

! Please enjoy your visit.
<<formTiddler NewBookTemplate>><data>{"author":"Ward Just","booktitle":"To What End","pubinfo":"Ballantine Book (1968)","mine":true,"medium":"Paperback","genre":"Analysis","primtopic":"Vietnam War","rating":"0"}</data>not read yet
!!!Comments:
<<comment>>
[>img[Bookcovers/zorbathegreeka.jpg]]<<formTiddler NewBookTemplate>><data>{"author":"Nikos Kazantzakis","booktitle":"Zorba The Greek","medium":"Paperback","genre":"Fiction, general","primtopic":"Philosophy","synopsis":"Naive Englishman learns about life from an old Greek","rating":"90","pubinfo":"Simon & Shuster (1952)","mine":true}</data>Beautifully written book, with a simple plot but densely sculpted characters and heavy with morally enigmatic situations, this book is a pleasure from first to last page.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Jesse Kellerman","booktitle":"Sunstroke","pubinfo":"Jove (2006)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Fiction, general","primtopic":"Missing person","synopsis":"Someone goes missing in Mexico...secretary goes looking.","rating":"75"}</data>When her Boss of many years goes missing, assistant Gloria goes looking for him in mexico; it's a bit like an extended road trip of self-discovery, but she finds a lot more than herself along the way. An interesting and novel plot, so good characters, and some quite readable passages.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Jonathan Kellerman","booktitle":"The Conspiracy Club","pubinfo":"Ballantine (2003)","mine":true,"medium":"Paperback [2nd hand]","genre":"Fiction, general","primtopic":"Secret club of do-gooders","synopsis":"Folks who try to right wrongs secretly.","rating":"70"}</data>Page-turner about a guy whose girlfriend is killed and who is then drawn into a gory serial-killer hunt.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Jack Kerouac","booktitle":"Lonesome Traveller","pubinfo":"Grove (1970)","mine":true,"medium":"Paperback [2nd hand]","genre":"Autobiography","primtopic":"Culture","rating":"75","synopsis":"Beat hero, Jack on his life while on the road and writing famous works","keep":true}</data>Absorbing account of the author's life during the "Beat" years, written in a slightly maore accessable style than many of his other works. Not my favourite work by this author.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Tracy Kidder","booktitle":"The Soul of a new Machine","pubinfo":"Back Bay Books (1981)","mine":true,"medium":"Paperback","genre":"Non-fiction - Technology","primtopic":"Project Management","synopsis":"Good PM's are fatalistic","rating":"85"}</data>Hugely interesting and entertaining journalist's account of the creation of the Data General 32bit mini-computer. It reads like a well-written and pacy novel, but is an authentic account to the life of a team trying to build a computer that would save the company from extinction. It is a very fine handbook for PM's.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Dean Koontz","booktitle":"Lightning","pubinfo":"Berkely (1988)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Fiction, general","primtopic":"Horror/Thriller","synopsis":"Folks are being killed by spies from the past who can time travel,","rating":"60"}</data>The words are not hung together well, and the plot defies belief. 
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Milan Kundera","booktitle":"Ignorance","pubinfo":"Faber & Faber (2002)","mine":true,"medium":"Paperback","genre":"Fiction, general","rating":"0"}</data>Not read yet.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"John le Carre","booktitle":"Absolute Friends","pubinfo":"Coronet (2004)","mine":true,"medium":"Paperback","genre":"Thriller","primtopic":"Spies and terrorists","synopsis":"Several periods in the life of two characters...there will be violence.","rating":"80","keep":true}</data>Tightly written, dense plot, interesting but damaged characters. This is classic Lecarre writing, and is absorbing from first page to last.
!!!Comments:
<<comment>>
/***
|Name:|LessBackupsPlugin|
|Description:|Intelligently limit the number of backup files you create|
|Version:|3.0.1 ($Rev: 2320 $)|
|Date:|$Date: 2007-06-18 22:37:46 +1000 (Mon, 18 Jun 2007) $|
|Source:|http://mptw.tiddlyspot.com/#LessBackupsPlugin|
|Author:|Simon Baird|
|Email:|simon.baird@gmail.com|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Description
You end up with just backup one per year, per month, per weekday, per hour, minute, and second.  So total number won't exceed about 200 or so. Can be reduced by commenting out the seconds/minutes/hours line from modes array
!!Notes
Works in IE and Firefox only.  Algorithm by Daniel Baird. IE specific code by by Saq Imtiaz.
***/
//{{{

var MINS  = 60 * 1000;
var HOURS = 60 * MINS;
var DAYS  = 24 * HOURS;

if (!config.lessBackups) {
	config.lessBackups = {
		// comment out the ones you don't want or set config.lessBackups.modes in your 'tweaks' plugin
		modes: [
			//["YYYY",  365*DAYS], // one per year for ever
			//["MMM",   31*DAYS],  // one per month
			["ddd",   7*DAYS],   // one per weekday
			//["d0DD",  1*DAYS],   // one per day of month
		//	["h0hh",  24*HOURS], // one per hour
		//	["m0mm",  1*HOURS],  // one per minute
		//	["s0ss",  1*MINS],   // one per second
			["latest",0]         // always keep last version. (leave this).
		]
	};
}

window.getSpecialBackupPath = function(backupPath) {

	var now = new Date();

	var modes = config.lessBackups.modes;

	for (var i=0;i<modes.length;i++) {

		// the filename we will try
		var specialBackupPath = backupPath.replace(/(\.)([0-9]+\.[0-9]+)(\.html)$/,
				'$1'+now.formatString(modes[i][0]).toLowerCase()+'$3')

		// open the file
		try {
			if (config.browser.isIE) {
				var fsobject = new ActiveXObject("Scripting.FileSystemObject")
				var fileExists  = fsobject.FileExists(specialBackupPath);
				if (fileExists) {
					var fileObject = fsobject.GetFile(specialBackupPath);
					var modDate = new Date(fileObject.DateLastModified).valueOf();
				}
			}
			else {
				netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
				var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
				file.initWithPath(specialBackupPath);
				var fileExists = file.exists();
				if (fileExists) {
					var modDate = file.lastModifiedTime;
				}
			}
		}
		catch(e) {
			// give up
			return backupPath;
		}

		// expiry is used to tell if it's an 'old' one. Eg, if the month is June and there is a
		// June file on disk that's more than an month old then it must be stale so overwrite
		// note that "latest" should be always written because the expiration period is zero (see above)
		var expiry = new Date(modDate + modes[i][1]);
		if (!fileExists || now > expiry)
			return specialBackupPath;
	}
}

// hijack the core function
window.getBackupPath_mptw_orig = window.getBackupPath;
window.getBackupPath = function(localPath) {
	return getSpecialBackupPath(getBackupPath_mptw_orig(localPath));
}

//}}}

/***
|''Name:''|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack)|
|''Description:''|When the TiddlyWiki file is located on the web (view over http) the content of [[SiteProxy]] tiddler is added in front of the file url. If [[SiteProxy]] does not exist "/proxy/" is added. |
|''Version:''|1.1.0|
|''Date:''|mar 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#LoadRemoteFileHijack|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
***/
//{{{
version.extensions.LoadRemoteFileThroughProxy = {
 major: 1, minor: 1, revision: 0, 
 date: new Date("mar 17, 2007"), 
 source: "http://tiddlywiki.bidix.info/#LoadRemoteFileThroughProxy"};

if (!window.bidix) window.bidix = {}; // bidix namespace
if (!bidix.core) bidix.core = {};

bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
 if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){ 
 url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
 }
 return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
<<formTiddler NewBookTemplate>><data>{"author":"Jim Lovell, Jeffrey Kluger","booktitle":"Apollo 13","pubinfo":"Pocket Book (1995)","mine":true,"medium":"Paperback [2nd hand]","genre":"Non-fiction","primtopic":"Space-flight","rating":"80","synopsis":"Account of the nearly fatal Apollo 13 flight"}</data>Astronaut Jim Lovell's account of the crisis of the aborted Apollo 13 mission. Lots of technology, but not allowed to get in the way of the spinning of an excellent yarn about heroism.
!!!Comments:
<<comment>>
[[Bibliography by author]]
[[By title]]
[[By rating]]
[[By genre]]
[[By synopsis]]
[[By topic]]
[[By medium]]
[[By all topics]]
[[Articles only]]
[[My library]]
<<fontSize 'font'>>

<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->

<style type="text/css">#contentWrapper {display:none;}</style><div id="SplashScreen" style="border: 3px solid #ccc; display: block; text-align: center; width: 320px; margin: 100px auto; padding: 50px; color:#000; font-size: 28px; font-family:Tahoma; background-color:#eee;"><b>raybooks</b> is loading<blink> ...</blink><br><br><span style="font-size: 14px; color:red;">Requires Javascript.</span></div>
<<formTiddler NewBookTemplate>><data>{"author":"George R. R. Martin","booktitle":"A Game of thrones","pubinfo":"Bantam Spectra (1996)","mine":true,"medium":"Paperback [2nd hand]","genre":"Fantasy","primtopic":"Dragons & Kings","synopsis":"After the era of the dragons, there are several Kingdoms at war","rating":"85","keep":true}</data>Nearly 800 pages of dense, rich, gutsy, sexy fantasy...and this is merely volume 1 of what is said to be going to be a 7 book work.
So stunningly written, this book is very hard to put down and, once finished, triggers a frantic search for Book 2. IMHO LOTR is not in the same class as this work. 
To this date [mid 2008] 4 books have been published; it is rumoured that the author has become exhausted or bored by the saga, and so no-one has a publish date for Book 5...how frustrating is that!! I have books 2-4 in eBook format.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Daniel Mason","booktitle":"The Piano Tuner","pubinfo":"Picador (2002)","mine":true,"medium":"Paperback","genre":"Fiction, general","primtopic":"Drama","synopsis":"Out of control in Burma","rating":"80"}</data>Extremely well written first novel. Mason takes the information he gathered about the region, during a 1 year medical research assignment on the Thailand/Burma border, and weaves an absorbing plot set in the colonial era of the mid-19th century. I reminded me a great deal of the Joseph Conrad masterwork...Heart of Darkness.
!!!Comments:
<<comment>>
Background: #ffeedd
Foreground: #000
PrimaryPale: #ddaa99
PrimaryLight: #cc9999
PrimaryMid: #552233
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #cccccc
SecondaryDark: #552233
TertiaryPale: #ddaa99
TertiaryLight: #EEC591
TertiaryMid: #552233
TertiaryDark: #8B7355
Background: #eeddaa
Foreground: #000
PrimaryPale: #ddcc99
PrimaryLight: #bb8833
PrimaryMid: #553322
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #cccccc
SecondaryDark: #553322
TertiaryPale: #ddcc99
TertiaryLight: #EEC591
TertiaryMid: #553322
TertiaryDark: #8B7355
<<formTiddler NewBookTemplate>><data>{"author":"Christopher G. Moore","booktitle":"God of Darkness","pubinfo":"Asia Books (1998)","mine":true,"medium":"Paperback","genre":"Thriller","primtopic":"Bangkok seedy life","synopsis":"Irrelevant plot merely serves as a frame onto which to hang anecdotes.","rating":"75"}</data>Full of interesting and sometimes quite funny little anecdotes about the general subject of life in Bangkok. Might not be so interesting to readers who have not lived in Thailand.
!!!Comments:
<<comment>>
[[My library by author]]
[[My library by title]]
[[My library by primary topic]]
[[My library by all topics]] - @@not working yet@@
[[My library by call number]]
[[My library by location]]

<<forEachTiddler 
where 'tiddler.tags.contains("bibentry") && tiddler.data("mine")'
sortBy
'tiddler.data("primtopic")+"-"+ ! tiddler.getTags("bibentry")'
write
'+tiddler.tags.contains()+'
>>

<<forEachTiddler 
where 
'tiddler.tags.contains("bibentry") && tiddler.data("mine")' 
sortBy
'tiddler.data("author")'
write 
 '"{{justfine{"+tiddler.data("author")+",  }}} {{italic{ "+tiddler.data("booktitle")+".}}} "+tiddler.data("pubinfo")+" [[here|"+tiddler.title+"]]<br>\n"' 
>>
<<forEachTiddler 
where 
'tiddler.tags.contains("bibentry") && tiddler.data("mine")' 
sortBy
'tiddler.data("callnumber")'
write 
 '"{{bold{"+tiddler.data("callnumber")+"}}}{{indent{"+tiddler.data("author")+",  }}} {{italic{ "+tiddler.data("booktitle")+".}}} [[here|"+tiddler.title+"]]<br>\n"' 
>>
<<forEachTiddler 
where 
'tiddler.tags.contains("bibentry") && tiddler.data("mine")' 
sortBy
'tiddler.data("location")'
write 
 '"{{bold{"+tiddler.data("location")+"}}}<br>{{indent{{{justfine{"+tiddler.data("author")+",}}}}}} {{italic{ "+tiddler.data("booktitle")+".}}}  [[here|"+tiddler.title+"]]<br>\n"' 
>>
<<forEachTiddler 
where 
'tiddler.tags.contains("bibentry") && tiddler.data("mine")' 
sortBy
'tiddler.data("primtopic")'
write 
 '"{{bold{"+tiddler.data("primtopic")+"}}}<br>{{indent{{{justfine{"+tiddler.data("author")+",}}}}}} {{italic{ "+tiddler.data("booktitle")+".}}} "+tiddler.data("pubinfo")+" [[here|"+tiddler.title+"]]<br>\n"' 
>>
<<forEachTiddler 
where 
'tiddler.tags.contains("bibentry") && tiddler.data("mine")' 
sortBy
'tiddler.data("location")'
write
 '"{{bold{"+tiddler.data("location")+"}}}<br>{{indent{"+tiddler.data("author")+",  }}} {{italic{ "+tiddler.data("booktitle")+".}}} "+tiddler.data("pubinfo")+" [[here|"+tiddler.title+"]]<br>\n"' 
>>
<<forEachTiddler 
where 
'tiddler.tags.contains("bibentry") && tiddler.data("mine")' 
sortBy
'tiddler.data("title")'
write 
 '"{{justfine{"+tiddler.data("author")+",  }}} {{italic{ "+tiddler.data("booktitle")+".}}} "+tiddler.data("pubinfo")+" [[here|"+tiddler.title+"]]<br>\n"' 
>>
body {
 background: #fffaae;
 color: #000;
}

.tiddler {
 background: #fffaae;
 padding: 1em 1em 0.5em 1em;
 margin-bottom: 1em;
 border: none;
}

.viewer .button {
 background: #e4ff70;
 color: #000;
 border: none;
}

.viewer .button:hover {
 background: #228b22;
 color: #fffaae;
}

.title {
text-align: right;
background: #e4ff70;
 -moz-border-radius: 0.5em;
padding: 0.2em;
}

#jsMath_button {
display: none;
}

/* navigator always visible
.pageFooterOff #navigator{
 visibility: visible;
}*/

/* remove clock 
.slideClock{
 display: none;
}*/
/*{{{*/
input {font-size: 100%;}

button {font-size: 100%;}

.txtOptionInput {
 width: 15em;
}

.tabContents li{
 list-style: none;
}

.viewer .center {
margin-left: auto;
margin-right: auto;
}

.center {
text-align:center;
}
/*}}}*/
If you don't know "Tiddly Squat" about TiddlyWiki, see our very simple tutorial at http://www.giffmex.org/twfortherestofus.html. TiddlyWiki may seem to have a high initial learning curve at first, but our tutorial takes much of the sting out of it.

What you probably want or need to know right now is how to save this file to your computer. This is not done in the usual way. Here you go:
#Right click on the left-hand menu where it says "save this file". 
#Choose "save link as" or "save target as" in the box that comes up. Choose a name and a location on your computer for your copy of the file, then click "Save".
#Close this webpage and feel free to open your copy in your computer.

[[How to Format Text]]

<html>
<style>
.rolodex table {
border: 0px solid;
background-color:#eeeff;
}

.rolodex tr, .rolodex td {
border: 0px solid;
}
</style>
<span class="rolodex">
 <table>
 <tr>
 <td align="right"><b>Author(s):</b></td>
 <td colspan="3"><input name=author type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Article title (put in "quotes"):</b></td>
 <td colspan="3"><input name=articletitle type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Journal Title:</b></td>
 <td colspan="3"><input name=journalinfo type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Volume (year): page numbers:</b></td>
 <td colspan="3"><input name=pagenumbers type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>url:</b></td>
 <td colspan="3"><input name=url type=url style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Synopsis:</b></td>
 <td colspan="3"><input name=synopsis type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Primary topic:</b></td>
 <td colspan="3"><input name=primtopic type=text style="width:300%" /></td></tr>
 <tr></span> </html>
1. In viewing mode, add data to form fields
2. In edit mode, add your notes below and in the bottom window add extra tags for any additional topics
3. In edit mode, add an url for an image of the magazine or journal cover at the top of the tiddler if you wish. Here's how: {{{[img[YOUR URL HERE]]}}}

! Article
<html>
<style>
.rolodex table {
border: 0px solid;
background-color:#eeeff;
}

.rolodex tr, .rolodex td {
border: 0px solid;
}
</style>
<span class="rolodex">
 <table>
 <tr>
 <td align="right"><b>Author(s):</b></td>
 <td colspan="3"><input name=author type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Book title:</b></td>
 <td colspan="3"><input name=booktitle type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Publisher information:</b></td>
 <td colspan="3"><input name=pubinfo type=text style="font-style:italic; width:300%;" /></td></tr>
 <tr>
<td align="right"><b>I own it:</b></td>
<input name=mine type=checkbox /></td></tr>
<td align="right"><b>I kept it:</b></td>
<input name=keep type=checkbox /></td></tr>
 <td align="right"><b>Medium:</b></td>
 <td colspan="3"><input name=medium type=text style="width:300%" /></td></tr>
<tr>
 <td align="right"><b>Genre:</b></td>
 <select name=genre >
  <option>Non-fiction, general
  <option>Reference
  <option>Short stories
  <option>Fiction, general
  <option>Thriller
  <option>Satire
  <option>Drama
  <option>Epic
  <option>Science Fiction
  <option>Fantasy
  <option>Other
 </select >
 <tr>
 <tr>
 <td align="right"><b>Main topic:</b></td>
 <td colspan="3"><input name=primtopic type=text style="width:300%" /></td></tr>
  <tr>
<td align="right"><b>Synopsis:</b></td>
 <td colspan="3"><input name=synopsis type=text style="font-style:italic; width:300%" /></td></tr>
  <tr>
 <td align="right"><b>Rating:</b></td>
 <td colspan="3"><input name=rating type=text style="width:300%" /></td></tr><tr></span> </html>
1. In viewing mode add data to the form fields above
2. In edit mode add image URL above form fields using the following syntax: {{{[img[URL for your image here]]}}}
3. In edit mode enter the following after the data section: {{{<<notes heading:'Rays Notes'>> !!!Comments <<comment>>}}}
<<formTiddler NewBookTemplate>><data>{"author":"Darian North","booktitle":"Criminal Seduction","pubinfo":"Signet (1994)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Thriller","primtopic":"Murder","rating":"70","synopsis":"??"}</data>I recall it was quite well written for the genre, but cannot recall the plot!!
!!!Comments
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Darian North","booktitle":"Violation","pubinfo":"Signet (1998)","mine":true,"medium":"Paperback [2nd hand]","genre":"Thriller","primtopic":"Murder","synopsis":"Violated woman withdraws from life - temporarily.","rating":"65"}</data>A woman who was raped as a school-girl withdraws from life until pulled back in by events that threaten her son.
!!!Comments:
<<comment>>
These InterfaceOptions are saved in your browser

Your username for signing your edits. Write as a WikiWord (eg JoeBloggs)

<<option txtUserName>>
<<option chkSaveBackups>> SaveBackups
<<option chkAutoSave>> AutoSave
<<option chkRegExpSearch>> RegExpSearch
<<option chkCaseSensitiveSearch>> CaseSensitiveSearch
<<option chkAnimate>> EnableAnimations

----
AdvancedOptions
PluginManager
ImportTiddlers
<<permaview>>
//{{{
config.options.chkSearchTitles=true;
config.options.chkSearchText=true;
config.options.chkSearchTags=true;
config.options.chkSearchFields=true;
config.options.chkSearchTitlesFirst=false;
config.options.chkSearchList=true;
config.options.chkSearchByDate=false;
config.options.chkSearchIncremental=true;
config.options.chkSearchShadows=false; 
//}}}
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<!-- horizontal MainMenu -->
<div id='topMenu' refresh='content' tiddler='MainMenu'></div>
<!-- original MainMenu menu -->
<!-- <div id='mainMenu' refresh='content' tiddler='MainMenu'></div> -->
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<<formTiddler NewBookTemplate>><data>{"author":"Chuck Palahniuk","booktitle":"Invisible Monsters","pubinfo":"Vintage (2003)","mine":true,"medium":"Paperback","genre":"Satire","primtopic":"Life","rating":"80","synopsis":"Damaged supermodel on a roadtrip with some strange friends"}</data>Seriously off-beat satire from the author famous for "Fight Club". So many twists and turns in the plot that by halfway though it is almost impossible to work out where you are and where you are going. Very entertaining reading, and could be pointing at an entirely new novel style.
!!!Comments:
<<comment>>
I'm using ShowPaletteMacro in my ViewTemplate to display a palettes with a colour swatch. Look at some <<tag palette>>s to see how it looks. The colour swatches update automatically if you edit the colours. Try it and see.

As well as that there is an "apply" button in the toolbar which uses a macro from SelectPaletteMacro to apply that palette's colour scheme.

SelectPaletteMacro also provides a drop-down selector for palettes. It looks like this:
<<selectPalette>>
/***
|''Name:''|PasswordOptionPlugin|
|''Description:''|Extends TiddlyWiki options with non encrypted password option.|
|''Version:''|1.0.2|
|''Date:''|Apr 19, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#PasswordOptionPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.PasswordOptionPlugin = {
	major: 1, minor: 0, revision: 2, 
	date: new Date("Apr 19, 2007"),
	source: 'http://tiddlywiki.bidix.info/#PasswordOptionPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
	coreVersion: '2.2.0 (Beta 5)'
};

config.macros.option.passwordCheckboxLabel = "Save this password on this computer";
config.macros.option.passwordInputType = "password"; // password | text
setStylesheet(".pasOptionInput {width: 11em;}\n","passwordInputTypeStyle");

merge(config.macros.option.types, {
	'pas': {
		elementType: "input",
		valueField: "value",
		eventName: "onkeyup",
		className: "pasOptionInput",
		typeValue: config.macros.option.passwordInputType,
		create: function(place,type,opt,className,desc) {
			// password field
			config.macros.option.genericCreate(place,'pas',opt,className,desc);
			// checkbox linked with this password "save this password on this computer"
			config.macros.option.genericCreate(place,'chk','chk'+opt,className,desc);			
			// text savePasswordCheckboxLabel
			place.appendChild(document.createTextNode(config.macros.option.passwordCheckboxLabel));
		},
		onChange: config.macros.option.genericOnChange
	}
});

merge(config.optionHandlers['chk'], {
	get: function(name) {
		// is there an option linked with this chk ?
		var opt = name.substr(3);
		if (config.options[opt]) 
			saveOptionCookie(opt);
		return config.options[name] ? "true" : "false";
	}
});

merge(config.optionHandlers, {
	'pas': {
 		get: function(name) {
			if (config.options["chk"+name]) {
				return encodeCookie(config.options[name].toString());
			} else {
				return "";
			}
		},
		set: function(name,value) {config.options[name] = decodeCookie(value);}
	}
});

// need to reload options to load passwordOptions
loadOptionsCookie();

/*
if (!config.options['pasPassword'])
	config.options['pasPassword'] = '';

merge(config.optionsDesc,{
		pasPassword: "Test password"
	});
*/
//}}}
<<formTiddler NewBookTemplate>><data>{"author":"Richard North Patterson","pubinfo":"Macmillon (2005)","booktitle":"Conviction","mine":true,"medium":"Paperback [2nd hand]","genre":"Drama","primtopic":"Law","rating":"70","synopsis":"Death row convict is really innocent"}</data>Pretty standard fare from this best-selling author who specialises in law and courts...to be expected I suppose as he is a trial lawyer in USA.
!!!Comment:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Richard North Patterson","booktitle":"Degree of Guilt","pubinfo":"Ballantine Books (1992)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Drama","primtopic":"Courtroom drama","synopsis":"Women kills rapist...how can she prove it?","rating":"70"}</data>One of Patterson's better books of this ilk. Interesting plot, but the characters are a bit shallow.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Richard North Patterson","booktitle":"Escape The Night","pubinfo":"Ballantine (1983)","mine":true,"medium":"Paperback","genre":"Drama","primtopic":"Family dysfunction","synopsis":"Turgid story of a family  loaded down with envy and jealousy","rating":"70"}</data>Rich folks behaving badly. Quite well written, but drags on too long.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Richard North Patterson","booktitle":"Protect and Defend","pubinfo":"Ballantine Book (2000)","mine":true,"medium":"Paperback [2nd hand]","genre":"Drama","primtopic":"Ethics","rating":"70"}</data>Standard fare from this author, who is also a practicing Trial lawyer. It has a good plot, complete with meaty issues of ethics and the dilemma that can exist with imperfect Laws. Ultimately, though, little remains in the brain a week after the book has been closed.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Richard North patterson","booktitle":"Silent Witness","pubinfo":"Ballantine Books (1995)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Drama","rating":"65","primtopic":"Murder","synopsis":"Attorney defends a friend who is the main suspect."}</data>Forgettable page-turner.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Richard North Patterson","booktitle":"The Final Judgement","pubinfo":"Ballantine (1995)","mine":true,"medium":"Paperback [2nd hand]","genre":"Drama","primtopic":"Murder","synopsis":"A murder in the family draws the lady Attorney into the country.","rating":"65"}</data> Attorney Caroline masters is asked to assist when a neice is accused of the murder of her boyfriend. Quie well written to hold the attention, but nothing lingers longer than a few days after the back cover is shut.
!!!Comments:
<<comment>>
Click on SiteTitle. Double click the tiddler that pops up. Add and remove text as desired.
Click on SiteSubtitle. Double click the tiddler that pops up. Add and remove text as desired.
<<formTiddler NewBookTemplate>><data>{"author":"Robert. M. Pirsig","booktitle":"Zen and the Art of Motorcycle Maintenance","pubinfo":"Bantam Books (1974)","mine":true,"medium":"Paperback","genre":"Non-fiction","primtopic":"Philosophy","synopsis":"man and his son undertake a roadtrip of self-discovery","rating":"85","keep":true}</data>Stands up to multiple readings. This book is a useful handbook on ethics and quality, and I have drawn on it for inspiration for issues in Leadership and project Management. Subtitle of "An Inquiry into Values" goes some way to explaining the central theme of the book.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Susan Power","booktitle":"The Grass Dancer","pubinfo":"Berkely (1995)","mine":true,"medium":"Paperback [2nd hand]","genre":"Fantasy","primtopic":"Culture","rating":"80","synopsis":"A family of American Indians and their dancing communication"}</data>Interesting  for its divulging of the paranormal aspects of Sioux culture as much as for its story and quality of writing, this book is unusual.
!!!Comments 
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Helen Prejean","booktitle":"Dead Man Walking","pubinfo":"Harper Collins (1994)","mine":true,"medium":"Paperback [2nd hand]","genre":"Non-fiction","primtopic":"Ethics","rating":"85","synopsis":"Author gets to know a prisoner on Death Row"}</data>(Nominated for Pulitzer prize) Powerful, well-written book that starts a little like a journalist's research project, but gets out of hand when the author gets emotionally involved with the situation of the prisoner.
Made into an high-quality movie starring Susan Sarandon and Sean Penn.
!!!Comments 
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Phya Anuman Rajadhon","booktitle":"Essay on Thai Folklore","pubinfo":"Editions Duang Kamol (1968)","mine":true,"keep":true,"medium":"Hardcover","genre":"Non-fiction - Reference","primtopic":"Thai Folklore","rating":"0"}</data>Not read yet.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Anne Rice","booktitle":"Interview with The Vampire","pubinfo":"Ballantine Books (1976)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Fantasy","primtopic":"Vampires","synopsis":"Vampire tells his life to a youth.","rating":"80"}</data>Very imaginative fantasy work, with impressive plot, well developed characters and wide sweep.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Tom Robbins","booktitle":"Wild Ducks Flying Backwards","pubinfo":"Bantam Books","mine":true,"medium":"eBook (eReader)","genre":"Satire","primtopic":"Spoof","rating":"80"}</data>Another romp from Tom Robbins.
!!!Comments:
<<comment>>
Do not save this file by conventional methods! Instead, follow these simple instructions. Right click here: [[save this file|bibblywiki.html]], and select "Save link as" or its equivalent. Choose a filename and a location on your computer, and save the file. (Many people save TiddlyWikis to a USB stick so that they can edit their organizer from any computer with an internet browser). Then exit this file and open your saved version on your computer.

<<formTiddler NewBookTemplate>><data>{"author":"Jack Schaeffer","booktitle":"Shane","pubinfo":"Heineman Educational (1957)","mine":true,"medium":"Hardcover","genre":"Fiction, general","primtopic":"personal strength","synopsis":"Some men are islands","rating":"85"}</data>A novella of the "pulp fiction" genre, but which stands up well to frequent re-reading. It tries to illustrate the characteristics of those rare people who possess great self-awareness and determination to live their life according to their own rules. The books has been fashioned into a very competently made movie that would make many all-time 100 lists.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Jason Schoonover","booktitle":"Thai Gold","pubinfo":"Asia Books (2002)","mine":true,"medium":"Paperback","genre":"Thriller","primtopic":"Thai adventure","rating":"70","synopsis":"Ancient art black marketeer chases treasure in SEA"}</data>Originally published about 1988, this book is possibly the template used extensively for writing novels based on life in SEA, especially Thailand.It is quite well written, has a good plot, and the author makes extensive use of his knowledge in ancient artworks in the region.
!!!Comments:
<<comment>>
To search for a book or article you have added to your collection, just go to the search window above and begin typing words that are found in the title or the text of your book's tiddler. A list will quickly pop up of books that contain the text you type in the search window.

You may also look for books and articles in the tabbed folders at the bottom of the right-hand sidebar. 
*''Timeline'' displays all tiddlers beginning with the tiddlers most recently modified
*''All'' displays all tiddlers in alphabetical order
*''Tags'' displays all the tags assigned to tiddlers, and each tag has a dropdown list of all the tiddlers with that tag
*''More'' gives you access to other tiddlers

//{{{
window.reportSearchResults=function(text,matches)
{
	var title=config.macros.search.reportTitle
	var q = config.options.chkRegExpSearch ? "/" : "'";
	var body="\n";

	// numbered list of links to matching tiddlers
	body+="\n<<<";
	for(var t=0;t<matches.length;t++) {
		var date=config.options.chkSearchByDate?(matches[t].modified.formatString('YYYY.0MM.0DD 0hh:0mm')+" "):"";
		body+="\n# "+date+"[["+matches[t].title+"]]";
	}
	body+="\n<<<\n";

	// create/update the tiddler
	var tiddler=store.getTiddler(title); if (!tiddler) tiddler=new Tiddler();
	tiddler.set(title,body,config.options.txtUserName,(new Date()),"excludeLists excludeSearch");
	store.addTiddler(tiddler); story.closeTiddler(title);

	// use alternate "search again" label in <<search>> macro
	var oldprompt=config.macros.search.label;
	config.macros.search.label="search again";

	// render/refresh tiddler
	story.displayTiddler(null,title,1);
	store.notify(title,true);

	// restore standard search label
	config.macros.search.label=oldprompt;

}

//}}}
/***
|''Name:''|SearchOptionsPlugin|
|''Source:''|http://www.TiddlyTools.com/#SearchOptionsPlugin|
|''Author:''|Eric Shulman - ELS Design Studios|
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|''~CoreVersion:''|2.0.10|

The TiddlyWiki search function normally looks in both tiddler titles and tiddler body content ('text').  However, narrowing the search so that it examines only titles or only text, or expanding the search to include text contained in tiddler tags can be very helpful, especially when searching on common words or phrases.  In addition, it is often useful for the search results to show tiddlers with matching titles before tiddlers that contain matching text or tags.

!!!!!Usage
<<<
This plugin adds checkboxes (see below and in AdvancedOptions) to let you selectively configure the TiddlyWiki search function to just examine any combination of tiddler titles, text, or tags.  It also provides an option to switch the search results order between 'titles mixed in' (default) and 'titles shown first', as well as an option display the search results as a list of links (in an auto-generated "SearchResults" tiddler), rather than actually displaying all matching tiddlers.  You can also enable/disable the "incremental search" (key-by-key searching), so that a search is only initiated when you press the ENTER key or click on the "search:" prompt text.
<<<
!!!!!Configuration
<<<
In additional to the checkboxes in AdvancedOptions, a self-contained control panel is included here for your convenience:
<<option chkSearchTitles>> Search in titles
<<option chkSearchText>> Search in tiddler text
<<option chkSearchTags>> Search in tags
<<option chkSearchFields>> Search in data fields
<<option chkSearchShadows>> Search shadow tiddlers
<<option chkSearchTitlesFirst>> Show title matches first
<<option chkSearchByDate>> Sort matching tiddlers by date
<<option chkSearchList>> Show list of matches in [[SearchResults]]
<<option chkSearchIncremental>> Incremental searching
<<<
!!!!!Installation
<<<
import (or copy/paste) the following tiddlers into your document:
''SearchOptionsPlugin'' (tagged with <<tag systemConfig>>)
^^documentation and javascript for SearchOptionsPlugin handling^^

When installed, this plugin automatically adds checkboxes in the AdvancedOptions shadow tiddler so you can enable/disable the extended search behavior.  However, if you have customized your AdvancedOptions, you will need to manually add {{{<<option chkSearchTitles>>}}},  {{{<<option chkSearchText>>}}} and {{{<<option chkSearchTitlesFirst>>}}}  (with suitable prompt text) to your customized tiddler.
<<<
!!!!!Revision History
<<<
''2007.01.29 [2.5.0]'' added support for "sort results by date".  Default is to sort alphabetically (standard).  When sorted by dates, most recent changes are shown first
''2006.10.10 [2.4.0]'' added support for "search in tiddler data" (tiddler.fields)  Default is to search extended data.
''2006.04.06 [2.3.0]'' added support for "search in shadow tiddlers".  Default is *not* to search in the shadows (i.e. standard TW behavior).  Note: if a shadow tiddler has a 'real' counterpart, only the real tiddler is searched, since the shadow is inaccessible for viewing/editing.
''2006.02.03 [2.2.1]'' rewrite timeout clearing code and blank search text handling to match 2.0.4 core release changes.  note that core no longer permits "blank=all" searches, so neither does this plugin.  To search for all, use "." with text patterns enabled.
''2006.02.02 [2.2.0]'' in search.handler(), KeyHandler() function clears 'left over' timeout when search input is < 3 chars.  Prevents searching on shorter text when shortened by rapid backspaces (<500msec)
''2006.02.01 [2.1.9]'' in Story.prototype.search(), correct inverted logic for using/not using regular expressions when searching
also, blank search text now presents "No search text.  Continue anyway?" confirm() message box, so search on blank can still be processed if desired by user.
''2006.02.01 [2.1.8]'' in doSearch(), added alert/return if search text is blank
''2006.01.20 [2.1.7]'' fixed setting of config.macros.search.reportTitle so that Tweaks can override it.
''2006.01.19 [2.1.6]'' improved SearchResults formatting, added a "search again" form to the report (based on a suggestion from MorrisGray)
define results report title using config.macros.search.reportTitle instead of hard-coding the tiddler title
''2006.01.18 [2.1.5]'' Created separate functions for reportSearchResults(text,matches) and discardSearchResults(), so that other developers can create alternative report generators.
''2006.01.17 [2.1.4]'' Use regExp.search() instead of regExp.test() to scan for matches.  Correctd the problem where only half the matching tiddlers (the odd-numbered ones) were being reported.
''2006.01.15 [2.1.3]'' Added information (date/time, username, search options used) to SearchResults output
''2006.01.10 [2.1.2]'' use displayTiddlers() to render matched tiddlers.  This lets you display multiple matching tiddlers, even if SinglePageModePlugin is enabled.
''2006.01.08 [2.1.1]'' corrected invalid variable reference, "txt.value" to "text" in story.search()
''2006.01.08 [2.1.0]'' re-write to match new store.search(), store.search.handler() and story.search() functions.
''2005.12.30 [2.0.0]'' Upgraded to TW2.0
when rendering SearchResults tiddler, closeTiddler() first to ensure display is refreshed.
''2005.12.26 [1.4.0]'' added option to search for matching text in tiddler tags
''2005.12.21 [1.3.7]'' use \\ to 'escape' single quotes in tiddler titles when generating "Open all matching tiddlers" link.  Also, added access key: "O", to trigger "open all" link.
Based on a suggestion by UdoBorkowski.
''2005.12.18 [1.3.6]'' call displayMessage() AFTER showing matching tiddlers so message is not cleared too soon
''2005.12.17 [1.3.5]'' if no matches found, just display message and delete any existing SearchResults tiddler.
''2005.12.17 [1.3.4]'' use {/%%/{/%%/{  and }/%%/}/%%/} to 'escape' display text in SearchResults tiddler to ensure that formatting contained in search string is not rendered 
Based on a suggestion by UdoBorkowski.
''2005.12.14 [1.3.3]'' tag SearchResults tiddler with 'excludeSearch' so it won't list itself in subsequent searches
Based on a suggestion by UdoBorkowski.
''2005.12.14 [1.3.2]'' added "open all matching tiddlers..." link to search results output.
Based on a suggestion by UdoBorkowski.
''2005.12.10 [1.3.1]'' added "discard search results" link to end of search list tiddler output for quick self-removal of 'SearchResults' tiddler.
''2005.12.01 [1.3.0]'' added chkSearchIncremental to enable/disable 'incremental' searching (i.e., search after each keystroke) (default is ENABLED).
added handling for Enter key so it can be used to start a search.
Based on a suggestion by LyallPearce
''2005.11.25 [1.2.1]'' renamed from SearchTitleOrTextPlugin to SearchOptionsPlugin
''2005.11.25 [1.2.0]'' added chkSearchList option
Based on a suggestion by RodneyGomes
''2005.10.19 [1.1.0]'' added chkSearchTitlesFirst option.
Based on a suggestion by ChristianHauck
''2005.10.18 [1.0.0]'' Initial Release
Based on a suggestion by LyallPearce.
<<<
!!!!!Credits
<<<
This feature was developed by EricShulman from [[ELS Design Studios|http:/www.elsdesign.com]].
<<<
!!!!!Code
***/
//{{{
version.extensions.SearchTitleOrText = {major: 2, minor: 4, revision: 0, date: new Date(2006,10,12)};
//}}}

//{{{
if (config.options.chkSearchTitles==undefined) config.options.chkSearchTitles=true;
if (config.options.chkSearchText==undefined) config.options.chkSearchText=true;
if (config.options.chkSearchTags==undefined) config.options.chkSearchTags=true;
if (config.options.chkSearchFields==undefined) config.options.chkSearchFields=true;
if (config.options.chkSearchTitlesFirst==undefined) config.options.chkSearchTitlesFirst=false;
if (config.options.chkSearchList==undefined) config.options.chkSearchList=false;
if (config.options.chkSearchByDate==undefined) config.options.chkSearchByDate=false;
if (config.options.chkSearchIncremental==undefined) config.options.chkSearchIncremental=true;
if (config.options.chkSearchShadows==undefined) config.options.chkSearchShadows=false;

config.shadowTiddlers.AdvancedOptions += "\n<<option chkSearchTitles>> Search in tiddler titles";
config.shadowTiddlers.AdvancedOptions += "\n<<option chkSearchText>> Search in tiddler text";
config.shadowTiddlers.AdvancedOptions += "\n<<option chkSearchTags>> Search in tiddler tags";
config.shadowTiddlers.AdvancedOptions += "\n<<option chkSearchFields>> Search in tiddler data fields";
config.shadowTiddlers.AdvancedOptions += "\n<<option chkSearchShadows>> Search in shadow tiddlers";
config.shadowTiddlers.AdvancedOptions += "\n<<option chkSearchTitlesFirst>> Search results show title matches first";
config.shadowTiddlers.AdvancedOptions += "\n<<option chkSearchList>> Search results show list of matching tiddlers";
config.shadowTiddlers.AdvancedOptions += "\n<<option chkSearchByDate>> Search results sorted by modification date ";
config.shadowTiddlers.AdvancedOptions += "\n<<option chkSearchIncremental>> Incremental searching";
//}}}

//{{{
if (config.macros.search.reportTitle==undefined)
	config.macros.search.reportTitle="SearchResults";
//}}}

//{{{
config.macros.search.handler = function(place,macroName,params)
{
	var lastSearchText = "";
	var searchTimeout = null;
	var doSearch = function(txt)
		{
		if (txt.value.length>0)
			{
			story.search(txt.value,config.options.chkCaseSensitiveSearch,config.options.chkRegExpSearch);
			lastSearchText = txt.value;
			}
		};
	var clickHandler = function(e)
		{
		doSearch(this.nextSibling);
		return false;
		};
	var keyHandler = function(e)
		{
		if (!e) var e = window.event;
		switch(e.keyCode)
			{
			case 13: // ELS: handle enter key
				doSearch(this);
				break;
			case 27:
				this.value = "";
				clearMessage();
				break;
			}
		if (config.options.chkSearchIncremental)
			{
			if(this.value.length > 2)
				{
				if(this.value != lastSearchText)
					{
					if(searchTimeout) clearTimeout(searchTimeout);
					var txt = this;
					searchTimeout = setTimeout(function() {doSearch(txt);},500);
					}
				}
			else
				if(searchTimeout) clearTimeout(searchTimeout);
			}
		};
	var focusHandler = function(e)
		{
		this.select();
		};
	var btn = createTiddlyButton(place,this.label,this.prompt,clickHandler);
	var txt = createTiddlyElement(place,"input",null,null,null);
	if(params[0])
		txt.value = params[0];
	txt.onkeyup = keyHandler;
	txt.onfocus = focusHandler;
	txt.setAttribute("size",this.sizeTextbox);
	txt.setAttribute("accessKey",this.accessKey);
	txt.setAttribute("autocomplete","off");
	if(config.browser.isSafari)
		{
		txt.setAttribute("type","search");
		txt.setAttribute("results","5");
		}
	else
		txt.setAttribute("type","text");
}
//}}}

//{{{
Story.prototype.search = function(text,useCaseSensitive,useRegExp)
{
	highlightHack = new RegExp(useRegExp ? text : text.escapeRegExp(),useCaseSensitive ? "mg" : "img");
	var matches = store.search(highlightHack,config.options.chkSearchByDate?"modified":"title","excludeSearch");
	if (config.options.chkSearchByDate) matches=matches.reverse(); // most recent changes first
	var q = useRegExp ? "/" : "'";
	clearMessage();
	if (!matches.length) {
		if (config.options.chkSearchList) discardSearchResults();
		displayMessage(config.macros.search.failureMsg.format([q+text+q]));
	} else {
		if (config.options.chkSearchList) 
			reportSearchResults(text,matches);
		else {
			var titles = []; for(var t=0; t<matches.length; t++) titles.push(matches[t].title);
			this.closeAllTiddlers(); story.displayTiddlers(null,titles);
			displayMessage(config.macros.search.successMsg.format([matches.length, q+text+q]));
		}
	}
	highlightHack = null;
}
//}}}

//{{{
TiddlyWiki.prototype.search = function(searchRegExp,sortField,excludeTag)
{
	var candidates = this.reverseLookup("tags",excludeTag,false,sortField);

	// scan for matching titles first...
	var results = [];
	if (config.options.chkSearchTitles) {
		for(var t=0; t<candidates.length; t++)
			if(candidates[t].title.search(searchRegExp)!=-1)
				results.push(candidates[t]);
		if (config.options.chkSearchShadows)
			for (var t in config.shadowTiddlers)
				if ((t.search(searchRegExp)!=-1) && !store.tiddlerExists(t))
					results.push((new Tiddler()).assign(t,config.shadowTiddlers[t]));
	}
	// then scan for matching text, tags, or field data
	for(var t=0; t<candidates.length; t++) {
		if (config.options.chkSearchText && candidates[t].text.search(searchRegExp)!=-1)
			results.pushUnique(candidates[t]);
		if (config.options.chkSearchTags && candidates[t].tags.join(" ").search(searchRegExp)!=-1)
			results.pushUnique(candidates[t]);
		if (config.options.chkSearchFields && store.forEachField!=undefined) // requires TW2.1 or above
			store.forEachField(candidates[t],
				function(tid,field,val) { if (val.search(searchRegExp)!=-1) results.pushUnique(candidates[t]); },
				true); // extended fields only
	}
	// then check for matching text in shadows
	if (config.options.chkSearchShadows)
		for (var t in config.shadowTiddlers)
			if ((config.shadowTiddlers[t].search(searchRegExp)!=-1) && !store.tiddlerExists(t))
				results.pushUnique((new Tiddler()).assign(t,config.shadowTiddlers[t]));

	// if not 'titles first', or sorting by modification date,  re-sort results to so titles, text, tag and field matches are mixed together
	if(!sortField) sortField = "title";
	var bySortField=function (a,b) {if(a[sortField] == b[sortField]) return(0); else return (a[sortField] < b[sortField]) ? -1 : +1; }
	if (!config.options.chkSearchTitlesFirst || config.options.chkSearchByDate) results.sort(bySortField);

	return results;
}
//}}}

// // ''REPORT GENERATOR''
//{{{
if (!window.reportSearchResults) window.reportSearchResults=function(text,matches)
{
	var title=config.macros.search.reportTitle
	var q = config.options.chkRegExpSearch ? "/" : "'";
	var body="\n";

	// summary: nn tiddlers found matching '...', options used
	body+="''"+config.macros.search.successMsg.format([matches.length,q+"{{{"+text+"}}}"+q])+"''\n";
	body+="^^//searched in:// ";
	body+=(config.options.chkSearchTitles?"''titles'' ":"");
	body+=(config.options.chkSearchText?"''text'' ":"");
	body+=(config.options.chkSearchTags?"''tags'' ":"");
	body+=(config.options.chkSearchFields?"''fields'' ":"");
	body+=(config.options.chkSearchShadows?"''shadows'' ":"");
	if (config.options.chkCaseSensitiveSearch||config.options.chkRegExpSearch) {
		body+=" //with options:// ";
		body+=(config.options.chkCaseSensitiveSearch?"''case sensitive'' ":"");
		body+=(config.options.chkRegExpSearch?"''text patterns'' ":"");
	}
	body+="^^";

	// numbered list of links to matching tiddlers
	body+="\n<<<";
	for(var t=0;t<matches.length;t++) {
		var date=config.options.chkSearchByDate?(matches[t].modified.formatString('YYYY.0MM.0DD 0hh:0mm')+" "):"";
		body+="\n# "+date+"[["+matches[t].title+"]]";
	}
	body+="\n<<<\n";

	// open all matches button
	body+="<html><input type=\"button\" href=\"javascript:;\" ";
	body+="onclick=\"story.displayTiddlers(null,["
	for(var t=0;t<matches.length;t++)
		body+="'"+matches[t].title.replace(/\'/mg,"\\'")+"'"+((t<matches.length-1)?", ":"");
	body+="],1);\" ";
	body+="accesskey=\"O\" ";
	body+="value=\"open all matching tiddlers\"></html> ";

	// discard search results button
	body+="<html><input type=\"button\" href=\"javascript:;\" ";
	body+="onclick=\"story.closeTiddler('"+title+"'); store.deleteTiddler('"+title+"'); store.notify('"+title+"',true);\" ";
	body+="value=\"discard "+title+"\"></html>";

	// search again
	body+="\n\n----\n";
	body+="<<search \""+text+"\">>\n";
	body+="<<option chkSearchTitles>>titles ";
	body+="<<option chkSearchText>>text ";
	body+="<<option chkSearchTags>>tags";
	body+="<<option chkSearchFields>>fields";
	body+="<<option chkSearchShadows>>shadows";
	body+="<<option chkCaseSensitiveSearch>>case-sensitive ";
	body+="<<option chkRegExpSearch>>text patterns";
	body+="<<option chkSearchByDate>>sort by date";

	// create/update the tiddler
	var tiddler=store.getTiddler(title); if (!tiddler) tiddler=new Tiddler();
	tiddler.set(title,body,config.options.txtUserName,(new Date()),"excludeLists excludeSearch");
	store.addTiddler(tiddler); story.closeTiddler(title);

	// use alternate "search again" label in <<search>> macro
	var oldprompt=config.macros.search.label;
	config.macros.search.label="search again";

	// render/refresh tiddler
	story.displayTiddler(null,title,1);
	store.notify(title,true);

	// restore standard search label
	config.macros.search.label=oldprompt;

}

if (!window.discardSearchResults) window.discardSearchResults=function()
{
	// remove the tiddler
	story.closeTiddler(config.macros.search.reportTitle);
	store.deleteTiddler(config.macros.search.reportTitle);
}
//}}}

<<<
# [[Adler - Cult]]
# [[Albom - Tuesdays with Morrie]]
# [[Baldacci - Absolute Power]]
# [[Baldacci - Stone Cold]]
# [[Barclay - Dawnthief]]
# [[Bear - Darwin's Radio]]
# [[Birmingham - Weapons of Choice]]
# [[Blume - Summer Sisters]]
# [[Boyle - Home Body]]
# [[Bryson - A Short History of Nearly Everything]]
# [[Burdett - Bangkok Haunts]]
# [[Burke - Nine]]
# [[Cook - Chromosome6]]
# [[Cook - Coma]]
# [[Cook - Mutation]]
# [[Cook - vector]]
# [[Cornwell - The Body farm]]
# [[Cornwell - Trace]]
# [[Crichton - Next]]
# [[Desai - The Inheritance of Loss]]
# [[Diamond - Collapse]]
# [[Diamond - Guns, germs and Steel]]
# [[Dibdin - End games]]
# [[Dubus - The House of Sand and Fog]]
# [[Elton - Blind Faith]]
# [[Flagg - Welcome to The World, baby Girl]]
# [[Forster - A Room with a View]]
# [[Gautreaux - The Next Step In The Dance]]
# [[Gautreaux - the Clearing]]
# [[Hassler - North of Hope]]
# [[Hoag - Dust to Dust]]
# [[Hospital - Charades]]
# [[Hospital - Due Preparations for the Plague]]
# [[Hosseini - A Thousand Splendid Suns]]
# [[Hosseini - The Kite Runner]]
# [[Just - To What End]]
# [[Kazantzakis - Zorba The Greek]]
# [[Kellerman - Sunstroke]]
# [[Kellerman - The Conspiracy Club]]
# [[Kerouac - Lonesome Traveller]]
# [[Kidder - The Soul of a new Machine]]
# [[Koontz - Lightning]]
# [[Kundera - Ignorance]]
# [[Lecarre - Absolute Friends]]
# [[Lovell - Apollo 13]]
# [[Martin - A Game of Thrones]]
# [[Mason - The Piano Tuner]]
# [[Moore - God of Darkness]]
# [[NewBookTemplate]]
# [[North - Criminal Seduction]]
# [[North - Violation]]
# [[Palahniuk - Invisible Monsters]]
# [[Patterson - Conviction]]
# [[Patterson - Degree of Guilt]]
# [[Patterson - Escape the Night]]
# [[Patterson - Protect and Defend]]
# [[Patterson - Silent Witness]]
# [[Patterson - The Final Judgement]]
# [[Pirsig - Zen and the Art of Motorcycle Maintenance]]
# [[Power - the Grass Dancer]]
# [[Prejean - Dead Man Walking]]
# [[Rajadhon - Essay on Thai Folklore]]
# [[Rice - Interview With The Vampire]]
# [[Robbins - Wild Ducks Flying Backwards]]
# [[Schaeffer - Shane]]
# [[Schoonover - Thai Gold]]
# [[SideBarOptions]]
# [[SideBarOptionsa]]
# [[Smith - On Beauty]]
# [[Spindler - Dead Run]]
# [[Start this title with author last name]]
# [[Stephenson - Cryptonomicon]]
# [[Swick - Evening news]]
# [[Tan - The Joy Luck Club]]
# [[Tan - The Kitchen God's Wife]]
# [[Updike - Gertrude and Claudious]]
# [[Vonnegut - Galapagos]]
# [[Whitman - Leaves of Grass]]
# [[Williams - The Dragon's Tail]]
# [[Winton - The Turning]]
# [[Wolfe - The Bonfire of The Vanities]]
# [[Wolfe - The Right Stuff]]
# [[Wright - Meditations in Green]]
# [[pramoj - Four Reigns]]
<<<
/***
Quick and dirtly palette switcher for 2.1.x
<<selectPalette>>
WARNING this will overwrite your ColorPalette tiddler.
***/

//{{{

merge(config.macros,{

	setPalette: {

		handler: function(place,macroName,params,wikifier,paramString,tiddler) {
			var paletteName = params[0] ? params[0] : tiddler.title;
			createTiddlyButton(place,"apply","Apply this palette",function(e) {
				config.macros.selectPalette.updatePalette(tiddler.title);
				return false;
			});
		}
	},

	selectPalette: {

		handler: function(place,macroName,params,wikifier,paramString,tiddler) {
			createTiddlyDropDown(place,this.onPaletteChange,this.getPalettes());
		},

		getPalettes: function() {
			var result = [
				{caption:"-select palette-", name:""},
				{caption:"(Default)", name:"(default)"}
			];
			var tagged = store.getTaggedTiddlers("palette","title");
			for(var t=0; t<tagged.length; t++)
				result.push({caption:tagged[t].title, name:tagged[t].title});
			return result;
		},

		onPaletteChange: function(e) {
			config.macros.selectPalette.updatePalette(this.value);
			return true;
		},

		updatePalette: function(title) {
			if (title != "") {
				store.deleteTiddler("ColorPalette");
				if (title != "(default)")
					store.saveTiddler("ColorPalette","ColorPalette",store.getTiddlerText(title),
								config.options.txtUserName,undefined,"");
				this.refreshPalette();
				if(config.options.chkAutoSave)
					saveChanges(true);
			}
		},

		refreshPalette: function() {
			config.macros.refreshDisplay.onClick();
		}
	}
});

//}}}
<<search>>
<<newTiddler title:"Start this title with author last name" label:"new book" text:{{"<<formTiddler NewBookTemplate\>\>"}} tag:"bibentry">><<newTiddler title:"Add title here" label:"new article" text:{{"<<formTiddler NewArticleTemplate\>\>"}} tag:"bibentry" tag:"article">><<newTiddler>><<slider chkSliderOptionsPanel OptionsPanel 'options »' 'Change TiddlyWiki advanced options'>><<closeAll>><<saveChanges>>[[TspotControls|Tiddlyspot options]]<<slider chkSideMenu SideMenu 'How to use BibblyWiki »'>>
<<search>>
<<newTiddler title:"Start this title with author last name" label:"new book" text:{{"<<formTiddler NewBookTemplate\>\>"}} tag:"bibentry">><<newTiddler title:"Add title here" label:"new article" text:{{"<<formTiddler NewArticleTemplate\>\>"}} tag:"bibentry" tag:"article">><<newTiddler>><<slider chkSliderOptionsPanel OptionsPanel 'options »' 'Change TiddlyWiki advanced options'>><<closeAll>><<saveChanges>>[[WelcomeToTiddlyspot|web upload]]
[[http://raybooks.tiddlyspot.com/download|go offline]]<<slider chkSideMenu SideMenu 'How to use BibblyWiki »'>>
[[First things first]]<br>[[New to TiddlyWiki?]]<br>[[How to use BibblyWiki]]<br>[[Tweak the colors]]<br>[[How to Format Text]]<br>[[Credits]]
book reviews on a Tiddlywiki
raybooks
<<slideShow noClicks forceRefresh>> - A simple slide show that keeps the TW style 
<<slideShow style:'MySSStyleSheet' clock:'+'>> - A themed slide show with a clock showing the presentation elapsed time
<<slideShow repeat clock:'-20'>> - A looping slide show with a 20 minutes countdown clock
<<slideShow slidePause:1000>> - A timed slideshow that runs once
<<slideShow slidePause:1000 repeat>> - A timed looping slideshow
-s-
!The [[SlideShowPlugin]]
Press F11 to go fullscreen and adjust the font sizes with Ctrl++ Ctrl+- (or Ctrl+mousewheel).

This plugin was developed by Paulo Soares and Clint Checketts.
{{Comment{This block is not shown in the slide show.
@@Don't show me!!!@@}}}
-s-
!How slides are separated
In a tiddler, you start each slide with the markup {{{-s-}}}
-s-
Slides don't have to have titles like this poor one
-s-
!A slide with subsections and a long title
Check to TOC below to see how this slide title is abbreviated.
!!Section 1
This is a section
!!!Subsection 1.1
This is a subsection
!!!Subsection 1.2
This is another subsection
!!!!Subsubsection 1.2.1
This is a subsubsection
-s-
!Using the keyboard
The following keys are defined:
*Left arrow - previous overlay
*Down arrow - previous slide
*Right arrow - next overlay
*Up arrow - next slide
*Home - first slide
*End - last slide
*Escape - exit slide show
*Spacebar - pause/resume slide show in auto advance mode
-s-
!Slide show parameters
*The slide show can be themed by providing a ~StyleSheet ({{{<<slideShow style:'MyStyleSheet'>>}}})
*By default, there is a clock at bottom of the browser window that displays the current time. This clock can also show the presentation elapsed time with {{{<<slideShow clock:'+'>>}}} or a countdown clock with {{{<<slideShow clock:'-20'>>}}} (for 20 minutes). In these two cases, if you click on the clock display it will be restarted
*The slide show can be set to loop ({{{<<slideShow repeat>>}}})
*You can set it so each slide changes after X milliseconds ({{{<<slideShow slidePause:X>>}}}) (auto advance mode)
*Use auto start mode to begin the slideshow the moment the tiddler is opened ({{{<<slideShow autostart>>>}}})
*You can disable overlays with {{{<<slideShow noOverlays>>}}}
*These parameters can be mixed and matched in any order: {{{<<slideShow slidePause:1000 repeat>>}}} is the same as {{{<<slideShow repeat slidePause:1000>>}}}
-s-
!Overlays
To see how incremental display works use the left and right mouse buttons.
{{Overlay1{You can}}} {{Overlay2{present things}}} {{Overlay1{in an arbitrary order!!!}}}
{{Overlay3{Its a bit harder with lists but it works:}}}
<html>
<ol>
<li class="Overlay4">First item</li>
<li class="Overlay5">Second item</li>
<li class="Overlay4">Last item</li>
</ol>
</html>
{{Comment{You can hide comments on a slide that won't display in the slide show}}}
/***
|''Name:''|SlideShowPlugin|
|''Description:''|Creates a simple slide show type display|
|''Version:''|1.6|
|''Date:''|Feb 12, 2008|
|''Source:''|http://www.math.ist.utl.pt/~psoares/addons.html|
|''Documentation:''|[[SlideShowPlugin Documentation|SlideShowPluginDoc]]|
|''Author:''|Paulo Soares and [[Clint Checketts|http://www.checkettsweb.com]]|
|''License:''|[[Creative Commons Attribution-Share Alike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.1.0|
***/
//{{{
config.macros.slideShow = {label: "slide show", maxTOCLength: 30};
config.macros.slideShow.messages = {gotoLabel: "Go to slide:"};
config.views.wikified.slideShow = {text: "slide show", tooltip: "Start slide show"};
config.views.wikified.slideShow.quit = {text: "end", tooltip: "Quit the slide show"};
config.views.wikified.slideShow.firstSlide = {text: "<<", tooltip: "first slide"};
config.views.wikified.slideShow.previousSlide = {text: "<", tooltip: "previous slide"};
config.views.wikified.slideShow.nextSlide = {text: ">", tooltip: "next slide"};
config.views.wikified.slideShow.lastSlide = {text: ">>", tooltip: "last slide"};
config.views.wikified.slideShow.resetClock = {text: " ", tooltip: "reset"};

config.formatters.push( {
	name: "SlideSeparator",
	match: "^-s-+$\\n?",
	handler: function(w) {
		createTiddlyElement(w.output,"hr",null,'slideSeparator');
	}
});

function changeStyleSheet(tiddlerName) {
	setStylesheet(store.getRecursiveTiddlerText("StyleSheetColors"),"StyleSheetColors");
	setStylesheet(store.getRecursiveTiddlerText("StyleSheetLayout"),"StyleSheetLayout");
	setStylesheet(store.getRecursiveTiddlerText(tiddlerName == null ? "StyleSheet" : tiddlerName,""),"StyleSheet");
}

//Excellent (and versatile) reparser created by Paul Petterson for parsing the paramString in a macro
function reparse( params ) {
	var re = /([^:\s]+)(?:\:((?:\d+)|(?:["'](?:[^"']+)["']))|\s|$)/g;
	var ret = new Array();
	var m;
	while( (m = re.exec( params )) != null ) ret[ m[1] ] = m[2]?m[2]:true;
	return ret;
}

function getElementsByClass(searchClass,node,tag) {
	var classElements = new Array();
	if ( node == null ) node = document;
	if ( tag == null ) tag = '*';
	var els = node.getElementsByTagName(tag);
	var elsLen = els.length;
	var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
	var j=0;
	for (var i = 0; i < elsLen; i++) {
		if ( pattern.test(els[i].className) ) {
			classElements[j] = els[i];
			j++;
		}
	}
	return classElements;
}

// 'keys' code adapted from S5 which in turn was adapted from MozPoint (http://mozpoint.mozdev.org/)
function keys(key) {
with(config.macros.slideShow){
	if (document.getElementById('contentWrapper').className == "slideShowMode"){
		if (!key) {
			key = event;
			key.which = key.keyCode;
		}
 		switch (key.which) {
			case 32: // spacebar
				if(time>0){
					if(autoAdvance){
						clearInterval(autoAdvance);
						autoAdvance = null;
					} else {
						autoAdvance=setInterval("GoToSlide(1)", time);
					}
				}
				break;
			case 34: // page down
			case 39: // rightkey
				GoToSlide("n");
				break;
			case 40: // downkey
				GoToSlide(-1);
				break;
			case 33: // page up
			case 37: // leftkey
				GoToSlide("p");
				break;
			case 38: // upkey
				GoToSlide(1);
				break;
			case 36: // home
				GoToSlide("f");
				break;
			case 35: // end
				GoToSlide("l");
				break;
			case 27: // escape
				endSlideShow();
				break;
			case 66: // B
				blankScreen();
				break;
		}
	}
	return false;
}
}

function blankScreen(){
	var blanker = document.getElementById('slideBlanker');
	if (blanker.style.display == 'block'){
		blanker.style.display = 'none';
	} else {
		blanker.style.display = 'block';
	}
}

function clicker(e) {
	if (!e) var e = window.event;
	var target = resolveTarget(e);
	//Whenever something is clicked that won't advance the slide make sure that the table of contents gets hidden
	if (target.getAttribute('href') != null || isParentOrSelf(target, 'toc') || isParentOrSelf(target,'embed') || isParentOrSelf(target,'object') || isParentOrSelf(target, 'slideFooter') || isParentOrSelf(target, 'navigator')){
		 //Don't hide the TOC if the indexNumbers (which trigger the index) is clicked
		if(isParentOrSelf(target,'indexNumbers') || isParentOrSelf(target,'jumpInput')){
 			return true;
		}
		showHideTOC('none');
		return true;
	}
	//Advance a slide if the TOC is visible otherwise make sure that the TOC gets hidden
	if ((!e.which && e.button == 1) || e.which == 1) {
		if (document.getElementById('toc').style.display != 'block'){
			GoToSlide("n");
		} else {
			showHideTOC('none');
		}
	}
	if ((!e.which && e.button == 2) || e.which == 3) {
		if (document.getElementById('toc').style.display != 'block'){
			GoToSlide("p");
		} else {
			showHideTOC('none');
		}
		return false;
	}
}

function isParentOrSelf(element, id) {
	if (element == null || element.nodeName=='BODY') return false;
	else if (element.id == id) return true;
	else return isParentOrSelf(element.parentNode, id);
}

GoToSlide = function(step) {
	var new_pos;
	var slideHolder = document.getElementById('slideContainer');
	//The parse float ensures that the attribute is returned as a number and not a string.
	var cur_pos = parseFloat(slideHolder.getAttribute('currentslide'));
	var numberSlides = parseFloat(slideHolder.getAttribute('numberSlides'));
	switch (step) {
		case "f":
			new_pos=0;
			break;
		case "l":
			new_pos=numberSlides-1;
			break;
		case "n":
			var numberOverlays = parseFloat(slideHolder.childNodes[cur_pos].getAttribute('numberOverlays'));
			var currentOverlay = parseFloat(slideHolder.getAttribute('currentOverlay'));
			if(numberOverlays==0 || currentOverlay==numberOverlays){
				if(noClicks==false) new_pos=cur_pos+1;
			} else {
				var className="Overlay"+currentOverlay;
				var overlay=getElementsByClass(className,slideHolder.childNodes[cur_pos]);
				for(var i=0; i<overlay.length; i++) {overlay[i].className=className+' previousOverlay';}
				currentOverlay++;
				slideHolder.setAttribute('currentOverlay',currentOverlay);
				className="Overlay"+currentOverlay;
				overlay=getElementsByClass(className,slideHolder.childNodes[cur_pos]);
				for(i=0; i<overlay.length; i++) {overlay[i].className=className+' currentOverlay';}
				return false;
			}
			break;
		case "p":
			var numberOverlays = parseFloat(slideHolder.childNodes[cur_pos].getAttribute('numberOverlays'));
			var currentOverlay = parseFloat(slideHolder.getAttribute('currentOverlay'));
			if(numberOverlays==0 || currentOverlay==0){
				if(noClicks==false) new_pos=cur_pos-1;
			} else {
				var className="Overlay"+currentOverlay;
				var overlays=getElementsByClass(className,slideHolder.childNodes[cur_pos]);
				for(var i=0; i<overlays.length; i++) {overlays[i].className=className+' nextOverlay';}
				currentOverlay--;
				className="Overlay"+currentOverlay;
				overlays=getElementsByClass(className,slideHolder.childNodes[cur_pos]);
				for(i=0; i<overlays.length; i++) {overlays[i].className=className+' currentOverlay';}
				slideHolder.setAttribute('currentOverlay',currentOverlay);
				return false;
			}
			break;
		default:
			new_pos=cur_pos+step;
	}
	if(slideShowCircularMode && new_pos == numberSlides) new_pos=0;
	if(slideShowCircularMode && new_pos<0) new_pos=(numberSlides - 1);
	if(step!=0 && new_pos>=0 && new_pos<numberSlides) {
		slideHolder.childNodes[cur_pos].style.display='none';
		slideHolder.childNodes[new_pos].style.display='block';
		slideHolder.setAttribute('currentslide',new_pos);
		var numberOverlays = parseFloat(slideHolder.childNodes[new_pos].getAttribute('numberOverlays'));
		if(step=="p"){
			var currentOverlay=numberOverlays;
			var state=' previousOverlay';
		} else {
			var currentOverlay=0;
			var state=' nextOverlay';
		}
		slideHolder.setAttribute('currentOverlay',currentOverlay);
		if(numberOverlays>0) {
			for(var i=1; i<=numberOverlays; i++){
				var className="Overlay"+i;
				var overlays=getElementsByClass(className,slideHolder.childNodes[new_pos]);
				for(var j=0; j<overlays.length; j++) {overlays[j].className=className+state;}
			}
			if(step=="p"){
				var className="Overlay"+numberOverlays;
				var overlays=getElementsByClass(className,slideHolder.childNodes[new_pos]);
				for(var j=0; j<overlays.length; j++) {overlays[j].className=className+' currentOverlay';}
			}
		}
		new_pos++;
		var indexNumbers = document.getElementById('indexNumbers');
		indexNumbers.firstChild.data = new_pos+'/'+numberSlides;
		if((new_pos==numberSlides) && !slideShowCircularMode && autoAdvance) clearInterval(autoAdvance);
		return true;
	}
	return false;
}

function tocShowSlide(e) {
	if (!e) var e = window.event;
	var target = resolveTarget(e);
	var slide = target.getAttribute('slideNumber');
	var cur_pos = document.getElementById('slideContainer').getAttribute('currentslide');
	var step = slide-cur_pos;
	if(step!=0) GoToSlide(step);
	showHideTOC('none');
	return;
}

//Toggle the display of the table of contents
function showHideTOC(display){
	var toc = document.getElementById('toc');
	//Reset the input box
	document.getElementById('jumpInput').value = "";
	if (display == null || display.length == null){
		if (toc.style.display == 'none' || toc.style.display == ''){
			toc.style.display = 'block';
			document.getElementById('jumpInput').focus();
		} else {
			toc.style.display = 'none';
		}
	} else {
		toc.style.display = display;
		if (display == 'block')
			document.getElementById('jumpInput').focus();
	}
}

function padZero(x){return (x>=10 || x<0 ? "" : "0")+x;}

setClock = function(){
	var actualTime = new Date();
	var newTime = actualTime.getTime() - clockStartTime;
	newTime = clockMultiplier*newTime+clockInterval+clockCorrection;
	actualTime.setTime(newTime);
	newTime = padZero(actualTime.getHours()) + ":" + padZero(actualTime.getMinutes());
//+ ":" + padZero(actualTime.getSeconds());
	var clock = document.getElementById('slideClock');
	clock.firstChild.nodeValue = newTime;
}

function resetClock(){
	var time = new Date(0);
	if(clockStartTime>time){
		var startTime = new Date();
		clockStartTime=startTime.getTime();
	}
}

var title;
var place;
var autoAdvance=null;
var slideClock=null;
var noOverlays=false;
var noClicks=false;
var forceRefresh=false;
var time = 0;
var slideShowCircularMode;
var slideShowStyleSheet;
var slideShowParams;
var clockMultiplier;
var clockInterval;
var clockCorrection=0;
var clockStartTime;
var openTiddlers;

config.macros.slideShow.handler = function(aPlace,macroName,params,wikifier,paramString,tiddler){
	if(tiddler instanceof Tiddler){
		var lingo = config.views.wikified.slideShow;
		if (!e) var e = window.event;
 		place = aPlace;
		title = tiddler.title;
		params = reparse(paramString);
		var onclick = function(){config.macros.slideShow.onClickSlideShow(params);};
		createTiddlyButton(aPlace,lingo.text,lingo.tooltip,onclick);
	}
}

config.macros.slideShow.onClickSlideShow = function(newParams) {
//	if(typeof(newParams)=="number") newParams=slideShowParams;
	openTiddlers = new Array;
	var viewer=document.getElementById('tiddlerDisplay');
	for(var i=0; i<viewer.childNodes.length; i++){
		var name = viewer.childNodes[i].getAttribute('tiddler');
		openTiddlers.push(name);
	}
	document.oncontextmenu = function(e){return false;}
	clockMultiplier = 1;
	clockInterval = 0;
	var startTime = new Date(0);
	slideShowCircularMode = false;
	time = 0;
	slideShowStyleSheet = null;
	if(newParams['style']){
		slideShowStyleSheet = eval(newParams['style']);
	} 
	if(newParams['repeat']){
		slideShowCircularMode = true;
	}
	if(newParams['noClicks']){
		noClicks = true;
	}
	if(newParams['forceRefresh']){
		forceRefresh = true;
	}
	if(newParams['slidePause'] > 0){
		time = newParams['slidePause'];
	}
	if(newParams['clock']){
		clockCorrection=startTime.getTimezoneOffset()*60000;
		startTime = new Date();
		var clockType= eval(newParams['clock']);
		if(clockType != '+') {
			clockMultiplier = -1;
			clockInterval = -clockType*60000;
		}
	}
	clockStartTime=startTime.getTime();
	if(newParams['noOverlays']){
		noOverlays = true;
	}
	clearMessage();
	//Attach the key and mouse listeners
	document.onkeyup = keys;
	document.onmouseup = clicker;
	story.refreshTiddler(title,"SlideShowViewTemplate",true);
	createSlides(newParams);
	slideClock=setInterval('setClock()', 1000); 
	if(time>0) autoAdvance=setInterval("GoToSlide(1)", time); 
	story.closeAllTiddlers(title);
	toggleSlideStyles();
	return;
}

config.macros.slideShow.endSlideShow=function(){
	var showHolder = document.getElementById('slideShowWrapper');
	showHolder.parentNode.removeChild(showHolder);
	document.oncontextmenu =  function(e){};
	if(autoAdvance) clearInterval(autoAdvance);
	if(slideClock) clearInterval(slideClock);
	noClicks=false;
	story.refreshTiddler(title,null,true);
	story.closeAllTiddlers();
	toggleSlideStyles();
	story.displayTiddlers(null,openTiddlers,DEFAULT_VIEW_TEMPLATE);
	document.onmouseup = function(){};
}

function isInteger(s){
	var i;
	for (i = 0; i < s.length; i++){
		// Check that current character is number.
		var c = s.charAt(i);
		if (((c < "0") || (c > "9"))) return false;
	}
	// All characters are numbers.
	return true;
}

function jumpInputToSlide(e){
	if (!e) {
		e = window.event;
		e.which = e.keyCode;
	}
	if(e.which==13){
		var jumpInput= document.getElementById("jumpInput").value;
		if(isInteger(jumpInput)){
			var step=jumpInput-document.getElementById('slideContainer').getAttribute('currentslide')-1;
			if (GoToSlide(step)){
				showHideTOC('none'); 
			}
		}
	}
	return;
}

//Used to shorten the TOC fields
function abbreviateLabel(label){
	var maxTOCLength = config.macros.slideShow.maxTOCLength;
	if(label.length>maxTOCLength) {
		var temp = new Array();
		temp = label.split(' ');
		label = temp[0];
		for(var j=1; j<temp.length; j++){
			if((label.length+temp[j].length)<=maxTOCLength){
				label += " " + temp[j];
			} else {
				label += " ...";
				break;
			}
		}
	}
	return label;
}

function createSlides(newParams){
	var lingo = config.views.wikified.slideShow;
	//Remove dblClick on edit function
	var theTiddler = document.getElementById("tiddler"+title);
	theTiddler.ondblclick = function() {};
	// Grab the 'viewer' element and give it a signature so the show can be resumed if stopped
	var tiddlerElements = theTiddler.childNodes;
	var viewer;
	for (var i = 0; i < tiddlerElements.length; i++){
		if (tiddlerElements[i].className == "viewer") viewer = tiddlerElements[i];
	}
	viewer.id = 'slideShowWrapper';
	//Hide the text that comes before the first H1 element (I think I may put this into a cover page type thing)
	while(viewer.childNodes.length > 0 && viewer.firstChild.nodeName.toUpperCase() != "HR" && viewer.firstChild.className!="slideSeparator") {
		viewer.removeChild(viewer.firstChild);
	}
	//Cycle through the content and each time you hit an H1 begin a new slide div
	var slideNumber = 0;
	var slideHolder = document.createElement('DIV');
	slideHolder.id = "slideContainer";
	slideHolder.setAttribute('currentslide',0);

	while(viewer.childNodes.length > 0){
		//Create a new slide a append it to the slide holder
		if (viewer.firstChild.nodeName.toUpperCase() == "HR" && viewer.firstChild.className=="slideSeparator"){
			slideNumber++;
			var slide = document.createElement('DIV');
			slide.id = "slideNumber"+slideNumber;
			slide.className = "slide";
			if (slideNumber > 1) {
				//slideHolder.setAttribute('currentslide',0);
				slide.style.display='none';
			} else {
				slide.style.display='block';
			}
			slideHolder.appendChild(slide); 
			viewer.removeChild(viewer.firstChild);
		} else {
			if(viewer.firstChild.nodeName=="SPAN" && viewer.firstChild.className=="" && viewer.firstChild.hasChildNodes()) {
				var anchor=viewer.firstChild.nextSibling;
				for (var ii=0;ii<viewer.firstChild.childNodes.length;ii++) {
					var clone=viewer.firstChild.childNodes[ii].cloneNode(true);
					viewer.insertBefore(clone,anchor);
				}
				viewer.removeChild(viewer.firstChild);
			} else {
				slide.appendChild(viewer.firstChild);
			}
		}
	} 
	//Stick the slides back into the viewer

	var blanker= createTiddlyElement(viewer,"DIV","slideBlanker");
	blanker.style.display="none";

	viewer.appendChild(slideHolder);
	slideHolder.setAttribute('numberSlides',slideNumber);
	//Create the navigation bar
	var slidefooter = createTiddlyElement(viewer,"DIV","slideFooter","slideFooterOff");
	var navigator = createTiddlyElement(slidefooter,"SPAN","navigator");
	//Make it so that when the footer is hovered over the class will change to make it visible
	slidefooter.onmouseover = function () {slidefooter.className = "slideFooterOn"};
	slidefooter.onmouseout = function () {slidefooter.className = "slideFooterOff"};
	//Create the control button for the navigation 
	var onClickQuit = function(){config.macros.slideShow.endSlideShow();};
	createTiddlyButton(navigator,lingo.quit.text,lingo.quit.tooltip,onClickQuit);
	createTiddlyButton(navigator,lingo.firstSlide.text,lingo.firstSlide.tooltip,first_slide);
	createTiddlyButton(navigator,lingo.previousSlide.text,lingo.previousSlide.tooltip,previous_slide);
	createTiddlyButton(navigator,lingo.nextSlide.text,lingo.nextSlide.tooltip,next_slide);
	createTiddlyButton(navigator,lingo.lastSlide.text,lingo.lastSlide.tooltip,last_slide); 
	createTiddlyButton(navigator,lingo.resetClock.text,lingo.resetClock.tooltip,resetClock,"button","slideClock");
	var indexNumbers = createTiddlyElement(slidefooter,"SPAN","indexNumbers","indexNumbers","1/"+slideNumber)
	indexNumbers.onclick = showHideTOC;
	var toc = createTiddlyElement(slidefooter,"UL","toc");
	var ovl=1;
	for (var i=0;i<slideHolder.childNodes.length;i++) {
		if(!noOverlays) {
			var ovl=1;
			while(1){
				var className="Overlay"+ovl;
				var overlays=getElementsByClass(className,slideHolder.childNodes[i]);
				if(overlays.length>0){
					for(var j=0; j<overlays.length; j++) {overlays[j].className+=' nextOverlay';}
					ovl++;
				} else {break;}
			}
		}
		slideHolder.childNodes[i].setAttribute("numberOverlays",ovl-1);
		slideHolder.setAttribute("currentOverlay",0);
		//Loop through each slide and check the header's content
		var tocLabel = null; 
		for (var j=0;j<slideHolder.childNodes[i].childNodes.length;j++) {
			var node = slideHolder.childNodes[i].childNodes[j];
			if(node.nodeName=="H1" || node.nodeName=="H2" || node.nodeName=="H3" || node.nodeName=="H4") {
				var htstring = node.innerHTML;
				var stripped = htstring.replace(/(<([^>]+)>)/ig,"");
				tocLabel = abbreviateLabel(stripped);
				var tocLevel="tocLevel"+node.nodeName.charAt(1);
				var tocItem = createTiddlyElement(toc,"LI",null,tocLevel);
				var tocLink = createTiddlyElement(tocItem,"A",null,"tocItem",tocLabel);
				tocLink.setAttribute("slideNumber",i);
				tocLink.onclick=tocShowSlide;
			}
		}
	}
	//Input box to jump to s specific slide
	var tocItem = createTiddlyElement(toc,"LI",null,"tocJumpItem",config.macros.slideShow.messages.gotoLabel);
	var tocJumpInput = createTiddlyElement(tocItem,"INPUT","jumpInput");
	tocJumpInput.type="text";
	tocJumpInput.onkeyup=jumpInputToSlide;
}

var next_slide= function(e){GoToSlide(1);}
var first_slide= function(e){GoToSlide("f");}
var previous_slide= function(e){GoToSlide(-1);}
var last_slide= function(e){GoToSlide("l");}

function toggleSlideStyles(){
	var contentWrapper = document.getElementById('contentWrapper');
	if (contentWrapper.className == "slideShowMode"){
		contentWrapper.className = "";
		refreshPageTemplate();
		setStylesheet("#backstageShow{display: block;}","SlideShowStyleSheet"); 
		changeStyleSheet();
	} else{
		contentWrapper.className = "slideShowMode";
		refreshPageTemplate("SlideShowPageTemplate");
		setStylesheet(store.getRecursiveTiddlerText("SlideShowStyleSheet"),"SlideShowStyleSheet");
		if(slideShowStyleSheet) changeStyleSheet(slideShowStyleSheet);
	}
}

config.shadowTiddlers.SlideShowPageTemplate="<!--{{{-->\n<div id='displayArea'>\n<div id='tiddlerDisplay'></div>\n</div>\n<!--}}}-->";

config.shadowTiddlers.SlideShowViewTemplate="<!--{{{-->\n<div class='title' macro='view title'></div>\n<div class='viewer' macro='view text wikified'></div>\n<!--}}}-->";

config.shadowTiddlers.SlideShowStyleSheet = "/***\n!Slide Mode Styles\n***/\n/*{{{*/\n#slideBlanker {\n position:absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 90; \n background-color: #000;\n}\n#backstageShow{\n display: none !important;\n}\n\n#contentWrapper.slideShowMode #slideContainer{\n display: block;\n}\n\n#contentWrapper.slideShowMode .Comment{\n display: none;\n}\n\n#contentWrapper.slideShowMode .nextOverlay{\n visibility: hidden;\n}\n\n#contentWrapper.slideShowMode .currentOverlay{\n visibility: visible;\n}\n\n#contentWrapper.slideShowMode .previousOverlay{\n visibility: visible;\n}\n\n#jump{\n text-align: right;\n}\n\n.slideFooterOff #navigator{\n visibility: hidden;\n}\n\n.slideFooterOn #navigator{\n visibility: visible;\n}\n\n#contentWrapper.slideShowMode #slideClock{\n cursor: pointer; margin: 0 5px 0 5px; border: 1px solid #db4\n}\n\n#contentWrapper.slideShowMode,\n #contentWrapper.slideShowMode #displayArea{\n width: 100%;\n font-size: 1.5em;\n margin: 0 !important;\n padding: 0;\n}\n\n#slideContainer{\n display: none;\n}\n\n.indexNumbers{\n cursor: pointer;\n}\n\n#navigator{\n visibility: hidden;\n bottom: 0;\n}\n\n#toc{\n display: none;\n position: absolute;\n font-size: .75em;\n bottom: 2em;\n right: 0;\n background: #fff;\n border: 1px solid #000;\n text-align: left;\n}\n\nul#toc, #toc li{\n margin: 0;\n padding: 0;\n list-style: none;\n line-height: 1em;\n}\n\n.tocJumpItem{\n margin-right: 2em;\n}\n\n.tocJumpItem input{\nmargin-right: 1em;\n border: 0;\n}\n\n#toc a,\n#toc a.button{\n display: block;\n padding: .1em;\n}\n\n#toc .tocLevel1{\nfont-size: .8em;\n}\n\n#toc .tocLevel2{\n margin-left: 1em;\n font-size: .75em;\n}\n\n#toc .tocLevel3{\n margin-left: 2em;\nfont-size: .75em;\n}\n\n#toc .tocLevel4{\n margin-left: 3em;\nfont-size: .65em;\n}\n\n#toc a{\n cursor: pointer;\n}\n\nh1{\n min-height: 1em;\n}\n\n.slide h1{\n min-height: 0;\n}\n\n/* The '>' selector is ignored by IE6 and earlier so the proper rules are given */\n#slideFooter{\n position: fixed;\n bottom: 2px;\n right: 2px;\n width: 100%;\n text-align: right;\n}\n\n/* This is a hack to trick IE6 and earlier to put the navbar on the bottom of the page */\n* html #slideFooter {\n position: absolute;\n width: 100%;\n text-align: right;\n right: auto; bottom: auto;\n left: expression( ( -20 - slideFooter.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n top: expression( ( -10 - slideFooter.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\n\n\n/*}}}*/";

config.shadowTiddlers.SlideShowPluginDoc="The documentation is missing. It is available [[here|http://www.math.ist.utl.pt/~psoares/addons.html#SlideShowPluginDoc]].";
//}}}
!Description
This plugin turns a TiddlyWiki tiddler into a simple slide show type display. Most features that are usually found in presentation software are available. It should work in a way that does not interfere with TiddlyWiki. When you close the slide show you get back to your good old TW. 

This plugin has been tested in Firefox and Internet Explorer. Let me know if something seems broken.
!Usage
To use this plugin you //must// be using TiddlyWiki 2.0. Some optional features (as the incremental display) require version 2.0.8 or higher. To install the plugin copy the tiddlers SlideShowPlugin, SlideShowPageTemplate and SlideShowViewTemplate to your TW, label the first one with the //systemConfig// tag, save the TW and refresh the browser.

To make a slide show simply drop {{{<<slideShow>>}}} at the beginning of a tiddler and use {{{-s-}}} to start each slide. 

If you move your mouse over the bottom of the browser window you will see a few navigation buttons, a clock and a table of contents that shows up when you click the slide number.

Any block of text marked as {{{{{Comment{For my eyes only!}}}}}} will not be displayed in the slide show.

See these and other features in this [[SlideShowExample]].
!Incremental display
A succession of overlays (or layers) can be defined in each slide by marking blocks of text with {{{{{Overlay1{...some text...}}}}}}, {{{{{Overlay2{...some text...}}}}}}, {{{{{Overlay3{...some text...}}}}}}, ...

To costumize the way overlays are shown you can redefine the following CSS classes
*contentWrapper.slideShowMode .previousOverlay 
*contentWrapper.slideShowMode .currentOverlay 
*contentWrapper.slideShowMode .nextOverlay 
in a ~StyleSheet. The default style simply hides the next overlays and shows the current and the previous ones as normal text.
!Slide show parameters
*The slide show can be themed by providing a ~StyleSheet ({{{<<slideShow style:'MyStyleSheet'>>}}})
*By default, there is a clock at bottom of the browser window that displays the current time. This clock can also show the presentation elapsed time with {{{<<slideShow clock:'+'>>}}} or a countdown clock with {{{<<slideShow clock:'-20'>>}}} (for 20 minutes). In these two cases, if you click on the clock display it will be restarted
*The slide show can be set to loop ({{{<<slideShow repeat>>}}})
*You can set it so each slide changes after X milliseconds ({{{<<slideShow slidePause:X>>}}}) (auto advance mode)
*To not use the mouse to navigate through the presentation use  {{{<<slideShow noClicks>>>}}}. This is useful when there are clickable elements in the presentation
*{{{<<slideShow forceRefresh>>>}}} forces a refresh of the presentation tiddler (useful when a presentation is built from separate tiddlers using the {{{<<tiddler>>}}} macro)
*Overlays can be disabled  with {{{<<slideShow noOverlays>>}}}
*These parameters can be mixed and matched in any order: {{{<<slideShow slidePause:1000 repeat>>}}} is the same as {{{<<slideShow repeat slidePause:1000>>}}}
!Slide show navigation
You can navigate through a slide show using the keyboard or the mouse. To quickly move to titled sections you can use the table of contents. 
!!Mouse navigation
Left (right) clicking on a slide jumps to the next (previous) overlay. To move to the beginning of the next or previous slide you must use the navigation bar at the bottom of the browser's window. If there are no overlays defined both operations are equivalent.
!!Keyboard
The following keys are defined:
*Left arrow - previous overlay
*Down arrow - previous slide
*Right arrow - next overlay
*Up arrow - next slide
*Home - first slide
*End - last slide
*Escape - exit slide show
*Spacebar - pause/resume slide show in auto advance mode
*B - blank screen
!Revision history
*1.6
**removed seconds from clock
**added B key to blank screen
**a few fixes to make it work with IE7
*1.5.3
**fix for ~TW2.2
**forceRefresh and noClicks
**removed autoStart feature
**templates are now in shadow tiddlers
*1.5.2 13/02/2007
**fixed a conflict with TW pageFooter
*1.5.1 10/11/2006
**added SlideShowPageTemplate and SlideShowViewTemplate. This way, the plugin no longer requires a standard TW layout. Thanks to Andrew Lister for the idea.
*1.5.0 18/09/2006
**fixed restoring stylesheet on exit
**changed (again!) the way how slides are separated (slide shows prepared for previous versions must be fixed)
*1.4.0 20/04/2006
**changed the way how slides are separated (slide shows prepared for previous versions must be fixed)
**now works with content included with the {{{<<tiddler>>}}} macro
**added incremental display (overlays)
**improved documentation
**assorted small fixes
*1.3.1 10/03/2006
**removed empty slide titles
**fixed wrong numberSlides when slides have div's
**fixed wrong time in Windows
*1.3.0 26/02/2006
**restore open tiddlers on exit
**fixed problem with markup in headers (should work with NestedSlidersPlugin)
**added slide comments (blocks of text in the tiddler that don't show up in the presentation)
*1.2.1 28/01/2006
**pause timed slideshow with spacebar
**added clock with 3 different modes
**fixed bugs with style and abbreviation options
**general cleanup
*1.2.0 07/01/2006
**added a resume feature
**added themes support
*1.1.5 14/12/2005
**added mouse support
**cleaned up navbar generation
*1.1.0 12/12/2005
**added support for IE
**added key listeners
*1.0.0 11/12/2005
**initial release
!Todo
*Time code is still very hackerish and unreliable.
<<formTiddler NewBookTemplate>><data>{"author":"Zadie Smith","booktitle":"On Beauty","pubinfo":"Penguin (2006)","mine":true,"medium":"Paperback","genre":"Fiction, general","primtopic":"Communication","rating":"80","synopsis":"Dis-functional family trying to stay alive in the suburbs"}</data>[Short-listed for the 2005 Man Booker prize]
It took me about 40 pages of struggle before I finally became hooked...then I couldn't put the darn thing down until I had finished it. It is beautifully written, and Smith has a way of injecting wicked humour into the most painful of interpersonal situations. Not very much actually happens in the story, but the telling is very entertaining.
!!!Comments 
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Erica Spindler","booktitle":"Dead Run","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Thriller","primtopic":"Murder","rating":"0","pubinfo":"Mira (2002)"}</data>Not read yet.
!!!Comments:
<<comment>>
/***

''Inspired by [[TiddlyPom|http://www.warwick.ac.uk/~tuspam/tiddlypom.html]]''

|Name|SplashScreenPlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#SplashScreenPlugin|
|Version|0.21 |
|Requires|~TW2.08+|
!Description:
Provides a simple splash screen that is visible while the TW is loading.

!Installation
Copy the source text of this tiddler to your TW in a new tiddler, tag it with systemConfig and save and reload. The SplashScreen will now be installed and will be visible the next time you reload your TW.

!Customizing
Once the SplashScreen has been installed and you have reloaded your TW, the splash screen html will be present in the MarkupPreHead tiddler. You can edit it and customize to your needs.

!History
* 20-07-06 : version 0.21, modified to hide contentWrapper while SplashScreen is displayed.
* 26-06-06 : version 0.2, first release

!Code
***/
//{{{
var old_lewcid_splash_restart=restart;

restart = function()
{   if (document.getElementById("SplashScreen"))
        document.getElementById("SplashScreen").style.display = "none";
      if (document.getElementById("contentWrapper"))
        document.getElementById("contentWrapper").style.display = "block";
    
    old_lewcid_splash_restart();
   
    if (splashScreenInstall)
       {if(config.options.chkAutoSave)
			{saveChanges();}
        displayMessage("TW SplashScreen has been installed, please save and refresh your TW.");
        }
}


var oldText = store.getTiddlerText("MarkupPreHead");
if (oldText.indexOf("SplashScreen")==-1)
   {var siteTitle = store.getTiddlerText("SiteTitle");
   var splasher='\n\n<style type="text/css">#contentWrapper {display:none;}</style><div id="SplashScreen" style="border: 3px solid #ccc; display: block; text-align: center; width: 320px; margin: 100px auto; padding: 50px; color:#000; font-size: 28px; font-family:Tahoma; background-color:#eee;"><b>'+siteTitle +'</b> is loading<blink> ...</blink><br><br><span style="font-size: 14px; color:red;">Requires Javascript.</span></div>';
   if (! store.tiddlerExists("MarkupPreHead"))
       {var myTiddler = store.createTiddler("MarkupPreHead");}
   else
      {var myTiddler = store.getTiddler("MarkupPreHead");}
      myTiddler.set(myTiddler.title,oldText+splasher,config.options.txtUserName,null,null);
      store.setDirty(true);
      var splashScreenInstall = true;
}
//}}}
Updated to hide the contentWrapper while the SplashScreen is displayed. 
Coming Soon: easier editing of the SplashScreen.
Get it here: SplashScreenPlugin.
<<formTiddler NewBookTemplate>>
<<formTiddler NewBookTemplate>><data>{"author":"Neal Stephenson","booktitle":"Cryptonomicon","pubinfo":"Arrow Books (1999)","mine":false,"keep":true,"medium":"Paperback","genre":"Science Fiction","rating":"0"}</data>Not read yet
!!!Comments:
<comment>>
/*{{{*/
/*SideBar tweaks*/

#sidebar {
 position: absolute;
 right: 0px;
 width: 16em;
 font-size: .9em;
font-style: bold;
font-color: #000;
}


#sidebarOptions .sliderPanel {
 margin-left: 1em;
 padding: 0.5em;
 font-size: 1em;
}

.bold {
font-weight: bold;
}


/* horizontal main menu */
/*{{{*/

#displayArea { margin: 1em 15.5em 0em 1em; } /* use the full horizontal width */

#topMenu { background: [[ColorPalette::PrimaryMid]]; color: [[ColorPalette::PrimaryPale]]; padding: 0.2em 0.2em 0.2em 0.5em;}

#topMenu br { display: none; }

#topMenu .button, #topMenu .tiddlyLink, #topMenu a { margin-left: 0.25em; margin-right: 0.25em; padding-left: 0.5em; padding-right: 0.5em; color: [[ColorPalette::PrimaryPale]]; font-size: 1em; }

#topMenu .button:hover, #topMenu .tiddlyLink:hover { background: [[ColorPalette::PrimaryDark]]; }

/* GIFFMEX TWEAKS TO STYLESHEETPRINT (so that nothing but tiddler title and text are printed) */


@media print {#mainMenu {display: none ! important;}}
@media print {#sidebar {display: none ! important;}}
@media print {#messageArea {display: none ! important;}} 
@media print {#toolbar {display: none ! important;}}
@media print {.header {display: none ! important;}}
@media print {.tiddler .subtitle {display: none ! important;}}
@media print {.tiddler .toolbar {display; none ! important; }}
@media print {.tiddler .tagging {display; none ! important; }}
@media print {.tiddler .tagged {display; none ! important; }}
@media print {#displayArea {margin: 1em 1em 0em 1em;}}
@media print {.pageBreak {page-break-before: always;}}


/*GIFFMEX TWEAKS TO STYLESHEETCOLORS */

.subtitle {
 color: [[ColorPalette::#ffffff]];
}


/*(1) Changes table header text color to black */

.viewer th, thead td {
        color: #000; 
}

/* (2) Adjusts the color for all headlines so they are both readable and match my color schemes. */

h1,h2,h3,h4,h5 {
 color: #000;
 background: [[ColorPalette::TertiaryPale]];
}


/* GIFFMEX TWEAKS TO STYLESHEETLAYOUT */


/* (1) Narrows the gap between 4th level headlines, because that is what I use for collapsible main menus */

h4 { margin-top: .3em; margin-bottom: .3em; padding-right: .6em
} 

/* (2) Makes text verdana. */

body {
 font-family: verdana;
}

/* (3) Makes the tiddler background white to contrast with overall background */

#displayArea {background: #fff;
}

/* (4) Allows for Greek - one way */

   .greek {
      font-family: Palatino Linotype;
      font-style: normal;
      font-size: 150%;
   }

.italic {
font-style: italic;
}

/* (5) Shortens the height of the Header */

.headerShadow {
 padding: 2em 0em 1em 1em;
}

.headerForeground {
 padding: 2em 0em 1em 1em;
}

/* (8) Makes ordered and unordered lists double-spaced between items but single-spaced within items. */

.viewer li {
   padding-top: 0.5em;
   padding-bottom: 0.5em;

} 

/*(9) - only applied to Spanish Bible resources - double forward slashes become Palatino linotype for Greek text, rather than italic. */

.viewer em {
font-family: Palatino Linotype;
font-style: normal;
font-size: 150%;
} 


/*}}}*/
/*{{{*/
body {
 background: [[ColorPalette::Background]];
 color: [[ColorPalette::Foreground]];
}

a{
 color: [[ColorPalette::PrimaryMid]];
}

a:hover{
 background: [[ColorPalette::PrimaryMid]];
 color: [[ColorPalette::Background]];
}

a img{
 border: 0;
}

h1,h2,h3,h4,h5 {
 color: #000;
 background: [[ColorPalette::TertiaryPale]];
}

.button {
 color: [[ColorPalette::PrimaryDark]];
 border: 1px solid [[ColorPalette::Background]];
}

.button:hover {
 color: [[ColorPalette::PrimaryDark]];
 background: [[ColorPalette::SecondaryLight]];
 border-color: [[ColorPalette::SecondaryMid]];
}

.button:active {
 color: [[ColorPalette::Background]];
 background: [[ColorPalette::SecondaryMid]];
 border: 1px solid [[ColorPalette::SecondaryDark]];
}

.header {
 background: [[ColorPalette::PrimaryMid]];
}

#displayArea {background: #fff;}

.headerShadow {
 color: [[ColorPalette::Foreground]];
}

.headerShadow a {
 font-weight: normal;
 color: [[ColorPalette::Foreground]];
}

.headerForeground {
 color: [[ColorPalette::Background]];
}

.headerForeground a {
 font-weight: normal;
 color: [[ColorPalette::PrimaryPale]];
}

.tabSelected{
 color: [[ColorPalette::PrimaryDark]];
 background: [[ColorPalette::TertiaryPale]];
 border-left: 1px solid [[ColorPalette::TertiaryLight]];
 border-top: 1px solid [[ColorPalette::TertiaryLight]];
 border-right: 1px solid [[ColorPalette::TertiaryLight]];
}

.tabUnselected {
 color: [[ColorPalette::Background]];
 background: [[ColorPalette::TertiaryMid]];
}

.tabContents {
 color: [[ColorPalette::PrimaryDark]];
 background: [[ColorPalette::TertiaryPale]];
 border: 1px solid [[ColorPalette::TertiaryLight]];
}

.tabContents .button {
 border: 0;}

#sidebar {
}

#sidebarOptions input {
 border: 1px solid [[ColorPalette::PrimaryMid]];
}

#sidebarOptions .sliderPanel {
 background: [[ColorPalette::PrimaryPale]];
}

#sidebarOptions .sliderPanel a {
 border: none;
 color: [[ColorPalette::PrimaryMid]];
}

#sidebarOptions .sliderPanel a:hover {
 color: [[ColorPalette::Background]];
 background: [[ColorPalette::PrimaryMid]];
}

#sidebarOptions .sliderPanel a:active {
 color: [[ColorPalette::PrimaryMid]];
 background: [[ColorPalette::Background]];
}

.wizard {
 background: [[ColorPalette::SecondaryLight]];
 border-top: 1px solid [[ColorPalette::SecondaryMid]];
 border-left: 1px solid [[ColorPalette::SecondaryMid]];
}

.wizard h1 {
 color: [[ColorPalette::SecondaryDark]];
}

.wizard h2 {
 color: [[ColorPalette::Foreground]];
}

.wizardStep {
 background: [[ColorPalette::Background]];
 border-top: 1px solid [[ColorPalette::SecondaryMid]];
 border-bottom: 1px solid [[ColorPalette::SecondaryMid]];
 border-left: 1px solid [[ColorPalette::SecondaryMid]];
}

.wizard .button {
 color: [[ColorPalette::Background]];
 background: [[ColorPalette::PrimaryMid]];
 border-top: 1px solid [[ColorPalette::PrimaryLight]];
 border-right: 1px solid [[ColorPalette::PrimaryDark]];
 border-bottom: 1px solid [[ColorPalette::PrimaryDark]];
 border-left: 1px solid [[ColorPalette::PrimaryLight]];
}

.wizard .button:hover {
 color: [[ColorPalette::PrimaryLight]];
 background: [[ColorPalette::PrimaryDark]];
 border-color: [[ColorPalette::PrimaryLight]];
}

.wizard .button:active {
 color: [[ColorPalette::Background]];
 background: [[ColorPalette::PrimaryMid]];
 border-top: 1px solid [[ColorPalette::PrimaryLight]];
 border-right: 1px solid [[ColorPalette::PrimaryDark]];
 border-bottom: 1px solid [[ColorPalette::PrimaryDark]];
 border-left: 1px solid [[ColorPalette::PrimaryLight]];
}

#messageArea {
 border: 1px solid [[ColorPalette::SecondaryDark]];
 background: [[ColorPalette::SecondaryMid]];
 color: [[ColorPalette::PrimaryDark]];
}

#messageArea .button {
 padding: 0.2em 0.2em 0.2em 0.2em;
 color: [[ColorPalette::PrimaryDark]];
 background: [[ColorPalette::Background]];
}

.popup {
 background: [[ColorPalette::PrimaryLight]];
 border: 1px solid [[ColorPalette::PrimaryMid]];
}

.popup hr {
 color: [[ColorPalette::PrimaryDark]];
 background: [[ColorPalette::PrimaryDark]];
 border-bottom: 1px;
}

.listBreak div{
 border-bottom: 1px solid [[ColorPalette::PrimaryDark]];
}

.popup li.disabled {
 color: [[ColorPalette::PrimaryMid]];
}

.popup li a, .popup li a:visited {
 color: [[ColorPalette::TertiaryPale]];
 border: none;
}

.popup li a:hover {
 background: [[ColorPalette::PrimaryDark]];
 color: [[ColorPalette::Background]];
 border: none;
}

.tiddler .defaultCommand {
 font-weight: bold;
}

.shadow .title {
 color: [[ColorPalette::TertiaryDark]];
}

.title {
 color: [[ColorPalette::SecondaryDark]];
}

.subtitle {
 color: [[ColorPalette::PrimaryDark]];
}

.toolbar {
 color: [[ColorPalette::PrimaryMid]];
}

.tagging, .tagged {
 border: 1px solid [[ColorPalette::TertiaryPale]];
 background-color: [[ColorPalette::TertiaryPale]];
}

.selected .tagging, .selected .tagged {
 background-color: [[ColorPalette::TertiaryLight]];
 border: 1px solid [[ColorPalette::TertiaryMid]];
}

.tagging .listTitle, .tagged .listTitle {
 color: [[ColorPalette::PrimaryDark]];
}

.tagging .button, .tagged .button {
 border: none;
}

.footer {
 color: [[ColorPalette::TertiaryLight]];
}

.selected .footer {
 color: [[ColorPalette::TertiaryMid]];
}

.sparkline {
 background: [[ColorPalette::PrimaryPale]];
 border: 0;
}

.sparktick {
 background: [[ColorPalette::PrimaryDark]];
}

.error, .errorButton {
 color: [[ColorPalette::Foreground]];
 background: [[ColorPalette::Error]];
}

.warning {
 color: [[ColorPalette::Foreground]];
 background: [[ColorPalette::SecondaryPale]];
}

.cascade {
 background: [[ColorPalette::TertiaryPale]];
 color: [[ColorPalette::TertiaryMid]];
 border: 1px solid [[ColorPalette::TertiaryMid]];
}

.imageLink, #displayArea .imageLink {
 background: transparent;
}

.viewer .listTitle {list-style-type: none; margin-left: -2em;}

.viewer .button {
 border: 1px solid [[ColorPalette::SecondaryMid]];
}

.viewer blockquote {
 border-left: 3px solid [[ColorPalette::TertiaryDark]];
}

.viewer table {
 border: 2px solid [[ColorPalette::TertiaryDark]];
}

.viewer th, thead td {
 background: [[ColorPalette::SecondaryMid]];
 border: 1px solid [[ColorPalette::TertiaryDark]];
 color: [[ColorPalette::Background]];
}

.viewer td, .viewer tr {
 border: 1px solid [[ColorPalette::TertiaryDark]];
}

.viewer pre {
 border: 1px solid [[ColorPalette::SecondaryLight]];
 background: [[ColorPalette::SecondaryPale]];
}

.viewer code {
 color: [[ColorPalette::SecondaryDark]];
}

.viewer hr {
 border: 0;
 border-top: dashed 1px [[ColorPalette::TertiaryDark]];
 color: [[ColorPalette::TertiaryDark]];
}

.highlight, .marked {
 background: [[ColorPalette::SecondaryLight]];
}

.editor input {
 border: 1px solid [[ColorPalette::PrimaryMid]];
}

.editor textarea {
 border: 1px solid [[ColorPalette::PrimaryMid]];
 width: 100%;
}

.editorFooter {
 color: [[ColorPalette::TertiaryMid]];
}

/*}}}*/
/*{{{*/
* html .tiddler {
 height: 1%;
}

body {
 font-size: .75em;
 font-family: verdana;
 margin: 0;
 padding: 0;
}

h1,h2,h3,h4,h5 {
 font-weight: bold;
 text-decoration: none;
 padding-left: 0.4em;
 font-color: #ccc;
}

h1 {font-size: 1.35em; font-family: arial; font-color: #ccc;}
h2 {font-size: 1.25em; font-family: arial; font-color: #ccc;}
h3 {font-size: 1.1em; font-family: arial; font-color: #ccc;}
h4 {font-size: 1em; font-family: arial; font-color: #ccc;}
h5 {font-size: .9em; font-family: arial; font-color: #ccc;}

hr {
 height: 1px;
}

a{
 text-decoration: none;
}

dt {font-weight: bold;}

ol { list-style-type: decimal }
ol ol { list-style-type: lower-alpha }
ol ol ol { list-style-type: lower-roman }
ol ol ol ol { list-style-type: decimal }
ol ol ol ol ol { list-style-type: lower-alpha }
ol ol ol ol ol ol { list-style-type: lower-roman }
ol ol ol ol ol ol ol { list-style-type: decimal }

.txtOptionInput {
 width: 11em;
}

#contentWrapper .chkOptionInput {
 border: 0;
}

.externalLink {
 text-decoration: underline;
}

.indent { display:margin:0;padding:0;border:0;margin-left:3em; }
.indent {margin-left:4em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.italic { 
font-style:italic; 
} 

.tiddlyLinkExisting {
 font-weight: bold;
}



.tiddlyLinkNonExisting {
 font-style: italic;
}

/* the 'a' is required for IE, otherwise it renders the whole tiddler a bold */
a.tiddlyLinkNonExisting.shadow {
 font-weight: bold;
}

#mainMenu .tiddlyLinkExisting, 
#mainMenu .tiddlyLinkNonExisting,
#sidebarTabs .tiddlyLinkNonExisting{
 font-weight: normal;
 font-style: normal;
}

#sidebarTabs .tiddlyLinkExisting {
 font-weight: bold;
 font-style: normal;
}

.header {
 position: relative;
}

.header a:hover {
 background: transparent;
}

.headerShadow {
 position: relative;
 padding: 2em 0em 1em 1em;
 left: -1px;
 top: -1px;
}

.headerForeground {
 position: absolute;
 padding: 2em 0em 1em 1em;
 left: 0px;
 top: 0px;
}

.siteTitle {
 font-size: 3em;
}

.siteSubtitle {
 font-size: 1.2em;
}

#mainMenu {
 position: absolute;
 left: 0;
 width: 17em;
 text-align: right;
 line-height: 1.6em;
 padding: 4em 2em 2em 0.5 em;
 font-size: 1.1em;
}

#sidebar {
 position: absolute;
 right: 0px;
 width: 16em;
 font-size: .9em;
}

#sidebarOptions {
 padding-top: 0.3em;
}

#sidebarOptions a {
 margin: 0em 0.2em;
 padding: 0.2em 0.3em;
 display: block;
}

#sidebarOptions input {
 margin: 0.4em 0.5em;
}

#sidebarOptions .sliderPanel {
 margin-left: 1em;
 padding: 0.5em;
 font-size: .85em;
}

#sidebarOptions .sliderPanel a {
 font-weight: bold;
 display: inline;
 padding: 0;
}

#sidebarOptions .sliderPanel input {
 margin: 0 0 .3em 0;
}

#sidebarTabs .tabContents {
 width: 15em;
 overflow: hidden;
}

.wizard {
 padding: 0.1em 0em 0em 2em;
}

.wizard h1 {
 font-size: 2em;
 font-weight: bold;
 background: none;
 padding: 0em 0em 0em 0em;
 margin: 0.4em 0em 0.2em 0em;
}

.wizard h2 {
 font-size: 1.2em;
 font-weight: bold;
 background: none;
 padding: 0em 0em 0em 0em;
 margin: 0.2em 0em 0.2em 0em;
}

.wizardStep {
 padding: 1em 1em 1em 1em;
}

.wizard .button {
 margin: 0.5em 0em 0em 0em;
 font-size: 1.2em;
}

#messageArea {
position:absolute; top:0; right:0; margin: 0.5em; padding: 0.5em;
}

*[id='messageArea'] {
position:fixed !important; z-index:99;}

.messageToolbar {
display: block;
text-align: right;
}

#messageArea a{
 text-decoration: underline;
}

.popup {
 font-size: .9em;
 padding: 0.2em;
 list-style: none;
 margin: 0;
}

.popup hr {
 display: block;
 height: 1px;
 width: auto;
 padding: 0;
 margin: 0.2em 0em;
}

.listBreak {
 font-size: 1px;
 line-height: 1px;
}

.listBreak div {
 margin: 2px 0;
}

.popup li.disabled {
 padding: 0.2em;
}

.popup li a{
 display: block;
 padding: 0.2em;
}

.tabset {
 padding: 1em 0em 0em 0.5em;
}

.tab {
 margin: 0em 0em 0em 0.25em;
 padding: 2px;
}

.tabContents {
 padding: 0.5em;
}

.tabContents ul, .tabContents ol {
 margin: 0;
 padding: 0;
}

.txtMainTab .tabContents li {
 list-style: none;
}

.tabContents li.listLink {
 margin-left: .75em;
}

#displayArea {
 margin: 1em 17em 0em 19.5em;
}


.toolbar {
 text-align: right;
 font-size: .9em;
 visibility: hidden;
}

.selected .toolbar {
 visibility: visible;
}

.tiddler {
 padding: 1em 1em 0em 1em;
}

.missing .viewer,.missing .title {
 font-style: italic;
}

.title {
 font-size: 1.6em; font-family: arial;
 font-weight: bold;
}

.missing .subtitle {
 display: none;
}

.subtitle {
 font-size: 1.1em;
}

.tiddler .button {
 padding: 0.2em 0.4em;
}

.tagging {
margin: 0.5em 0.5em 0.5em 0;
float: left;
display: none;
}

.isTag .tagging {
display: block;
}

.tagged {
margin: 0.5em;
float: right;
}

.tagging, .tagged {
font-size: 0.9em;
padding: 0.25em;
}

.tagging ul, .tagged ul {
list-style: none;margin: 0.25em;
padding: 0;
}

.tagClear {
clear: both;
}

.footer {
 font-size: .9em;
}

.footer li {
display: inline;
}

* html .viewer pre {
 width: 99%;
 padding: 0 0 1em 0;
}

.viewer {
 line-height: 1.4em;
 padding-top: 0.5em;
}

.viewer .button {
 margin: 0em 0.25em;
 padding: 0em 0.25em;
}

.viewer blockquote {
 line-height: 1.5em;
 padding-left: 0.8em;
 margin-left: 2.5em;
}

.viewer em {
font-family: Palatino Linotype;
font-style: normal;
font-size: 150%;
} 

.viewer ul, .viewer ol{
 margin-left: 0.5em;
 padding-left: 1.5em;
}

.viewer table {
 border-collapse: collapse;
 margin: 0.8em 1.0em;
}

.viewer th, .viewer td, .viewer tr,.viewer caption{
 padding: 3px;
}

.viewer table.listView {
 font-size: 0.85em;
 margin: 0.8em 1.0em;
}

.viewer table.listView th, .viewer table.listView td, .viewer table.listView tr {
 padding: 0px 3px 0px 3px;
}

.viewer pre {
 padding: 0.5em;
 margin-left: 0.5em;
 font-size: 1.2em;
 line-height: 1.4em;
 overflow: auto;
}

.viewer code {
 font-size: 1.2em;
 line-height: 1.4em;
}

.editor {
font-size: 1.1em;
}

.editor input, .editor textarea {
 display: block;
 width: 100%;
 font: inherit;
}

.editorFooter {
 padding: 0.25em 0em;
 font-size: .9em;
}

.editorFooter .button {
padding-top: 0px; padding-bottom: 0px;}

.fieldsetFix {border: 0;
padding: 0;
margin: 1px 0px 1px 0px;
}

.li {padding-bottom: 1em;
}

.sparkline {
 line-height: 1em;
}

.sparktick {
 outline: 0;
}

.zoomer {
 font-size: 1.1em;
 position: absolute;
 padding: 1em;
}

.cascade {
 font-size: 1.1em;
 position: absolute;
 overflow: hidden;
}

.viewer li {
   padding-top: 0.5em;
   padding-bottom: 0.5em;
} 

// {{{
if (!config.options.chkEnableFade) config.options.chkEnableFade=false; // ELS: added conditional option for fade-in/fade-out
Slider.prototype.tick = function()
{
 this.progress += this.step;
 if(this.progress < 0 || this.progress > 1)
 {
 this.stop();
 return false;
 }
 else
 {
 var f = Animator.slowInSlowOut(this.progress);
 var h = this.realHeight * f;
 this.element.style.height = h + "px";
 if (config.options.chkEnableFade) // ELS: added conditional option for fade-in/fade-out
 {
 this.element.style.opacity = f;
 this.element.style.filter = "alpha(opacity:" + f * 100 +")";
 }
 return true;
 }
}
//}}}
// // }}}
/*}}}*/

/*{{{*/
@media print {#mainMenu {display: none ! important;}}
@media print {#sidebar {display: none ! important;}}
@media print {#messageArea {display: none ! important;}} 
@media print {#toolbar {display: none ! important;}}
@media print {.header {display: none ! important;}}
@media print {.tiddler .subtitle {display: none ! important;}}
@media print {.tiddler .toolbar {display; none ! important; }}
@media print {.tiddler .tagging {display; none ! important; }}
@media print {.tiddler .tagged {display; none ! important; }}
@media print {#displayArea {margin: 1em 1em 0em 1em;}}
@media print {.pageBreak {page-break-before: always;}}

/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/


<<formTiddler NewBookTemplate>><data>{"author":"Marly Swick","booktitle":"Evening News","pubinfo":"Little, Brown & Company (1999)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Drama","primtopic":"Family tragedy","synopsis":"Young boy accidently shoots his baby sister, and  things happen.","rating":"75"}</data>Well written book about a tragedy and its consequences. The book is all about relationships, and the characters having them. Characters are richly developed, and interesting.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Amy Tan","booktitle":"The Joy Luck Club","pubinfo":"Ivy Book (1989)","mine":true,"medium":"Paperback [2nd hand]","primtopic":"Culture","genre":"Fiction, general","rating":"0","synopsis":"Chinese mythology in USA"}</data>Not read yet.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Amy Tan","booktitle":"The kitchen God's Wife","pubinfo":"Ivy Books (1991)","mine":true,"medium":"Paperback [2nd hand]","rating":"0","genre":"Fiction, general","primtopic":"Culture","synopsis":"Chinese mythology in USA"}</data>Not read yet.
!!!Comments:
<<comment>>
<<formTiddler NewArticleTemplate>><data>{"articletitle":"\"Thank God, this will only get worse\"","journalinfo":"New York Times","primtopic":"Endurance sport","author":"Stuart Stevens","pagenumbers":"2007-08-19","url":"http://www.nytimes.com","synopsis":"Craziness of endurance cyclists"}</data>@@Thank God, This Will Only Get Worse@@
Paolo Pellizzari

OH SUCH FUN Slogging up the Pyrenees in this summer's Étape du Tour, a 196-kilometer race that followed a 2007 Tour de France stage route.

Published: August 19, 2007

It was about five hours and 8,000 vertical feet into the ride when I found myself next to Nigel. He was English and a member of a somewhat ridiculous, somewhat serious cycling club not far from London called the Old Portilians. A year earlier we had ridden the Raid Pyrénéen together. That had been 450 miles of hard riding from the Atlantic to the Mediterranean, over many of the great climbs of the Pyrenees, and I’d never heard Nigel complain once. But now he was on a rant:

“This is goddamn insane, this ride. We’re going to die. What were we thinking?”

I always ask myself the same question at a certain point in any preposterous endurance endeavor. But it was still early in the day, and besides, the thought should never be uttered aloud.

“Cheer up, man. It’s a gorgeous day and we’re in the middle of the French Alps. How bad could it be? You think those goats up there aren’t enjoying the day?”

“What goats?”

I pointed to the top of the massive peak in front of us.

“You idiot,” Nigel said through his sweat. “Those aren’t bloody goats, those are cyclists. That’s where we have to climb.”

“Up there?” High above, the tiny figures were moving. God, they were riders.

“Depressed now, mate?”

I nodded. “We’re going to die.”

“Right.”

You hear a lot of reasons why kids are drawn to sports — a sense of belonging, the sheer love of the game, a chance to earn attention, all those highly touted social benefits. But for me it was always the violence.

As a kid growing up in the Deep South, what I liked most about sports was the endless opportunities presented to hit somebody and not get into trouble. The same sort of violent outburst that doomed you to days of detention would have coaches jumping up and down and shouting gleefully: “You knocked the snot out of ’em! Way to go!”

At least it was that way with football, and where I grew up, football wasn’t just a part of life, it was life, and all that other stuff we did to fill our days seemed monochromatic and slightly sissified. The notion of engaging in an athletic endeavor in which you were penalized for hitting someone seemed an utter waste of time. I was vaguely aware of endurance sports but lumped them together in the same oddball category as race walking. You do that for fun?

So I played football and rugby, boxed and wrestled, none of it particularly well. I tried basketball but always got into fights, mostly as a way to cover for the fact that I never could master that dribbling thing. This all works well enough through high school and college, but at a certain point you look up and the options for participating in sports as a socially accepted way to commit pleasurable acts of violence have narrowed. When most peers are focused on building a career and starting a family, it becomes problematic to admit that what you most enjoy in life is lining up and knocking the snot out of somebody, or vice versa. What once made you seem fun-loving and enthusiastic — so well-rounded! — now begins to paint a darker portrait of an emerging psychopath with serious developmental issues. You’re not just the aging lifeguard whose friends have all left the beach — you’re the aging lifeguard with a little serial killer practice on the side.

Eventually, the time came for me to find other athletic outlets equally gratifying and consuming, though I swore I’d never take up any sports that fat people do well. Like golf.

As is typical, the first endurance sport I tried was running. I hated it.

Freud says that anatomy is destiny, and my destiny as a runner was utter mediocrity. Short of a mandate that all races end with a refrigerator-lifting contest, I was doomed. Those countless hours spent in the gym building a certain mass were suddenly as helpful as lugging around a crate of rocks. It just didn’t seem fair.

I ran my first marathon on a flat course and was feeling quite proud of myself when at around mile 19 I fell into conversation with a stick figure of a guy who seemed fresh enough to have just started. He explained that he was training for an upcoming 100-kilometer race and that this was his off day, so he had decided to run the marathon. Then I noticed he was wearing hiking boots. “I need to make this a challenge,” he said. I had to stop and pretend to be tying my shoe so that I wouldn’t tackle him.

Then, by chance, I stumbled across one of the few endurance sports that didn’t automatically favor those with the body of a P.O.W. — cross-country skiing. I’d never really considered cross-country skiing a sport but more an excuse to wander in the woods and talk to God, both of which had little appeal. I’d tried it once in college when an exceptionally gorgeous girl of a Nordic type suggested a trip up Pikes Peak in Colorado as something of a first date. (That sort of squeaky-clean approach was popular at that time and place, a phase I hope has passed for those still dating in Colorado.) Our romance floundered as we slogged through deep snow on heavy skis, and I quickly progressed from mere gasping to throwing up while she kept demanding, “What’s wrong with you?”

All this changed when I discovered track skiing — Nordic racing. It happened in my late 20s when I was living in Switzerland, where my wife was teaching. I coached the school’s rugby team, but it would be a charitable understatement to say that I had a lot of time on my hands. One of the faculty members had raced cross-country at Middlebury, and he convinced me to tag along to a nearby ski area for a training session.

With the well-practiced efficiency of a racer, my friend quickly stripped down to a Lycra suit and bolted off. On his borrowed racing skis, I tried to follow, still wearing my heavy warm-ups. It didn’t take long to leave my half-digested breakfast in the snow (again!), but an hour or so later, I began to get a hint of the allure of Nordic skiing. It was the glide that seduced me.

Gliding. It was a transforming experience, as if suddenly sprouting wings and darting into the air, a complete rearranging of one’s relationship with gravity. Sheer magic.

The sun glistened off the snow, groomed to perfect corduroy and bisected by miles of parallel tracks. A train of skiers passed by wearing team warm-ups. They were double poling in unison, reaching high with both hands and then thrusting their poles into the snow with tremendous force, their upper bodies bent toward the ground for an instant before their poles shot out behind them in a fluid stroke. Again and again, the same motions repeated, their bodies hurtling across the snow with amazing speed, all synchronized grace and power.

In that moment I didn’t understand what I was seeing — later I would study the mysteries of double poling with an intensity worthy of cracking the genetic code — there was just the sense of a door opening to a hidden world I suddenly wanted to be part of.

A year later, my entire life revolved around cross-country skiing. Any pretense of career or nonathletic ambition had been tossed aside for a slavish devotion to training, technique, equipment and racing. Actually, the races were just a small part of the equation. It was the 20-plus hours a week of skiing I craved, the two and sometimes three workouts a day, that blissful, purposeful exhaustion that made staying awake through dinner a legitimate challenge.

On its most basic level, mine had become a supremely hedonistic existence; I lived in a world totally consumed with my body. Had I been spending 18 hours a day on the beach in search of the perfect tan, I would have been no more useless a member of society. But I’d discovered that having race ambitions gave a patina of respectability to what in fact was exceedingly self-indulgent behavior.

As I immersed myself in cross-country skiing, I learned of a circuit of long-distance events called the Worldloppet: 10 races (later it would expand), each in a different country, 8 in Europe and 2 in North America. In my cross-country frenzy, I decided to do all of them in one eight-week season. It was a silly idea, but of course that only increased the appeal. To do all 10 races, I’d have to spend back-to-back weekends flying across the Atlantic, racing on Saturday, then catching an overnight flight to make the start of another race Sunday morning.

No one had ever done it, but then again, no one had ever bothered to try. There was a whimsical “how many goldfish can you swallow” quality to the project, and yet there was something about its being a series of races that made it seem almost important. When friends or family asked what I was up to — a polite way of wondering if I had a job yet — I’d assume a somber look and say, usually with a sigh, “I’m training to do all the Worldloppet races.” This usually got me a puzzled look — no one having the remotest idea what the Worldloppet was — followed by a serious nod and the inevitable, “How’s it going?”

I loved it.

I had played sports since I was 3 and had been on a million teams, but racing the Worldloppet was the first time I began to define myself as an athlete. Even though I was mediocre on my best days, my obsession with cross-country skiing gave me an entirely new perspective on life and self.

Then, when the season was over, I told myself it was time to grow up and get serious about pursuits worthy of an adult. Reluctantly, I moved on, working as a writer and as a political consultant, which, if nothing else, served as an outlet for my violent tendencies. But it didn’t take long to realize that my taste of the endurance life had created a hunger that normal life didn’t come close to satisfying.

Endurance sports brought order to my days. In an ever-confusing and chaotic world in which truth seems elusive, a serious training session or race made it inescapable. Truth, often ugly and disappointing but honest, was impossible to deny.

But as you get older and life becomes more complicated, it’s easy to start questioning the value of spending huge chunks of your days going in what amounts to glorified circles. One morning you wake up and it suddenly hits you — all the things you could be doing with an extra 15 to 25 hours a week. It’s an entirely rational epiphany and one that must, of course, be crushed immediately.

The key is to reassure yourself that what you are doing is perfectly normal and worthwhile and that it’s all those other people who clearly don’t understand the true meaning of life. I’m sure that’s how Jim Jones or David Koresh kept wavering disciples from leaving the cult — What are you, crazy? We have everything figured out. Here, drink some of this.

My personal garden of Gethsemane came after an encounter between my bike and a cement truck about a month before an Ironman race. Almost inevitably, I’d fallen into a triathlon stage, a near mandatory passage for someone like me — middle-aged, unaccomplished at any specific sport, afflicted with an equipment fetish and in desperate need of new ways to underperform. Why be good at one sport when you can be unimpressive at three?

The crash left my bike unscathed but mangled my left shoulder, a problem not helped when I proceeded to race the Ironman a few weeks later, tucking my bad arm into my wet suit for the 2.4 mile swim. I convinced myself that this would do no harm and, given my miserable swimming skills, might even improve my time. I finished the race, but the surgeon who subsequently repaired my shoulder threatened to commit me to a psychiatric unit if I didn’t give up the long and hard stuff for the foreseeable future.

It was all very depressing. When you’ve depended on silly physical challenges as the organizing principle of your life, it’s terribly disorienting to watch it slip away. It’s like the devout learning that all Masses have been canceled. I told myself this was a sign from some higher power to stop the insanity. But then I met Bob Breedlove.

I was in the Arizona desert at a winter cycling camp. Miserable about not being able to ski with my bum shoulder, I’d signed up for a week of riding. I had no particular aspiration or goal and promised myself that I would stick to my new regimen of moderation. That first day, while most of us were struggling through the hot and windy miles, one guy kept riding, smiling and waving, easily doubling everyone else’s distance. It was highly annoying. Though not a big fellow, his muscles bulged out of ragged shorts and a jersey with hacked-off sleeves. It was as if a smaller version of the Incredible Hulk had taken up cycling. His hands were covered in strange Day-Glo orange gloves. Clearly one of those Rain Man nut jobs who rides his bike too much because he can’t deal with life.

That night there was a lecture by a legendary ultradistance rider and physician whom I’d never met but had heard about for years. In walked the Hulk with the orange gloves. “I’m Bob Breedlove,” he said. The room of riders burst into applause, like an Apple convention greeting Steve Jobs. Bob gave a goofy, embarrassed grin. “I like to ride bikes.”

We rode together every day, and by the end of the week, Bob had pushed me off the long-distance-cycling cliff.

Bob Breedlove was a star of an event known as RAAM — the Race Across America — a yearly phenomenon that compels a self-selecting group of fanatics to meet on the West Coast and ride like hell across the country, arriving at the Atlantic in about 10 days. Ten days.

Even to someone like me, who wasted countless hours finding different ways to get tired, the RAAM riders seemed to be a species apart. But

Bob — a renowned orthopedic surgeon, father of four, deacon of his church — radiated a glorious normalcy while still operating from the assumption that if you weren’t spending huge amounts of time expanding your limits, there was something egregiously out of kilter in your life.

On one of our first rides, I’d asked what had lured him to a race in which you ride your bike from coast to coast. He’d shrugged in his self-deprecating way and said, “I wanted to know what it felt like the last day.”

So there it was. Of course.

The next summer Bob and I were riding a tandem bike together in Paris-Brest-Paris, a 1,200-kilometer event held every four years in France. Bob had ridden P.B.P. many times and, for reasons that baffled me, loved to do it on a tandem. I’d never been on a tandem and always thought it was one of those regrettable inventions that gave couples who didn’t really like each other a chance to pretend they did.

Entrance to the race requires completion of a series of long qualifying rides, and Bob had been working through them with a partner from his hometown of Des Moines. After their final 600-kilometer ride, Bob called me up.

“My tandem partner says he doesn’t want to do P.B.P.,” he announced in a perplexed sort of tone. “I don’t really get it. I mean, he wanted to sleep on the 600k. I said fine, we’d sleep some.”

I pointed out that this was not entirely unreasonable for an event that took 24 to 30 hours of hard riding. Bob begrudgingly agreed, though it was clear he thought sleeping at all on a ride that short was ridiculous. I asked if his partner had any problems on the ride.

“Not really,” Bob said. “He had some trouble with food and was throwing up, but no real problems.”

An image flashed through my mind of some poor guy trapped on the back of Bob’s tandem, vomiting and nodding asleep while Bob powered through the Iowa night.

“He got off the bike at the end,” Bob continued, “and said he never wanted to ride again.”

“Imagine that.”

“So that means you have to ride with me.”

I had already qualified for P.B.P. on a “real” bike and explained to Bob that I hated even the idea of tandems. But of course I knew I’d accept.

It takes a lot of practice for a tandem pair to find a rhythm that overcomes the drag of double weight on one bike. Bob had won RAAM twice with a tandem partner and set a blistering pace at Paris-Brest-Paris. We’d agreed that practice was essential, but naturally it never happened.

“How do you get on this thing?” I asked in Paris when Bob rolled out his shiny new handmade tandem. There was a long pause followed by something of a shudder when Bob and his support crew realized I wasn’t joking.

“Well, we don’t need to worry about a lot of people drafting off us,” Bob said after our first of only two practice spins.

“Why’s that?” I asked.

“We’re too slow.”

We started at dawn with 4,000 other riders in a mad sort of jailbreak, hurtling through gorgeous French countryside where it seemed that the internal combustion fad had never caught on. Our plan was to sleep twice a day in three-hour stints. We’d be met at each stop by Bob’s four-person crew — family and friends who had helped him on his many cross-country rides. For a strictly amateur event in which the winner and the last-place finisher get exactly the same prize — which is to say, nothing — having a support staff that could solve any problem was a bit like entering a soapbox derby with a Nascar pit crew.

We were about 10 hours into it, working through the near constant climbs, when Bob announced almost gleefully: “This is really a terrible course for a tandem. It’s all hills.”

As we rode, Bob kept pushing harder and harder, as if eager to reach the point when muscles surrender and the long battle begins between exhaustion and will.

“Now it starts to get fun,” he exulted. It was dawn of the second day, and all around us cyclists were sleeping on the ground next to their bikes. Two riders were leaning upright against a telephone pole, still on their bikes, sound asleep.

At the last rest stop before the finish, I was wandering around in a daze, envying everyone who was eating the “real” food like pasta that the organizers provided. Bob’s rule, enforced rigorously by his crew, was to stick to an all-liquid diet to avoid the intestinal issues that felled so many riders. We had consumed vast quantities of something called Spizz, which Bob relied on for all his RAAM crossings. But now I found myself wanting solid food in the worst way, and as I was standing in the corner, a few delicious bites into a huge plate of linguine, Bob’s sister-in-law, LaJean Breedlove, caught me.

She took my plate, put her face right up to mine, grasped me by both shoulders and shook me, saying: “Stuart, you’re almost finished. Just stay on the bike!”

Vince Lombardi could not have been more compelling or terrifying. I all but ran to the bike, where Bob was waiting, looking fresh as ever. “It’s good you didn’t argue,” he said, as we pulled away. “That can get messy.”

Two years later, Bob was killed while racing RAAM, struck by a 15-year-old unlicensed driver on a lonely stretch of Colorado highway.

When Bob had proclaimed that the fun really started on that second day of P.B.P., I’d laughed and told him he was nuts, but of course I knew what he meant. “Fun” is what happens when you enter that zone where the ordinary is suspended and the normal rules of time and space are strikingly rearranged. Ask anyone who runs a marathon about the difference between those first miles — the ordinary ones — and the last few, when each stride requires the effort of 10 earlier ones. That’s the Fun Zone, when minutes can seem like hours or, just as capriciously, hours can zoom by in a trance-like state. It’s not why most of us take on absurd endurance endeavors, but I doubt we would keep coming back without those moments. It’s a sweaty sort of transcendence.

At a certain point, as the cliché goes, all endurance activities are more mental than physical. If you get your mind right, you can probably succeed. That’s what I was trying to explain to my pal Nigel high in the French Alps last summer as we slowly forced our bikes up the stunning climb known as the Col du Galibier.

We were riding La Marmotte — a swooping, looped course that covered almost 17,000 feet of climbing over some of the most notorious ascents of the Alps. It was part of a circuit of long, hard rides that is known in Europe as Cyclo Sportive. La Marmotte was billed as arguably the toughest one-day amateur cycling event in the world, and if it wasn’t, God knows I never hope to ride the one that tops it.

At first light, I joined 8,000 other cyclists riding to the start at the base of l’Alpe d’Huez, the most famous climb in the Tour de France. It was a scene that resembled the hometown parades of soldiers marching to war — everyone clean and well fed, victory assured, glory assumed. We filled the village streets of Bourg d’Oisans, packed bike to bike.

A loud mechanical sound broke the quiet, thousands of bike shoe cleats clicking into pedals. The great snake of riders in front of me started to move, though I never heard a start pistol.

We went slowly. In the flats of the valley, no one appeared to be riding hard; everyone was holding back, waiting. Various bike clubs gathered, wearing matching jerseys. It was a perfect morning — clear, not too warm, the peaks ahead sparkling in the early sun. This was going to be easy. I accelerated toward the front. In every group I passed, some wise soul glanced my way with a look somewhere between disdain and pity.

I hope sometime before I die not to be seized by an overwhelming urge to quit as soon as a race requires real effort. It happens to me every time, and it happened to me at La Marmotte. From the valley we turned on to the Col du Glandon, and the road suddenly shot skyward. All around me smaller guys and women (I’d long ago given up the notion that I could hang with the fast women in any sport) shot forward. I had worked hard to stay lean, and my body fat was around 8 percent, which wasn’t horrible, but I still weighed just under 200 pounds. I once heard about a professional basketball player who showed up at an early season practice 10 pounds overweight, and when he scoffed that it didn’t matter, his coach tied a 10-pound ham around his waist. He lost the weight.

Compared with the riders gliding past me, I was lugging a lot of ham up this alp. I looked at my watch — we’d been riding about 45 minutes. As the sweat began to pour off me and my heart rate accelerated, I wasn’t sure I could keep it up. For a moment I let myself focus on the horribly unfair reality that it would probably take me 11-plus hours to get to the finish at the top of l’Alpe d’Huez. If there hadn’t been thousands of riders behind me, I would have made a U-turn and looked for a nice place to have breakfast.

Without the innate human capacity for self-deception, these events would be impossible. You swear to yourself that it will get easier. Oddly, it usually does, or the body adjusts and it seems easier. After about three brutal miles, the Glandon dips for about a mile, giving you hope that the entire day won’t be spent climbing to the moon, then resumes at a slightly less horrible grade.

I’ve learned it’s rarely a good idea to allow yourself to look upward on long climbs. Unfortunately, the famous climbs of the Alps are usually lined with signs detailing the remaining distance to the summit and the grade of the next kilometer. More often than not, I glance away, as if avoiding the sight of some particularly gruesome accident. Don’t tell me. I don’t want to know.

So, head down and grinding away, I almost ran into the crowd of riders stopped on the road just beyond the summit of the Glandon.

“There was a nasty crash on the descent, and they’re stopping everybody from riding down,” a Dutch rider told me. In the distance I could hear the rescue helicopter.

“How bad?” I asked.

He shrugged. “I think several guys died.”

Several? Dead?

“That’s impossible,” I blurted.

It’s shameful but true that of all the thoughts bouncing around in my head — how long are we going to be here? will they deduct this from our official times? what if they cancel the race? (the latter eliciting more hope than disappointment) — I don’t think I spent more than a nanosecond worrying about the crashed riders. Had I passed them lying bleeding on the road, I’m sure I would have stopped. Really, I am.

We milled around, and gradually I began to get as restless as the other riders, who had been trapped on the top for almost an hour. When they finally let us proceed in waves of fives, I flew down the mountain, focused only on the clock, calculating how much time I had lost, swooping around the tight corners in a near frenzy. It’s strange how that works. Yes, someone might have died, but there’s this ticking clock to beat. I had to get to the base of l’Alpe d’Huez by the 6 p.m. cutoff. Beyond that time, riders weren’t allowed to continue up to the finish.

The panic of lost time got me up the relatively mild Col du Télégraphe, but then there was the Galibier. The Tour de France ranks climbs for difficulty, and this one was “hors catégorie” — beyond classification.

By the time Nigel and I hooked up, riders were starting to crack. For a sport that has an aura of gentleness and grace — children ride bikes, grandmothers ride bikes — the violence of race language is telling. Riders don’t slow down, they “crack” or “blow up”; cocky riders promise “to rip the legs off” the competition. It’s an acknowledgment of the true nature of the sport — unrelenting and cruel.

“This is when the fun starts,” I said, but coming from me, Bob Breedlove’s call to arms sounded like an asthmatic’s gasp for air.

Nigel grunted.

The Galibier is one of those climbs that toy with you; just when you think it can’t get worse, it does. A lot worse. The final two kilometers is perilously steep, twisting and turning, making it impossible to tell how much farther you have to go. The air is so thin it’s like trying to breathe through a pillow.

At the top, riders were sprawled out everywhere, despite the sudden wind and sharp cold. Nigel wanted to rest, too, but I knew that stopping would only make us more tired. I checked my watch. It was 4:40, and l’Alpe d’Huez was more than 25 miles away. I said: “We go. Now.”

I outweighed Nigel by at least 30 pounds, and at last this was an advantage. “Stay on my wheel,” I said, handing him a bunch of Endurolyte pills, to ward off leg cramps, and a handful of gel packets. Many Europeans still take a perverse pride in eating the same stuff that Eddy Merckx downed 35 years ago at the Tour de France — little sandwiches and mushy bananas. “Eat this,” I ordered.

We dropped from the summit, Nigel locked behind me as my weight propelled us past lighter riders. Thank you, Newton.

I vaguely remembered reading about some tunnels on the Galibier but was totally unprepared when we rounded a bend and plunged into total darkness. Curses and shouts bounced off the tunnel walls. I had no idea who was ahead of me or to the side. I started to laugh giddily, trying to pull my sunglasses off my nose.

We dropped through 10 more tunnels on the descent, though they became easier as we got used to them. To my shock, I felt something close to strong, using different muscles on the descent and the rolling flats than the long day of climbing had demanded. Then we hit a stretch of uphill, and I felt the energy shoot out of me like air from a torn balloon.

When the angle of the descent relaxed, Nigel powered ahead and we traded off, taking turns in front, trying desperately to keep up our speed. I glanced at my heart rate monitor and shuddered. It was way over 160 beats per minute, pure redline.

At 5:55 p.m., we arrived at the check point at the base of l’Alpe d’Huez. For a moment, a short moment, it was exhilarating and we pounded each other on the back. We noticed a line of riders removing their timing chips, and it dawned on us that they were giving up. Nigel and I both found it offensive, a useful emotion at a time when any sort of motivation was desperately needed.

“You ready?” Nigel asked, a dead look in his eye. “Let’s get the hell out of here.”

We started up the first of the switchbacks, each one marked with a sign commemorating a previous winner of the l’Alpe d’Huez stage of the Tour de France.

“This is going to be easy,” Nigel rasped.

We passed a rider, bent over beside his bike, retching in a spasm of dry heaves.

“Piece of cake,” I agreed.

We pedaled on. Slowly.

Stuart Stevens is the author of “The Big Enchilada” and “Feeding Frenzy.” His next big event is a 93-kilometer Nordic race in Sweden next winter.
<<notes heading:'Rays Notes'>>
!!!Comments:
<<comment>>
20080831...This article makes a fair fist of the task of describing the eccentricity of Endurance athletes. The main protagonist is a bit of a nut case at the best of times, but seems to go seriously crazy as he gets into the event...somehow, though he keeps it together sufficiently to still perform at astonishing levels.
/***
|''Name:''|TiddlerNotesPlugin|
|''Description:''|Add notes to tiddlers without modifying the original content|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#TiddlerNotesPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.1|
|''Date:''|26/10/07|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.3|

!!Concept:
*The TiddlerNotesPlugin allows you to add notes to tiddlers, without needing to edit the original tiddler. This means that your original content will remain unaltered, and if you update it in the future, you won’t lose your notes. Notes are stored in separate tiddlers, but can be viewed and edited from within the original tiddler.
*For a tiddler titled "~MySlide", the notes are by default saved in a tiddler titled "~MySlide-Notes" and is given a tag of "Notes". The suffix and tags of the notes tiddlers are customizable. You can have one or multiple notes per tiddlers. So it is possible to have for example, teacher's notes and student's notes in the same file.
*Notes can be configured to start off blank, or pre-filled with the contents of the original tiddler.

!!Usage:
*{{{<<notes>>}}} is the simplest usage form.
* additional optional parameters include:
**{{{heading:}}} the heading to use for the notes box
**{{{tag:}}} the tag to be given to the notes tiddler
**{{{suffix:}}} the suffix to be used when naming the notes tiddler
* a full macro call could look like: {{{<<notes heading:"My Notes" tag:"NoteTiddlers" suffix:"Comments">>}}}
* To avoid adding {{{<<notes>>}}} to each tiddler you want notes for, you could add the macro call to the ViewTemplate
** below the line {{{<div class='viewer' macro='view text wikified'></div>}}} add the following line: <br> {{{<div class='viewer' macro='notes'></div>}}}
** Used in combination with the ~HideWhenPlugin or ~PublisherPlugin, you could have notes be shown only for tiddlers with specific tags. The ~PublisherPlugin would allow you for instance to only have the ~TeachersNotes visible to the teacher, and the ~StudentsNotes for the same tiddler visible to the Student.

!!Configuration
*<<option chkPrefillNotes>> Enable to pre-fill notes with the original tiddler's contents

!!Demo:
* [[MySlide]]

***/
// /%
//!BEGIN-PLUGIN-CODE

if (!config.options.chkPrefillNotes)
	config.options.chkPrefillNotes = false;
	
function createTiddlyElement(theParent,theElement,theID,theClass,theText,attribs)
{
	var e = document.createElement(theElement);
	if(theClass != null)
		e.className = theClass;
	if(theID != null)
		e.setAttribute("id",theID);
	if(theText != null)
		e.appendChild(document.createTextNode(theText));
	if(attribs){
		for(var n in attribs){
			e.setAttribute(n,attribs[n]);
		}
	}
	if(theParent != null)
		theParent.appendChild(e);
	return e;
}

function createTiddlyButton(theParent,theText,theTooltip,theAction,theClass,theId,theAccessKey,attribs)
{
	var theButton = document.createElement("a");
	if(theAction) {
		theButton.onclick = theAction;
		theButton.setAttribute("href","javascript:;");
	}
	if(theTooltip)
		theButton.setAttribute("title",theTooltip);
	if(theText)
		theButton.appendChild(document.createTextNode(theText));
	if(theClass)
		theButton.className = theClass;
	else
		theButton.className = "button";
	if(theId)
		theButton.id = theId;
	if(attribs){
		for(var n in attribs){
			e.setAttribute(n,attribs[n]);
		}
	}
	if(theParent)
		theParent.appendChild(theButton);
	if(theAccessKey)
		theButton.setAttribute("accessKey",theAccessKey);
	return theButton;
}

config.macros.notes={
	
	cancelWarning: "Are you sure you want to abandon changes to your notes for '%0'?",
	editLabel: "edit notes",
	editTitle: "double click to edit",
	saveLabel: "save notes",
	saveTitle: "double click to save",
	cancelLabel: "cancel",
	heading: "Notes",
	suffix: "Notes",
	tag: "Notes",
	
	saveNotes: function(ev){
		e = ev? ev : window.event;
		var theTarget = resolveTarget(e);
		if (theTarget.nodeName.toLowerCase() == "textarea")
			return false;
		var title = story.findContainingTiddler(theTarget).getAttribute("tiddler");
		story.setDirty(title,false);
		var box = document.getElementById("notesContainer"+title);
		var textarea = document.getElementById("notesTextArea"+title);
		if(textarea.getAttribute("oldText")!=textarea.value && !hasClass(theTarget,"cancelNotesButton")){
			var suffix = box.getAttribute("suffix");
			var t = store.getTiddler(title+"-"+suffix);
			store.saveTiddler(title+"-"+suffix,title+"-"+suffix,textarea.value,config.options.txtUserName,new Date(),t?t.tags:box.getAttribute("tag"),t?t.fields:{});
		}
		story.refreshTiddler(title,1,true);
		autoSaveChanges(true);
		return false;
	},
	
	editNotes: function(box,tiddler){
		removeChildren(box);
		story.setDirty(tiddler,true);
		box.title = this.saveTitle;
		box.ondblclick = this.saveNotes;
		createTiddlyButton(box,this.cancelLabel,this.cancelLabel,this.saveNotes,"cancelNotesButton");
		createTiddlyButton(box,this.saveLabel,this.saveLabel,this.saveNotes,"saveNotesButton");
		wikify("!!"+box.getAttribute("heading")+"\n",box);
		addClass(box,"editor");
		var wrapper1 = createTiddlyElement(null,"fieldset",null,"fieldsetFix");
		var wrapper2 = createTiddlyElement(wrapper1,"div");
		var e = createTiddlyElement(wrapper2,"textarea","notesTextArea"+tiddler);
		var v = store.getValue(tiddler+"-"+box.getAttribute("suffix"),"text");
		if(!v) 
			v = config.options.chkPrefillNotes? store.getValue(tiddler,"text"):'';
		e.value = v;
		e.setAttribute("oldText",v);
		var rows = 10;
		var lines = v.match(/\n/mg);
		var maxLines = Math.max(parseInt(config.options.txtMaxEditRows),5);
		if(lines != null && lines.length > rows)
			rows = lines.length + 5;
		rows = Math.min(rows,maxLines);
		e.setAttribute("rows",rows);
		box.appendChild(wrapper1);
	},
	
	editNotesButtonOnclick: function(e){
		var title = story.findContainingTiddler(this).getAttribute("tiddler");
		var box = document.getElementById("notesContainer"+title);
		config.macros.notes.editNotes(box,title);
		return false;
	},
	
	ondblclick : function(ev){
		e = ev? ev : window.event;
		var theTarget = resolveTarget(e);
		var title = story.findContainingTiddler(theTarget).getAttribute("tiddler");
		var box = document.getElementById("notesContainer"+title);
		config.macros.notes.editNotes(box,title);
		e.cancelBubble = true;
		if(e.stopPropagation) e.stopPropagation();
		return false;
	},
	
	handler : function(place,macroName,params,wikifier,paramString,tiddler){
		
		params = paramString.parseParams("anon",null,true,false,false);
		var heading = getParam(params,"heading",this.heading);
		var tag = getParam(params,"tag",this.tag);
		var suffix = getParam(params,"suffix",this.suffix);
		var box = createTiddlyElement(place,"div","notesContainer"+tiddler.title,"TiddlerNotes",null,{"source":tiddler.title,params:paramString,heading:heading,tag:tag,suffix:suffix});
		createTiddlyButton(box,this.editLabel,this.editLabel,this.editNotesButtonOnclick,"editNotesButton");
		wikify("!!"+heading+"\n",box);
		box.title=this.editTitle;
		box.ondblclick = this.ondblclick;
		wikify("<<tiddler [["+tiddler.title+"-"+suffix+"]]>>",box);
	}		
};

Story.prototype.old_notes_closeTiddler = Story.prototype.closeTiddler;
Story.prototype.closeTiddler = function(title,animate,unused){
	if(story.isDirty(title)) {
		if(!confirm(config.macros.notes.cancelWarning.format([title])))
			return false;
	}
	return this.old_notes_closeTiddler.apply(this,arguments);
}

setStylesheet(".TiddlerNotes {\n"+ " background:#eee;\n"+ " border:1px solid #ccc;\n"+ " padding:10px;\n"+ " margin:15px;\n"+ "}\n"+ "\n"+ ".cancelNotesButton,.editNotesButton, .saveNotesButton {\n"+ " float:right;\n"+ " border:1px solid #ccc;\n"+ " padding:2px 5px;\n"+ "}\n"+ "\n"+ ".saveNotesButton{\n"+ " margin-right:0.5em;\n"+ "}\n"+ "\n"+ ".TiddlerNotes.editor textarea{\n"+ " border:1px solid #ccc;\n"+ "}","NotesPluginStyles");
//!END-PLUGIN-CODE
// %/
/***
Description: Contains the stuff you need to use Tiddlyspot
Note, you also need UploadPlugin, PasswordOptionPlugin and LoadRemoteFileThroughProxy
from http://tiddlywiki.bidix.info for a complete working Tiddlyspot site.
***/
//{{{

// edit this if you are migrating sites or retrofitting an existing TW
config.tiddlyspotSiteId = 'raybooks';

// make it so you can by default see edit controls via http
config.options.chkHttpReadOnly = false;
window.readOnly = false; // make sure of it (for tw 2.2)
window.showBackstage = true; // show backstage too

// disable autosave in d3
if (window.location.protocol != "file:")
	config.options.chkGTDLazyAutoSave = false;

// tweak shadow tiddlers to add upload button, password entry box etc
with (config.shadowTiddlers) {
	SiteUrl = 'http://'+config.tiddlyspotSiteId+'.tiddlyspot.com';
	SideBarOptions = SideBarOptions.replace(/(<<saveChanges>>)/,"$1<<tiddler TspotSidebar>>");
	OptionsPanel = OptionsPanel.replace(/^/,"<<tiddler TspotOptions>>");
	DefaultTiddlers = DefaultTiddlers.replace(/^/,"[[WelcomeToTiddlyspot]] ");
	MainMenu = MainMenu.replace(/^/,"[[WelcomeToTiddlyspot]] ");
}

// create some shadow tiddler content
merge(config.shadowTiddlers,{

'WelcomeToTiddlyspot':[
 "This document is a ~TiddlyWiki from tiddlyspot.com.  A ~TiddlyWiki is an electronic notebook that is great for managing todo lists, personal information, and all sorts of things.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //What now?// &nbsp;&nbsp;@@ Before you can save any changes, you need to enter your password in the form below.  Then configure privacy and other site settings at your [[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]] (your control panel username is //" + config.tiddlyspotSiteId + "//).",
 "<<tiddler TspotControls>>",
 "See also GettingStarted.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Working online// &nbsp;&nbsp;@@ You can edit this ~TiddlyWiki right now, and save your changes using the \"save to web\" button in the column on the right.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Working offline// &nbsp;&nbsp;@@ A fully functioning copy of this ~TiddlyWiki can be saved onto your hard drive or USB stick.  You can make changes and save them locally without being connected to the Internet.  When you're ready to sync up again, just click \"upload\" and your ~TiddlyWiki will be saved back to tiddlyspot.com.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Help!// &nbsp;&nbsp;@@ Find out more about ~TiddlyWiki at [[TiddlyWiki.com|http://tiddlywiki.com]].  Also visit [[TiddlyWiki.org|http://tiddlywiki.org]] for documentation on learning and using ~TiddlyWiki. New users are especially welcome on the [[TiddlyWiki mailing list|http://groups.google.com/group/TiddlyWiki]], which is an excellent place to ask questions and get help.  If you have a tiddlyspot related problem email [[tiddlyspot support|mailto:support@tiddlyspot.com]].",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Enjoy :)// &nbsp;&nbsp;@@ We hope you like using your tiddlyspot.com site.  Please email [[feedback@tiddlyspot.com|mailto:feedback@tiddlyspot.com]] with any comments or suggestions."
].join("\n"),

'TspotControls':[
 "| tiddlyspot password:|<<option pasUploadPassword>>|",
 "| site management:|<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . .  " + config.tiddlyspotSiteId + ">>//(requires tiddlyspot password)//<br>[[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]], [[download (go offline)|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download]]|",
 "| links:|[[tiddlyspot.com|http://tiddlyspot.com/]], [[FAQs|http://faq.tiddlyspot.com/]], [[blog|http://tiddlyspot.blogspot.com/]], email [[support|mailto:support@tiddlyspot.com]] & [[feedback|mailto:feedback@tiddlyspot.com]], [[donate|http://tiddlyspot.com/?page=donate]]|"
].join("\n"),

'TspotSidebar':[
 "<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . .  " + config.tiddlyspotSiteId + ">><html><a href='http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download' class='button'>download</a></html>"
].join("\n"),

'TspotOptions':[
 "tiddlyspot password:",
 "<<option pasUploadPassword>>",
 ""
].join("\n")

});
//}}}
Select a color palette from the dropdown list below to change the color scheme of this file.

<<selectPalette>>

Want more colors? We stripped out most of the colorpalettes to make BibblyWiki leaner. If you want more color options, see [[here|http://www.giffmex.org/twfortherestofus.html#%5B%5BChanging%20the%20colors%20of%20a%20TiddlyWiki%5D%5D]] for palettes and installation instructions.

For more information on how to adjust the colors of a TiddlyWiki file, and for alternate color combinations, see [[this tiddler from our tutorial|http://www.giffmex.org/twfortherestofus.html#%5B%5BChanging%20the%20colors%20of%20a%20TiddlyWiki%5D%5D]].


<<formTiddler NewBookTemplate>><data>{"author":"John Updike","booktitle":"Gertrude and Claudius","pubinfo":"Penguin (2000)","mine":true,"medium":"Paperback","genre":"Drama","primtopic":"History","rating":"80","synopsis":"A prequel, recounting the 30 years leading up to  \"Hamlet\""}</data><<notes heading:'Rays Notes'>> 
!!!Comments:
<<comment>>
Slim novel giving a well developed and entirely credible account of the life of the Danish royal family in the 30 years prior to the tragedy of Hamlet. Updike's word pictures are elegant and great fun to read, and the book leaves a lasting impression on this reader.
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 28/08/2008 11:19:53 | RayStorey | [[raybookreviews20080827.html|file:///M:/RealTiddlywikis/raybookreviews20080827.html]] | [[store.cgi|http://raybooks.tiddlyspot.com/store.cgi]] | . | [[index.html | http://raybooks.tiddlyspot.com/index.html]] | . |
| 28/08/2008 16:25:12 | RayStorey | [[raybooks20080828.html|file:///E:/RealTiddlywikis/raybooks20080828.html]] | [[store.cgi|http://raybooks.tiddlyspot.com/store.cgi]] | . | [[index.html | http://raybooks.tiddlyspot.com/index.html]] | . | ok |
| 15/09/2008 15:30:48 | RayStorey | [[raybooks20080828.html|file:///M:/RealTiddlywikis/raybooks20080828.html#%5B%5BBibliography%20by%20author%5D%5D]] | [[store.cgi|http://raybooks.tiddlyspot.com/store.cgi]] | . | [[index.html | http://raybooks.tiddlyspot.com/index.html]] | . | ok |
| 23/09/2008 11:37:35 | RayStorey | [[raybooks20080828.html|file:///M:/RealTiddlywikis/raybooks20080828.html]] | [[store.cgi|http://raybooks.tiddlyspot.com/store.cgi]] | . | [[index.html | http://raybooks.tiddlyspot.com/index.html]] | . |
| 08/07/2009 08:19:45 | YourName | [[/|http://raybooks.tiddlyspot.com/]] | [[store.cgi|http://raybooks.tiddlyspot.com/store.cgi]] | . | [[index.html | http://raybooks.tiddlyspot.com/index.html]] | . | ok |
| 08/07/2009 08:23:31 | YourName | [[/|http://raybooks.tiddlyspot.com/]] | [[store.cgi|http://raybooks.tiddlyspot.com/store.cgi]] | . | [[index.html | http://raybooks.tiddlyspot.com/index.html]] | . |
| 27/08/2013 12:31:29 | RayStorey | [[/|http://raybooks.tiddlyspot.com/]] | [[store.cgi|http://raybooks.tiddlyspot.com/store.cgi]] | . | [[index.html | http://raybooks.tiddlyspot.com/index.html]] | . | failed |
| 27/08/2013 12:32:25 | RayStorey | [[/|http://raybooks.tiddlyspot.com/]] | [[store.cgi|http://raybooks.tiddlyspot.com/store.cgi]] | . | [[index.html | http://raybooks.tiddlyspot.com/index.html]] | . | ok |
| 27/08/2013 12:36:34 | RayStorey | [[/|http://raybooks.tiddlyspot.com/]] | [[store.cgi|http://raybooks.tiddlyspot.com/store.cgi]] | . | [[index.html | http://raybooks.tiddlyspot.com/index.html]] | . | ok |
| 27/08/2013 12:46:17 | RayStorey | [[/|http://raybooks.tiddlyspot.com/]] | [[store.cgi|http://raybooks.tiddlyspot.com/store.cgi]] | . | [[index.html | http://raybooks.tiddlyspot.com/index.html]] | . |
/***
|''Name:''|UploadPlugin|
|''Description:''|Save to web a TiddlyWiki|
|''Version:''|4.1.3|
|''Date:''|Feb 24, 2008|
|''Source:''|http://tiddlywiki.bidix.info/#UploadPlugin|
|''Documentation:''|http://tiddlywiki.bidix.info/#UploadPluginDoc|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
|''Requires:''|PasswordOptionPlugin|
***/
//{{{
version.extensions.UploadPlugin = {
	major: 4, minor: 1, revision: 3,
	date: new Date("Feb 24, 2008"),
	source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0'
};

//
// Environment
//

if (!window.bidix) window.bidix = {}; // bidix namespace
bidix.debugMode = false;	// true to activate both in Plugin and UploadService
	
//
// Upload Macro
//

config.macros.upload = {
// default values
	defaultBackupDir: '',	//no backup
	defaultStoreScript: "store.php",
	defaultToFilename: "index.html",
	defaultUploadDir: ".",
	authenticateUser: true	// UploadService Authenticate User
};
	
config.macros.upload.label = {
	promptOption: "Save and Upload this TiddlyWiki with UploadOptions",
	promptParamMacro: "Save and Upload this TiddlyWiki in %0",
	saveLabel: "save to web", 
	saveToDisk: "save to disk",
	uploadLabel: "upload"	
};

config.macros.upload.messages = {
	noStoreUrl: "No store URL in parmeters or options",
	usernameOrPasswordMissing: "Username or password missing"
};

config.macros.upload.handler = function(place,macroName,params) {
	if (readOnly)
		return;
	var label;
	if (document.location.toString().substr(0,4) == "http") 
		label = this.label.saveLabel;
	else
		label = this.label.uploadLabel;
	var prompt;
	if (params[0]) {
		prompt = this.label.promptParamMacro.toString().format([this.destFile(params[0], 
			(params[1] ? params[1]:bidix.basename(window.location.toString())), params[3])]);
	} else {
		prompt = this.label.promptOption;
	}
	createTiddlyButton(place, label, prompt, function() {config.macros.upload.action(params);}, null, null, this.accessKey);
};

config.macros.upload.action = function(params)
{
		// for missing macro parameter set value from options
		if (!params) params = {};
		var storeUrl = params[0] ? params[0] : config.options.txtUploadStoreUrl;
		var toFilename = params[1] ? params[1] : config.options.txtUploadFilename;
		var backupDir = params[2] ? params[2] : config.options.txtUploadBackupDir;
		var uploadDir = params[3] ? params[3] : config.options.txtUploadDir;
		var username = params[4] ? params[4] : config.options.txtUploadUserName;
		var password = config.options.pasUploadPassword; // for security reason no password as macro parameter	
		// for still missing parameter set default value
		if ((!storeUrl) && (document.location.toString().substr(0,4) == "http")) 
			storeUrl = bidix.dirname(document.location.toString())+'/'+config.macros.upload.defaultStoreScript;
		if (storeUrl.substr(0,4) != "http")
			storeUrl = bidix.dirname(document.location.toString()) +'/'+ storeUrl;
		if (!toFilename)
			toFilename = bidix.basename(window.location.toString());
		if (!toFilename)
			toFilename = config.macros.upload.defaultToFilename;
		if (!uploadDir)
			uploadDir = config.macros.upload.defaultUploadDir;
		if (!backupDir)
			backupDir = config.macros.upload.defaultBackupDir;
		// report error if still missing
		if (!storeUrl) {
			alert(config.macros.upload.messages.noStoreUrl);
			clearMessage();
			return false;
		}
		if (config.macros.upload.authenticateUser && (!username || !password)) {
			alert(config.macros.upload.messages.usernameOrPasswordMissing);
			clearMessage();
			return false;
		}
		bidix.upload.uploadChanges(false,null,storeUrl, toFilename, uploadDir, backupDir, username, password); 
		return false; 
};

config.macros.upload.destFile = function(storeUrl, toFilename, uploadDir) 
{
	if (!storeUrl)
		return null;
		var dest = bidix.dirname(storeUrl);
		if (uploadDir && uploadDir != '.')
			dest = dest + '/' + uploadDir;
		dest = dest + '/' + toFilename;
	return dest;
};

//
// uploadOptions Macro
//

config.macros.uploadOptions = {
	handler: function(place,macroName,params) {
		var wizard = new Wizard();
		wizard.createWizard(place,this.wizardTitle);
		wizard.addStep(this.step1Title,this.step1Html);
		var markList = wizard.getElement("markList");
		var listWrapper = document.createElement("div");
		markList.parentNode.insertBefore(listWrapper,markList);
		wizard.setValue("listWrapper",listWrapper);
		this.refreshOptions(listWrapper,false);
		var uploadCaption;
		if (document.location.toString().substr(0,4) == "http") 
			uploadCaption = config.macros.upload.label.saveLabel;
		else
			uploadCaption = config.macros.upload.label.uploadLabel;
		
		wizard.setButtons([
				{caption: uploadCaption, tooltip: config.macros.upload.label.promptOption, 
					onClick: config.macros.upload.action},
				{caption: this.cancelButton, tooltip: this.cancelButtonPrompt, onClick: this.onCancel}
				
			]);
	},
	options: [
		"txtUploadUserName",
		"pasUploadPassword",
		"txtUploadStoreUrl",
		"txtUploadDir",
		"txtUploadFilename",
		"txtUploadBackupDir",
		"chkUploadLog",
		"txtUploadLogMaxLine"		
	],
	refreshOptions: function(listWrapper) {
		var opts = [];
		for(i=0; i<this.options.length; i++) {
			var opt = {};
			opts.push();
			opt.option = "";
			n = this.options[i];
			opt.name = n;
			opt.lowlight = !config.optionsDesc[n];
			opt.description = opt.lowlight ? this.unknownDescription : config.optionsDesc[n];
			opts.push(opt);
		}
		var listview = ListView.create(listWrapper,opts,this.listViewTemplate);
		for(n=0; n<opts.length; n++) {
			var type = opts[n].name.substr(0,3);
			var h = config.macros.option.types[type];
			if (h && h.create) {
				h.create(opts[n].colElements['option'],type,opts[n].name,opts[n].name,"no");
			}
		}
		
	},
	onCancel: function(e)
	{
		backstage.switchTab(null);
		return false;
	},
	
	wizardTitle: "Upload with options",
	step1Title: "These options are saved in cookies in your browser",
	step1Html: "<input type='hidden' name='markList'></input><br>",
	cancelButton: "Cancel",
	cancelButtonPrompt: "Cancel prompt",
	listViewTemplate: {
		columns: [
			{name: 'Description', field: 'description', title: "Description", type: 'WikiText'},
			{name: 'Option', field: 'option', title: "Option", type: 'String'},
			{name: 'Name', field: 'name', title: "Name", type: 'String'}
			],
		rowClasses: [
			{className: 'lowlight', field: 'lowlight'} 
			]}
};

//
// upload functions
//

if (!bidix.upload) bidix.upload = {};

if (!bidix.upload.messages) bidix.upload.messages = {
	//from saving
	invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki",
	backupSaved: "Backup saved",
	backupFailed: "Failed to upload backup file",
	rssSaved: "RSS feed uploaded",
	rssFailed: "Failed to upload RSS feed file",
	emptySaved: "Empty template uploaded",
	emptyFailed: "Failed to upload empty template file",
	mainSaved: "Main TiddlyWiki file uploaded",
	mainFailed: "Failed to upload main TiddlyWiki file. Your changes have not been saved",
	//specific upload
	loadOriginalHttpPostError: "Can't get original file",
	aboutToSaveOnHttpPost: 'About to upload on %0 ...',
	storePhpNotFound: "The store script '%0' was not found."
};

bidix.upload.uploadChanges = function(onlyIfDirty,tiddlers,storeUrl,toFilename,uploadDir,backupDir,username,password)
{
	var callback = function(status,uploadParams,original,url,xhr) {
		if (!status) {
			displayMessage(bidix.upload.messages.loadOriginalHttpPostError);
			return;
		}
		if (bidix.debugMode) 
			alert(original.substr(0,500)+"\n...");
		// Locate the storeArea div's 
		var posDiv = locateStoreArea(original);
		if((posDiv[0] == -1) || (posDiv[1] == -1)) {
			alert(config.messages.invalidFileError.format([localPath]));
			return;
		}
		bidix.upload.uploadRss(uploadParams,original,posDiv);
	};
	
	if(onlyIfDirty && !store.isDirty())
		return;
	clearMessage();
	// save on localdisk ?
	if (document.location.toString().substr(0,4) == "file") {
		var path = document.location.toString();
		var localPath = getLocalPath(path);
		saveChanges();
	}
	// get original
	var uploadParams = new Array(storeUrl,toFilename,uploadDir,backupDir,username,password);
	var originalPath = document.location.toString();
	// If url is a directory : add index.html
	if (originalPath.charAt(originalPath.length-1) == "/")
		originalPath = originalPath + "index.html";
	var dest = config.macros.upload.destFile(storeUrl,toFilename,uploadDir);
	var log = new bidix.UploadLog();
	log.startUpload(storeUrl, dest, uploadDir,  backupDir);
	displayMessage(bidix.upload.messages.aboutToSaveOnHttpPost.format([dest]));
	if (bidix.debugMode) 
		alert("about to execute Http - GET on "+originalPath);
	var r = doHttp("GET",originalPath,null,null,username,password,callback,uploadParams,null);
	if (typeof r == "string")
		displayMessage(r);
	return r;
};

bidix.upload.uploadRss = function(uploadParams,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		if(status) {
			var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
			displayMessage(bidix.upload.messages.rssSaved,bidix.dirname(url)+'/'+destfile);
			bidix.upload.uploadMain(params[0],params[1],params[2]);
		} else {
			displayMessage(bidix.upload.messages.rssFailed);			
		}
	};
	// do uploadRss
	if(config.options.chkGenerateAnRssFeed) {
		var rssPath = uploadParams[1].substr(0,uploadParams[1].lastIndexOf(".")) + ".xml";
		var rssUploadParams = new Array(uploadParams[0],rssPath,uploadParams[2],'',uploadParams[4],uploadParams[5]);
		var rssString = generateRss();
		// no UnicodeToUTF8 conversion needed when location is "file" !!!
		if (document.location.toString().substr(0,4) != "file")
			rssString = convertUnicodeToUTF8(rssString);	
		bidix.upload.httpUpload(rssUploadParams,rssString,callback,Array(uploadParams,original,posDiv));
	} else {
		bidix.upload.uploadMain(uploadParams,original,posDiv);
	}
};

bidix.upload.uploadMain = function(uploadParams,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		var log = new bidix.UploadLog();
		if(status) {
			// if backupDir specified
			if ((params[3]) && (responseText.indexOf("backupfile:") > -1))  {
				var backupfile = responseText.substring(responseText.indexOf("backupfile:")+11,responseText.indexOf("\n", responseText.indexOf("backupfile:")));
				displayMessage(bidix.upload.messages.backupSaved,bidix.dirname(url)+'/'+backupfile);
			}
			var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
			displayMessage(bidix.upload.messages.mainSaved,bidix.dirname(url)+'/'+destfile);
			store.setDirty(false);
			log.endUpload("ok");
		} else {
			alert(bidix.upload.messages.mainFailed);
			displayMessage(bidix.upload.messages.mainFailed);
			log.endUpload("failed");			
		}
	};
	// do uploadMain
	var revised = bidix.upload.updateOriginal(original,posDiv);
	bidix.upload.httpUpload(uploadParams,revised,callback,uploadParams);
};

bidix.upload.httpUpload = function(uploadParams,data,callback,params)
{
	var localCallback = function(status,params,responseText,url,xhr) {
		url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
		if (xhr.status == 404)
			alert(bidix.upload.messages.storePhpNotFound.format([url]));
		if ((bidix.debugMode) || (responseText.indexOf("Debug mode") >= 0 )) {
			alert(responseText);
			if (responseText.indexOf("Debug mode") >= 0 )
				responseText = responseText.substring(responseText.indexOf("\n\n")+2);
		} else if (responseText.charAt(0) != '0') 
			alert(responseText);
		if (responseText.charAt(0) != '0')
			status = null;
		callback(status,params,responseText,url,xhr);
	};
	// do httpUpload
	var boundary = "---------------------------"+"AaB03x";	
	var uploadFormName = "UploadPlugin";
	// compose headers data
	var sheader = "";
	sheader += "--" + boundary + "\r\nContent-disposition: form-data; name=\"";
	sheader += uploadFormName +"\"\r\n\r\n";
	sheader += "backupDir="+uploadParams[3] +
				";user=" + uploadParams[4] +
				";password=" + uploadParams[5] +
				";uploaddir=" + uploadParams[2];
	if (bidix.debugMode)
		sheader += ";debug=1";
	sheader += ";;\r\n"; 
	sheader += "\r\n" + "--" + boundary + "\r\n";
	sheader += "Content-disposition: form-data; name=\"userfile\"; filename=\""+uploadParams[1]+"\"\r\n";
	sheader += "Content-Type: text/html;charset=UTF-8" + "\r\n";
	sheader += "Content-Length: " + data.length + "\r\n\r\n";
	// compose trailer data
	var strailer = new String();
	strailer = "\r\n--" + boundary + "--\r\n";
	data = sheader + data + strailer;
	if (bidix.debugMode) alert("about to execute Http - POST on "+uploadParams[0]+"\n with \n"+data.substr(0,500)+ " ... ");
	var r = doHttp("POST",uploadParams[0],data,"multipart/form-data; ;charset=UTF-8; boundary="+boundary,uploadParams[4],uploadParams[5],localCallback,params,null);
	if (typeof r == "string")
		displayMessage(r);
	return r;
};

// same as Saving's updateOriginal but without convertUnicodeToUTF8 calls
bidix.upload.updateOriginal = function(original, posDiv)
{
	if (!posDiv)
		posDiv = locateStoreArea(original);
	if((posDiv[0] == -1) || (posDiv[1] == -1)) {
		alert(config.messages.invalidFileError.format([localPath]));
		return;
	}
	var revised = original.substr(0,posDiv[0] + startSaveArea.length) + "\n" +
				store.allTiddlersAsHtml() + "\n" +
				original.substr(posDiv[1]);
	var newSiteTitle = getPageTitle().htmlEncode();
	revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
	revised = updateMarkupBlock(revised,"PRE-HEAD","MarkupPreHead");
	revised = updateMarkupBlock(revised,"POST-HEAD","MarkupPostHead");
	revised = updateMarkupBlock(revised,"PRE-BODY","MarkupPreBody");
	revised = updateMarkupBlock(revised,"POST-SCRIPT","MarkupPostBody");
	return revised;
};

//
// UploadLog
// 
// config.options.chkUploadLog :
//		false : no logging
//		true : logging
// config.options.txtUploadLogMaxLine :
//		-1 : no limit
//      0 :  no Log lines but UploadLog is still in place
//		n :  the last n lines are only kept
//		NaN : no limit (-1)

bidix.UploadLog = function() {
	if (!config.options.chkUploadLog) 
		return; // this.tiddler = null
	this.tiddler = store.getTiddler("UploadLog");
	if (!this.tiddler) {
		this.tiddler = new Tiddler();
		this.tiddler.title = "UploadLog";
		this.tiddler.text = "| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |";
		this.tiddler.created = new Date();
		this.tiddler.modifier = config.options.txtUserName;
		this.tiddler.modified = new Date();
		store.addTiddler(this.tiddler);
	}
	return this;
};

bidix.UploadLog.prototype.addText = function(text) {
	if (!this.tiddler)
		return;
	// retrieve maxLine when we need it
	var maxLine = parseInt(config.options.txtUploadLogMaxLine,10);
	if (isNaN(maxLine))
		maxLine = -1;
	// add text
	if (maxLine != 0) 
		this.tiddler.text = this.tiddler.text + text;
	// Trunck to maxLine
	if (maxLine >= 0) {
		var textArray = this.tiddler.text.split('\n');
		if (textArray.length > maxLine + 1)
			textArray.splice(1,textArray.length-1-maxLine);
			this.tiddler.text = textArray.join('\n');		
	}
	// update tiddler fields
	this.tiddler.modifier = config.options.txtUserName;
	this.tiddler.modified = new Date();
	store.addTiddler(this.tiddler);
	// refresh and notifiy for immediate update
	story.refreshTiddler(this.tiddler.title);
	store.notify(this.tiddler.title, true);
};

bidix.UploadLog.prototype.startUpload = function(storeUrl, toFilename, uploadDir,  backupDir) {
	if (!this.tiddler)
		return;
	var now = new Date();
	var text = "\n| ";
	var filename = bidix.basename(document.location.toString());
	if (!filename) filename = '/';
	text += now.formatString("0DD/0MM/YYYY 0hh:0mm:0ss") +" | ";
	text += config.options.txtUserName + " | ";
	text += "[["+filename+"|"+location + "]] |";
	text += " [[" + bidix.basename(storeUrl) + "|" + storeUrl + "]] | ";
	text += uploadDir + " | ";
	text += "[[" + bidix.basename(toFilename) + " | " +toFilename + "]] | ";
	text += backupDir + " |";
	this.addText(text);
};

bidix.UploadLog.prototype.endUpload = function(status) {
	if (!this.tiddler)
		return;
	this.addText(" "+status+" |");
};

//
// Utilities
// 

bidix.checkPlugin = function(plugin, major, minor, revision) {
	var ext = version.extensions[plugin];
	if (!
		(ext  && 
			((ext.major > major) || 
			((ext.major == major) && (ext.minor > minor))  ||
			((ext.major == major) && (ext.minor == minor) && (ext.revision >= revision))))) {
			// write error in PluginManager
			if (pluginInfo)
				pluginInfo.log.push("Requires " + plugin + " " + major + "." + minor + "." + revision);
			eval(plugin); // generate an error : "Error: ReferenceError: xxxx is not defined"
	}
};

bidix.dirname = function(filePath) {
	if (!filePath) 
		return;
	var lastpos;
	if ((lastpos = filePath.lastIndexOf("/")) != -1) {
		return filePath.substring(0, lastpos);
	} else {
		return filePath.substring(0, filePath.lastIndexOf("\\"));
	}
};

bidix.basename = function(filePath) {
	if (!filePath) 
		return;
	var lastpos;
	if ((lastpos = filePath.lastIndexOf("#")) != -1) 
		filePath = filePath.substring(0, lastpos);
	if ((lastpos = filePath.lastIndexOf("/")) != -1) {
		return filePath.substring(lastpos + 1);
	} else
		return filePath.substring(filePath.lastIndexOf("\\")+1);
};

bidix.initOption = function(name,value) {
	if (!config.options[name])
		config.options[name] = value;
};

//
// Initializations
//

// require PasswordOptionPlugin 1.0.1 or better
bidix.checkPlugin("PasswordOptionPlugin", 1, 0, 1);

// styleSheet
setStylesheet('.txtUploadStoreUrl, .txtUploadBackupDir, .txtUploadDir {width: 22em;}',"uploadPluginStyles");

//optionsDesc
merge(config.optionsDesc,{
	txtUploadStoreUrl: "Url of the UploadService script (default: store.php)",
	txtUploadFilename: "Filename of the uploaded file (default: in index.html)",
	txtUploadDir: "Relative Directory where to store the file (default: . (downloadService directory))",
	txtUploadBackupDir: "Relative Directory where to backup the file. If empty no backup. (default: ''(empty))",
	txtUploadUserName: "Upload Username",
	pasUploadPassword: "Upload Password",
	chkUploadLog: "do Logging in UploadLog (default: true)",
	txtUploadLogMaxLine: "Maximum of lines in UploadLog (default: 10)"
});

// Options Initializations
bidix.initOption('txtUploadStoreUrl','');
bidix.initOption('txtUploadFilename','');
bidix.initOption('txtUploadDir','');
bidix.initOption('txtUploadBackupDir','');
bidix.initOption('txtUploadUserName','');
bidix.initOption('pasUploadPassword','');
bidix.initOption('chkUploadLog',true);
bidix.initOption('txtUploadLogMaxLine','10');


// Backstage
merge(config.tasks,{
	uploadOptions: {text: "upload", tooltip: "Change UploadOptions and Upload", content: '<<uploadOptions>>'}
});
config.backstageTasks.push("uploadOptions");


//}}}

The menu at the top of BibblyWiki contains links to tiddlers that sort your library by author, primary topic, all topics, call number, and title. 

There are also links  for articles only (sorted by article author) and for resources that you tell BibblyWiki that you own. The latter list is helpful since the other lists include all books and articles in your BibblyWiki, even books you don't personally own.

These lists are automatically updated as you add to them, assuming that you add the appropriate information in your book and article tiddlers.

<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler permalink references jump'></div>
<div class='title' macro='view title'></div>
<div class='tagClear'></div>
<div class='viewer' macro='view text wikified'></div>

<!--}}}-->
<<formTiddler NewBookTemplate>><data>{"author":"Kurt Vonnegut","booktitle":"Galapagos","pubinfo":"Dell (1985)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Satire","primtopic":"Spoof","synopsis":"Unlikely members of a  Galapagos expedition.","rating":"0"}</data>Not read yet
!!!Comments:
<<comment>>
!My site for Book Review, Article discussion, perhaps even Movie Review.
This facility is:
# Based heavily on [[http://www.giffmex.org/bibblywiki.html|Dave Gifford's BibliWiki]] iteration of [[http://tiddlywiki.com|Tiddlywiki]].
# Mainly used as a portable Wiki-on-a-thumbdrive, but [[http://raybooks.tiddlyspot.com|also exists on the web]], hosted by [[http://tiddlyspot.com|Tiddlyspot]].
# giving opinions which are those of [[Introducing Ray Storey|RayStorey]], with the exception of those expressed in comments.
Enjoy!

This site also uses the following Tiddlywiki plugins, from 3rd part developers:
|!Plugin|!Description|
|[[http://tiddlyspot.com|Tiddlyspot]]|Components that assist in upload/sync of off-line & on-line copies|
|[[http://www.tiddlytools.com|Splashscreen]]|Provides something to look at while the site is loading in browser|
|[[http://www.martinswiki.com|Creole]]|Markup compatibility with Creole standard|
|[[http://www.math.ist.utl.pt/~psoares/addons.html#Plugins|Slideshow]]|Enables full-screen display of simple slideshows|
|[[http://www.tiddlytools.com|CommentPlugin]]|To allow for feedback through a device at the bottom of a page|
|[[http://tw.lewcid.org/#%5B%5BExtensions%20Overview%5D%5D|TiddlerNotesPlugin]]|Allows notes to be appended to tiddlers|
<<formTiddler NewBookTemplate>><data>{"author":"Walt Whitman","booktitle":"Leaves of Grass","pubinfo":"Project Gutenberg","mine":true,"medium":"eBook (eReader)","genre":"Fiction, general","primtopic":"Joy of Life","rating":"80"}</data>First published about 1880, this major work of Poetry resonates with the Joy of Life.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Adam Williams","booktitle":"The Dragon's Tail","pubinfo":"Hodder & Stoughton (2007)","mine":true,"medium":"Paperback","genre":"Fiction, general","primtopic":"Unconsumated love","synopsis":"Trials & tribulations over 50 years in the life of a Chinese peasant.","rating":"75"}</data>
<<notes heading:'Rays Notes'>>
!!!Comments:
<<comment>>
Interesting, historically authentic, tale of the life of a Chinese peasant, and her ultimate relief. Author clearly has deep personal experience of life in China, and draws on this to paint rich pictures of China during the second half of the 20th century. Well written and interesting.
<<formTiddler NewBookTemplate>><data>{"author":"Tim Winton","booktitle":"The Turning","pubinfo":"Picador (2005)","mine":true,"medium":"Paperback","genre":"Short stories","primtopic":"Life","rating":"85","synopsis":"Connected shortstories about growing up in Western Australia"}</data>Winton might be from Western Australia, which is a bit backward, but there is nothing light-weight about his superb writing skills. Here, he has created a set of self-standing shorts that eventually pull together into a flowing novel. The characters are rich, and the word-craft is brilliant.
!!!Comments 
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Tom Wolfe","booktitle":"The Bonfire of The Vanities","pubinfo":"Bantam (1988)","mine":true,"medium":"Paperback (2nd hand)","genre":"Satire","primtopic":"Society","rating":"70","synopsis":"Well2Do New York banking gets into trouble"}</data>High expectations after reading "The Right Stuff" were dashed. This thick "best seller" gets off quite a lot of biting satire, but there is too much long-winded connecting tissue.
!!!Comments:
<<comment>>
<<formTiddler NewBookTemplate>><data>{"author":"Tom Wolfe","booktitle":"The right Stuff","pubinfo":"Bantam Books (1979)","mine":true,"keep":true,"medium":"Paperback [2nd hand]","genre":"Non-fiction - Space","primtopic":"Space race","synopsis":"Choosing and training the first USA Astronauts.","rating":"80"}</data>Brilliant, witty and informative piece of journalism and writing about the selection and training of the first USA astronauts. Wolfe is great fun in the book, and entertains while informing from cover to cover. This book has also been turned into a brilliant movie.
!!!Comments:
<<comment>>
[>img[Bookcovers/meditationsingreen.jpg]]<<formTiddler NewBookTemplate>><data>{"author":"Stephen Wright","booktitle":"Meditations in Green","pubinfo":"Bantam Books (1984)","medium":"Paperback","genre":"Fantasy","primtopic":"War","synopsis":"Vietnam War was a place of madness","rating":"90"}</data>The best book I have read relating to the Vietnam War. It has all the quirkiness of Catch-22, but with additional doses of madness, pathos and weirdness. Extraordinary work!
!!!Comments:
<<comment>>
!Reader comments go here.
----
Background: #eeffcc
Foreground: #000
PrimaryPale: #bbcc99
PrimaryLight: #bbdd88
PrimaryMid: #445533
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #99dd55
SecondaryMid: #cccccc
SecondaryDark: #445533
TertiaryPale: #bbcc99
TertiaryLight: #EEC591
TertiaryMid: #552233
TertiaryDark: #8B7355
<<formTiddler NewBookTemplate>><data>{"pubinfo":"Silkworm Books (1953)","author":"Kukrit Pramoj","booktitle":"Four Reigns","mine":true,"medium":"Paperback","genre":"Epic","primtopic":"Thai life under 4 kings","synopsis":"The long life of a woman during the reigns of Rama5 to Rama8.","rating":"80"}</data>Excellent family epic, based around the life of a Thai woman living in Bangkok through the reigns of 4 Thai kings. The Author was a PM of Thailand, and he wrote this very long work as a serial for one of the local newspapers. Interesting and imaginative storyline, and very informative regarding siciey and culture of Thailand.
!!!Comments:
<<comment>>