<!--{{{-->
<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]];}

#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; 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>>
/%
|''URL:''|http://tiddlywiki.abego-software.de/|
|''Description:''|AbegoExtensions for TiddlyWiki|
|''Author:''|UdoBorkowski|
%/
/***
|''Name:''|AccordionMenuPlugin|
|''Description:''|Turn an unordered list into an accordion style menu|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#AccordionMenuPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.0|
|''Date:''|03/11/2007|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.5|
!!Usage:
* put {{{<<accordion>>}}} on the line after your unordered list

!!Customizing:
* customize the css via the shadow tiddler StyleSheetAccordionMenuPlugin
* or give the list a custom class by passing the classes as parameters to the macro.
** Eg: {{{<<accordion ClassName1 ClassName2>>}}}

!!Examples:
*[[AccordionMenuPluginDemo]]

***/
// /%
//!BEGIN-PLUGIN-CODE
config.macros.accordion={
	dropchar : " \u00BB",
	handler : function(place,macroName,params,wikifier,paramString,tiddler){
		list = findRelated(place.lastChild,"UL","tagName","previousSibling");
		if (!list)
			return;
		addClass(list,"accordion");
		if (params.length){
			addClass(list,paramString);
		}
		this.fixLinks(list.childNodes);		
	},

	fixLinks : function(els){
		for (var i=0; i<els.length; i++){
			if(els[i].tagName.toLowerCase()=="li"){
				var link = findRelated(els[i].firstChild,"A","tagName","nextSibling");
				if(!link){
					var ih = els[i].firstChild.data;
					els[i].removeChild(els[i].firstChild);
					link = createTiddlyElement(null,"a",null,null,ih+this.dropchar,{href:"javascript:;"});
					els[i].insertBefore(link,els[i].firstChild);
				}
				else{
					link.firstChild.data = link.firstChild.data + this.dropchar;
					removeClass(link,"tiddlyLinkNonExisting");
				}
				link.onclick = this.show;
			}
		}
	},
	
	show : function(e){
		var list = this.parentNode.parentNode;
		var els = list.childNodes;
		for (var i=0; i<els.length; i++){
			removeClass(els[i],"accordion-active");
		}
		addClass(this.parentNode,"accordion-active");
	}	
};

config.shadowTiddlers["StyleSheetAccordionMenuPlugin"] = "/*{{{*/\n"+
	 "ul.accordion, ul.accordion li, ul.accordion li ul  {margin:0; padding:0; list-style-type:none;text-align:left;}\n"+
	 "ul.accordion li ul {display:none;}\n"+
	 "ul.accordion li.accordion-active ul {display:block;}\n"+
	 "\n"+
	 "ul.accordion li.accordion-active a {cursor:default;}\n"+
	 "ul.accordion li.accordion-active ul li a{cursor:pointer;}\n"+
	 "\n"+
	 "ul.accordion a {display:block; padding:0.5em;}\n"+
	 "ul.accordion li a.tiddlyLink, ul.accordion li a.tiddlyLinkNonExisting, ul.accordion li a {font-weight:bold;}\n"+
	 "ul.accordion li a {background:#0066aa; color:#FFF; border-bottom:1px solid #fff;}\n"+
	 "ul.accordion li.accordion-active a, ul.accordion li a:hover {background:#00558F;color:#FFF;}\n"+
	 "\n"+
	 "ul.accordion li ul li{display:inline-block;overflow:hidden;}\n"+
	 "ul.accordion li.accordion-active ul li {background:#eff3fa; color:#000; padding:0em;}\n"+
	 "ul.accordion li.accordion-active ul li div {padding:1em 1.5em; background:#eff3fa;}\n"+
	 "ul.accordion li.accordion-active ul a{background:#eff3fa; color:#000; padding:0.5em 0.5em 0.5em 1.0em;border:none;}\n"+
	 "ul.accordion li.accordion-active ul a:hover {background:#e0e8f5; color:#000;}\n" +
	 "/*}}}*/";
 
 store.addNotification("StyleSheetAccordionMenuPlugin",refreshStyles);
 //!END-PLUGIN-CODE
// %/
@@display:none;clear:both;@@

''Creating a navigation menu using the AccordionMenuPlugin is as simple as:''
# writing a two level unordered list using ~TiddlyWiki syntax
# and placing {{{<<accordion>>}}} on the line after it.
Example:
{{{
* Section 1
** [[Link1]]
** [[Link2]]
** [[Link3]]
*Section 2
** [[Link4]]
** [[Link5]]
** [[Link6]]
*Section 3
**[[Link7]]
**[[Link8]]
**[[Link9]]
<<accordion>>
}}}
gives:

* Section 1
** [[Link1]]
** [[Link2]]
** [[Link3]]
*Section 2
** [[Link4]]
** [[Link5]]
** [[Link6]]
*Section 3
**[[Link7]]
**[[Link8]]
**[[Link9]]
<<accordion>>

''The AccordionMenuPlugin was written with navigation menu's in mind but can be put to other uses as well. ''
By wrapping the content in a DIV, you can have multi-line content as well. Example:
{{{
* [[section1]]
**{{myclass{
Praesent posuere sodales tortor. Mauris ut erat non lacus semper porta. Mauris enim. 
Phasellus tempor, metus ut dapibus lobortis, leo magna ornare metus, et pellentesque neque massa eget turpis.
Proin nec tellus. Donec aliquet.
Nullam sed leo bibendum justo rutrum rhoncus.}}}
* section2
**{{myclass{
Donec rhoncus sem eget urna.
Aenean tempor dolor vitae nisi.
Donec leo urna, placerat porttitor, auctor ut, volutpat a, purus,
Etiam eu sapien id nulla malesuada scelerisque.
Maecenas rhoncus, nibh ut aliquam consequat, mi odio luctus sem, eu lobortis dolor neque nec lectus. }}}
* section3
**{{myclass{
Donec rhoncus sem eget urna.
Aenean tempor dolor vitae nisi.
Donec leo urna, placerat porttitor, auctor ut, volutpat a, purus,
Etiam eu sapien id nulla malesuada scelerisque.
Maecenas rhoncus, nibh ut aliquam consequat, mi odio luctus sem, eu lobortis dolor neque nec lectus. }}}
}}}

gives you:

* [[section1]]
**{{myclass{
Praesent posuere sodales tortor. Mauris ut erat non lacus semper porta. Mauris enim. 
Phasellus tempor, metus ut dapibus lobortis, leo magna ornare metus, et pellentesque neque massa eget turpis.
Proin nec tellus. Donec aliquet.
Nullam sed leo bibendum justo rutrum rhoncus.}}}
* section2
**{{myclass{
Donec rhoncus sem eget urna.
Aenean tempor dolor vitae nisi.
Donec leo urna, placerat porttitor, auctor ut, volutpat a, purus,
Etiam eu sapien id nulla malesuada scelerisque.
Maecenas rhoncus, nibh ut aliquam consequat, mi odio luctus sem, eu lobortis dolor neque nec lectus. }}}
* section3
**{{myclass{
Donec rhoncus sem eget urna.
Aenean tempor dolor vitae nisi.
Donec leo urna, placerat porttitor, auctor ut, volutpat a, purus,
Etiam eu sapien id nulla malesuada scelerisque.
Maecenas rhoncus, nibh ut aliquam consequat, mi odio luctus sem, eu lobortis dolor neque nec lectus. }}}
<<accordion>>
/***
|Name|AliasPlugin|
|Source|http://www.TiddlyTools.com/#AliasPlugin|
|Documentation|http://www.TiddlyTools.com/#AliasPluginInfo|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Create text-substitution macros|
Define macros for abbreviations and other "aliases", and then embed them in the rest of your tiddler content to quickly insert common terms, phrases and links without a lot of repetitive typing.
!!!!!Documentation
> see [[AliasPluginInfo]]
!!!!!Revisions
<<<
2008.03.11 [*.*.*] plugin size reduction - documentation moved to [[AliasPluginInfo]]
2007.03.21 [1.1.0] added support for parameter substitution into alias macros, using format() method and%0..%9 markers
| Please see [[AliasPluginInfo]] for previous revision details |
2005.08.12 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.alias= {major: 1, minor: 1, revision: 0, date: new Date(2007,3,21)};
config.macros.alias= { };
config.macros.alias.handler = function(place,macroName,params) {
	var alias=params.shift(); if (!alias) return; alias=alias.replace(/ /g,"_"); // don't allow spaces in alias
	if (config.macros[alias]==undefined) // create new macro (as needed)
		{	 
		config.macros[alias] = { };
		config.macros[alias].handler =
			function (place,macroName,params)
				{ wikify(config.macros[macroName].text.format(params),place,null,null); }
		}
	config.macros[alias].text = params[0]?params.join(' '):alias;	// set alias text
}
//}}}
/***
|Name|AliasPlugin|
|Source|http://www.TiddlyTools.com/#AliasPlugin|
|Documentation|http://www.TiddlyTools.com/#AliasPluginInfo|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for AliasPlugin|
Define macros for abbreviations and other "aliases", and then embed them in the rest of your tiddler content to quickly insert common terms, phrases and links without a lot of repetitive typing.
!!!!!Usage
<<<
First, decide upon a suitable "alias" for the text to be substituted.  This is usually a short keyword or other abbreviated term that is easily input with just a few keystrokes.  You can use any alias you like, but don't include any spaces in the alias name, since it will be used as the name of the 'alias macro' that is created, and macro names cannot contain spaces.

//Note: If you use an alias name that ''does'' contain spaces, they will be automatically replaced with underscores ("_"), so that the resulting alias name will still be a valid macro name//

To create alias definitions, embed {{{<<alias newname "text to display"}}} >> macros in a tiddler.  These macros don't actually produce any visible output, but simply define the alias macros that you want to use in your document, and thus they can be safely added to practically any tiddler without producing a change in that tiddler's appearance.

//Note: In order to ensure that your aliases are defined and available for use throughout your document, you should add your definitions to a tiddler that you are certain will be displayed when your TW is first loaded, such as //[[MainMenu]]// or //[[SiteTitle]]// (or, any tiddler listed in //[[DefaultTiddlers]]//).//

Then, you can use the aliases you have defined like this: {{{<<newname>>}}}.  You can include additional parameters when you invoke the macro: {{{<<newname param param param...>>}}}.  These parameters are inserted into the macro's "text to display" by substituting for %0...%9 markers.  

For example, to define a quick alias for inserting a link to any given subject on www.wikipedia.com, you can write:
{{{
<<alias wikipedia "[[Wikipedia:%0|http://www.wikipedia.com/wiki/%0]]">>
}}}
which allows you to then write:
{{{
<<wikipedia TiddlyWiki>>
}}}
which is processed as if you wrote:
{{{
[[Wikipedia:TiddlyWiki|http://www.wikipedia.com/wiki/TiddlyWiki]]
}}}
and is displayed this way:
><<alias wikipedia "[[Wikipedia:%0|http://www.wikipedia.com/wiki/%0]]">><<wikipedia TiddlyWiki>>

Another interesting example uses the substitution markers to automatically display a reference to a TiddlerSlice value:
{{{
<<alias describe {{"\<\<tiddler [[%0::Description]]\>\>"}}>>
}}}
which allows you to then write:
{{{
<<describe AliasPlugin>>
}}}
which is processed as if you wrote:
{{{
<<tiddler [[AliasPlugin::Description]]>>
}}}
and is displayed this way:
><<alias describe {{"\<\<tiddler [[%0::Description]]\>\>"}}>><<describe AliasPlugin>>
<<<
!!!!!Examples
<<<
<<alias>> {{{<<alias>>}}}
missing alias name: fail safe, do nothing

<<alias alias1>> {{{<<alias alias1>>}}}
missing text params, default to text=name (e.g., "<<alias1>>")

<<alias alias2 simple multi-word text substitution>> {{{<<alias alias2 simple multi-word text substitution>>}}}
<<alias2>>

<<alias "alias3 with spaces" "spaces in aliasname converted to _">> {{{<<alias "alias3 with spaces" "spaces in aliasname converted to _ ">>}}}
<<alias3_with_spaces>>

<<alias alias4 "multi-line 
text
substitution">> {{{<<alias alias4 "multi-line
text
substitution">>}}}
<<alias4>>
<<<
!!!!!Revisions
<<<
2008.03.11 [*.*.*] plugin size reduction - documentation moved to [[AliasPluginInfo]]
2007.03.21 [1.1.0] added support for parameter substitution into alias macros, using format() method and%0..%9 markers
2005.10.09 [1.0.3] combined documentation and code into a single tiddler
2005.08.12 [1.0.0] initial release
<<<
/***
|Name|AnimationEffectsPlugin|
|Source|http://www.TiddlyTools.com/#AnimationEffectsPlugin|
|Documentation|http://www.TiddlyTools.com/#AnimationEffectsPluginInfo|
|Version|3.1.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.2|
|Type|plugin|
|Requires||
|Overrides||
|Description|display content with timer-based animations to manipulate multiple CSS attributes|
|Status|!BETA - EXPERIMENTAL - UNDER DEVELOPMENT - USE WITH CAUTION|
This plugin defines the {{{<<animate>>}}} macro that can be used to peform simple animations of formatted tiddler content by saving/setting/reseting the values of CSS style attributes at specified times.  The macro can also be used to smoothly animate CSS styles that use ''numeric values'', by automatically computing a series of incremental values, ranging from //start// to //stop//, for a specified //duration//, with optional "pause-and-reverse" //cycles// to create repeating animations or continuous loops.
!!!!!Documentation
>see [[AnimationEffectsPluginInfo]] for macro syntax
>see [[AnimationEffectsSample]] for a live animation example...
!!!!!Revisions
<<<
2008.01.08 [*.*.*] plugin size reduction: documentation moved to [[AnimationEffectsPluginInfo]]
2008.01.07 [3.1.1] when animation is disabled, set inner container to original DIV/SPAN
2007.12.16 [3.1.0] added support for "add/remove" classname functionality.  Also, in handling for "set", only stored previous attribute value if not already saved and, on "reset", clear saved value.  This blocks animations from inadvertently overwriting the saved value while simulaneously processing animation sequences that act on the same attribute.
2007.12.08 [3.0.0] Combined ZoomTextPlugin and AnimateTiddler inline script into single plugin
2007.08.03 [2.1.0] converted from ZoomText inline script
2007.07.16 [2.0.0] added TW2.2-compatible Morpher handling for smoother animation on slower systems
2007.02.17 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.AnimationEffects= {major: 3, minor: 1, revision: 1, date: new Date(2008,1,7)};
config.macros.animate = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var id=new Date().getTime()+Math.random().toString(); // globally unique ID (GUID)
		if (params[0] && (params[0].toUpperCase()=="DIV"||params[0].toUpperCase()=="SPAN"))
			var nodetype=params.shift().toUpperCase(); // optional param to force DIV/SPAN
		var src=params.shift(); if (!src) src="="; // content is first parameter (if no params, animate container)
		if (src.substr(0,1)=="=") { // content=DOM element... use "=here" or "=" (without ID) for current container
			var target=place;
			if (src.length>1 && src.substr(1).toUpperCase()!='HERE') target=document.getElementById(src.substr(1));
			if (!target) return; // couldn't locate target element... do nothing.
			var nodetype=nodetype||target.nodeName.toUpperCase();
		} else { // use content from tiddler or "inline" param
			if (src.substr(0,1)=="@") src=store.getTiddlerText(src.substr(1)); // "@TiddlerName"
			var nodetype=nodetype||"span";
			var target=createTiddlyElement(place,nodetype);
			wikify(src,target);
		}
		if (params[0]) switch(params[0].toUpperCase()) {
			case "SAVE":
				var s=params[1]; if (!s) return; // must specify style attribute
				if (s.substr(0,1)=="+") s=s.substr(1); // ignore leading "+" (if any)
				var w=(params[2]!=undefined && config.options.chkAnimate)?parseInt(params[2]):0; // wait time before saving
				if (!target.savedStyle) target.savedStyle={};
				if (target.savedStyle[s]!==undefined) return; // value already saved... do nothing.
				if (!w) { target.savedStyle[s]=target.style[s]; return; } // save style immediately... done.
				target.id=target.id||id; // use existing ID if target has one, otherwise assign GUID
				var fn='var e=document.getElementById("'+target.id+'"); \
					if(e&&e.savedStyle["'+s+'"]==undefined) \
					e.savedStyle["'+s+'"]=e.style["'+s+'"]';
				setTimeout(fn,w); return; // timer is set... done.
			case "SET":
				var s=params[1]; if (!s) return; // must specify style attribute
				if (s.substr(0,1)=="+") s=s.substr(1); // ignore leading "+" (if any)
				var v=params[2]!=undefined?params[2]:""; // value to set
				var w=(params[3]!=undefined && config.options.chkAnimate)?parseInt(params[3]):0; // wait time before setting
				if (!w) { target.style[s]=v; return; } // set style immediately... done.
				target.id=target.id||id; // use existing ID if target has one, otherwise assign GUID
				var fn='var e=document.getElementById("'+target.id+'");if(e)e.style["'+s+'"]="'+v+'"';
				setTimeout(fn,w); return; // timer is set... done.
			case "RESET":
				var s=params[1]; if (!s) return; // must specify style attribute
				if (s.substr(0,1)=="+") s=s.substr(1); // ignore leading "+" (if any)
				var w=(params[2]!=undefined && config.options.chkAnimate)?parseInt(params[2]):0; // wait time before reset
				if (!w && target.savedStyle && (s in target.savedStyle))
					{ target.style[s]=target.savedStyle[s]; target.savedStyle[s]=undefined; return; } // reset style immediately
				target.id=target.id||id; // use existing ID if target has one, otherwise assign GUID
				var fn='var e=document.getElementById("'+target.id+'"); \
					if(e&&e.savedStyle&&("'+s+'" in e.savedStyle)) \
					e.style["'+s+'"]=e.savedStyle["'+s+'"]; e.savedStyle["'+s+'"]=undefined';
				setTimeout(fn,w); return; // timer is set... done.
			case "ADD":
				var add=true; // fall-through for further processing
			case "REMOVE":
				var c=params[1]; if (!c) return; // must specify a classname
				if (c.substr(0,1)=="+") c=c.substr(1); // ignore leading "+" (if any)
				var w=(params[2]!=undefined && config.options.chkAnimate)?parseInt(params[2]):0; // wait time before setting
				if (!w) { (add?addClass:removeClass)(target,c); return; } // add class immediately... done.
				target.id=target.id||id; // use existing ID if target has one, otherwise assign GUID
				var fn='var e=document.getElementById("'+target.id+'");if(e)'+(add?'addClass':'removeClass')+'(e,"'+c+'")';
				setTimeout(fn,w); return; // timer is set... done.
		}

		// remove old containers before RE-animating, unless combining effects (using "+style" param)
		if (params[0] && params[0].substr(0,1)!="+") cleanup(target);
		function cleanup(here) { // recursively finds all animation containers
			if (here.childNodes) for (var n=0; n<here.childNodes.length; n++)
				if (here.childNodes[n].className=="animationContainer") cleanup(here.childNodes[n]);
			if (here.className=="animationContainer") { // move content up a level and remove container
				var e=here.firstChild;
				while (e) { var next=e.nextSibling; here.parentNode.insertBefore(e,here); e=next; }
				removeNode(here);
			}
		}
		// create animation outer "clipping" container and inner "formatting" container
		var outer=createTiddlyElement(null,nodetype,null,"animationContainer");
		outer.style.overflow="hidden";
		var inner=createTiddlyElement(outer,nodetype,id,"animationContainer");
		inner.style.position="relative"; inner.style.lineHeight="100%";
		target.insertBefore(outer,target.firstChild);

		// move content elements into the inner container
		var e=target.firstChild.nextSibling;
		while (e) { var next=e.nextSibling; inner.insertBefore(e,null); e=next; }

		// params and defaults for morph
		inner.OriginalType=target.nodeName.toUpperCase(); // SPAN or DIV
		inner.What=params[0]?params[0]:'left';
		if (inner.What.substr(0,1)=="+") inner.What=inner.What.substr(1); // trim off "+" prefix (if any)
		inner.Format=params[1]!=undefined?params[1]:'%0%';
		inner.Start=params[2]!=undefined?parseInt(params[2]):100;
		inner.Stop=params[3]!=undefined?parseInt(params[3]):0;
		inner.Wait=params[4]!=undefined?parseInt(params[4]):0;
		inner.Duration=params[5]!=undefined?parseInt(params[5]):2000;
		inner.Cycle=params[6]!=undefined?parseInt(params[6]):1
		inner.Pause=params[7]!=undefined?parseInt(params[7]):0;

		if (!config.options.chkAnimate) { // if not animating
			if (inner.Cycle && (inner.Cycle % 2)) inner.Start=inner.Stop; // odd # of cycles: apply ending value
			inner.style.display=inner.OriginalType!="DIV"?"inline":"block"; // restore original display style
			var outer=inner.parentNode; if (outer && outer.parentNode) // remove outer clipping container
				{ outer.parentNode.insertBefore(inner,outer); removeNode(outer); }
		}
		inner.style[inner.What]=inner.Format.format([inner.Start]); // set initial style value
		if (inner.What=="fontSize" && inner.Start<=0)  inner.style.display="none"; // hide text if initial size is 0

		if (config.options.chkAnimate) setTimeout("config.macros.animate.morph('"+inner.id+"')",inner.Wait); // ANIMATE!
	},
//}}}
//{{{
	// animation 'tick' handler (timer callback)
	morph: function(id) {
		var inner=document.getElementById(id); if (!inner) return; 
		var p = [{style: inner.What, start: inner.Start, end: inner.Stop, template: inner.Format}];
		var c = function(inner,p) { // reverse and re-animate until cycle count==0 (use -1 for continuous looping)
			if (inner.Cycle==0 || inner.Cycle==1) {
				 // finished animation... discard outer container but keep inner container to display final style(s)
				inner.style.display=inner.OriginalType!="DIV"?"inline":"block"; // restore original display style
				if (p[0].style=="fontSize" && p[0].end<=0) inner.style.display="none"; // hide text if final size=0
				var outer=inner.parentNode; if (outer && outer.parentNode) // remove outer clipping container
					{ outer.parentNode.insertBefore(inner,outer); removeNode(outer); }
			}
			else { // reverse-and-repeat 
	 			inner.Cycle--; var t=inner.Start; inner.Start=inner.Stop; inner.Stop=t;
				setTimeout("config.macros.animate.morph('"+inner.id+"')",inner.Pause);
			}
		};
		inner.style.display=inner.nodeName.toUpperCase()!="DIV"?"inline":"block"; // show starting content
		anim.startAnimating(new Morpher(inner,inner.Duration,p,c));
	}
};
//}}}
//{{{
// for backward-compatibility with retired [[ZoomTextPlugin]]
config.macros.zoomText = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		// convert old params to new params and invoke new handler
		var Text=params[0]!=undefined?params[0]:"";
		if (Text.substr(0,1)=="@") Text=store.getTiddlerText(Text.substr(1));
		var Wait=params[1]!=undefined?parseInt(params[1]):0;
		var Start=params[2]!=undefined?parseInt(params[2]):1;
		var Stop=params[3]!=undefined?parseInt(params[3]):100;
		var Duration=params[4]!=undefined?parseInt(params[4]):config.animDuration;
		var Cycle=params[5]!=undefined?parseInt(params[5]):0
		var Pause=params[6]!=undefined?parseInt(params[6]):0;
		var newParams=[Text,"fontSize","%0%",Start,Stop,Wait,Duration,Cycle,Pause];
		var newParamString=["[["+Text+"]]","fontSize","%0%",Start,Stop,Wait,Duration,Cycle,Pause].join(" ");
		return config.macros.animate.handler(place,macroName,newParams,wikifier,newParamString,tiddler)
	}
}
//}}}
/***
|Name|AnimationEffectsPlugin|
|Source|http://www.TiddlyTools.com/#AnimationEffectsPlugin|
|Documentation|http://www.TiddlyTools.com/#AnimationEffectsPluginInfo|
|Version|3.1.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.2|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for AnimationEffectsPlugin|
|Status|!BETA - EXPERIMENTAL - UNDER DEVELOPMENT - USE WITH CAUTION|
This plugin defines the {{{<<animate>>}}} macro that can be used to peform simple animations of formatted tiddler content by saving/setting/reseting the values of CSS style attributes at specified times.  The macro can also be used to smoothly animate CSS styles that use ''numeric values'', by automatically computing a series of incremental values, ranging from //start// to //stop//, for a specified //duration//, with optional "pause-and-reverse" //cycles// to create repeating animations or continuous loops.
!!!!!Examples
>Please see [[AnimationEffectsSample]] for a live animation example...
!!!!!Usage
<<<
The macro syntax is:
{{{
<<animate type source style format start stop wait duration cycles pause>>
<<animate type source "set" style value wait>>
<<animate source "save" style wait>>
<<animate source "reset" style wait>>
<<animate source "add" classname wait>>
<<animate source "remove" classname wait>>
}}}
> //note: default values are shown in parentheses for //optional// parameters.  To ensure the correct order and number of parameters in the macro, you should enter these default values as 'placeholders' when using non-default values for other parameters.  Of course, if all the remaining values that follow a non-default parameter are default values, they do not need to be specified, and can be safely omitted.//
where:
* ''//type// (="span")''<br>is either ''div'' or ''span'', and forces the animation container to be a "DIV" or "SPAN" element (i.e., displayed on a separate line, or inline with other content), which can affect how the specified CSS style will be applied.  When this param is omitted (which is the general use case), the animation container defaults to the same type as the original content.  When using a parameter with "inline" content (see below), a span element is created by default.
* ''//source//''<br>specifies the source content to be animated, and can be one of:
**''"text to display"''<br>inline wiki-syntax content, entered directly as a //quoted// macro parameter.  The {{{<<animate>>}}} macro automatically creates a container at the current location and renders the content into it before animating.
**''@~TiddlerName''<br>as above, but retrieves and renders wiki-syntax content from another tiddler.
**''=elementID''<br>indicates a specific DOM element, by assigned ID (e.g., "mainMenu", "displayArea", "sidebar", etc.).  The macro will animate this content from it's original location.
**''='' (or ''=here'')<br>indicates the current containing DOM element (i.e, the one in which the {{{<<animate>>}}} macro is embedded.  The animation will affect all content that //precedes the macro// within the current container.
* ''"set"'', ''"save"'', ''"reset"'', ''"add"'', ''"remove"''<br>are keywords to indicate how to process the rest of the macro parameters.  If ''set'' is used, the remaining parameters are interpeted as //style//, //value//, and //wait//, respectively, and the macro assigns the value to the specified style at the indicated time.  The ''save'' and ''reset'' keywords expect only //style// and //wait// parameters following the keyword, where ''save'' retains a copy of the current CSS style value so that you can later use ''reset'' to re-assign the original saved value back to the specified CSS style.   The ''add'' and ''remove'' keywords expect and //classname// and //wait// value, and adds/removes the specified classname from the animated element.  If no keyword (or ''morph'') is specified, the remaining macro parameters are used to calculate and apply multiple incremental CSS values for smooth animation processing (a.k.a., "morphing").
* ''//style// (="left")''<br>indicates the CSS attribute to be animated (e.g., "left", "marginTop", "width", "fontSize", etc.).  Note: if you embed more than one {{{<<animate>>}}} macro in the same container (to simultaneously alter multiple CSS attributes), only the //''last''// animation effect will be applied.  To combine several effects, you must precede the //style// parameter value with a "+" symbol for all uses of {{{<<animate>>}}} //except// for the first occurrence within that container, which must //NOT// have a "+" symbol).
* ''//format// (="%0%")''<br>provides a 'text template' for generating CSS attribute values during animation, by using "%0" as a substitution marker to be automatically replaced by the current animation value, combined with a CSS measurement type (e.g., px, em, %, in, cm).  For example: "%0px" produces pixel-based values (e.g., "27px", "342.873px", etc.), while "%0%" generates percentage-based relative measurements, (e.g., "-100%", "42%", etc.), and "%0em" results in measurements that are relative to the current font size (em).
* ''//start// (=-100) and //stop// (=0)'' or ''//value// (="")''<br>define the initial and ending values for the CSS attribute being animated.  Note that, except when using the alternative ''set'' keyword syntax, these values must be numeric, as they are used to //calculate// the incremental values for each 'tick' of the animation processing.
* ''//wait// (=0)''<br>indicates the number of milliseconds to wait before starting the animation sequence.  All animation macros that are embedded in the same content begin simultaneously.  The //wait// value allows you to use several effects in sequence, by defining the start of each effect so that it does not begin until the previous one has completed.
* ''//duration// (=2000)''<br>indicates the number of milliseconds during which to animate from the //start// value to the //stop// value.
* ''//cycles// (=1)'' and ''//pause// (=1000)''<br>indicates the number of "reverse-and-repeat" cycles to perform and the pause (in milliseconds) in between each part of the cycle.  When cycles=1 (or zero, or is omitted entirely), animation progresses from //start// to //stop// just once.  However, if cycles>1, then the animation can pause for a specified amount of time before swapping the //start// and //stop// values and continuing ''//in reverse//''.  A value of cycles=2 performs the animation twice, completing a single loop from //start// to //stop// and then back to //start// again, while cycles=3 does 1.5 loops (ending with the //stop// value), and cycles=4 does 2 complete loops (ending with the //start// value), etc.  To loop forever, specify a cycle value of "-1".

In addition to the {{{<<animate>>}}} macro, the plugin also defines the following macro for backward-compatibility with the now retired [[ZoomTextPlugin]]:
{{{
<<zoomText "text to display" wait start stop duration cycles pause>>
<<zoomText @TiddlerName wait start stop duration cycles pause>>
}}}
This permits rendering of existing tiddlers that already contain the {{{<<zoomText>>}}} macro without needing to update those tiddlers.  However, use of this older syntax is deprecated in favor of the more robust and flexible {{{<<animate>>}}} syntax described above.  
<<<
/%
|Name|AnimationEffectsSample|
|Source|http://www.TiddlyTools.com/#AnimationEffectsSample|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|AnimationEffectsPlugin, InlineJavascriptPlugin, EditTiddlerPlugin, TextAreaPlugin, StyleSheetShortcuts, HideTiddlerTags, HideTiddlerBackground, HideTiddlerSubtitle, CloseOtherTiddlers, RefreshTiddler, ReplaceTiddlerTitle|
|Overrides||
|Description|demonstrates techniques for animating wiki-formatted content|

SET SPEED MULTIPLIER (global variable) [0:00]
%/<<tiddler {{ 
	window.sec=config.options.txtAnimationEffectsRate||1000; // global abbreviation/default multiplier
	config.options.txtAnimationEffectsRate=window.sec; // user option value initialization
	""; // return blank tiddlername so macro doesn't produce output
}}>>/%

HIDE TIDDLER ELEMENTS [0:00]
%/<<tiddler HideTiddlerTags>>/%
%/<<tiddler HideTiddlerBackground>>/%
%/<<tiddler HideTiddlerSubtitle>>/%

CLOSE OTHER TIDDLERS [0:00]
%/<<tiddler CloseOtherTiddlers>>/%

HIDE PAGE ELEMENTS BEFORE ANIMATION [0:00]
%/<<animate =mainMenu     save  display       {{0*sec}}>>/%
%/<<animate =mainMenu     set   display none  {{0*sec}}>>/%
%/<<animate =sidebar      save  display       {{0*sec}}>>/%
%/<<animate =sidebar      set   display none  {{0*sec}}>>/%
%/<<animate =storyMenu    save  display       {{0*sec}}>>/%
%/<<animate =storyMenu    set   display none  {{0*sec}}>>/%
%/<<animate =siteTitle    save  display       {{0*sec}}>>/%
%/<<animate =siteTitle    set   display none  {{0*sec}}>>/%
%/<<animate =siteSubtitle save  display       {{0*sec}}>>/%
%/<<animate =siteSubtitle set   display none  {{0*sec}}>>/%
%/<<animate =displayArea  save  marginLeft    {{0*sec}}>>/%
%/<<animate =displayArea  set   marginLeft 0  {{0*sec}}>>/%
%/<<animate =displayArea  save  marginRight   {{0*sec}}>>/%
%/<<animate =displayArea  set   marginRight 0 {{0*sec}}>>/%
%/<<animate =siteMenu     save  visibility        {{0*sec}}>>/%
%/<<animate =siteMenu     set   visibility hidden {{0*sec}}>>/%
%/<<animate =breadCrumbs  save  visibility        {{0*sec}}>>/%
%/<<animate =breadCrumbs  set   visibility hidden {{0*sec}}>>/%

CONTAINER FOR SHOWING TIDDLER VIEWER BACKGROUND AT END OF ANIMATION
%/{{block{/%

LEFT/RIGHT SLIDING TEXT EFFECT [0:00 - 0:10]
%/@@position:absolute;width:100%;{{nowrap italic{/%
	%/<<animate div "{{red{Are you}}}"
		left %0% 0 50 {{0*sec}} {{1.5*sec}} 7>>/%
	%/<<animate div "{{blue{getting dizzy?}}}"
		left %0% 50 0 {{0*sec}} {{1.5*sec}} 7>>/%
	%/<<animate = fontSize    %0% 0 400 {{0*sec}} {{2.5*sec}} 4>>/%
	%/<<animate = +marginTop  %0% 0 10  {{0*sec}} {{1*sec}}   6>>/%
%/}}}@@/%

UP/DOWN SPINNING TEXT EFFECT [0:00 - 0:09]
%/{{big italic{
	<<animate "{{floatleft right green{Are<br>you}}}"
		fontSize %0% 0 300 {{0*sec}}   {{1.5*sec}} 6>>/%
	%/<<animate div "getting<br>dizzy?"
		fontSize %0% 0 300 {{1.5*sec}} {{1.5*sec}} 6>>/%
	%/<<animate = left       %0% 20 35 {{0*sec}} {{1*sec}} 6>>/%
	%/<<animate = +marginTop %0% 0  15 {{0*sec}} {{1*sec}} 6>>/%
	%/<<animate = +right     %0% 0  30 {{5*sec}} {{1*sec}} 6>>/%
%/}}}/%

ALMOST DONE MESSAGE [0:08 - 0:16.5]
%/{{big floatleft green{/%
	%/''//almost done...//''/%
	%/<<animate = set display none {{0*sec}}>>/%
	%/<<animate = set display inline {{8*sec}}>>/%
	%/<<animate = letterSpacing %0px  25 0 {{8*sec}}  {{8*sec}}>>/%
	%/<<animate = +fontSize     %0%  100 0 {{16*sec}} {{.5*sec}}>>/%
%/}}}/%

SIDE-TO-SIDE "SWING" EFFECT (ALL TIDDLER CONTENT) [0:00 - 0:11.2]
%/<<animate = left %0% 45 0 {{0*sec}} {{1.6*sec}} 7>>/%

FINAL COUNTDOWN [0:11.5 - 0:16.5]
%/{{floatleft bold italic{/%
	%/<<animate "5" fontSize %0% 0 400 {{11.5*sec}} {{.5*sec}} 2>>/%
	%/<<animate "4" fontSize %0% 0 350 {{12.5*sec}} {{.5*sec}} 2>>/%
	%/<<animate "3" fontSize %0% 0 300 {{13.5*sec}} {{.5*sec}} 2>>/%
	%/<<animate "2" fontSize %0% 0 250 {{14.5*sec}} {{.5*sec}} 2>>/%
	%/<<animate "1" fontSize %0% 0 200 {{15.5*sec}} {{.5*sec}} 2>>/%
%/}}}/%

RESTORE PAGE ELEMENTS AFTER PRIMARY ANIMATION [0:17]
%/<<animate =mainMenu     reset display     {{17*sec}}>>/%
%/<<animate =sidebar      reset display     {{17*sec}}>>/%
%/<<animate =storyMenu    reset display     {{17*sec}}>>/%
%/<<animate =siteTitle    reset display     {{17*sec}}>>/%
%/<<animate =siteSubtitle reset display     {{17*sec}}>>/%
%/<<animate =displayArea  reset marginLeft  {{17*sec}}>>/%
%/<<animate =displayArea  reset marginRight {{17*sec}}>>/%
%/<<animate =siteMenu     reset visibility  {{17*sec}}>>/%
%/<<animate =breadCrumbs  reset visibility  {{17*sec}}>>/%

SHOW CONTROL PANEL AND SOURCE DISPLAY [0:17 - 0:18.5] (END)
%/{{small{/%
	%/<<animate = set display none {{0*sec}}>>/%
	%/<<animate = set display inline {{17*sec}}>>/%
	%/{{selected{{{toolbar{/%
		%/{{fine{enable animation:}}}<<option chkAnimate>> /%
		%/{{fine{speed: }}}{{threechar smallform{<<option txtAnimationEffectsRate>>}}}/%
		%/{{medium{<<tiddler RefreshTiddler with: "replay">>}}}/%
		%/<<animate = top %0px 200 0 {{17*sec}} {{1.5*sec}}>>/%
	%/}}}}}}/%
	%/{{block{/%
		%/{{green{''animation sequence completed''}}}
		//(see //[[AnimationEffectsPlugin]]// for macro definition/usage)// /%
		%/<<animate = left %0% 100 0 {{17*sec}} {{1.5*sec}}>>/%
	%/}}}/%
	%/{{smallform stretch center clear{/%
		%/<<edit text 30>>/%
		%/@@display:none;<<resizeEditor>>@@/%
		%/<<animate = left %0% -100 0 {{17*sec}} {{1.5*sec}}>>/%
	%/}}}/%
%/}}}/%

SHOW TIDDLER TITLE [0:17 - 0:18.5] (END)
%/<<tiddler ReplaceTiddlerTitle with:
   "~AnimationEffectsSample\<\<animate div = left %0% -100 0 {{17*sec}} {{1.5*sec}}\>\>">>/%

SHOW VIEWER BACKGROUND [0:18]
%/<<animate = add viewer {{17.5*sec}}>>/%

%/}}}/% END OF CONTAINER FOR VIEWER BACKGROUND %/
/***
|''Name:''|AnnotationsPlugin|
|''Description:''|Inline annotations for tiddler text.|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#AnnotationsPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.0|
|''Date:''||
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.3|

!!Usage:
*{{{((text to annotate(annotation goes here)}}}
* To include the text being annotated, in the popup as a title, put {{{^}}} as the first letter of the annotation text.
** {{{((text to annotate(^annotation goes here)}}}

!!Examples:
Mouse over, the text below:
* ((banana(the best fruit in the world)))
* ((banana(^ the best fruit in the world)))

***/
// /%
config.formatters.unshift({name:"annotations",match:"\\(\\(",lookaheadRegExp:/\(\((.*?)\((\^?)((?:.|\n)*?)\)\)\)/g,handler:function(w){
this.lookaheadRegExp.lastIndex=w.matchStart;
var _2=this.lookaheadRegExp.exec(w.source);
if(_2&&_2.index==w.matchStart){
var _3=createTiddlyElement(w.output,"span",null,"annosub",_2[1]);
_3.anno=_2[3];
if(_2[2]){
_3.subject=_2[1];
}
_3.onmouseover=this.onmouseover;
_3.onmouseout=this.onmouseout;
_3.ondblclick=this.onmouseout;
w.nextMatch=_2.index+_2[0].length;
}
},onmouseover:function(e){
popup=createTiddlyElement(document.body,"div",null,"anno");
this.popup=popup;
if(this.subject){
wikify("!"+this.subject+"\n",popup);
}
wikify(this.anno,popup);
addClass(this,"annosubover");
Popup.place(this,popup,{x:25,y:7});
},onmouseout:function(e){
removeNode(this.popup);
this.popup=null;
removeClass(this,"annosubover");
}});
setStylesheet(".anno{position:absolute;border:2px solid #000;background-color:#DFDFFF; color:#000;padding:0.5em;max-width:15em;width:expression(document.body.clientWidth > (255/12) *parseInt(document.body.currentStyle.fontSize)?'15em':'auto' );}\n"+".anno h1, .anno h2{margin-top:0;color:#000;}\n"+".annosub{background:#ccc;}\n"+".annosubover{z-index:25; background-color:#DFDFFF;cursor:help;}\n","AnnotationStyles");


// %/
text/plain
.txt .text .js .vbs .asp .cgi .pl
----
text/html
.htm .html .hta .htx .mht
----
text/comma-separated-values
.csv
----
text/javascript
.js
----
text/css
.css
----
text/xml
.xml .xsl .xslt
----
image/gif
.gif
----
image/jpeg
.jpg .jpe .jpeg
----
image/png
.png
----
image/bmp
.bmp
----
image/tiff
.tif .tiff
----
audio/basic
.au .snd
----
audio/wav
.wav
----
audio/x-pn-realaudio
.ra .rm .ram
----
audio/x-midi
.mid .midi
----
audio/mp3
.mp3
----
audio/m3u
.m3u
----
video/x-ms-asf
.asf
----
video/avi
.avi
----
video/mpeg
.mpg .mpeg
----
video/quicktime
.qt .mov .qtvr
----
application/pdf
.pdf
----
application/rtf
.rtf
----
application/postscript
.ai .eps .ps
----
application/wordperfect
.wpd
----
application/mswrite
.wri
----
application/msexcel
.xls .xls3 .xls4 .xls5 .xlw
----
application/msword
.doc
----
application/mspowerpoint
.ppt .pps
----
application/x-director
.swa
----
application/x-shockwave-flash
.swf
----
application/x-zip-compressed
.zip
----
application/x-gzip
.gz
----
application/x-rar-compressed
.rar
----
application/octet-stream
.com .exe .dll .ocx
----
application/java-archive
.jar
[[AttachFilePlugin]] reads binary data from locally-stored files (e.g., images, PDFs, mp3's, etc.) and converts it to base64-encoded text that is stored in tiddlers tagged with<<tag attachment>>. [[AttachFilePluginFormatters]] allows you to use those tiddlers in place of the external path/file references that are normally part of the image and external links wiki syntax.

[[FileDropPlugin]] and [[FileDropPluginConfig]] allow you to quickly create attachment tiddlers simply by dragging files directly from your system's desktop folder display and dropping it onto an open TiddlyWiki document.  Text files are automatically created as simple tiddlers, while binary files are automatically encoded and attached.
/***
|Name|AttachFilePlugin|
|Source|http://www.TiddlyTools.com/#AttachFilePlugin|
|Documentation|http://www.TiddlyTools.com/#AttachFilePluginInfo|
|Version|3.8.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|AttachFilePluginFormatters, AttachFileMIMETypes|
|Overrides||
|Description|Store binary files as base64-encoded tiddlers with fallback links for separate local and/or remote file storage|
Store or link binary files (such as jpg, gif, pdf or even mp3) within your TiddlyWiki document and then use them as images or links from within your tiddler content.
> Important note: As of version 3.6.0, in order to //render// images and other binary attachments created with this plugin, you must also install [[AttachFilePluginFormatters]], which extends the behavior of the TiddlyWiki core formatters for embedded images ({{{[img[tooltip|image]]}}}), linked embedded images ({{{[img[tooltip|image][link]]}}}), and external/"pretty" links ({{{[[label|link]]}}}), so that these formatter will process references to attachment tiddlers as if a normal file reference had been provided. |
!!!!!Documentation
>see [[AttachFilePluginInfo]]
!!!!!Inline interface (live)
>see [[AttachFile]] (shadow tiddler)
><<tiddler AttachFile>>
!!!!!Revisions
<<<
2008.05.12 [3.8.1] automatically add 'attach' task to backstage (moved from BackstageTweaks)
2008.04.09 [3.8.0] in onChangeSource(), if source matches current document folder, use relative reference for local link.  Also, disable 'embed' when using IE (which //still// doesn't support data: URI)
2008.04.07 [3.7.3] fixed typo in HTML for 'local file link' so that clicking in input field doesn't erase current path/file (if any)
2008.04.07 [3.7.2] auto-create AttachFile shadow tiddler for inline interface
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.12.03 [3.7.1] in createAttachmentTiddler(), added optional "noshow" flag to suppress display of newly created tiddlers.
|please see [[AttachFilePluginInfo]] for additional revision details|
2005.07.20 [1.0.0] Initial Release
<<<
!!!!!Code
***/
// // version
//{{{
version.extensions.attach = {major: 3, minor: 8, revision: 1, date: new Date(2008,5,12)};

// shadow tiddler
config.shadowTiddlers.AttachFile="<<attach inline>>";

// add 'attach' backstage task (insert before built-in 'importTask')
if (config.tasks) { // for TW2.2b or above
	config.tasks.attachTask = {
		text: "attach",
		tooltip: "Attach a binary file as a tiddler",
		content: "<<attach inline>>"
	}
	config.backstageTasks.splice(config.backstageTasks.indexOf("importTask"),0,"attachTask");
}

config.macros.attach = {
// // lingo
//{{{
	label: "attach file",
	tooltip: "Attach a file to this document",
	linkTooltip: "Attachment: ",

	typeList: "AttachFileMIMETypes",

	titlePrompt: " enter tiddler title...",
	MIMEPrompt: "<option value=''>select MIME type...</option><option value='editlist'>[edit list...]</option>",
	localPrompt: " enter local path/filename...",
	URLPrompt: " enter remote URL...",

	tiddlerErr: "Please enter a tiddler title",
	sourceErr: "Please enter a source path/filename",
	storageErr: "Please select a storage method: embedded, local or remote",
	MIMEErr: "Unrecognized file format.  Please select a MIME type",
	localErr: "Please enter a local path/filename",
	URLErr: "Please enter a remote URL",
	fileErr: "Invalid path/file or file not found",

	sourceReport: "| source file:|{{{%0}}}|\n",
	nosourceReport: "| source file:|//none//|\n",
	dateReport: "| attached on:|%0 by %1|\n",
	notesReport: "| description:|%0|\n",
	dataReport: "| embedded:|[[%0|%0]] - {{{type=%1, size=%2 bytes, encoded=%3 bytes}}}|\n",
	nodataReport: "| embedded:|//none//|\n",
	localReport: "| local file:|/%LOCAL_LINK%/[[%0|%1]]|\n",
	nolocalReport: "| local file:|//none//|\n",
	URLReport: "| remote link:|/%REMOTE_LINK%/[[%0|%0]]|\n",
	noURLReport: "| remote link:|//none//|\n",

	imageReport: "image\n<<<\nusage: {{{[img[tooltip|%0]] or [img[tooltip|%0][link]]}}}\n[img[tooltip|%0]]\n<<<\n",
	dataBlock: "\n/% DO NOT EDIT BELOW THIS POINT\n---BEGIN_DATA---\n%0;base64,\n%1\n---END_DATA---\n%/",
//}}}
// // macro definition
//{{{
	handler:
	function(place,macroName,params) {
		if (params && !params[0]) { createTiddlyButton(place,this.label,this.tooltip,this.toggleAttachPanel); return; }
		var id=params.shift();
		this.createAttachPanel(place,id+"_attachPanel",params);
		document.getElementById(id+"_attachPanel").style.position="static";
		document.getElementById(id+"_attachPanel").style.display="block";
	},
//}}}
//{{{
	createAttachPanel:
	function(place,panel_id,params) {
		if (!panel_id || !panel_id.length) var panel_id="_attachPanel";
		// remove existing panel (if any)
		var panel=document.getElementById(panel_id); if (panel) panel.parentNode.removeChild(panel);
		// set styles for this panel
		setStylesheet(this.css,"attachPanel");
		// create new panel
		var title=""; if (params && params[0]) title=params.shift();
		var types=this.MIMEPrompt+this.formatListOptions(store.getTiddlerText(this.typeList)); // get MIME types
		panel=createTiddlyElement(place,"span",panel_id,"attachPanel",null);
		var html=this.html.replace(/%id%/g,panel_id);
		html=html.replace(/%title%/g,title);
		html=html.replace(/%disabled%/g,title.length?"disabled":"");
		html=html.replace(/%IEdisabled%/g,config.browser.isIE?"disabled":"");
		html=html.replace(/%types%/g,types);
		panel.innerHTML=html;
		return panel;
	},
//}}}
//{{{
	toggleAttachPanel:
	function (e) {
		if (!e) var e = window.event;
		var parent=resolveTarget(e).parentNode;
		var panel = document.getElementById("_attachPanel");
		if (panel==undefined || panel.parentNode!=parent)
			panel=config.macros.attach.createAttachPanel(parent,"_attachPanel");
		var isOpen = panel.style.display=="block";
		if(config.options.chkAnimate)
			anim.startAnimating(new Slider(panel,!isOpen,e.shiftKey || e.altKey,"none"));
		else
			panel.style.display = isOpen ? "none" : "block" ;
		e.cancelBubble = true;
		if (e.stopPropagation) e.stopPropagation();
		return(false);
	},
//}}}
//{{{
	formatListOptions:
	function(text) {
		if (!text || !text.trim().length) return "";
		// get MIME list content from text
		var parts=text.split("\n----\n");
		var out="";
		for (var p=0; p<parts.length; p++) {
			var lines=parts[p].split("\n");
			var label=lines.shift(); // 1st line=display text
			var value=lines.shift(); // 2nd line=item value
			out +='<option value="%1">%0</option>'.format([label,value]);
		}
		return out;
	},
//}}}
// // interface definition
//{{{
	css:
	".attachPanel { display: none; position:absolute; z-index:10; width:35em; right:105%; top:0em;\
		background-color: #eee; color:#000; font-size: 8pt; line-height:110%;\
		border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;\
		padding: 0.5em; margin:0em; -moz-border-radius:1em; text-align:left }\
	.attachPanel form { display:inline;border:0;padding:0;margin:0; }\
	.attachPanel select { width:99%;margin:0px;font-size:8pt;line-height:110%;}\
	.attachPanel input  { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%}\
	.attachPanel textarea { width:98%;margin:0px;height:2em;font-size:8pt;line-height:110%}\
	.attachPanel table { width:100%;border:0;margin:0;padding:0;color:inherit; }\
	.attachPanel tbody, .attachPanel tr, .attachPanel td { border:0;margin:0;padding:0;color:#000; }\
	.attachPanel .box { border:1px solid black; padding:.3em; margin:.3em 0px; background:#f8f8f8; -moz-border-radius:5px; }\
	.attachPanel .chk { width:auto;border:0; }\
	.attachPanel .btn { width:auto; }\
	.attachPanel .btn2 { width:49%; }\
	",
//}}}
//{{{
	html:
	'<form>\
		attach from source file <input type="file" name="source" size=56 onChange="config.macros.attach.onChangeSource(this)">\
		<div class="box">\
		<table style="border:0"><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
			embed data <input type=checkbox class=chk name="useData" %IEdisabled% \
				onclick="if (!this.form.MIMEType.value.length)\
					this.form.MIMEType.selectedIndex=this.checked?1:0; ">&nbsp;\
		</td><td style="border:0">\
			<select size=1 name="MIMEType" \
				onchange="this.title=this.value; if (this.value==\'editlist\')\
					{ this.selectedIndex=this.form.useData.checked?1:0; story.displayTiddler(null,config.macros.attach.typeList,2); return; }">\
				<option value=""></option>\
				%types%\
			</select>\
		</td></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
			local link <input type=checkbox class=chk name="useLocal"\
				onclick="this.form.local.value=this.form.local.defaultValue=this.checked?config.macros.attach.localPrompt:\'\';">&nbsp;\
		</td><td style="border:0">\
			<input type=text name="local" size=15 autocomplete=off value=""\
				onchange="this.form.useLocal.checked=this.value.length" \
				onkeyup="this.form.useLocal.checked=this.value.length" \
				onfocus="if (!this.value.length) this.value=config.macros.attach.localPrompt; this.select()">\
		</td></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
			remote link <input type=checkbox class=chk name="useURL"\
				onclick="this.form.URL.value=this.form.URL.defaultValue=this.checked?config.macros.attach.URLPrompt:\'\';\">&nbsp;\
		</td><td style="border:0">\
			<input type=text name="URL" size=15 autocomplete=off value=""\
				onfocus="if (!this.value.length) this.value=config.macros.attach.URLPrompt; this.select()"\
				onchange="this.form.useURL.checked=this.value.length;"\
				onkeyup="this.form.useURL.checked=this.value.length;">\
		</td></tr></table>\
		</div>\
		<table style="border:0"><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
			attach as&nbsp;\
		</td><td style="border:0" colspan=2>\
			<input type=text name="tiddlertitle" size=15 autocomplete=off value="%title%"\
				onkeyup="if (!this.value.length) { this.value=config.macros.attach.titlePrompt; this.select(); }"\
				onfocus="if (!this.value.length) this.value=config.macros.attach.titlePrompt; this.select()" %disabled%>\
		</td></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
			description&nbsp;\
		</td><td style="border:0" colspan=2>\
			<input type=text name="notes" size=15 autocomplete=off>\
		</td></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
			add tags&nbsp;\
		</td><td style="border:0">\
			<input type=text name="tags" size=15 autocomplete=off value="" onfocus="this.select()">\
		</td><td style="width:40%;text-align:right;border:0">\
			<input type=button class=btn2 value="attach"\
				onclick="config.macros.attach.onClickAttach(this)"><!--\
			--><input type=button class=btn2 value="close"\
				onclick="var panel=document.getElementById(\'%id%\'); if (panel) panel.parentNode.removeChild(panel);">\
		</td></tr></table>\
	</form>',
//}}}
// // control processing
//{{{
	onChangeSource:
	function(here) {
		var form=here.form;
		var list=form.MIMEType;
		var theFilename  = form.source.value;
		var theExtension = theFilename.substr(theFilename.lastIndexOf('.')).toLowerCase();
		// if theFilename is in current document folder, remove path prefix and use relative reference
		var h=document.location.href; folder=getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf("/")+1)));
		if (theFilename.substr(0,folder.length)==folder) theFilename='./'+theFilename.substr(folder.length);
		else theFilename='file:///'+theFilename; // otherwise, use absolute reference
		theFilename=theFilename.replace(/\\/g,"/"); // fixup: change \ to /
		form.useLocal.checked = true;
		form.local.value = theFilename;
		form.useData.checked = !form.useData.disabled;
		list.selectedIndex=1;
		for (var i=0; i<list.options.length; i++) // find matching MIME type
			if (list.options[i].value.indexOf(theExtension)!=-1) { list.selectedIndex = i; break; }
		if (!form.tiddlertitle.disabled)
			form.tiddlertitle.value=theFilename.substr(theFilename.lastIndexOf('/')+1); // get tiddlername from filename
	},
//}}}
//{{{
	onClickAttach:
	function (here) {
		clearMessage();
		// get input values
		var form=here.form;
		var theDate=(new Date()).formatString(config.macros.timeline.dateFormat);
		var theSource = form.source.value!=form.source.defaultValue?form.source.value:"";
		var theTitle=form.tiddlertitle.value;
		var theLocal = form.local.value!=form.local.defaultValue?form.local.value:"";
		var theURL = form.URL.value!=form.URL.defaultValue?form.URL.value:"";
		var theNotes = form.notes.value;
		var theTags = "attachment excludeMissing "+form.tags.value;
		var useData=form.useData.checked;
		var useLocal=form.useLocal.checked;
		var useURL=form.useURL.checked;
		var theMIMEType = form.MIMEType.value.length?form.MIMEType.options[form.MIMEType.selectedIndex].text:"";
		// validate checkboxes and get filename
		if (useData) {
			if (theSource.length) { if (!theLocation) var theLocation=theSource; }
			else { alert(this.sourceErr); form.source.focus(); return false; }
		}
		if (useLocal) {
			if (theLocal.length) { if (!theLocation) var theLocation = theLocal; }
			else { alert(this.localErr); form.local.focus(); return false; }
		}
		if (useURL) {
			if (theURL.length) { if (!theLocation) var theLocation = theURL; }
			else { alert(this.URLErr); form.URL.focus(); return false; }
		}
		if (!(useData||useLocal||useURL))
			{ form.useData.focus(); alert(this.storageErr); return false; }
		if (!theLocation)
			{ form.source.focus(); alert(this.sourceErr); return false; }
		if (!theTitle || !theTitle.trim().length || theTitle==this.titlePrompt)
			{ form.tiddlertitle.focus(); alert(this.tiddlerErr); return false; }
		// if not already selected, determine MIME type based on filename extension (if any)
		if (useData && !theMIMEType.length && theLocation.lastIndexOf('.')!=-1) {
			var theExt = theLocation.substr(theLocation.lastIndexOf('.')).toLowerCase();
			var theList=form.MIMEType;
			for (var i=0; i<theList.options.length; i++)
				if (theList.options[i].value.indexOf(theExt)!=-1)
					{ var theMIMEType=theList.options[i].text; theList.selectedIndex=i; break; }
		}
		// attach the file
		return this.createAttachmentTiddler(theSource, theDate, theNotes, theTags, theTitle,
			useData, useLocal, useURL, theLocal, theURL, theMIMEType);
	},
	getMIMEType:
	function(src,def) {
		var ext = src.substr(src.lastIndexOf('.')).toLowerCase();
		var list=store.getTiddlerText(this.typeList);
		if (!list || !list.trim().length) return def;
		// get MIME list content from tiddler
		var parts=list.split("\n----\n");
		for (var p=0; p<parts.length; p++) {
			var lines=parts[p].split("\n");
			var mime=lines.shift(); // 1st line=MIME type
			var match=lines.shift(); // 2nd line=matching extensions
			if (match.indexOf(ext)!=-1) return mime;
		}
		return def;
	},
	createAttachmentTiddler:
	function (theSource, theDate, theNotes, theTags, theTitle,
		useData, useLocal, useURL, theLocal, theURL, theMIMEType, noshow) {
		// encode the data
		if (useData) {
			if (!theMIMEType.length) {
				alert(this.MIMEErr);
				form.MIMEType.selectedIndex=1; form.MIMEType.focus();
				return false;
			}
			var theData = this.readFile(theSource); if (!theData) { return false; }
			displayMessage('encoding '+theSource);
			var theEncoded = this.encodeBase64(theData);
			displayMessage('file size='+theData.length+' bytes, encoded size='+theEncoded.length+' bytes');
		}
		// generate tiddler and refresh
		var theText = "";
		theText +=theSource.length?this.sourceReport.format([theSource]):this.nosourceReport;
		theText +=this.dateReport.format([theDate,config.options.txtUserName]);
		theText +=theNotes.length?this.notesReport.format([theNotes]):"";
		theText +=useData?this.dataReport.format([theTitle,theMIMEType,theData.length,theEncoded.length]):this.nodataReport;
		theText +=useLocal?this.localReport.format([theLocal,theLocal.replace(/\\/g,"/")]):this.nolocalReport;
		theText +=useURL?this.URLReport.format([theURL]):this.noURLReport;
		theText +=(theMIMEType.substr(0,5)=="image")?this.imageReport.format([theTitle]):"";
		theText +=useData?this.dataBlock.format([theMIMEType,theEncoded]):"";
		store.saveTiddler(theTitle,theTitle,theText,config.options.txtUserName,new Date(),theTags);
		var panel=document.getElementById("attachPanel"); if (panel) panel.style.display="none";
		if (!noshow) { story.displayTiddler(null,theTitle); story.refreshTiddler(theTitle,null,true); }
		displayMessage('attached "'+theTitle+'"');
		return true;
	},
//}}}
// // base64 conversion
//{{{
	encodeBase64:
	function (theData) {
		if (!theData) return null;
		// encode as base64
		var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
		var out = "";				//This is the output
		var chr1, chr2, chr3 = "";		//These are the 3 bytes to be encoded
		var enc1, enc2, enc3, enc4 = "";	//These are the 4 encoded bytes
		for (var count=0,i=0; i<theData.length; )
			{
			chr1 = theData.charCodeAt(i++); //Grab the first byte
			chr2 = theData.charCodeAt(i++); //Grab the second byte
			chr3 = theData.charCodeAt(i++); //Grab the third byte
			enc1 = chr1 >> 2;
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
			enc4 = chr3 & 63;
			if (isNaN(chr2))
				enc3 = enc4 = 64;
			else if (isNaN(chr3))
				enc4 = 64;
			out += keyStr.charAt(enc1)+keyStr.charAt(enc2)+keyStr.charAt(enc3)+keyStr.charAt(enc4);
			chr1 = chr2 = chr3 = "";
			enc1 = enc2 = enc3 = enc4 = "";
			count+=4; if (count>60) { out+='\n'; count=0; } // add line break every 60 chars for readability
			}
		return out;
	},
//}}}
// // I/O functions
//{{{
	readFile: // read local BINARY file data
	function(filePath) {
		if(!window.Components) { return null; }
		try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
		catch(e) { alert("access denied: "+filePath); return null; }
		var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
		try { file.initWithPath(filePath); } catch(e) { alert("cannot read file - invalid path: "+filePath); return null; }
		if (!file.exists()) { alert("cannot read file - not found: "+filePath); return null; }
		var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
		inputStream.init(file, 0x01, 00004, null);
		var bInputStream = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);
		bInputStream.setInputStream(inputStream);
		return(bInputStream.readBytes(inputStream.available()));
	},
//}}}
//{{{
	writeFile:
	function(filepath,data) {
		// TBD: decode base64 and write BINARY data to specified local path/filename
		return(false);
	}
};
//}}}
/***
|Name|AttachFilePluginFormatters|
|Source|http://www.TiddlyTools.com/#AttachFilePluginFormatters|
|Version|3.7.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|'image' and 'prettyLink' formatters, TiddlyWiki.prototype.getRecursiveTiddlerText|
|Description|run-time library for displaying attachment tiddlers|

This plugin provides "stand-alone" processing for //rendering// attachment tiddlers created by [[AttachFilePlugin]].   Attachment tiddlers are tagged with<<tag attachment>>and contain binary file content (e.g., jpg, gif, pdf, mp3, etc.) that has been stored directly as base64 text-encoded data or can be loaded from external files stored on a local filesystem or remote web server.

NOTE: This plugin does not include the "control panel" and supporting functions needed to //create// new attachment tiddlers.  Those features are provided by [[AttachFilePlugin]], which can be installed while building your document, and then safely omitted to reduce the overall file size when you publish your finished document (assuming you don't intend to create any additional attachment tiddlers in that document)
!!!!!Formatters
<<<
This plugin extends the behavior of the following TiddlyWiki core "wikify()" formatters:
* embedded images: {{{[img[tooltip|image]]}}}
* linked embedded images: {{{[img[tooltip|image][link]]}}}
* external/"pretty" links: {{{[[label|link]]}}}

''Please refer to AttachFilePlugin (source: http://www.TiddlyTools.com/#AttachFilePlugin) for additional information.''
<<<
!!!!!Revisions
<<<
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.29 [3.7.0] more code reduction: removed upload handling from AttachFilePlugin (saves ~7K!)
2007.10.28 [3.6.0] removed duplicate formatter code from AttachFilePlugin (saves ~10K!) and updated documentation accordingly.  This plugin ([[AttachFilePluginFormatters]]) is now //''required''// in order to display attached images/binary files within tiddler content.
2006.05.20 [3.4.0] through 2007.03.01 [3.5.3] sync with AttachFilePlugin
2006.05.13 [3.2.0] created from AttachFilePlugin v3.2.0
<<<
!!!!!Code
***/
// // version
//{{{
version.extensions.attach = {major: 3, minor: 7, revision: 0, date: new Date(2007,10,28)};
//}}}

//{{{
if (config.macros.attach==undefined) config.macros.attach= { };
//}}}
//{{{
if (config.macros.attach.isAttachment==undefined) config.macros.attach.isAttachment=function (title) {
	var tiddler = store.getTiddler(title);
	if (tiddler==undefined || tiddler.tags==undefined) return false;
	return (tiddler.tags.indexOf("attachment")!=-1);
}
//}}}

//{{{
// test for local file existence
// Returns true/false without visible error display
// Uses Components for FF and ActiveX FSO object for MSIE
if (config.macros.attach.fileExists==undefined) config.macros.attach.fileExists=function(theFile) {
	var found=false;
	// DEBUG: alert('testing fileExists('+theFile+')...');
	if(window.Components) {
		try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
		catch(e) { return false; } // security access denied
		var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
		try { file.initWithPath(theFile); }
		catch(e) { return false; } // invalid directory
		found = file.exists();
	}
	else { // use ActiveX FSO object for MSIE 
		var fso = new ActiveXObject("Scripting.FileSystemObject");
		found = fso.FileExists(theFile)
	}
	// DEBUG: alert(theFile+" "+(found?"exists":"not found"));
	return found;
}
//}}}

//{{{
if (config.macros.attach.getAttachment==undefined) config.macros.attach.getAttachment=function(title) {

	// extract embedded data, local and remote links (if any)
	var startmarker="---BEGIN_DATA---\n";
	var endmarker="\n---END_DATA---";
	var pos=0; var endpos=0;
	var text = store.getTiddlerText(title);
	var embedded="";
	var locallink="";
	var remotelink="";

	// look for embedded data, convert to data: URI
	if ((pos=text.indexOf(startmarker))!=-1 && (endpos=text.indexOf(endmarker))!=-1)
		embedded="data:"+(text.substring(pos+startmarker.length,endpos)).replace(/\n/g,'');
	if (embedded.length && !config.browser.isIE)
		return embedded; // use embedded data if any... except for IE, which doesn't support data URI

	// no embedded data... fallback to local/remote reference links...

	// look for 'attachment link markers'
	if ((pos=text.indexOf("/%LOCAL_LINK%/"))!=-1)
		locallink=text.substring(text.indexOf("|",pos)+1,text.indexOf("]]",pos));
	if ((pos=text.indexOf("/%REMOTE_LINK%/"))!=-1)
		remotelink=text.substring(text.indexOf("|",pos)+1,text.indexOf("]]",pos));

	// document is being served remotely... use remote URL (if any)  (avoids security alert)
	if (remotelink.length && document.location.protocol!="file:")
		return remotelink;  

	// local link only... return link without checking file existence (avoids security alert)
	if (locallink.length && !remotelink.length) 
		return locallink; 

	// local link, check for file exist... use local link if found
	if (locallink.length) { 
		if (this.fileExists(getLocalPath(locallink))) return locallink;
		// maybe local link is relative... add path from current document and try again
		var pathPrefix=document.location.href;  // get current document path and trim off filename
		var slashpos=pathPrefix.lastIndexOf("/"); if (slashpos==-1) slashpos=pathPrefix.lastIndexOf("\\"); 
		if (slashpos!=-1 && slashpos!=pathPrefix.length-1) pathPrefix=pathPrefix.substr(0,slashpos+1);
		if (this.fileExists(getLocalPath(pathPrefix+locallink))) return locallink;
	}

	// no embedded data, no local (or not found), fallback to remote URL (if any)
	if (remotelink.length) 
		return remotelink;

	return ""; // attachment URL doesn't resolve
}
//}}}
//{{{
if (config.macros.attach.init_formatters==undefined) config.macros.attach.init_formatters=function() {
	if (this.initialized) return;
	// find the formatter for "image" and replace the handler
	for (var i=0; i<config.formatters.length && config.formatters[i].name!="image"; i++);
	if (i<config.formatters.length)	config.formatters[i].handler=function(w) {
		if (!this.lookaheadRegExp)  // fixup for TW2.0.x
			this.lookaheadRegExp = new RegExp(this.lookahead,"mg");
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) // Simple bracketted link
			{
			var e = w.output;
			if(lookaheadMatch[5])
				{
				var link = lookaheadMatch[5];
				// ELS -------------
				if (!config.formatterHelpers.isExternalLink) // fixup for TW2.0.x
					var external=!store.tiddlerExists(link)&&!store.isShadowTiddler(link);
				else
					var external=config.formatterHelpers.isExternalLink(link);
				if (external)
					{
					if (config.macros.attach.isAttachment(link))
						{
						e = createExternalLink(w.output,link);
						e.href=config.macros.attach.getAttachment(link);
						e.title = config.macros.attach.linkTooltip + link;
						}
					else
						e = createExternalLink(w.output,link);
					}
				else 
					e = createTiddlyLink(w.output,link,false,null,w.isStatic);
				// ELS -------------
				addClass(e,"imageLink");
				}
			var img = createTiddlyElement(e,"img");
			if(lookaheadMatch[1])
				img.align = "left";
			else if(lookaheadMatch[2])
				img.align = "right";
			if(lookaheadMatch[3])
				img.title = lookaheadMatch[3];
			img.src = lookaheadMatch[4];
			// ELS -------------
			if (config.macros.attach.isAttachment(lookaheadMatch[4]))
				img.src=config.macros.attach.getAttachment(lookaheadMatch[4]);
			// ELS -------------
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
//}}}
//{{{
	// find the formatter for "prettyLink" and replace the handler
	for (var i=0; i<config.formatters.length && config.formatters[i].name!="prettyLink"; i++);
	if (i<config.formatters.length)	{
		var v=version.major+.1*version.minor+.01*version.revision;
		if (v>=2.13) {
		config.formatters[i].handler=function(w) 
			{
			this.lookaheadRegExp.lastIndex = w.matchStart;
			var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
			if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
				{
				var e;
				var text = lookaheadMatch[1];
				if(lookaheadMatch[3])
					{
					// Pretty bracketted link
					var link = lookaheadMatch[3];
					if (config.macros.attach.isAttachment(link))
						{
						e = createExternalLink(w.output,link);
						e.href=config.macros.attach.getAttachment(link);
						e.title=config.macros.attach.linkTooltip+link;
						}
					else e = (!lookaheadMatch[2] && config.formatterHelpers.isExternalLink(link))
						? createExternalLink(w.output,link)
						: createTiddlyLink(w.output,link,false,null,w.isStatic);
					}
				else
					{
					e = createTiddlyLink(w.output,text,false,null,w.isStatic);
					}
				createTiddlyText(e,text);
				w.nextMatch = this.lookaheadRegExp.lastIndex;
				}
			}
		} else { // FALLBACK for TW2.1.2 and earlier
		config.formatters[i].handler=function(w)
			{
			if (!this.lookaheadRegExp)  // fixup for TW2.0.x
				this.lookaheadRegExp = new RegExp(this.lookahead,"mg");
			this.lookaheadRegExp.lastIndex = w.matchStart;
			var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
			if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
				{
				var e;
				var text = lookaheadMatch[1];
				if (lookaheadMatch[2]) // Simple bracketted link
					{
					e = createTiddlyLink(w.output,text,false,null,w.isStatic);
					}
				else if(lookaheadMatch[3]) // Pretty bracketted link
					{
					var link = lookaheadMatch[4];
					// ELS -------------
					if (!config.formatterHelpers.isExternalLink) // fixup for TW2.0.x
						var external=!store.tiddlerExists(link)&&!store.isShadowTiddler(link);
					else
						var external=config.formatterHelpers.isExternalLink(link);
					if (external)
						{
						if (config.macros.attach.isAttachment(link))
							{
							e = createExternalLink(w.output,link);
							e.href=config.macros.attach.getAttachment(link);
							e.title = config.macros.attach.linkTooltip + link;
							}
						else
							e = createExternalLink(w.output,link);
						}
					else 
						e = createTiddlyLink(w.output,link,false,null,w.isStatic);
					// ELS -------------
					}
				createTiddlyText(e,text);
				w.nextMatch = this.lookaheadRegExp.lastIndex;
				}
			}
		} // END FALLBACK
	} // if "prettyLink" formatter found
	this.initialized=true;
}
//}}}
//{{{
config.macros.attach.init_formatters(); // load time init
//}}}
//{{{
if (TiddlyWiki.prototype.coreGetRecursiveTiddlerText==undefined) {
	TiddlyWiki.prototype.coreGetRecursiveTiddlerText = TiddlyWiki.prototype.getRecursiveTiddlerText;
	TiddlyWiki.prototype.getRecursiveTiddlerText = function(title,defaultText,depth) {
		return config.macros.attach.isAttachment(title)?
			config.macros.attach.getAttachment(title):this.coreGetRecursiveTiddlerText.apply(this,arguments);
	}
}
//}}}
/***
|Name|AttachFilePluginInfo|
|Source|http://www.TiddlyTools.com/#AttachFilePlugin|
|Documentation|http://www.TiddlyTools.com/#AttachFilePluginInfo|
|Version|3.8.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Documentation for AttachFilePlugin|
Store or link binary files (such as jpg, gif, pdf or even mp3) within your TiddlyWiki document and then use them as images or links from within your tiddler content.
!!!!!Inline interface (live)
>see [[AttachFile]] (shadow tiddler)
><<tiddler AttachFile>>
!!!!!Syntax
<<<
''To display the attach file control panel, simply view the [[AttachFile]] shadow tiddler that is automatically created by the plugin, and contains an instance of the inline control panel.''.  Or, you can write:
{{{
<<attach inline>>
}}}
in any tiddler to display the control panel embedded within that tiddler.  Note: you can actually use any unique identifier in place of the "inline" keyword.  Each unique id creates a separate instance of the controls.  If the same ID is used in more than one tiddler, then the control panel is automatically moved to the most recently rendered location.  Or, you can write:
{{{
<<attach>>
}}}
(with no ID parameter) in SidebarOptions.  This adds a command link that opens the controls as a floating panel, positioned directly to the left of the sidebar.
<<<
!!!!!Usage
<<<
Binary file content can be stored in three different locations:
#embedded in the attachment tiddler (encoded as base64)
#on your filesystem (a 'local link' path/filename)
#on a web server (a 'remote link' URL)
The plugin creates an "attachment tiddler" for each file you attach.  Regardless of where you store the binary content, your document can refer to the attachment tiddler rather than using a direct file or URL reference in your embedded image or external links, so that changing document locations will not require updating numerous tiddlers or copying files from one system to another.
> Important note: As of version 3.6.0, in order to //render// images and other binary attachments created with this plugin, you must also install [[AttachFilePluginFormatters]], which extends the behavior of the TiddlyWiki core formatters for embedded images ({{{[img[tooltip|image]]}}}), linked embedded images ({{{[img[tooltip|image][link]]}}}), and external/"pretty" links ({{{[[label|link]]}}}), so that these formatter will process references to attachment tiddlers as if a normal file reference had been provided. |
When you attach a file, a tiddler (tagged with<<tag attachment>>) is generated (using the source filename as the tiddler's title).  The tiddler contains //''base64 text-encoded binary data''//, surrounded by {{{/%...%/}}} comment markers (so they are not visible when viewing the tiddler).  The tiddler also includes summary details about the file: when it was attached, by whom, etc. and, if the attachment is an image file (jpg, gif, or png), the image is automatically displayed below the summary information.
>Note: although you can edit an attachment tiddler, ''don't change any of the encoded content below the attachment header'', as it has been prepared for use in the rest of your document, and even changing a single character can make the attachment unusable.  //If needed, you ''can'' edit the header information or even the MIME type declaration in the attachment data, but be very careful not to change any of the base64-encoded binary data.//
With embedded data, your TW document can be completely self-contained...unfortunately, embedding just a few moderately-sized binary files using base64 text-encoding can dramatically increase the size of your document.   To avoid this problem, you can create attachment tiddlers that define external local filesystem (file://) and/or remote web server (http://) 'reference' links, without embedding the binary data directly in the tiddler (i.e., uncheck "embed data" in the 'control panel').

These links provide an alternative source for the binary data: if embedded data is not found (or you are running on Internet Explorer, which does not currently support using embedded data), then the plugin tries the local filesystem reference.  If a local file is not found, then the remote reference (if any) is used.  This "fallback" approach also lets you 'virtualize' the external links in your document, so that you can access very large binary content such as PDFs, MP3's, and even *video* files, by using just a 'remote reference link' without embedding any data or downloading huge files to your hard disk.

Of course, when you //do// download an attached file, the local copy will be used instead of accessing a remote server each time, thereby saving bandwidth and allowing you to 'go mobile' without having to edit any tiddlers to alter the link locations...
<<<
!!!!!Syntax / Examples
<<<
To embed attached files as images or link to them from other tiddlers, use the standard ~TiddlyWiki image syntax ({{{[img[tooltip|filename]]}}}), linked image syntax ({{{[img[tooltip|filename][tiddlername]]}}}) , or "external link" syntax ({{{[[text|URL]]}}}), replacing the filename or URL that is normally entered with the title of an attachment tiddler.

embedded image data:
>{{{[img[Meow|AttachFileSample]]}}}
>[img[Meow|AttachFileSample]]
embedded image data with link to larger remote image:
>{{{[img[click for larger view|AttachFileSample][AttachFileSample2]]}}}
>[img[click for larger view|AttachFileSample][AttachFileSample2]]
'external' link to embedded image data:
>{{{[[click to view attachment|AttachFileSample]]}}}
>[[click to view attachment|AttachFileSample]]
'external' link to remote image:
>{{{[[click to view attachment|AttachFileSample2]]}}}
>[[click to view attachment|AttachFileSample2]]
regular ~TiddlyWiki links to attachment tiddlers:
>{{{[[AttachFileSample]]}}} [[AttachFileSample]]
>{{{[[AttachFileSample2]]}}} [[AttachFileSample2]]
<<<
!!!!!Defining MIME types
<<<
When you select a source file, a ''[[MIME|http://en.wikipedia.org/wiki/MIME]]'' file type is automatically suggested, based on filename extension.  The AttachFileMIMETypes tiddler defines the list of MIME types that will be recognized by the plugin.  Each MIME type definition consists of exactly two lines of text: the official MIME type designator (e.g., "text/plain", "image/gif", etc.), and a space-separated list of file extensions associated with that type.  List entries are separated by "----" (horizontal rules).
<<<
!!!!!Known Limitations
<<<
Internet Explorer does not support the data: URI scheme, and cannot use the //embedded// data to render images or links.  However, you can still use the local/remote link definitions to create file attachments that are stored externally.  In addition, while it is relatively easy to read local //text// files, reading binary files is not directly supported by IE's FileSystemObject (FSO) methods, and other file I/O techniques are subject to security barriers or require additional MS proprietary technologies (like ASP or VB) that make implementation more difficult.  As a result, you cannot //create// new attachment tiddlers using IE.
<<<
!!!!!Installation
<<<
Import (or copy/paste) the following tiddlers into your document:
* [[AttachFilePlugin]] (tagged with <<tag systemConfig>>)
* [[AttachFilePluginFormatters]] ("runtime distribution library") (tagged with <<tag systemConfig>>)
* [[AttachFileSample]] and [[AttachFileSample2]] //(tagged with <<tag attachment>>)//
* [[AttachFileMIMETypes //(defines binary file types)//
> Important note: As of version 3.6.0, in order to //render// images and other binary attachments created with this plugin, you must also install [[AttachFilePluginFormatters]], which extends the behavior of the TiddlyWiki core formatters for embedded images ({{{[img[tooltip|image]]}}}), linked embedded images ({{{[img[tooltip|image][link]]}}}), and external/"pretty" links ({{{[[label|link]]}}}), so that these formatter will process references to attachment tiddlers as if a normal file reference had been provided. |
<<<
!!!!!Revisions
<<<
2008.04.09 [3.8.0] in onChangeSource(), if source matches current document folder, use relative reference for local link.  Also, disable 'embed' when using IE (which //still// doesn't support data: URI)
2008.04.07 [3.7.3] fixed typo in HTML for 'local file link' so that clicking in input field doesn't erase current path/file (if any)
2008.04.07 [3.7.2] auto-create AttachFile shadow tiddler for inline interface
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.12.03 [3.7.1] in createAttachmentTiddler(), added optional "noshow" flag to suppress display of newly created tiddlers.
2007.10.29 [3.7.0] code reduction: removed support for built-in upload to server... on-line hosting of binary attachments is left to the document author, who can upload/host files using 3rd-party web-based services (e.g. www.flickr.com, ) or stand-alone applications (e.g., FTP).
2007.10.28 [3.6.0] code reduction: removed duplicate definition of image and prettyLink formatters.  Rendering of attachment tiddlers now //requires// installation of AttachFilePluginFormatters
2007.03.01 [3.5.3] use apply() to invoke hijacked function
2007.02.25 [3.5.2] in hijack of "prettyLink", fix version check for TW2.2 compatibility (prevent incorrect use of fallback handler)
2007.01.09 [3.5.1] onClickAttach() refactored to create separate createAttachmentTiddler() API for use with FileDropPluginHandlers
2006.11.30 [3.5.0] in getAttachment(), for local references, add check for file existence and fallback to remote URL if local file not found.  Added fileExists() to encapsulate FF vs. IE local file test function (IE FSO object code is TBD).
2006.11.29 [3.4.8] in hijack for PrettyLink, 'simple bracketed link' opens tiddler instead of external link to attachment
2006.11.29 [3.4.7] in readFile(), added try..catch around initWithPath() to handle invalid/non-existent paths better.
2006.11.09 [3.4.6] REAL FIX for TWv2.1.3: incorporate new TW2.1.3 core "prettyLink" formatter regexp handling logic and check for version < 2.1.3 with fallback to old plugin code.  Also, cleanup table layout in HTML (added "border:0" directly to table elements to override stylesheet)
2006.11.08 [3.4.5] TEMPORARY FIX for TWv2.1.3: disable hijack of wikiLink formatter due to changes in core wikiLink regexp definition.  //Links to attachments are broken, but you can still use {{{[img[TiddlerName]]}}} to render attachments as images, as well as {{{background:url('[[TiddlerName]]')}}} in CSS declarations for background images.//
2006.09.10 [3.4.4] update formatters for 2.1 compatibility (use this.lookaheadRegExp instead of temp variable)
2006.07.24 [3.4.3] in prettyLink formatter, added check for isShadowTiddler() to fix problem where shadow links became external links.
2006.07.13 [3.4.2] in getAttachment(), fixed stripping of newlines so data: used in CSS will work
2006.05.21 [3.4.1] in getAttachment(), fixed substring() to extract data: URI (was losing last character, which broken rendering of SOME images)
2006.05.20 [3.4.0] hijack core getRecursiveTiddlerText() to support rendering attachments in stylesheets (e.g. {{{url([[AttachFileSample]])}}})
2006.05.20 [3.3.6] add "description" feature to easily include notes in attachment tiddler (you can always edit to add them later... but...)
2006.05.19 [3.3.5] add "attach as" feature to change default name for attachment tiddlers.  Also, new optional param to specify tiddler name (disables editing)
2006.05.16 [3.3.0] completed XMLHttpRequest handling for GET or POST to configurable server scripts
2006.05.13 [3.2.0] added interface for upload feature.  Major rewrite of code for clean object definitions.  Major improvements in UI interaction and validation.
2006.05.09 [3.1.1] add wikifer support for using attachments in links from "linked image" syntax: {{{[img[tip|attachment1][attachment2]]}}}
2006.05.09 [3.1.0] lots of code changes: new options for attachments that use embedded data and/or links to external files (local or remote)
2006.05.03 [3.0.2] added {{{/%...%/}}} comments around attachment data to hide it when viewing attachment tiddler.
2006.02.05 [3.0.1] wrapped wikifier hijacks in initAttachmentFormatters() function to eliminate globals and avoid FireFox 1.5.0.1 crash bug when referencing globals
2005.12.27 [3.0.0] Update for TW2.0.  Automatically add 'excludeMissing' tag to attachments
2005.12.16 [2.2.0] Dynamically create/remove attachPanel as needed to ensure only one instance of interface elements exists, even if there are multiple instances of macro embedding.
2005.11.20 [2.1.0] added wikifier handler extensions for "image" and "prettyLink" to render tiddler attachments
2005.11.09 [2.0.0] begin port from old ELS Design plugin/adaptation hybrid based on ~TW1.2.33
2005.08.05 [1.1.0] moved CSS and HTML definitions into plugin code tiddler instead of using separate tiddlers
2005.07.27 [1.0.2] core update 1.2.29: custom overlayStyleSheet() replaced with new core setStylesheet()
2005.07.23 [1.0.1] added parameter checks and corrected addNotification() usage
2005.07.20 [1.0.0] Initial Release
<<<
| source file|{{{...\images\meow.gif}}}|
| attached on|15 May 2006 by ELSDesignStudios|
| embedded data|[[meow.gif|AttachFileSample]] - {{{type=image/gif, size=3399 bytes, encoded=4602 bytes}}}|
| ~LocalFile|/%LOCAL_LINK%/[[images/meow.gif|images/meow.gif]]|
| ~RemoteLink|/%REMOTE_LINK%/[[http://www.TiddlyTools.com/images/meow.gif|http://www.TiddlyTools.com/images/meow.gif]]|
image
<<<
usage: {{{[img[tooltip|AttachFileSample]] or [img[tooltip|AttachFileSample][link]]}}})
[img[tooltip|AttachFileSample]]
<<<

/% DO NOT EDIT BELOW THIS POINT
---BEGIN_DATA---
image/gif;base64,
R0lGODlhOABQAPcAAAAACAAAEAAICAgICAgLDBAQCAQQGRAIEBgICBAQEBAQGBAY
FBoOEhwUFCEYEBgYGA4cIBkgGyEcHCEhISkYGCkcHCEpHCklIRAgMRkmNSElKSEp
NikeKykpKSExQiE5QjEhJTEpITEpKSkpMSkxISk1KTExITExKSktNTEpMTEpOTEx
MSk5MSkxOSkxQik5PTkrKTkxMTE8KTFCMTExOTExQjE5PTFCPTk3MzlCMTkxQjk5
QkI0MzlGPUg9M01JNi88TTlEUkI8REJCSkZDRFBDQkY/UFA/TjNMUkNOS1JKSkpW
Rj1KWEpKWj9OXEVZZlhMRlVLVVpSUlReUFdSYFVhX1JSa1VfbmBbU11ia2dcV3Fj
XVpldWVkb2tnb3tnbGZ1ZHV6aWVwe3d5c2N4iXN3gntzgHeBiYd2dYWHeoh/jIKL
kJWEfZmUh5CNlJ+VkICPn46XpZiSo5WfoJycnKaemaGcqKWlpZWnraWtqa2qoq2l
rZavvKW4xK2lta2ws/8A/7WcjLWllLWlpbWlrb2tnMatnLWtpbWtrb2trbWttb2t
tbWtvbW1pca1pbW1ra21va21xrW1tbW1vbW1xrW9tb21rb21tb21vb21xr29rb29
tca9sca1vc69rda9ra29wa3GxrW9vbW9xq29zrHGyrPB0rXG1r29vb29xr29zr3G
vb3Gxr3Gzr3G1sa9vcbGtc7GtdbGtcbGvc7GvdbGvd7Gvca9xsa9zsbGxsbGzsbG
1s7DyNbGxtbGzs7G1rjQ2MbO0sbO3sbW1s7Owc7OzsbW3sbe3s7O1s7W0tbQx+HU
zNDQ29bW1tvb1ufa1sPW6dDW4dbW3trY4sni7dbk797e3tbx9N7n3ufe3t7e597n
597i7+fe597s9N73++fn3ufn5+fn7+fv5+fv7+/e5+/r4vfr4ufn9+fv9+fv/+/n
7+/v8/Pz7/fv9+/v/+f3++f//+/39+/3/+//9+////f37/f39/f3//f/9/f////3
7//39//3////9////yH5BAEAAIAALAAAAAA4AFAAQAj+AAEJHEiwoMGDCBMqXIiw
iA8tXbxIgXHhgY+FICSIiCFFihIeXRgm9OKlDJMqYs506UIDRIUKD7w8kLCiAw0q
0ao8WCFhwgQqDx7E+EJHm0gpUaI0ibKDBo0dXeakazEkxYUOGjRMSQOmQw874eR9
IHNPXrFba5Y8CLNDyYULGlZQRVjtzJCmTnew2AGp2j19gAGTC6ctnLvDZfWR07Aj
CJAd4fTduxctFapbiDKTQ7gjSZcsT6PQqLmCxhA78v4GnuxOHuGzeei8kVLkh5I1
b9y80XPp0q1s+lK7E3eQjSIvbqJAEiPGjR0/c9REqyavtTx9rVtn09asmJsvbMb+
uLlcrFn3YsqsiRM33M3CDlkUsWMnT978cM206Y/WjH+187cEGOArqKCiCCJ00DEH
HXXkIdJBEgQVlEsS1iThAwlg+EAXcNgBySiQQILKJWOM8YYy2Tyo4oqA5HELMtxx
VwyLNA5UxAUxxPBWjTjGIIIWNSKUhhddUFFFU0O89BZjQ9DQwYUPVKABCEJg8cYZ
K5aRxRNM0JDCCimkQMUONXUAwlVOKbGDGHhAMEczgemjTV2jXeCTBqZFoZASVDDR
xGildTbHX3zUgJeTZ0Cimj5kBLHDEEM0IU59cd6TDmHm7WFQNHDAwcVoT5m2Qg2t
AJPYau6wY01/2ohTjDb+Z91hhiK3FMiILnkcWIw1iLlz0BuPquHEFaDWtEMVclyX
Wpz1pUNONdKkkkoWyEGSqyKXvYJeNtmEo6pRCEkyaX3ykMPOYOWSw41+2rDTGjnd
NoMMMsXoUkw05SFzXnlnFaiIikpOIIEUbrzaSit+RPFWByK4ocoordzC74iKKHLG
Fmm4kQciQSIkgQQIIEAAAQ+Q/IDIIieQAAFROPcHI9heUodh2ujT8c0CzcEdt8Ph
7DONGgwxxs+A7BADEUT4SOMEMWyBBRYiEA2ID16oYYYZDsXwQGNOMHGFFUz4ucMF
ND2qRBdmeDEE0Uq0IccWSuDQwdwXXrBCkxVFKOH+VVB8UceMNHohxhVNipDCEBqk
oIGUTu70AA4P3PUEYG6cEQXiM0lwwRBryKNiF1dcwYQQDK+wQxZijGYmnk+tsEIV
GrgTZ6VniMHUCHZ3EAWQCWlRxe+X47BCy8UEc08GcmfVwVUxLDHFECPoE01TTWhj
TRQimBBDEW64QUYTZczBhBcJCTFEFKODSkMUZcAJWDWMjDJHGW4089df3DiRBRDg
wzE7YPLgji5uIQmEzIMaeHgU+nbwqCaEaFEAXI82rqOav8gDLgOzjj5c9YpbXEIR
2bjHLQ5yBjdw4QxjGs0OOvA6MQSjGrNLjX2akQ1U0KEMXlACDYh0uS3M4Q3+CeoA
HbKBmHuE4yBJ6EEXUveomiBuCKhwA3AqOJmypIMb+ILEH1ChhTXoIUEbqwMiXsEL
ZThjOOEgB8cO4gYqKOEMDNxhFKjQBFmFw4IAZM25uJOKMWyhi35gxFk6WAxnqOcw
5wKcQdAgJz84shrVcIMfRpEOSMqjGtGoTnVSJY78dIcRf2ADFPwgsbM0Q2LmaRVm
GNKGYmzSPvYxFzsqOZ12dSsbACrlq85Sq1sQ6EBrfBAReHI1baTjUuGIhjZ0UZkC
3cI89CqPeQrkBzq4IQ1nWMOCCsijoPhgBUKoQstokJUJQOkBSlADJVqRimKgghEw
e4MW0KCxZvisIif+QwCUMnShkD2ABmaQAyQoMYoCXYINdCgGcKRmEAkRQAErI4DK
giIHP/wBEoy4hDvN0wxfMXRFo7CXNYh4j492TBG7VJVJV1oQKDBUCzi6WZQuUAai
+UAEPvDRBWikEaTxIGo/EwIP/igFH0hARZoTwRC+8AUtFEFqPlCCFryghZtSRE8H
6cIOHnABH0iBWl4wwxGgupIiKUEIPqjAqKhihSY4igYjMGcHUrCDKIS1hFKTAlVF
AwIq1W19NMCnhCRQgRBAAQ28SIPP1nCGNBTDaXfZQQoq8LGgYAVSILjQBC6wAyEQ
AQ11SFGNuvC7P+2ACXO4i+kipNYHdIBMppn+hxteRyYqCEwCOJDCHDyqIixoQQxu
leyXojA3rFxgBK57ixcmcNozAOYeeAjCGWZiN7hM4AmjUFEVmpCFJrjuSxEhE1ZA
YLq7KQFS0RjU/+5xhjI0YQcauEBesKoQM2QBUp113dzm4CjFZaVM8RWCGwA4u3sA
owmq1cAE8GQF+iJECXNkwg6E11kmuCEdGSATCLISlyqAwXkQSI0TuACHdBTjDh0A
gwmw0EAyiWElCilCEvDrlKfsoAzC0Ecc9uI6DXDVxxPwwgjuAQc8NSEa3UiDMngh
u3v8oXZ3QIYX/KCQIdCxKYGiQhei8dw5tHEIXqjCHGAImHR8QAhAuEL+FsrwP8E0
QxdwVogC71JjIXShFdcJDH6sUQxFQJAccHCvE87Qh0WVJRrhCJCBFEKNK0yYgZ3N
wgrcAIl0zK414qAPAPPsXQvBSR7TrNiBJKGPNyAkGsbgA1NcxwLXuQEPwrA0s9wR
Dms8N1XuOOYQJLCF/ESDPwOsVR7glCoSliEOZWCgapNwJDm0AoKSqc49FEGFMtyh
VqhIWArWoAgF5WEPLmqDfGTXM4M8oQxXSF2kxpSFHbTADX/wS6XIBatmSKILQzAc
pMIkhTSo4Q1pGGM2NqmYg1xhd2sYTQqcdAEqJMENmSywJtnBnVsoopomagMQGVSH
QVziFc1AETn+qmNPg1CBCkFwQxC+RKa71bUMsnvuZDRZrmog45138HKu6FCxzGhr
VdkQRzhEexAiZRMFe2nSClB3B21AsIrycNav34lDN9wiDwW6TBmdEQ720NoaCTmD
GqgghnbvQA7ppt8twnKq+rwLktHIgxbaAIU1+AEVxSgGL3hRSF5tkFt3QEgsdOyG
O1zUDWVgxK/1lQ53jbwsnNzOKf2giDdAgQ54zzu/aLgePi9kMqZIRzBGMYpfV6Px
laxGu7BjH3FkwxqrwvYYftDO7jxTl2dBRBsYcongkKtcs4w63AszmGaIA1ZnyTtH
zaN5iQVIEXpwj0iw4Abr1OdcFKcPu/T+I/lc8rJftapYbOrAItNhQRHyyLS5CMOf
fb0qGvqqV949WDE63MEN2qRDbGgUg+WtQARbdnr/cUq6wAg5NwfK1H7TdAl+kAd5
4AYYswYJ8gpBQllcNTdj4AWMEAxyAAE+JiFKIB6jcAvBUC8jAjNugAUmQgfBVCNB
AVsLVwVZwAQPYE5Q8hZ/MAqM0AonqAiDoAXioQdEFyTnVIRBoTIJoAAg0AVyYAeR
ACIjgghh8AaoMFI+gyEhgwAJoE9QQgBaqAAvWAaBdBmXcQd1ACdl8VE6kk8ZsoVJ
CFEJMGl2MAdzADOv8AYdpQ+8wFIDUTIj44VBAQgeQlC1ogvNgAouykAHFMiHCkEJ
qtAK0rQqjKgipWcNvyE7k6gip8QOXTeEmcgQbAAI3VByNBIQAAA7
---END_DATA---
%/
| source file|{{{...images\meow2.jpg}}}|
| attached on|15 May 2006 by ELSDesignStudios|
| embedded data|//none//|
| local link|/%LOCAL_LINK%/[[images/meow2.jpg|images/meow2.jpg]]|
| remote link|/%REMOTE_LINK%/[[http://www.TiddlyTools.com/images/meow2.jpg|http://www.TiddlyTools.com/images/meow2.jpg]]|
image
<<<
usage: {{{[img[tooltip|AttachFileSample2]] or [img[tooltip|AttachFileSample2][link]]}}})
[img[tooltip|AttachFileSample2]]
<<<
/***
|Name|AutoOpenTiddlersPlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#AutoOpenTiddlersPlugin|
|Version|0.21|
|Requires|~TW2.x|
!!!Description:
Open a user defined number of recent tiddlers automatically when the TW loads.
You can also specify a tag and only load tiddlers that have that tag.
To change the number of tiddlers automatically opened, or define a tag to use, ed the config.autoOpenTiddlers part of the code below.

!!!To Do
*add an option to exclude tiddlers with a particular tag

!!!Code
***/
//{{{
//edit this section to change the default settings
config.autoOpenTiddlers = 
{
          count: 5,   //number of tiddlers opened.
          tag: undefined //change if you want to open tiddlers with a specific tag, eg: 'DefaultTiddlers'
}


config.autoOpenTiddlers.handler = function()
{
          if (this.tag == undefined)
             var newTiddlers = store.getTiddlers("modified");
          else
             var newTiddlers = store.getTaggedTiddlers(this.tag,"modified");
          var newTiddlers = newTiddlers.reverse();
           var max = Math.min(this.count,newTiddlers.length-1);
          for (var i=max; i>=0; i--)
               { story.displayTiddler(null,newTiddlers[i].title);} 
}

window.old_lewcid_autoOpenTiddlers_restart = restart;
restart = function ()
{
        window.old_lewcid_autoOpenTiddlers_restart();
        config.autoOpenTiddlers.handler();
}
//}}}
AutoOpenTiddlersPlugin: fixed potential problems with empty TW's.
/%
|Name|AutoRefresh|
|Source|http://www.TiddlyTools.com/#AutoRefresh|
|Version|0.6.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|enable/disable auto-refresh of selected content to force/prevent re-rendering when tiddler changes occur|

usage:
	<<tiddler AutoRefresh with: mode id>>

where:
	mode - (optional) is one of:
		off (or disable) - prevent refresh of rendered content (except when PageTemplate is changed!)
		on (or enable)- re-render content whenever corresponding tiddler source is changed
		force - re-render content whenever ANY tiddler content is changes (or refreshDisplay() is triggered)
	id - (optional)
		is a unique DOM element identifier on which to operate.
		If not specified, the current tiddler (or containing parent if not in a tiddler) is used.

%/<script>
	var here=story.findContainingTiddler(place);
	if (here) { // in a tiddler, get containing viewer element
		var here=place; while (here && here.className!='viewer') here=here.parentNode;
		if (!here) return; // no 'viewer' element (perhaps a custom template?)
	}
	else here=place.parentNode; // not in a tiddler, use immediate parent container

	// if DOM id param, get element by ID instead of using container
	if ("$2"!="$"+"2") var here=document.getElementById("$2");

	if (!here) return; // safety check

	var mode="$1"; if (mode=="$"+"1") mode="on";

	switch (mode.toLowerCase()) {
		case 'on':
		case 'enable':
		case 'force':
			var title=here.getAttribute("tiddler");
			if (!title) { // find source tiddler title
				var tid=story.findContainingTiddler(place);
				if (!tid) return; // can't determine source tiddler
				title=tid.getAttribute("tiddler");
			}
			here.setAttribute("tiddler",title);
			here.setAttribute("refresh","content");
			here.setAttribute("force",(mode=='force')?"true":"");
			break;
		case 'off':
		case 'disable':
			here.setAttribute("refresh","");
			here.setAttribute("force","");
			break;
	}
</script>
/***
|Name|AutoTaggerPlugin|
|Source|http://www.TiddlyTools.com/#AutoTaggerPlugin|
|Documentation|http://www.TiddlyTools.com/#AutoTaggerPluginInfo|
|Version|1.7.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|TiddlyWiki.prototype.saveTiddler|
|Options|##Configuration|
|Description|Tag tiddlers with date, author, etc. and/or scan the tiddler for any tags that are embedded in the content|
~AutoTagger ''automatically generates tag values for all newly created or edited tiddlers''
!!!!!Documentation
> see [[AutoTaggerPluginInfo]]
!!!!!Configuration
<<<
|<<option chkAutoTagAuthor>> add 'created by' author tag //(when a tiddler is first created)//||
|<<option chkAutoTagEditor>> add 'edited by' author tag //(when a tiddler is updated)//||
|<<option chkAutoTagDate>> add 'creation date' tag, using date format:|<<option txtAutoTagFormat>>|
|<<option chkAutoTagModDate>> add 'modification date' tag, using date format:|<<option txtAutoTagModFormat>>|
|<<option chkAutoTagNewTags>> add default tag(s) when creating new tiddlers:|<<option txtAutoTagNewTags>>|
|<<option chkAutoTagDefault>> add default tag(s) when saving tiddlers that are not otherwise tagged:|<<option txtAutoTagDefault>>|
|<<option chkAutoTagTrigger>> scan tiddler content for matching tags when tagged with:|<<option txtAutoTagTrigger>>|
|<<option chkAutoTagAliases>> replace 'aliased' tags using definitions contained in:|<<option txtAutoTagAliases>>|
|borderless|k
<<<
!!!!!Revisions
<<<
2008.03.29 [1.7.1] in displayTiddler(), get title from tiddler object (if needed).  Fixes errors caused when calling function passes a tiddler *object* instead of a tiddler *title*
2008.03.27 [1.7.0] added aliasing (using [[AutoTaggerAliases]] definition)
2008.03.11 [*.*.*] plugin size reduction - moved documentation to [[AutoTaggerPluginInfo]]
2007.10.18 [1.6.0] hijack displayTiddler() to add option to use default tags when creating new tiddlers (preloads tag edit field).  Based on requests from RA and DavidWinfield.
| Please see [[AutoTaggerPluginInfo]] for previous revision details |
2005.08.15 [1.0.0] Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.autoTagger = {major: 1, minor: 7, revision: 1, date: new Date(2008,3,29)};

var co=config.options; // shorthand temp variable
if (co.chkAutoTagDate==undefined) co.chkAutoTagDate=false;
if (co.chkAutoTagModDate==undefined) co.chkAutoTagModDate=false;
if (co.chkAutoTagEditor==undefined) co.chkAutoTagEditor=false;
if (co.chkAutoTagAuthor==undefined) co.chkAutoTagAuthor=false;
if (co.chkAutoTagTrigger==undefined) co.chkAutoTagTrigger=false;
if (co.txtAutoTagTrigger==undefined) co.txtAutoTagTrigger="auto";
if (co.chkAutoTagDefault==undefined) co.chkAutoTagDefault=false;
if (co.txtAutoTagDefault==undefined) co.txtAutoTagDefault="untagged";
if (co.txtAutoTagFormat==undefined) co.txtAutoTagFormat="YYYY.0MM.0DD";
if (co.txtAutoTagModFormat==undefined) co.txtAutoTagModFormat="YYYY.0MM.0DD";
if (co.chkAutoTagNewTags==undefined) co.chkAutoTagNewTags=false;
if (co.txtAutoTagNewTags==undefined) co.txtAutoTagNewTags="";
if (co.chkAutoTagAliases==undefined) co.chkAutoTagAliases=true;
if (co.txtAutoTagAliases==undefined) co.txtAutoTagAliases="AutoTaggerAliases";

// hijack displayTiddler()
Story.prototype.autotagger_displayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler=function(srcElement,tiddler,template,animate,unused,customFields,toggle)
{
	var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
        this.autotagger_displayTiddler.apply(this,arguments);
	if (!config.options.chkAutoTagNewTags) return; // IF add new tags is enabled
	if (!story.isDirty(title)) return; // AND tiddler is being edited
	if (store.tiddlerExists(title)) return; // AND tiddler doesn't exist
	var newtags=config.options.txtAutoTagNewTags.readBracketedList(); // get new tags
	for (var t=0; t<newtags.length; t++)
		story.setTiddlerTag(title,newtags[t],+1); // preload tag edit field
} 

// hijack saveTiddler()
TiddlyWiki.prototype.autotagger_SaveTiddler=TiddlyWiki.prototype.saveTiddler;
TiddlyWiki.prototype.saveTiddler=function(title,newTitle,newBody,modifier,modified,tags,fields)
{
	var co=config.options; // shorthand temp variable
	var newTags = [];
	if (tags) newTags = (typeof tags == "string") ? tags.readBracketedList() : tags;
	var txt=store.getTiddlerText(config.options.txtAutoTagAliases,'')
	if (config.options.chkAutoTagAliases && txt.length) {
		// replace tag aliases with one or more other tags
		var list=txt.split('\n');
		var map={};
		for (var i=0; i<list.length; i++)
			map[list[i].split('=')[0]]=list[i].split('=')[1].readBracketedList();
		for (var a in map) if (newTags.contains(a)) {
			newTags.splice(newTags.indexOf(a),1); // remove alias
			for (var i=0; i<map[a].length; i++) // add replacements
				newTags.pushUnique(map[a][i]);
		}
	}
	var now=new Date().formatString(co.txtAutoTagFormat);
	if (co.chkAutoTagDate && (store.getTiddler(title)==undefined))
		if (newTitle!=now) newTags.pushUnique(now); // created date - don't add to journals
	if (co.chkAutoTagAuthor && (store.getTiddler(title)==undefined))
		newTags.pushUnique(co.txtUserName); // creator
	if (co.chkAutoTagEditor && store.getTiddler(title))
		newTags.pushUnique(co.txtUserName); // modifier
	if (co.chkAutoTagModDate && store.getTiddler(title))
		newTags.pushUnique(new Date().formatString(co.txtAutoTagModFormat)); // modified
	var allTags = store.getTags(); // scan content for tags
	if (co.chkAutoTagTrigger && co.txtAutoTagTrigger.length	&& newTags.contains(co.txtAutoTagTrigger))
		for (var t=0; t<allTags.length; t++) {
			if (allTags[t][0]=='systemConfig') continue; // don't add 'systemConfig'
			if ((newBody.indexOf(allTags[t][0])!=-1) || (newTitle.indexOf(allTags[t][0])!=-1))
				newTags.pushUnique(allTags[t][0]); // autotag
		}
	for (var t=0; t<newTags.length; t++)
		newTags[t]=String.encodeTiddlyLink(newTags[t]); // add brackets around tags
	if (!newTags.length && co.chkAutoTagDefault && co.txtAutoTagDefault.length)
		newTags.push(co.txtAutoTagDefault); // untagged - add default tag
	arguments[5]=newTags.join(" ");
	return this.autotagger_SaveTiddler.apply(this,arguments);
}
//}}}
/***
|Name|AutoTaggerPlugin|
|Source|http://www.TiddlyTools.com/#AutoTaggerPlugin|
|Documentation|http://www.TiddlyTools.com/#AutoTaggerPluginInfo|
|Version|1.7.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for AutoTaggerPlugin|
~AutoTagger ''automatically generates tag values for all newly created or edited tiddlers''
!!!!!Usage
<<<
Whenever you //create a new tiddler//, ~AutoTagger can add various tags for you:
* original author
* creation date
* default tag(s) (pre-loaded into tiddler editor)
* default tag(s) (when saving tiddlers that are not otherwise tagged)
Whenever you //edit an existing tiddler//, ~AutoTagger can add various tags for you:
* most recent author
* modification date
* default tag(s) (when saving tiddlers that are not otherwise tagged)
If you enter ''//auto//'' as a tiddler tag value, ~AutoTagger ''scans the tiddler content'' (including title) for text that matches any existing tags, and ''automatically adds any embedded tags that it finds''.

You can also create a tiddler that defines a set of [[AutoTaggerAliases]] to ''replace a single tag with one or more alternative tags''.  The alias definitions use this format:
{{{
aliastag=tag1 tag2 tag3...
aliastag=tag4 tag5 tag6...
etc.
}}}
Notes:
* After the new tags have been added to the tiddler, they are treated just as if you had entered them by hand and can be edited to make any changes you want.
* As long as the "auto" tag is still present on a tiddler, ~AutoTagger will re-scan that tiddler's content each time it is edited.  If you DO edit the generated tags, you can remove the "auto" tag from the tiddler to prevent it from being re-scanned when you press 'done' to finish editing.  If you have set the "auto" tag on a tiddler, and then add several tags to your document, those tags will ''not'' be automatically added to the tiddler until you actually edit that tiddler and press 'done' to trigger an AutoTagger scan.  The special-purpose ''"systemConfig" tag is never added automatically, even if matched in the tiddler content'', since this tag should be added manually to ensure it is always used appropriately.
*@@display:inline;Normally, aliases are removed and replaced by the indicated alternatives defined in the [[AutoTaggerAliases]] configuration.  To retain an original alias tag (in addition to it's substitutes), include it in it's set of substitutes, like this:
{{{
aliastag=aliasgtag tag1 tag2 tag3...
}}}
@@
*@@display:inline;Alias definitions are processed in the order they occur in [[AutoTaggerAliases]].  If a given alias definition includes another alias that occurs after it in the configuration, the second alias will be replaced when it's definition is processed.
{{{
aliastag=tag1 anotheraliastag tag2...
anotheraliastag=tag3 tag4...
}}}
which results in: {{{tag1 tag2 tag3 tag4}}}
@@
<<<
!!!!!Configuration
<<<
|<<option chkAutoTagAuthor>> add 'created by' author tag //(when a tiddler is first created)//||
|{{{<<option chkAutoTagAuthor>>}}}||
|<<option chkAutoTagEditor>> add 'edited by' author tag //(when a tiddler is updated)//||
|{{{<<option chkAutoTagEditor>>}}}||
|<<option chkAutoTagDate>> add 'creation date' tag, using date format:|<<option txtAutoTagFormat>>|
|{{{<<option chkAutoTagDate>>}}}|{{{<<option txtAutoTagFormat>>}}}|
|<<option chkAutoTagModDate>> add 'modification date' tag, using date format:|<<option txtAutoTagModFormat>>|
|{{{<<option chkAutoTagModDate>>}}}|{{{<<option txtAutoTagModFormat>>}}}|
|<<option chkAutoTagNewTags>> add default tag(s) when creating new tiddlers:|<<option txtAutoTagNewTags>>|
|{{{<<option chkAutoTagNewTags>>}}}|{{{<<option txtAutoTagNewTags>>}}}|
|<<option chkAutoTagDefault>> add default tag(s) when saving tiddlers that are not otherwise tagged:|<<option txtAutoTagDefault>>|
|{{{<<option chkAutoTagDefault>>}}}|{{{<<option txtAutoTagDefault>>}}}|
|<<option chkAutoTagTrigger>> scan tiddler content for matching tags when tagged with:|<<option txtAutoTagTrigger>>|
|{{{<<option chkAutoTagTrigger>>}}}|{{{<<option txtAutoTagTrigger>>}}}|
|<<option chkAutoTagAliases>> replace 'aliased' tags using definitions contained in:|<<option txtAutoTagAliases>>|
|{{{<<option chkAutoTagAliases>>}}}|{{{<<option txtAutoTagAliases>>}}}|
|borderless|k
<<<
!!!!!Revisions
<<<
2008.03.29 [1.7.1] in displayTiddler(), get title from tiddler object (if needed).  Fixes errors caused when calling function passes a tiddler *object* instead of a tiddler *title*
2008.03.27 [1.7.0] added aliasing (using [[AutoTaggerAliases]] definition)
2008.03.11 [*.*.*] plugin size reduction - moved documentation to [[AutoTaggerPluginInfo]]
2007.10.18 [1.6.0] hijack displayTiddler() to add option to use default tags when creating new tiddlers (preloads tag edit field).  Based on requests from RA and DavidWinfield.
2007.06.28 [1.5.1] in hijack of saveChanges(), use apply() to allow additional params (such as "fields") to be correctly passed through to the core
2007.03.14 [1.5.0] added support for tagging tiddlers with modification date
2007.01.20 [1.4.1] don't add create date tag to dated journal tiddlers (based on request from ConalElliot)
2006.12.10 [1.4.0] added option to use default tag value when no tags are specified
2006.08.29 [1.3.3] use newTags.contains() instead of newTags.find() to check for 'auto' tag
2006.06.15 [1.3.2] hijack TiddlyWiki.prototype.saveTiddler instead of store.saveTiddler.  Permits other plugins to also hijack the function (thanks to Simon Baird for finding this!)
2006.05.31 [1.3.1] Re-assemble tags into a space-separated string (use encodeTiddlyLink to add {{{[[...]]}}} as needed) before passing it on to core (or other hijacked function)
2005.10.09 [1.3.0] Added 'edited by' tagging. Combined documentation and code into a single tiddler
2005.08.16 [1.2.0] Added optional scanning for tags in tiddler content (based on suggestion from Jacques Turbé)
2005.08.15 [1.1.0] Added 'created by' tag generation (based on suggestion from Elise Springer). Renamed from DateTag to AutoTagger
2005.08.15 [1.0.0] Initial Release
<<<
/***
|Name|BetterTimelineMacro|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#BetterTimelineMacro|
|Version|0.5 beta|
|Requires|~TW2.x|
!!!Description:
A replacement for the core timeline macro that offers more features:
*list tiddlers with only specfic tag
*exclude tiddlers with a particular tag
*limit entries to any number of days, for example one week
*specify a start date for the timeline, only tiddlers after that date will be listed.

!!!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.
Edit the ViewTemplate to add the fullscreen command to the toolbar.

!!!Syntax:
{{{<<timeline better:true>>}}}
''the param better:true enables the advanced features, without it you will get the old timeline behaviour.''

additonal params:
(use only the ones you want)
{{{<<timeline better:true  onlyTag:Tag1 excludeTag:Tag2 sortBy:modified/created firstDay:YYYYMMDD maxDays:7 maxEntries:30>>}}}

''explanation of syntax:''
onlyTag: only tiddlers with this tag will be listed. Default is to list all tiddlers.
excludeTag: tiddlers with this tag will not be listed.
sortBy: sort tiddlers by date modified or date created. Possible values are modified or created.
firstDay: useful for starting timeline from a specific date. Example: 20060701 for 1st of July, 2006
maxDays: limits timeline to include only tiddlers from the specified number of days. If you use a value of 7 for example, only tiddlers from the last 7 days will be listed.
maxEntries: limit the total number of entries in the timeline.


!!!History:
*28-07-06: ver 0.5 beta, first release

!!!Code
***/
//{{{
// Return the tiddlers as a sorted array
TiddlyWiki.prototype.getTiddlers = function(field,excludeTag,includeTag)
{
          var results = [];
          this.forEachTiddler(function(title,tiddler)
          {
          if(excludeTag == undefined || tiddler.tags.find(excludeTag) == null)
                        if(includeTag == undefined || tiddler.tags.find(includeTag)!=null)
                                      results.push(tiddler);
          });
          if(field)
                   results.sort(function (a,b) {if(a[field] == b[field]) return(0); else return (a[field] < b[field]) ? -1 : +1; });
          return results;
}



//this function by Udo
function getParam(params, name, defaultValue)
{
          if (!params)
          return defaultValue;
          var p = params[0][name];
          return p ? p[0] : defaultValue;
}

window.old_timeline_handler= config.macros.timeline.handler;
config.macros.timeline.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
          var args = paramString.parseParams("list",null,true);
          var betterMode = getParam(args, "better", "false");
          if (betterMode == 'true')
          {
          var sortBy = getParam(args,"sortBy","modified");
          var excludeTag = getParam(args,"excludeTag",undefined);
          var includeTag = getParam(args,"onlyTag",undefined);
          var tiddlers = store.getTiddlers(sortBy,excludeTag,includeTag);
          var firstDayParam = getParam(args,"firstDay",undefined);
          var firstDay = (firstDayParam!=undefined)? firstDayParam: "00010101";
          var lastDay = "";
          var field= sortBy;
          var maxDaysParam = getParam(args,"maxDays",undefined);
          var maxDays = (maxDaysParam!=undefined)? maxDaysParam*24*60*60*1000: (new Date()).getTime() ;
          var maxEntries = getParam(args,"maxEntries",undefined);
          var last = (maxEntries!=undefined) ? tiddlers.length-Math.min(tiddlers.length,parseInt(maxEntries)) : 0;
          for(var t=tiddlers.length-1; t>=last; t--)
                  {
                  var tiddler = tiddlers[t];
                  var theDay = tiddler[field].convertToLocalYYYYMMDDHHMM().substr(0,8);
                  if ((theDay>=firstDay)&& (tiddler[field].getTime()> (new Date()).getTime() - maxDays))
                     {
                     if(theDay != lastDay)
                               {
                               var theDateList = document.createElement("ul");
                               place.appendChild(theDateList);
                               createTiddlyElement(theDateList,"li",null,"listTitle",tiddler[field].formatString(this.dateFormat));
                               lastDay = theDay;
                               }
                  var theDateListItem = createTiddlyElement(theDateList,"li",null,"listLink",null);
                  theDateListItem.appendChild(createTiddlyLink(place,tiddler.title,true));
                  }
                  }
          }

          else
              {
              window.old_timeline_handler.apply(this,arguments);
              }
}
//}}}
/%
|''URL:''|http://tiddlywiki.bidix.info/|
|''Description:''|Repository for BidiX's TiddlyWiki Extensions|
|''Author:''|BidiX|
%/
/***
|Name|Blackout|
|Source|http://www.TiddlyTools.com/#Blackout|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|CSS|
|Requires||
|Overrides||
|Description|theme: black/blue-gray/gray backgrounds w/light text|
|StyleSheet|Blackout|
|PageTemplateReadOnly|PageTemplateReadOnly|
|EditTemplateReadOnly|EditTemplateReadOnly|
***/

[[StyleSheetAdjustments]]
[[BrightText]]
/* ==== blackout ==== */
/*{{{*/
body
	{ background-color:#000; }
.menubox
	{ background-color:#111; }
.viewer
	{ background-color:#111; border: 1px solid #999; -moz-border-radius:1em; padding:1em; }
.header
	{ background-image: none; background-color:transparent; color:#ccf; border:0; }
.floatingPanel, .attachPanel, #importPanel, #exportPanel,
	{ background: #eee; background-image: url('[[TexturesParchmentGray]]');}
.floatingPanel a, .attachPanel a, #messageArea a, #importPanel a, #exportPanel a, #sidebarTabs .tabContents a,
.floatingPanel .button, .attachPanel .button, #messageArea .button, #importPanel .button, #exportPanel .button, #sidebarTabs .tabContents .button,
.floatingPanel .tiddlyLinkExisting, .attachPanel .tiddlyLinkExisting, #messageArea .tiddlyLinkExisting, #importPanel .tiddlyLinkExisting, #exportPanel .tiddlyLinkExisting, #sidebarTabs .tabContents .tiddlyLinkExisting
	{ color:#009; }
.siteMenu .floatingPanel, #messageArea 
	{ background: #eee; }
.tiddlyCard { background:#ffd; }

.viewer h1,.viewer h2,.viewer h3,.viewer h4,.viewer h5 { background: #666; color:#fff; }
.viewer .tabContents, #sidebarTabs .tabContents
	{ background-color:#111; color:#fff; }
.tabContents a, .tabContents .button, .tabContents .tiddlyLinkExisting
	{ color:#99f; }
/*}}}*/
/%
|''URL:''|Enter a URL|
|''Description:''|enter a description|
|''Author:''|enter author/moderator info|
%/
enter your notes here
/%
|Description|enter FAQ list item text here|
%/
{{small{
__enter FAQ display title text here__

enter FAQ content here
}}}
/***
|Name|BlankPlugin|
|Source|http://www.TiddlyTools.com/#BlankPlugin|
|Documentation|http://www.TiddlyTools.com/#BlankPluginInfo|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description||
Summary description of purpose
!!!!!Documentation
>see [[BlankPluginInfo]]
!!!!!Configuration
<<<
checkboxes and input fields for plugin-specific options
<<<
!!!!!Revisions
<<<
2007.01.01 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.PLUGINNAME= {major: 0, minor: 0, revision: 0, date: new Date(2008,1,1)};
//}}}
/%
|Name|BlankScript|
|Source|http://www.TiddlyTools.com/#BlankScript|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description||
%/<script>
	var here=story.findContainingTiddler(place); if (!here) return;
	var tid=store.getTiddler(here.getAttribute('tiddler'));
	var out="";
	// add code here >>>
	return out;
</script>
Tiddlers that are tagged with<<tag bookmark>>can be used to define ''~URLs, descriptions and author information for favorite websites''.

Bookmark tiddlers are displayed using a custom BookmarkViewTemplate, which automatically embeds the website directly in the tiddler content using an HTML "IFRAME" element.  Most (but not all) bookmarks refer to TiddlyWiki documents and are also tagged with<<tag systemServer>>, allowing them to be selected as import sources when using the TiddlyWiki standard ImportTiddlers function.

To create additional bookmarks, simply copy the BlankBookmark tiddler, edit the URL, description, and author info, tag the new tiddler with<<tag bookmark>>and press 'done' to start viewing the remote URL.  Alternatively, you can add the following """<<newTiddler>>""" macro in your SideBarOptions (or any other tiddler) to insert a<<newTiddler label:'new bookmark' title:'NewBookmark' text:{{store.getTiddlerText('BlankBookmark','')}} tag:'bookmark' prompt:'create a bookmark tiddler'>>command into your document:
{{{
<<newTiddler label:'new bookmark' title:'NewBookmark' tag:'bookmark'
	text:{{store.getTiddlerText('BlankBookmark','')}}>>
}}}
<!--{{{-->
<!--
|Name|BookmarkViewTemplate|
|Source|http://www.TiddlyTools.com/#BookmarkViewTemplate|
|Version||
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands, WikifyPlugin, TaggedTemplateTweak|
|Overrides||
|Description|custom template used to display tiddlers tagged with "Bookmark"|

Usage:
Create a tiddler and enter URL, description and author using a 'slice table':
	|''URL:''|Enter a URL|
	|''Description:''|enter a description|
	|''Author:''|enter author/moderator info|
Tag the tiddler with "bookmark" (or "Bookmark")

-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></span>
<span class='title'>
	<span class='floatleft' macro='tiddlerIcons' style='cursor:auto !important;'></span>
	<span macro='view title'></span>
</span>
<span class='subtitle'>
	<span style='white-space:nowrap' macro='view modified date [[DDD, MMM DDth YYYY]]'></span>
</span>
<div class='tagClear'></div>
<div class='viewer'>
	<div class='floatleft' macro='wikify "{{big{[[%0|%1]]}}}<br>" here::Description here::URL'></div>
	<div class='toolbar'>
		<a class='button' href='javascript:;'
			onclick='window.history.go(-1);' title='go back one page'>back</a>
		<a class='button' href='javascript:;'
			onclick='window.history.go(+1);' title='go foward one page'>forward</a>
		<a class='button' href='javascript:;'
			onclick='var f=this.parentNode.parentNode.getElementsByTagName("iframe")[0];
			f.src=f.src'
			title='reload current page'>reload</a>
		<a class='button' href='javascript:;'
			onclick='var f=this.parentNode.parentNode.getElementsByTagName("iframe")[0];
				var w=prompt("Enter a new frame width (use px, em, cm, in, or %)","100%");
				if (!w||!w.length) return; if (!w.replace(/[0-9]*/,"").length) w+="px";
				f.style.width=w;'
			title='set frame width'>width</a>
		<a class='button' href='javascript:;'
			onclick='var f=this.parentNode.parentNode.getElementsByTagName("iframe")[0];
				var h=prompt("Enter a new frame height (use px, em, cm, or in)","500");
				if (!h||!h.length) return; if (!h.replace(/[0-9]*/,"").length) h+="px";
				f.style.height=h;'
			title='set frame height'>height</a>
		<a class='button' href='javascript:;'
			onclick='var f=this.parentNode.parentNode.getElementsByTagName("iframe")[0];
				var show=f.style.display=="none";
				f.style.display=show?"block":"none";
				this.innerHTML=show?"hide":"show";'
			title="toggle display of this frame (but DON'T reload content)">hide</a>
	</div><div class='tagClear'
		macro='wikify [[<html><iframe src="%0" height="500" width="100%" style="background:#fff"></iframe></html>]] here::URL'>
	</div>
	<div macro='view text wikified'></div>
</div>
<!--}}}-->
/%
|Name|BreadcrumbsCommand|
|Source|http://www.TiddlyTools.com/#BreadcrumbsCommand|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|BreadcrumbsPlugin|
|Overrides||
|Description|"crumbs" command displays current breadcrumbs list in a popup|

%/<html><hide linebreaks><a href="javascript:;" class="TiddlyLink" title="tiddlers viewed during this session"
	onclick="var p=Popup.create(this); if (!p) return;
		var d=createTiddlyElement(p,'div');
		d.style.whiteSpace='normal'; d.style.width='auto'; d.style.padding='2px';
	wikify('\<\<breadcrumbs [[\<html\>\<hr\>\</html\>]] [[<br>]]\>\>',d);
		Popup.show(p,false); event.cancelBubble = true; if (event.stopPropagation) event.stopPropagation();
		return(false);"
>crumbs</a></html>
/***
|Name|BreadcrumbsPlugin|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#BreadcrumbsPlugin|
|Documentation|http://www.TiddlyTools.com/#BreadcrumbsPluginInfo|
|Version|2.0.0|
|License|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.displayTiddler,TiddlyWiki.prototype.deleteTiddler|
|Options|##Configuration|
|Description|list/jump to tiddlers viewed during this session plus "back" button/macro|
This plugin provides a list of links to all tiddlers opened during the session, creating a "trail of breadcrumbs" from one tiddler to the next, allowing you to quickly navigate to any previously viewed tiddler, or select 'home' to reset the display to the initial set of tiddlers that were open at the start of the session (i.e., when the document was loaded into the browser).
!!!!!Documentation
<<<
see [[BreadcrumbsPluginInfo]]
<<<
!!!!!Configuration
<<<
<<option chkCreateDefaultBreadcrumbs>> automatically create breadcrumbs display (if needed)
<<option chkShowBreadcrumbs>> show/hide breadcrumbs display
<<option chkReorderBreadcrumbs>> re-order breadcrumbs when visiting a previously viewed tiddler
<<option chkBreadcrumbsHideHomeLink>> omit 'Home' link from breadcrumbs display
<<option chkShowStartupBreadcrumbs>> show breadcrumbs for 'startup' tiddlers
<<option chkBreadcrumbsReverse>> show breadcrumbs in reverse order (most recent first)
<<option chkBreadcrumbsLimit>> limit breadcrumbs display to {{twochar{<<option txtBreadcrumbsLimit>>}}} items
<<option chkBreadcrumbsLimitOpenTiddlers>> limit open tiddlers to {{twochar{<<option txtBreadcrumbsLimitOpenTiddlers>>}}} items

<<<
!!!!!Revisions
<<<
2008.05.01 [2.0.0] added 'limit open tiddlers' feature (with safety check for tiddler in edit mode)
| Please see [[BreadcrumbsPluginInfo]] for previous revision details |
2006.02.01 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.breadCrumbs = {major: 2, minor: 0, revision: 0, date: new Date("May 1, 2008")};

var co=config.options; // abbreviation

// show/hide display option (default is to SHOW breadcrumbs)
if (co.chkShowBreadcrumbs===undefined) co.chkShowBreadcrumbs=true;

// REORDER breadcrumbs when visiting previously viewed tiddler (default)
if (co.chkReorderBreadcrumbs===undefined) co.chkReorderBreadcrumbs=true;

// create default breadcrumbs display as needed (default is to CREATE)
if (co.chkCreateDefaultBreadcrumbs===undefined) co.chkCreateDefaultBreadcrumbs=true;

// show breadcrumbs for 'startup' tiddlers (default is FALSE = only show crumbs for tiddlers opened after startup)
if (co.chkShowStartupBreadcrumbs===undefined) co.chkShowStartupBreadcrumbs=false;

// show crumbs in reverse order (most recent first)
if (co.chkBreadcrumbsReverse===undefined) co.chkBreadcrumbsReverse=false;

// limit number of crumbs displayed
if (co.chkBreadcrumbsLimit===undefined) co.chkBreadcrumbsLimit=false;
if (co.txtBreadcrumbsLimit===undefined) co.txtBreadcrumbsLimit=5;

// limit number of open tiddlers
if (co.chkBreadcrumbsLimitOpenTiddlers===undefined) co.chkBreadcrumbsLimitOpenTiddlers=false;
if (co.txtBreadcrumbsLimitOpenTiddlers===undefined) co.txtBreadcrumbsLimitOpenTiddlers=3;

// omit home link from breadcrumbs display
if (co.chkBreadcrumbsHideHomeLink===undefined) co.chkBreadcrumbsHideHomeLink=false;

config.macros.breadcrumbs =  {
	crumbs: [], // the list of current breadcrumbs
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var area=createTiddlyElement(place,"span",null,"breadCrumbs",null);
		area.setAttribute("homeSep",params[0]?params[0]:this.homeSeparator); // custom home separator
		area.setAttribute("crumbSep",params[1]?params[1]:this.crumbSeparator); // custom crumb separator
		this.render(area);
	},
	add: function (title) {
		var thisCrumb = title;
		var ind = this.crumbs.indexOf(thisCrumb);
		if(ind === -1)
			this.crumbs.push(thisCrumb);
		else if (config.options.chkReorderBreadcrumbs)
			this.crumbs.push(this.crumbs.splice(ind,1)[0]); // reorder crumbs
		else
			this.crumbs=this.crumbs.slice(0,ind+1); // trim crumbs
		if (config.options.chkBreadcrumbsLimitOpenTiddlers)
			this.limitOpenTiddlers();
		this.refresh();
		return false;
	},
	getAreas: function() {
		var crumbAreas=[];
		// find all DIVs with classname=="breadCrumbs"
		// Note: use try/catch to avoid "Bad NPObject as private data" fatal error  caused when
		// some versions of embedded QuickTime player element is accessed by hasClass() function.
		var all=document.getElementsByTagName("*");
		for (var i=0; i<all.length; i++)
			try{ if (hasClass(all[i],"breadCrumbs")) crumbAreas.push(all[i]); } catch(e) {;}
		// find single DIV w/fixed ID (backward compatibility)
		var byID=document.getElementById("breadCrumbs")
		if (byID && !hasClass(byID,"breadCrumbs")) crumbAreas.push(byID);
		if (!crumbAreas.length && config.options.chkCreateDefaultBreadcrumbs) {
			// no existing crumbs display areas... create one...
			var defaultArea = createTiddlyElement(null,"span",null,"breadCrumbs",null);
		 	defaultArea.style.display= "none";
			var targetArea= document.getElementById("tiddlerDisplay");
		 	targetArea.parentNode.insertBefore(defaultArea,targetArea);
			crumbAreas.push(defaultArea);
		}
		return crumbAreas;
	},
	refresh: function() {
		var crumbAreas=this.getAreas();
		for (var i=0; i<crumbAreas.length; i++) {
			crumbAreas[i].style.display = config.options.chkShowBreadcrumbs?"block":"none";
			removeChildren(crumbAreas[i]);
			this.render(crumbAreas[i]);
		}
	},
	render: function(here) {
		var out=""
		var homeSep=here.getAttribute("homeSep"); if (!homeSep) homeSep=this.homeSeparator;
		var crumbSep=here.getAttribute("crumbSep"); if (!crumbSep) crumbSep=this.crumbSeparator;
		if (!config.options.chkBreadcrumbsHideHomeLink) {
			createTiddlyButton(here,"Home",null,this.home,"tiddlyLink tiddlyLinkExisting");
			out+=homeSep;
		}
		for (c=0; c<this.crumbs.length; c++) // remove non-existing tiddlers from crumbs
			if (!store.tiddlerExists(this.crumbs[c]) && !store.isShadowTiddler(this.crumbs[c]))
				this.crumbs.splice(c,1);
		var count=this.crumbs.length;
		if (config.options.chkBreadcrumbsLimit && config.options.txtBreadcrumbsLimit<count)
			count=config.options.txtBreadcrumbsLimit;
		var list=[];
		for (c=this.crumbs.length-count; c<this.crumbs.length; c++) list.push('[['+this.crumbs[c]+']]');
		if (config.options.chkBreadcrumbsReverse) list.reverse();
		out+=list.join(crumbSep);
		wikify(out,here);
	},
	home: function() {
		story.closeAllTiddlers();
		restart();
		config.macros.breadcrumbs.crumbs = [];
		var crumbAreas=config.macros.breadcrumbs.getAreas();
		for (var i=0; i<crumbAreas.length; i++) crumbAreas[i].style.display = "none";
		return false;
	},
	limitOpenTiddlers: function() {
		var limit=config.options.txtBreadcrumbsLimitOpenTiddlers; if (limit<1) limit=1;
		for (c=this.crumbs.length-1; c>=0; c--) {
			var tid=this.crumbs[c];
			var elem=document.getElementById(story.idPrefix+tid);
			if (elem) { // tiddler is displayed
				if (limit <=0) { // display limit has been reached
					if (elem.getAttribute("dirty")=="true") { // tiddler is being edited
						var msg="'"+tid+"' is currently being edited.\n\n";
						msg+="Press OK to save and close this tiddler\nor press Cancel to leave it opened";
						if (confirm(msg)) { story.saveTiddler(tid); story.closeTiddler(tid); }
					}
					else
						story.closeTiddler(this.crumbs[c]);
				}
				limit--;
			}
		}
	}
};
if (config.macros.breadcrumbs.homeSeparator==undefined) // note: not a cookie
	config.macros.breadcrumbs.homeSeparator=" | ";
if (config.macros.breadcrumbs.crumbSeparator==undefined)  // note: not a cookie
	config.macros.breadcrumbs.crumbSeparator=" > ";

config.commands.previousTiddler = {
	text: 'back',
	tooltip: 'view the previous tiddler',
	hideReadOnly: false,
	dateFormat: 'DDD, MMM DDth YYYY hh:0mm:0ss',
	handler: function(event,src,title) {
		var here=story.findContainingTiddler(src); if (!here) return;
		var crumbs=config.macros.breadcrumbs.crumbs;
		if (crumbs.length>1) {
			var crumb=crumbs[crumbs.length-2];
			story.displayTiddler(here,crumb);
		}
		else
			config.macros.breadcrumbs.home();
		return false;
	}
};

config.macros.previousTiddler= {
	label: 'back',
	prompt: 'view the previous tiddler',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var label=params.shift(); if (!label) label=this.label;
		var prompt=params.shift(); if (!prompt) prompt=this.prompt;
		createTiddlyButton(place,label,prompt,function() {
			var crumbs=config.macros.breadcrumbs.crumbs;
			if (crumbs.length>1) {
				var crumb=crumbs[crumbs.length-2];
				story.displayTiddler(place,crumb);
			}
			else
				config.macros.breadcrumbs.home();
		});
	}
}

// hijack story.displayTiddler() so crumbs can be refreshed when a tiddler is displayed
if (Story.prototype.breadCrumbs_coreDisplayTiddler==undefined)
	Story.prototype.breadCrumbs_coreDisplayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler,template,animate,slowly)
{
	var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
	this.breadCrumbs_coreDisplayTiddler.apply(this,arguments);
	// if not displaying tiddler during document startup, then add it to the breadcrumbs
	// note: 'startingUp' flag is a global, set/reset by the core init() function
	if (!startingUp || config.options.chkShowStartupBreadcrumbs) config.macros.breadcrumbs.add(title);
}

// hijack store.removeTiddler() so crumbs can be refreshed when a tiddler is deleted
if (TiddlyWiki.prototype.breadCrumbs_coreRemoveTiddler==undefined)
	TiddlyWiki.prototype.breadCrumbs_coreRemoveTiddler=TiddlyWiki.prototype.removeTiddler;
TiddlyWiki.prototype.removeTiddler= function(title)
{
	this.breadCrumbs_coreRemoveTiddler.apply(this,arguments);
	config.macros.breadcrumbs.refresh();
}
//}}}
/***
|Name|BreadcrumbsPluginInfo|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#BreadcrumbsPlugin|
|Documentation|http://www.TiddlyTools.com/#BreadcrumbsPluginInfo|
|Version|2.0.0|
|License|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.displayTiddler,TiddlyWiki.prototype.removeTiddler|
|Description|Documentation for BreadcrumbsPlugin|
This plugin provides a list of links to all tiddlers opened during the session, creating a "trail of breadcrumbs" from one tiddler to the next, allowing you to quickly navigate to any previously viewed tiddler, or select 'home' to reset the display to the initial set of tiddlers that were open at the start of the session (i.e., when the document was loaded into the browser).
!!!!!Usage
<<<
syntax:
{{{
<<breadcrumbs homeSeparator crumbSeparator>>
}}}
By default, the breadcrumbs are displayed as a continuous, //horizontal// word-wrapped line of text, using default character sequences for ''homeSeparator'' (" | ") and ''crumbSeparator'' (" > ").  The //optional// ''homeSeparator'' and ''crumbSeparator'' macro parameters allow you to specify alternative separators.  For example, to display the breadcrumbs //vertically// (in a stack, rather than a row), set the separator values to use {{{[[<br>]]}}}... and, to display a horizontal line as the home separator, use {{{[[<html><hr></html>]]}}}.
<<<
!!!!!Examples:
<<<
{{{
<<breadcrumbs>>
}}}
<<breadcrumbs>>
{{{
<<breadcrumbs [[<html><hr></html>]] [[<br>]]>>
}}}
<<breadcrumbs [[<html><hr></html>]] [[<br>]]>>
<<<
!!!!!Customization
<<<
Using CSS and a few of the plugin configuration options (see below), you can make the breadcrumbs display resemble browser tabs by adding the following to your [[StyleSheet]]:
{{{
.breadCrumbs { border-bottom:1px solid; }
.breadCrumbs a {
	border: 1px solid; padding: 0px 1em;
	-moz-border-radius-topleft:.5em; -moz-border-radius-topright:.5em;
}
}}}
and this in [[ConfigTweaks]] (tagged with systemConfig, of course):
{{{
config.options.chkShowStartupBreadcrumbs=true;
config.options.chkBreadcrumbsLimitOpenTiddlers=true;
config.options.txtBreadcrumbsLimitOpenTiddlers=1;
config.macros.breadcrumbs.homeSeparator=" ";
config.macros.breadcrumbs.crumbSeparator=" ";
}}}
<<<
!!!!!Configuration
<<<
__''display placement:''__
<<option chkCreateDefaultBreadcrumbs>> automatically create breadcrumbs display (if needed)
{{{<<option chkCreateDefaultBreadcrumbs>>}}}
>By default, the plugin automatically creates the "breadCrumbs" display element at the top of the story column, just above the tiddlerDisplay area.  To manually control the display and placement of the breadcrumbs display, you can define a DIV with class="breadCrumbs" in a custom [[PageTemplate]] or embed the {{{<<breadcrumbs>>}}} macro in specific tiddler content.
>
>For example, to add the breadcrumbs below the mainMenu, change this:
{{{
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
}}}
>to:
{{{
<div id='mainMenu'>
	<div refresh='content' tiddler='MainMenu'></div>
	<div id='breadCrumbs' class='breadCrumbs'></div>
</div>
}}}
>You can also block automatic creation of the breadcrumbs display by setting
{{{
config.options.chkCreateDefaultBreadcrumbs=false;
}}}
>in a [[CookieJar]]/[[ConfigTweaks]] plugin tiddler.

__''other settings:''__
<<option chkShowBreadcrumbs>> show/hide breadcrumbs display
{{{<<option chkShowBreadcrumbs>>}}}
>This checkbox toggles the visibility of the breadcrumbs display.  However, the display is not updated until the next crumb is added (or a previous crumb is clicked on).  For immediate effect, the [[ToggleBreadcrumbs]] script uses [[InlineJavascriptPlugin]] to synchronize the checkbox setting and the breadcrumbs display.
<<option chkReorderBreadcrumbs>> re-order breadcrumbs when visiting a previously viewed tiddler
{{{<<option chkReorderBreadcrumbs>>}}}
>When visiting a previously viewed tiddler, the title of the most-recently displayed tiddler is simply moved to the end of the list and individual breadcrumbs are not removed from the list unless the underlying tiddler is deleted.  When ''re-ordering'' is disabled, the breadcrumbs list is ''trimmed'' so that all crumbs following that tiddler are removed from the list.
<<option chkBreadcrumbsHideHomeLink>> omit 'Home' link from breadcrumbs display
{{{<<option chkBreadcrumbsHideHomeLink>>}}}
>Enabling this option suppresses the automatic display of the "Home" link (and home separator).  To manually add the home link elsewhere in your document, use the following HTML:
{{{
<html><a href="javascript:;" onclick="config.macros.breadcrumbs.home()">home</a></html>
}}}
<<option chkShowStartupBreadcrumbs>> show breadcrumbs for 'startup' tiddlers
{{{<<option chkShowStartupBreadcrumbs>>}}}
>Breadcrumbs are usually only added for tiddlers that are opened after the document has been loaded, and not for tiddlers displayed during initial startup (e.g., [[DefaultTiddlers]]).  Enabling this option displays breadcrumbs for all viewed tiddlers, regardless of when they are opened.
<<option chkBreadcrumbsReverse>> show breadcrumbs in reverse order
{{{<<option chkBreadcrumbsReverse>>}}}
>As tiddlers are displayed, breadcrumbs are usually added to the //end// of the list.  Enabling this option displays breadcrumbs in reverse order, so that the most recently visited tiddlers are listed first.
<<option chkBreadcrumbsLimit>> limit breadcrumbs display to {{twochar{<<option txtBreadcrumbsLimit>>}}} items
{{{<<option chkBreadcrumbsLimit>>}}} and {{{<<option txtBreadcrumbsLimit>>}}}
>By default, breadcrumbs are displayed for all tiddlers that have been visited (unless the list is being 'trimmed' by disabling the chkReorderBreadcrumbs option above).  Enabling this option limits the display of the list to a maximum specified number of breadcrumbs.
<<option chkBreadcrumbsLimitOpenTiddlers>> limit open tiddlers to {{twochar{<<option txtBreadcrumbsLimitOpenTiddlers>>}}} items
{{{<<option chkBreadcrumbsLimitOpenTiddlers>>}}} and {{{<<option txtBreadcrumbsLimitOpenTiddlers>>}}}
>By default, tiddlers remain open (e.g., displayed in the story column) until you explicitly close them.  When this option is enabled, only the most recently opened tiddlers will remain open: ''any tiddlers in excess of the specified limit are automatically closed.''  //Note: for 'data safety', if a tiddler is being edited, you will be asked for permission to "save-and-close" that tiddler or leave it open (even if that would exceed the specified limit).//
<<<
!!!!!Revisions
<<<
2008.05.01 [2.0.0] added 'limit open tiddlers' feature (with safety check for tiddler in edit mode)
2008.04.06 [1.9.1] corrected 'limit' logic so that //last// N crumbs are shown instead of //first// N crumbs.  Also, added chkBreadcrumbsHideHomeLink
2008.04.04 [1.9.0] added chkBreadcrumbsReverse and chk/txtBreadcrumbsLimit
2008.03.29 [1.8.4] in displayTiddler(), get title from tiddler object (if needed).  Fixes errors caused when calling function passes a tiddler *object* instead of a tiddler *title*
2008.03.24 [1.8.3] include shadow tiddlers in breadcrumbs list.  Also changed settings so that "reordering" breadcrumbs is the default, instead of "trimming" the list
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.26 [1.8.2] documentation cleanup
2007.10.18 [1.8.1] in GetAreas(), use try/catch to avoid "Bad NPObject as private data" fatal error caused when embedded QuickTime player element is accessed by hasClass() function.
2007.10.02 [1.8.0] major documentation and code cleanup.  Moved config.breadCrumbs.* to config.macros.breadcrumbs.* to consolidate objects.  Also, fixed homeSeparator and crumbSeparator default handling.
2007.10.02 [1.7.0] added config.options.chkShowStartupBreadcrumbs option
2007.09.16 [1.6.1] in getAreas(), removed errant use of 'place' (was causing fatal error when creating default breadcrumbs display element).  Also, added chkCreateDefaultBreadcrumbs configuration setting to enable/disable automatic creation of a default breadcrumbs display.
2007.09.16 [1.6.0] re-wrote refresh() to enable multiple display instances, by finding elements with "breadCrumbs" classname.  Fallback to fixed ID (="breadCrumbs") is still used for backward-compatibility.  move rendering code from refresh() to separate render() function, and added definition for {{{<<breadCrumbs>>}}} macro to support embedding breadcrumbs displays in tiddler content.
2007.09.15 [1.5.9.1] updated documentation
2007.09.15 [1.5.9] defined homeSeparator (" | ") and crumbSeparator (" > ") as object properties so that they can be redefined as desired for different layouts (e.g., using 'newline' for the crumbSeparator will arrange crumbs in a column rather than a row.
2007.06.21 [1.5.8.1] in home(), return false to prevent IE from attempting to navigate away...
2007.05.26 [1.5.8] added support for {{{<<option chkReorderBreadcrumbs>>}}} to toggle trim vs. re-order behavior when visiting previously viewed tiddlers
2007.05.25 [1.5.7] added support for {{{<<option chkShowBreadcrumbs>>}}} to toggle //display// of breadcrumbs
2007.05.24 [1.5.6] in refresh(), remove non-existing tiddler titles from crumb list.  Also, hijack removeTiddler() so crumbs can be updated after tiddler is deleted.
2007.04.11 [1.5.5] added optional params to previousTiddler macro handler() to allow alternative label and tooltip text (instead of default "back")
2007.03.02 [1.5.4] in refresh(), for TW2.2, look for "storyDisplay" instead of "tiddlerDisplay" but keep fallback to "tiddlerDisplay" for TW2.1 or earlier
2007.02.24 [1.5.3] changed from hijack of onClickTiddlerLink to hijack of displayTiddler() so that ALL displayed tiddlers are recorded in the crumbs, including programmatically displayed tiddlers opened by macros, scripts, etc., (such as [[GotoPlugin]], among many others) in addition to those opened by clicks on links.
2007.02.24 [1.5.2.0] eliminated global space clutter by moving function and data declarations so they are contained inside config.breadCrumbs object.
2007.02.06 [1.5.1] added "previousTiddler" macro (for use in sidebar)
2007.02.05 [1.5.0] added "previousTiddler" toolbar command (aka, "back")
2006.08.04 [1.4.0.1] change spaces to tabs
2006.08.04 [1.4.0] modified from 1.4.0 distro: in refresh(), set {{{display:none/block}}} instead of {{{visibility:hidden/visible}}}.  In home(), check for valid crumbArea before setting style.
2006.08.02 [1.4.0] Fixed bug, the redefined onClickTiddlerLink_orig_breadCrumbs works incorrectly on IE
2006.07.20 [1.3.0] Runs compatibly with TW 2.1.0 (rev #403+)
2006.02.07 [1.2.0] change global array breadCrumbs to config.breadCrumbs by Eric's suggestion
2006.02.04 [1.1.0] JSLint checked
2006.02.01 [1.0.0] initial release
<<<
/***
|Name|BrightText|
|Source|http://www.TiddlyTools.com/#BrightText|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|CSS|
|Requires||
|Overrides||
|Description|adjust font colors for use with dark backgrounds|
***/

/* background images */
/* colors and borders */
a, .button { color:#ccf; }
a:hover, .button:hover { color:#fff; }

#breadCrumbs { color:#ccc; }
#breadCrumbs a { color:#ccf; }
#titleLine { color: #fff; }
#titleLine a { color: #009900; }
.siteMenu { color: #fff; border:0;  }
.siteMenu a, .siteMenu .button, .siteMenu .tiddlyLink { color: #ccf; }
.storyMenu { color: #fff; border:0; }
.storyMenu a, .storyMenu .button, .storyMenu .tiddlyLink { color: #ccf; }
/*
#mainMenu { color: #fff; }
#mainMenu .tiddlyLink { color: #def; }
#mainMenu .tiddlyLink:hover { color: #fff; }
#mainMenu .externalLink { color: #def; }
#mainMenu .externalLink:hover { color: #fff; }
#mainMenu .button, #mainMenu A { color: #def; }
#mainMenu .button:hover, #mainMenu A:hover { color: #fff; }
*/
#messageArea { color: #006; }
#messageArea a:link, #messageArea a:visited { color: #006; }
#messageArea a:hover { color: #f00; }
#messageArea a:active { color: #006; }
#popup { color: #000; }
#popup a { color: #006; }
#popup .viewer a { color: #ccf; }
#popup a:hover { color: #006; }
#popup .viewer a:hover { color: #fff; }
#popup hr { color: #666; }
.tabContents { color: #000; }
.tiddler .button { color: #ccf; }
.tiddler .button:hover { color: #fff; }
.tiddler .button:active { color: #fff; }
.title { color: #def; }
.subtitle { color: #89a; }
.toolbar { color: #aaa; }
.footer { color: #888; }
.selectedTiddler .footer { color: #ddd; }
.viewer { color: #fff; }
.viewer a:link, .viewer a:visited { color: #ccf; }
.viewer a:hover { color: #fff; }
.viewer .button { color: #def; }
.viewer .button:hover { color: #fff; }
.viewer th { color: #fff; }
.viewer td { color: #fff; }
.viewer code { color: #ccc; }
.viewer pre { color: #000; }
.viewer hr { color: #666; }
.viewer .highlight, .viewer .marked { color: #fff; }
.viewer .tabSelected { background-color: #002; color:#fff; border-color:#999; border-width:1px; padding-bottom:1px !important; }
.viewer .tabUnselected { background-color: transparent; color:#999; border-color:#666}
.viewer .tabContents { background-color: #002; color:#fff; border-color:#999; border-width:1px }
.tagging a, .tagged a, .tagging .button, .tagged .button  { color: #009; }
.highlight, .marked { color: #fff; }
.lowlight a { color: #009 !important; }
.editor { color: #402C74; }
.editorFooter { color: #aaa; }
.editorFooter A { color: #930; }
.editorFooter A:hover { color: #cf6; }
.editorFooter A:active { color: #fff; }
#licensePanel A { color: #66f; }
#licensePanel A:hover { color: #fff; }
#licensePanel A:active { color: #fff; }
.errorNoSuchMacro { color: #ff0; }
.zoomer { color: #fff; }

.mouseover 
	{color:#336 !important;}
.mouseover a
	{color:#336 !important;}
.selected .mouseover
	{color:#ccf !important;}
.selected .mouseover .button, .selected .mouseover a
	{color:#ccf !important;}

.floatingPanel .button,
.floatingPanel a:link,
.floatingPanel a:hover,
.floatingPanel a:visited,
.selected .floatingPanel .button,
.selected .floatingPanel a:link,
.selected .floatingPanel a:hover,
.selected .floatingPanel a:visited,
.toolbar .floatingPanel .button,
.toolbar .floatingPanel a:link,
.toolbar .floatingPanel a:hover,
.toolbar .floatingPanel a:visited,
.viewer .floatingPanel .button,
.viewer .floatingPanel a:link,
.viewer .floatingPanel a:hover,
.viewer .floatingPanel a:visited {
	color: #009 !important;
}
.floatingPanel .viewer .button,
.floatingPanel .viewer a:link,
.floatingPanel .viewer a:visited {
	color: #ccf !important;
}
.floatingPanel a:hover,
.viewer .floatingPanel a:hover {
	color: #fff !important;
}
/***
----
***/
/*{{{*/
.attachPanel a, #importPanel a, #exportpanel a,
.attachPanel .button, #importPanel .button, #exportpanel .button,
.attachPanel .tiddlyLinkExisting, #importPanel .tiddlyLinkExisting, #exportpanel .tiddlyLinkExisting,
.attachPanel .tiddlyLinkNonExisting, #importPanel .tiddlyLinkNonExisting, #exportpanel .tiddlyLinkNonExisting,
.tab .button, .tab A,
.tab .tiddlyLinkExisting, .tab .tiddlyLinkNonExisting
	{ color:#009 !important; }
#sidebarOptions, #sidebarOptions .sliderPanel
	{ color: #fff; }
#sidebarOptions .button, #sidebarOptions A,
#sidebarOptions .tiddlyLinkExisting, #sidebarOptions .tiddlyLinkNonExisting,
#sidebarOptions .sliderPanel .button, #sidebarOptions .sliderPanel A,
#sidebarOptions .sliderPanel .tiddlyLinkExisting, #sidebarOptions .sliderPanel .tiddlyLinkNonExisting
	{ color: #def; }
#sidebarTabs, #sidebarTabs .sliderPanel, #sidebarTabs .tabContents
	{ color: #fff; }
#sidebarTabs .tabContents *[class="TOCList"] /* MOZ ONLY */
	{ color:#fff !important; }
#sidebarTabs .button, /* #sidebarTabs A, */
#sidebarTabs .tiddlyLinkExisting, #sidebarTabs .tiddlyLinkNonExisting
	{ color: #def; }
.menubox
	{ color:#fff; border-color:#999; }
.menubox .button, .menubox .tiddlyLinkExisting, .menubox .tiddlyLinkNonExisting
	{ color:#99f !important; }
.QOTD
	{ color:#fff !important; background:inherit !important; }
.groupbox, .groupbox table, .groupbox tbody, .groupbox tr, .groupbox td
	{ color:#000; }
.groupbox a, .groupbox .button, .groupbox .tiddlyLinkExisting, .groupbox .tiddlyLinkNonExisting
	{ color:#009 !important; }
.outline
	{ border-color:#999; }
.floatingPanel, .floatingPanel table, .floatingPanel tbody, .floatingPanel tr, .floatingPanel td
	{ color:#000; }
.toolbar {color:#336 !important;}
.toolbar a {color:#336 !important;}
.selected .toolbar { color:#999 !important; }
.selected .toolbar a {color:#ccf !important;}
.selected .toolbar a:hover {color:#fff !important; }
/*}}}*/
<!--{{{-->
<!--
|Name|CDEditTemplate|
|Source|http://www.TiddlyTools.com/#CDEditTemplate|
|Version||
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands|
|Overrides||
|Description|custom version of edit template used when tiddler is tagged with "CD"|
-->
<span class='toolbar' macro='toolbar +saveTiddler -cancelTiddler ! copyTiddler deleteTiddler ! fields '></span>
<div class='title' macro='view title'></div>
<div style='clear:both'></div>
<div class='editor' macro='edit title'></div>
<div class='borderless viewer'><span class='small'>album title:</span></div>
<div class='editor' macro='edit albumtitle'></div>
<table class='borderless viewer'><tr>
<td style='width:50%' style='width:100%'>
	<div class='small'>artist:</div>
	<div class='editor' macro='edit artist'></div>
</td><td style='width:10%'>
	<div class='small'>year:</div>
	<div class='editor' macro='edit year'></div>
</td><td style='width:20%'>
	<div class='small'>genre:</div>
	<div class='editor' macro='select genre rows:1 width:100% allowBlank allowOther +CDGenreList allowEdit'></div>
</td><td style='width:20%'>
	<div class='small'>media type:</div>
	<div class='editor' macro='select mediatype rows:1 width:100% allowBlank allowOther cd dvd mp3 cassette lp'></div>
</td></tr></table>
<table class='borderless viewer' style='width:100%'><tr>
<td style='width:33%'>
	<div class='small'>cover image URL (jpg/gif):</div>
	<div class='editor' macro='edit cover'></div>
</td><td style='width:33%'>
	<div class='small'>sample URL (mp3):</div>
	<div class='editor' macro='edit sample'></div>
</td><td style='width:33%'>
	<div class='small'>website URL (html):</div>
	<div class='editor' macro='edit website'></div>
</td></tr></table>
<div class='small borderless viewer'><span class='small'>notes (text):</span></div>
<div class='editor' macro='edit text 10'></div>
<div class='editor' macro='edit tags'></div>
<div class='toolbar editorFooter' style='text-align:left !important;float:left !important'>
	<span macro='message views.editor.tagPrompt'></span>
	<span macro='tagChooser'></span>
</div>
<div style='clear:both'></div>
<!--}}}-->
----
|borderless|k
|1 [[Candlelight|http://www.TiddlyTools.com/vlh/MFSB4/Candlelight.m3u]] (7:50) | &nbsp;&nbsp; |5 [[Fuego|http://www.TiddlyTools.com/vlh/MFSB4/Fuego.m3u]] (7:40) | |
|2 [[Kindling|http://www.TiddlyTools.com/vlh/MFSB4/Kindling.m3u]] (8:17) | |6 [[Flare|http://www.TiddlyTools.com/vlh/MFSB4/Flare.m3u]] (6:46) |
|3 [[Hearth|http://www.TiddlyTools.com/vlh/MFSB4/Hearth.m3u]] (7:14) | |7 [[Cold Fusion|http://www.TiddlyTools.com/vlh/MFSB4/ColdFusion.m3u]] (7:57) |
|4 [[Magma|http://www.TiddlyTools.com/vlh/MFSB4/Magma.m3u]] (8:35) | |8 [[Embers|http://www.TiddlyTools.com/vlh/MFSB4/Embers.m3u]] (7:52) |

{{fine block{
//All songs performed by Vernon L Hohenstein, except drum sequencing on "Kindling" by Eric Shulman.
Recorded at The Nano Studio, Sunnyvale, California USA.  Production/Sound Engineering by Eric Shulman.
(c) 2005 ''Made in U.S.A - all rights reserved'' Cover Photo: Yosemite National Park (c) 2002.//}}}
<!--{{{-->
<!--
|Name|CDViewTemplate|
|Source|http://www.TiddlyTools.com/#CDViewTemplate|
|Version||
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands|
|Overrides||
|Description|custom version of view template used when tiddler is tagged with "CD"|
-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></span>
<span class='title'>
	<span class='floatleft' macro='tiddlerIcons' style='cursor:auto !important;'></span>
	<span macro='view title'></span>
</span>
<span class='subtitle'>
	<span style='white-space:nowrap' macro='view modified date [[DDD, MMM DDth YYYY]]'></span>
</span>
<div class='tagClear'></div>
<div class='viewer'>
	<div class='menubox' style='float:left;margin:1em' macro='wikify [img[%0]] cover@here'></div> 
	<div class='menubox'>
		<div class='big' macro='view albumtitle wikified'></div> 
		<div><span macro='view artist wikified'></span> - &copy; <span macro='view year wikified'></span></div>
	</div>
	<div>
		<span class='small'><i>genre:</i></span>
		<span macro='view genre wikified'></span>
	</div>
	<div>
		<span class='small'><i>media type:</i></span>
		<span macro='view mediatype wikified'></span>
	</div>
	<div><span class='small'><i>sample:</i> </span><span macro='view sample wikified'></span></div>
	<div><span class='small'><i>website:</i> </span><span macro='view website wikified'></span></div>
	<div class='small' macro='view text wikified'></div>
</div>
<div class='tagClear'></div>
<!--}}}-->
/***
|Name|CalendarPlugin|
|Source|http://www.TiddlyTools.com/#CalendarPlugin|
|Version|2008.02.27|
|Author|Eric Shulman|
|Original Author|SteveRumsby|
|License|unknown|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|display monthly and yearly calendars|

NOTE: For enhanced date display (including popups), you must also install [[DatePlugin]]
!!!!!Usage:
<<<
|{{{<<calendar>>}}}|Produce a full-year calendar for the current year|
|{{{<<calendar year>>}}}|Produce a full-year calendar for the given year|
|{{{<<calendar year month>>}}}|Produce a one-month calendar for the given month and year|
|{{{<<calendar thismonth>>}}}|Produce a one-month calendar for the current month|
|{{{<<calendar lastmonth>>}}}|Produce a one-month calendar for last month|
|{{{<<calendar nextmonth>>}}}|Produce a one-month calendar for next month|
<<<
!!!!!Configuration:
<<<
|''First day of week:''<br>{{{config.options.txtCalFirstDay}}}|<<option txtCalFirstDay>>|(Monday = 0, Sunday = 6)|
|''First day of weekend:''<br>{{{config.options.txtCalStartOfWeekend}}}|<<option txtCalStartOfWeekend>>|(Monday = 0, Sunday = 6)|

<<option chkDisplayWeekNumbers>> Display week numbers //(note: Monday will be used as the start of the week)//
|''Week number display format:''<br>{{{config.options.txtWeekNumberDisplayFormat }}}|<<option txtWeekNumberDisplayFormat >>|
|''Week number link format:''<br>{{{config.options.txtWeekNumberLinkFormat }}}|<<option txtWeekNumberLinkFormat >>|
<<<
!!!!!Revisions
<<<
2008.02.27: in handler(), DON'T set hard-coded default date format, so that *customized* value (pre-defined in config.macros.calendar.journalDateFmt is used.
2008.02.17: in createCalendarYear(), fix next/previous year calculation (use parseInt() to convert to numeric value).  Also, use journalDateFmt for date linking when NOT using [[DatePlugin]].
2008.02.16: in createCalendarDay(), week numbers now created as TiddlyLinks, allowing quick creation/navigation to 'weekly' journals (based on request from Kashgarinn)
2008.01.08: in createCalendarMonthHeader(), "month year" heading is now created as TiddlyLink, allowing quick creation/navigation to 'month-at-a-time' journals
2007.11.30: added "return false" to onclick handlers (prevent IE from opening blank pages)
2006.08.23: added handling for weeknumbers (code supplied by Martin Budden (see "wn**" comment marks).  Also, incorporated updated by Jeremy Sheeley to add caching for reminders (see [[ReminderMacros]], if installed)
2005.10.30: in config.macros.calendar.handler(), use "tbody" element for IE compatibility.  Also, fix year calculation for IE's getYear() function (which returns '2005' instead of '105'). Also, in createCalendarDays(), use showDate() function (see [[DatePlugin]], if installed) to render autostyled date with linked popup.  Updated calendar stylesheet definition: use .calendar class-specific selectors, add text centering and margin settings
2006.05.29: added journalDateFmt handling
<<<
***/
/***
!!!!!Code section:
***/
//{{{
version.extensions.calendar = { major: 0, minor: 6, revision: 0, date: new Date(2008, 2, 27)};

if(config.options.txtCalFirstDay == undefined)
  config.options.txtCalFirstDay = 0;
if(config.options.txtCalStartOfWeekend == undefined)
  config.options.txtCalStartOfWeekend = 5;
if(config.options.chkDisplayWeekNumbers == undefined)//wn**
  config.options.chkDisplayWeekNumbers = false;
if(config.options.chkDisplayWeekNumbers)
  config.options.txtCalFirstDay = 0;
if(config.options.txtWeekNumberDisplayFormat == undefined)//wn**
  config.options.txtWeekNumberDisplayFormat = "w0WW";
if(config.options.txtWeekNumberLinkFormat == undefined)//wn**
  config.options.txtWeekNumberLinkFormat = "YYYY-w0WW";

config.macros.calendar = {};
config.macros.calendar.monthnames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
config.macros.calendar.daynames = ["M", "T", "W", "T", "F", "S", "S"];
config.macros.calendar.weekendbg = "#c0c0c0";
config.macros.calendar.monthbg = "#e0e0e0";
config.macros.calendar.holidaybg = "#ffc0c0";
config.macros.calendar.journalDateFmt = "DD MMM YYYY";
config.macros.calendar.monthdays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
config.macros.calendar.holidays = [ ]; // Not sure this is required anymore - use reminders instead
//}}}
//{{{
function calendarIsHoliday(date) // Is the given date a holiday?
{
	var longHoliday = date.formatString("0DD/0MM/YYYY");
	var shortHoliday = date.formatString("0DD/0MM");
	for(var i = 0; i < config.macros.calendar.holidays.length; i++) {
		if(config.macros.calendar.holidays[i] == longHoliday || config.macros.calendar.holidays[i] == shortHoliday)
			return true;
	}
	return false;
}
//}}}
//{{{
config.macros.calendar.handler = function(place,macroName,params) {
	var calendar = createTiddlyElement(place, "table", null, "calendar", null);
	var tbody = createTiddlyElement(calendar, "tbody", null, null, null);
	var today = new Date();
	var year = today.getYear();
	if (year<1900) year+=1900;

 	// get format for journal link by reading from SideBarOptions (ELS 5/29/06 - based on suggestion by Martin Budden)
	var text = store.getTiddlerText("SideBarOptions");
	var re = new RegExp("<<(?:newJournal)([^>]*)>>","mg"); var fm = re.exec(text);
	if (fm && fm[1]!=null) { var pa=fm[1].readMacroParams(); if (pa[0]) this.journalDateFmt = pa[0]; }

	if (params[0] == "thismonth") {
		cacheReminders(new Date(year, today.getMonth(), 1, 0, 0), 31);
		createCalendarOneMonth(tbody, year, today.getMonth());
	} 
	else if (params[0] == "lastmonth") {
		var month = today.getMonth()-1; if (month==-1) { month=11; year--; }
		cacheReminders(new Date(year, month, 1, 0, 0), 31);
		createCalendarOneMonth(tbody, year, month);
	}
	else if (params[0] == "nextmonth") {
		var month = today.getMonth()+1; if (month>11) { month=0; year++; }
		cacheReminders(new Date(year, month, 1, 0, 0), 31);
		createCalendarOneMonth(tbody, year, month);
	} else {
		if (params[0]) year = params[0];
		if(params[1]) {
			cacheReminders(new Date(year, params[1]-1, 1, 0, 0), 31);
			createCalendarOneMonth(tbody, year, params[1]-1);
		} else {
			cacheReminders(new Date(year, 0, 1, 0, 0), 366);
			createCalendarYear(tbody, year);
		}
	}
	window.reminderCacheForCalendar = null;
}
//}}}
//{{{
//This global variable is used to store reminders that have been cached
//while the calendar is being rendered.  It will be renulled after the calendar is fully rendered.
window.reminderCacheForCalendar = null;
//}}}
//{{{
function cacheReminders(date, leadtime)
{
	if (window.findTiddlersWithReminders == null) return;
	window.reminderCacheForCalendar = {};
	var leadtimeHash = [];
	leadtimeHash [0] = 0;
	leadtimeHash [1] = leadtime;
	var t = findTiddlersWithReminders(date, leadtimeHash, null, 1);
	for(var i = 0; i < t.length; i++) {
		//just tag it in the cache, so that when we're drawing days, we can bold this one.
		window.reminderCacheForCalendar[t[i]["matchedDate"]] = "reminder:" + t[i]["params"]["title"]; 
	}
}
//}}}
//{{{
function createCalendarOneMonth(calendar, year, mon)
{
	var row = createTiddlyElement(calendar, "tr", null, null, null);
	createCalendarMonthHeader(calendar, row, config.macros.calendar.monthnames[mon] + " " + year, true, year, mon);
	row = createTiddlyElement(calendar, "tr", null, null, null);
	createCalendarDayHeader(row, 1);
	createCalendarDayRowsSingle(calendar, year, mon);
}
//}}}
//{{{
function createCalendarMonth(calendar, year, mon)
{
	var row = createTiddlyElement(calendar, "tr", null, null, null);
	createCalendarMonthHeader(calendar, row, config.macros.calendar.monthnames[mon] + " " + year, false, year, mon);
	row = createTiddlyElement(calendar, "tr", null, null, null);
	createCalendarDayHeader(row, 1);
	createCalendarDayRowsSingle(calendar, year, mon);
}
//}}}
//{{{
function createCalendarYear(calendar, year)
{
	var row;
	row = createTiddlyElement(calendar, "tr", null, null, null);
	var back = createTiddlyElement(row, "td", null, null, null);
	var backHandler = function() {
		removeChildren(calendar);
		createCalendarYear(calendar, parseInt(year)-1);
		return false; // consume click
	};
	createTiddlyButton(back, "<", "Previous year", backHandler);
	back.align = "center";
	var yearHeader = createTiddlyElement(row, "td", null, "calendarYear", year);
	yearHeader.align = "center";
	yearHeader.setAttribute("colSpan",config.options.chkDisplayWeekNumbers?22:19);//wn**
	var fwd = createTiddlyElement(row, "td", null, null, null);
	var fwdHandler = function() {
		removeChildren(calendar);
		createCalendarYear(calendar, parseInt(year)+1);
		return false; // consume click
	};
	createTiddlyButton(fwd, ">", "Next year", fwdHandler);
	fwd.align = "center";
	createCalendarMonthRow(calendar, year, 0);
	createCalendarMonthRow(calendar, year, 3);
	createCalendarMonthRow(calendar, year, 6);
	createCalendarMonthRow(calendar, year, 9);
}
//}}}
//{{{
function createCalendarMonthRow(cal, year, mon)
{
	var row = createTiddlyElement(cal, "tr", null, null, null);
	createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon], false, year, mon);
	createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon+1], false, year, mon);
	createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon+2], false, year, mon);
	row = createTiddlyElement(cal, "tr", null, null, null);
	createCalendarDayHeader(row, 3);
	createCalendarDayRows(cal, year, mon);
}
//}}}
//{{{
function createCalendarMonthHeader(cal, row, name, nav, year, mon)
{
	var month;
	if (nav) {
		var back = createTiddlyElement(row, "td", null, null, null);
		back.align = "center";
		back.style.background = config.macros.calendar.monthbg;

		var backMonHandler = function() {
			var newyear = year;
			var newmon = mon-1;
			if(newmon == -1) { newmon = 11; newyear = newyear-1;}
			removeChildren(cal);
			cacheReminders(new Date(newyear, newmon , 1, 0, 0), 31);
			createCalendarOneMonth(cal, newyear, newmon);
			return false; // consume click
		};
		createTiddlyButton(back, "<", "Previous month", backMonHandler);
		month = createTiddlyElement(row, "td", null, "calendarMonthname")
		createTiddlyLink(month,name,true);
		month.setAttribute("colSpan", config.options.chkDisplayWeekNumbers?6:5);//wn**
		var fwd = createTiddlyElement(row, "td", null, null, null);
		fwd.align = "center";
		fwd.style.background = config.macros.calendar.monthbg; 

		var fwdMonHandler = function() {
			var newyear = year;
			var newmon = mon+1;
			if(newmon == 12) { newmon = 0; newyear = newyear+1;}
			removeChildren(cal);
			cacheReminders(new Date(newyear, newmon , 1, 0, 0), 31);
			createCalendarOneMonth(cal, newyear, newmon);
			return false; // consume click
		};
		createTiddlyButton(fwd, ">", "Next month", fwdMonHandler);
	} else {
		month = createTiddlyElement(row, "td", null, "calendarMonthname", name)
		month.setAttribute("colSpan",config.options.chkDisplayWeekNumbers?8:7);//wn**
	}
	month.align = "center";
	month.style.background = config.macros.calendar.monthbg;
}
//}}}
//{{{
function createCalendarDayHeader(row, num)
{
	var cell;
	for(var i = 0; i < num; i++) {
		if (config.options.chkDisplayWeekNumbers) createTiddlyElement(row, "td");//wn**
		for(var j = 0; j < 7; j++) {
			var d = j + (config.options.txtCalFirstDay - 0);
			if(d > 6) d = d - 7;
			cell = createTiddlyElement(row, "td", null, null, config.macros.calendar.daynames[d]);
			if(d == (config.options.txtCalStartOfWeekend-0) || d == (config.options.txtCalStartOfWeekend-0+1))
				cell.style.background = config.macros.calendar.weekendbg;
		}
	}
}
//}}}
//{{{
function createCalendarDays(row, col, first, max, year, mon) {
	var i;
	if (config.options.chkDisplayWeekNumbers){
		if (first<=max) {
			var ww = new Date(year,mon,first);
			var td=createTiddlyElement(row, "td");//wn**
			var link=createTiddlyLink(td,ww.formatString(config.options.txtWeekNumberLinkFormat),false);
			link.appendChild(document.createTextNode(ww.formatString(config.options.txtWeekNumberDisplayFormat)));
		}
		else createTiddlyElement(row, "td", null, null, null);//wn**
	}
	for(i = 0; i < col; i++)
		createTiddlyElement(row, "td", null, null, null);
	var day = first;
	for(i = col; i < 7; i++) {
		var d = i + (config.options.txtCalFirstDay - 0);
		if(d > 6) d = d - 7;
		var daycell = createTiddlyElement(row, "td", null, null, null);
		var isaWeekend = ((d == (config.options.txtCalStartOfWeekend-0) || d == (config.options.txtCalStartOfWeekend-0+1))? true:false);
		if(day > 0 && day <= max) {
			var celldate = new Date(year, mon, day);
			// ELS 2005.10.30: use <<date>> macro's showDate() function to create popup
			// ELS 5/29/06 - use journalDateFmt 
			if (window.showDate)
				showDate(daycell,celldate,"popup","DD",config.macros.calendar.journalDateFmt,true, isaWeekend);
			else {
				if(isaWeekend) daycell.style.background = config.macros.calendar.weekendbg;
				var title = celldate.formatString(config.macros.calendar.journalDateFmt);
				if(calendarIsHoliday(celldate))
					daycell.style.background = config.macros.calendar.holidaybg;
				if(window.findTiddlersWithReminders == null) {
					var link = createTiddlyLink(daycell, title, false);
					link.appendChild(document.createTextNode(day));
				} else
					var button = createTiddlyButton(daycell, day, title, onClickCalendarDate);
			}
		}
		day++;
	}
}
//}}}
//{{{
// We've clicked on a day in a calendar - create a suitable pop-up of options.
// The pop-up should contain:
//  * a link to create a new entry for that date
//  * a link to create a new reminder for that date
//  * an <hr>
//  * the list of reminders for that date
// NOTE: The following code is only used when [[DatePlugin]] is not present
function onClickCalendarDate(e)
{
	var button = this;
	var date = button.getAttribute("title");
	var dat = new Date(date.substr(6,4), date.substr(3,2)-1, date.substr(0, 2));

	date = dat.formatString(config.macros.calendar.journalDateFmt);
	var popup = createTiddlerPopup(this);
	popup.appendChild(document.createTextNode(date));
	var newReminder = function() {
		var t = store.getTiddlers(date);
		displayTiddler(null, date, 2, null, null, false, false);
		if(t) {
			document.getElementById("editorBody" + date).value += "\n<<reminder day:" + dat.getDate() +
				" month:" + (dat.getMonth()+1) + " year:" + (dat.getYear()+1900) + " title: >>";
		} else {
			document.getElementById("editorBody" + date).value = "<<reminder day:" + dat.getDate() +
				" month:" + (dat.getMonth()+1) +" year:" + (dat.getYear()+1900) + " title: >>";
		}
		return false; // consume click
	};
	var link = createTiddlyButton(popup, "New reminder", null, newReminder); 
	popup.appendChild(document.createElement("hr"));
	var t = findTiddlersWithReminders(dat, [0,14], null, 1);
	for(var i = 0; i < t.length; i++) {
		link = createTiddlyLink(popup, t[i].tiddler, false);
		link.appendChild(document.createTextNode(t[i].tiddler));
	}
	return false; // consume click
}
//}}}
//{{{
function calendarMaxDays(year, mon)
{
	var max = config.macros.calendar.monthdays[mon];
	if(mon == 1 && (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) max++;
	return max;
}
//}}}
//{{{
function createCalendarDayRows(cal, year, mon)
{
	var row = createTiddlyElement(cal, "tr", null, null, null);
	var first1 = (new Date(year, mon, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
	if(first1 < 0) first1 = first1 + 7;
	var day1 = -first1 + 1;
	var first2 = (new Date(year, mon+1, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
	if(first2 < 0) first2 = first2 + 7;
	var day2 = -first2 + 1;
	var first3 = (new Date(year, mon+2, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
	if(first3 < 0) first3 = first3 + 7;
	var day3 = -first3 + 1;

	var max1 = calendarMaxDays(year, mon);
	var max2 = calendarMaxDays(year, mon+1);
	var max3 = calendarMaxDays(year, mon+2);

	while(day1 <= max1 || day2 <= max2 || day3 <= max3) {
		row = createTiddlyElement(cal, "tr", null, null, null);
		createCalendarDays(row, 0, day1, max1, year, mon); day1 += 7;
		createCalendarDays(row, 0, day2, max2, year, mon+1); day2 += 7;
		createCalendarDays(row, 0, day3, max3, year, mon+2); day3 += 7;
	}
}
//}}}
//{{{
function createCalendarDayRowsSingle(cal, year, mon)
{
	var row = createTiddlyElement(cal, "tr", null, null, null);
	var first1 = (new Date(year, mon, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
	if(first1 < 0) first1 = first1+ 7;
	var day1 = -first1 + 1;
	var max1 = calendarMaxDays(year, mon);
	while(day1 <= max1) {
		row = createTiddlyElement(cal, "tr", null, null, null);
		createCalendarDays(row, 0, day1, max1, year, mon); day1 += 7;
	}
}
//}}}
//{{{
setStylesheet(".calendar, .calendar table, .calendar th, .calendar tr, .calendar td { text-align:center; } .calendar, .calendar a { margin:0px !important; padding:0px !important; }", "calendarStyles");
//}}}
// // override cookie settings for CalendarPlugin:
//{{{
config.options.txtCalFirstDay=6;
config.options.txtCalStartOfWeekend=5;
//}}}

// // override internal default settings for CalendarPlugin:
//{{{
config.macros.calendar.journalDateFmt="DDD MMM 0DD YYYY";
//}}}
/***
|Name|CheckboxPlugin|
|Source|http://www.TiddlyTools.com/#CheckboxPlugin|
|Documentation|http://www.TiddlyTools.com/#CheckboxPluginInfo|
|Version|2.4.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Add checkboxes to your tiddler content|
This plugin extends the TiddlyWiki syntax to allow definition of checkboxes that can be embedded directly in tiddler content.  Checkbox states are preserved by:
* by setting/removing tags on specified tiddlers,
* or, by setting custom field values on specified tiddlers,
* or, by saving to a locally-stored cookie ID,
* or, automatically modifying the tiddler content (deprecated)
When an ID is assigned to the checkbox, it enables direct programmatic access to the checkbox DOM element, as well as creating an entry in TiddlyWiki's config.options[ID] internal data.  In addition to tracking the checkbox state, you can also specify custom javascript for programmatic initialization and onClick event handling for any checkbox, so you can provide specialized side-effects in response to state changes.
!!!!!Documentation
>see [[CheckboxPluginInfo]]
!!!!!Revisions
<<<
2008.01.08 [*.*.*] plugin size reduction: documentation moved to [[CheckboxPluginInfo]]
2008.01.05 [2.4.0] set global "window.place" to current checkbox element when processing checkbox clicks.  This allows init/beforeClick/afterClick handlers to reference RELATIVE elements, including using "story.findContainingTiddler(place)".  Also, wrap handlers in "function()" so "return" can be used within handler code.
|please see [[CheckboxPluginInfo]] for additional revision details|
2005.12.07 [0.9.0] initial BETA release
<<<
!!!!!Code
***/
//{{{
version.extensions.CheckboxPlugin = {major: 2, minor: 4, revision:0 , date: new Date(2008,1,5)};
//}}}
//{{{
config.checkbox = { refresh: { tagged:true, tagging:true, container:true } };
config.formatters.push( {
	name: "checkbox",
	match: "\\[[xX_ ][\\]\\=\\(\\{]",
	lookahead: "\\[([xX_ ])(=[^\\s\\(\\]{]+)?(\\([^\\)]*\\))?({[^}]*})?({[^}]*})?({[^}]*})?\\]",
	handler: function(w) {
		var lookaheadRegExp = new RegExp(this.lookahead,"mg");
		lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = lookaheadRegExp.exec(w.source)
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			// get params
			var checked=(lookaheadMatch[1].toUpperCase()=="X");
			var id=lookaheadMatch[2];
			var target=lookaheadMatch[3];
			if (target) target=target.substr(1,target.length-2).trim(); // trim off parentheses
			var fn_init=lookaheadMatch[4];
			var fn_clickBefore=lookaheadMatch[5];
			var fn_clickAfter=lookaheadMatch[6];
			var tid=story.findContainingTiddler(w.output);  if (tid) tid=tid.getAttribute("tiddler");
			var srctid=w.tiddler?w.tiddler.title:null;
			config.macros.checkbox.create(w.output,tid,srctid,w.matchStart+1,checked,id,target,config.checkbox.refresh,fn_init,fn_clickBefore,fn_clickAfter);
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
	}
} );
config.macros.checkbox = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if(!(tiddler instanceof Tiddler)) { // if no tiddler passed in try to find one
			var here=story.findContainingTiddler(place);
			if (here) tiddler=store.getTiddler(here.getAttribute("tiddler"))
		}
		var srcpos=0; // "inline X" not applicable to macro syntax
		var target=params.shift(); if (!target) target="";
		var defaultState=params[0]=="checked"; if (defaultState) params.shift();
		var id=params.shift(); if (id && !id.length) id=null;
		var fn_init=params.shift(); if (fn_init && !fn_init.length) fn_init=null;
		var fn_clickBefore=params.shift();
		if (fn_clickBefore && !fn_clickBefore.length) fn_clickBefore=null;
		var fn_clickAfter=params.shift();
		if (fn_clickAfter && !fn_clickAfter.length) fn_clickAfter=null;
		var refresh={ tagged:true, tagging:true, container:false };
		this.create(place,tiddler.title,tiddler.title,0,defaultState,id,target,refresh,fn_init,fn_clickBefore,fn_clickAfter);
	},
	create: function(place,tid,srctid,srcpos,defaultState,id,target,refresh,fn_init,fn_clickBefore,fn_clickAfter) {
		// create checkbox element
		var c = document.createElement("input");
		c.setAttribute("type","checkbox");
		c.onclick=this.onClickCheckbox;
		c.srctid=srctid; // remember source tiddler
		c.srcpos=srcpos; // remember location of "X"
		c.container=tid; // containing tiddler (may be null if not in a tiddler)
		c.tiddler=tid; // default target tiddler 
		c.refresh = {};
		c.refresh.container = refresh.container;
		c.refresh.tagged = refresh.tagged;
		c.refresh.tagging = refresh.tagging;
		place.appendChild(c);
		// set default state
		c.checked=defaultState;
		// track state in config.options.ID
		if (id) {
			c.id=id.substr(1); // trim off leading "="
			if (config.options[c.id]!=undefined)
				c.checked=config.options[c.id];
			else
				config.options[c.id]=c.checked;
		}
		// track state in (tiddlername|tagname) or (fieldname@tiddlername)
		if (target) {
			var pos=target.indexOf("@");
			if (pos!=-1) {
				c.field=pos?target.substr(0,pos):"checked"; // get fieldname (or use default "checked")
				c.tiddler=target.substr(pos+1); // get specified tiddler name (if any)
				if (!c.tiddler || !c.tiddler.length) c.tiddler=tid; // if tiddler not specified, default == container
				if (store.getValue(c.tiddler,c.field)!=undefined)
					c.checked=(store.getValue(c.tiddler,c.field)=="true"); // set checkbox from saved state
			} else {
				var pos=target.indexOf("|"); if (pos==-1) var pos=target.indexOf(":");
				c.tag=target;
				if (pos==0) c.tag=target.substr(1); // trim leading "|" or ":"
				if (pos>0) { c.tiddler=target.substr(0,pos); c.tag=target.substr(pos+1); }
				if (!c.tag.length) c.tag="checked";
				var t=store.getTiddler(c.tiddler);
				if (t && t.tags)
					c.checked=t.isTagged(c.tag); // set checkbox from saved state
			}
		}
		// trim off surrounding { and } delimiters from init/click handlers
		if (fn_init) c.fn_init="(function(){"+fn_init.trim().substr(1,fn_init.length-2)+"})()";
		if (fn_clickBefore) c.fn_clickBefore="(function(){"+fn_clickBefore.trim().substr(1,fn_clickBefore.length-2)+"})()";
		if (fn_clickAfter) c.fn_clickAfter="(function(){"+fn_clickAfter.trim().substr(1,fn_clickAfter.length-2)+"})()";
		c.init=true; c.onclick(); c.init=false; // compute initial state and save in tiddler/config/cookie
	},
	onClickCheckbox: function(event) {
		window.place=this;
		if (this.init && this.fn_init) // custom function hook to set initial state (run only once)
			{ try { eval(this.fn_init); } catch(e) { displayMessage("Checkbox init error: "+e.toString()); } }
		if (!this.init && this.fn_clickBefore) // custom function hook to override changes in checkbox state
			{ try { eval(this.fn_clickBefore) } catch(e) { displayMessage("Checkbox onClickBefore error: "+e.toString()); } }
		if (this.id)
			// save state in config AND cookie (only when ID starts with 'chk')
			{ config.options[this.id]=this.checked; if (this.id.substr(0,3)=="chk") saveOptionCookie(this.id); }
		if (this.srctid && this.srcpos>0 && (!this.id || this.id.substr(0,3)!="chk") && !this.tag && !this.field) {
			// save state in tiddler content only if not using cookie, tag or field tracking
			var t=store.getTiddler(this.srctid); // put X in original source tiddler (if any)
			if (t && this.checked!=(t.text.substr(this.srcpos,1).toUpperCase()=="X")) { // if changed
				t.set(null,t.text.substr(0,this.srcpos)+(this.checked?"X":"_")+t.text.substr(this.srcpos+1),null,null,t.tags);
				if (!story.isDirty(t.title)) story.refreshTiddler(t.title,null,true);
				store.setDirty(true);
			}
		}
		if (this.field) {
			if (this.checked && !store.tiddlerExists(this.tiddler))
				store.saveTiddler(this.tiddler,this.tiddler,"",config.options.txtUserName,new Date());
			// set the field value in the target tiddler
			store.setValue(this.tiddler,this.field,this.checked?"true":"false");
			// DEBUG: displayMessage(this.field+"@"+this.tiddler+" is "+this.checked);
		}
		if (this.tag) {
			if (this.checked && !store.tiddlerExists(this.tiddler))
				store.saveTiddler(this.tiddler,this.tiddler,"",config.options.txtUserName,new Date());
			var t=store.getTiddler(this.tiddler);
			if (t) {
				var tagged=(t.tags && t.tags.indexOf(this.tag)!=-1);
				if (this.checked && !tagged) { t.tags.push(this.tag); store.setDirty(true); }
				if (!this.checked && tagged) { t.tags.splice(t.tags.indexOf(this.tag),1); store.setDirty(true); }
			}
			// if tag state has been changed, update display of corresponding tiddlers (unless they are in edit mode...)
			if (this.checked!=tagged) {
				if (this.refresh.tagged) {
					if (!story.isDirty(this.tiddler)) // the TAGGED tiddler in view mode
						story.refreshTiddler(this.tiddler,null,true); 
					else // the TAGGED tiddler in edit mode (with tags field)
						config.macros.checkbox.refreshEditorTagField(this.tiddler,this.tag,this.checked);
				}
				if (this.refresh.tagging)
					if (!story.isDirty(this.tag)) story.refreshTiddler(this.tag,null,true); // the TAGGING tiddler
			}
		}
		if (!this.init && this.fn_clickAfter) // custom function hook to react to changes in checkbox state
			{ try { eval(this.fn_clickAfter) } catch(e) { displayMessage("Checkbox onClickAfter error: "+e.toString()); } }
		// refresh containing tiddler (but not during initial rendering, or we get an infinite loop!) (and not when editing container)
		if (!this.init && this.refresh.container && this.container!=this.tiddler)
			if (!story.isDirty(this.container)) story.refreshTiddler(this.container,null,true); // the tiddler CONTAINING the checkbox
		return true;
	},
	refreshEditorTagField: function(title,tag,set) {
		var tagfield=story.getTiddlerField(title,"tags");
		if (!tagfield||tagfield.getAttribute("edit")!="tags") return; // if no tags field in editor (i.e., custom template)
		var tags=tagfield.value.readBracketedList();
		if (tags.contains(tag)==set) return; // if no change needed
		if (set) tags.push(tag); // add tag
		else tags.splice(tags.indexOf(tag),1); // remove tag
		for (var t=0;t<tags.length;t++) tags[t]=String.encodeTiddlyLink(tags[t]);
		tagfield.value=tags.join(" "); // reassemble tag string (with brackets as needed)
		return;
	}
}
//}}}
|Name|CheckboxPluginInfo|
|Source|http://www.TiddlyTools.com/#CheckboxPlugin|
|Documentation|http://www.TiddlyTools.com/#CheckboxPluginInfo|
|Version|2.4.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|documentation for CheckboxPlugin|
This plugin extends the TiddlyWiki syntax to allow definition of checkboxes that can be embedded directly in tiddler content.  Checkbox states are preserved by:
* setting/removing tags on specified tiddlers,
* or, setting custom field values on specified tiddlers,
* or, saving to a locally-stored cookie ID,
* or, automatically modifying the tiddler source content (deprecated).
When an ID is assigned to the checkbox, it enables direct programmatic access to the checkbox DOM element, as well as creating an entry in TiddlyWiki's config.options[ID] internal data.  In addition to tracking the checkbox state, you can also specify custom javascript for programmatic initialization and onClick event handling for any checkbox, so you can provide specialized side-effects in response to state changes.
!!!!!Inline (wiki syntax) Usage
<<<
//{{{
[ ]or[_] and [x]or[X]
//}}}
Simple checkboxes using 'Inline X' storage.  The current unchecked/checked state is indicated by the character between the {{{[}}} and {{{]}}} brackets ("_" means unchecked, "X" means checked).  When you click on a checkbox, the current state is retained by directly modifying the tiddler content to place the corresponding "_" or "X" character in between the brackets.
>//''NOTE: 'Inline X' syntax has been deprecated...''  This storage format only works properly for checkboxes that are directly embedded and accessed from content in a single tiddler.  However, if that tiddler is 'transcluded' into another (by using the {{{<<tiddler TiddlerName>>}}} macro), the 'Inline X' will be ''erroneously stored in the containing tiddler's source content, resulting in corrupted content in that tiddler.''  For anything but the most simple of "to do list" uses, you should select from the various alternative storage methods described below...//
//{{{
[x=id]
//}}}
Assign an optional ID to the checkbox so you can use {{{document.getElementByID("id")}}} to manipulate the checkbox DOM element, as well as tracking the current checkbox state in {{{config.options["id"]}}}.  If the ID starts with "chk" the checkbox state will also be saved in a cookie, so it can be automatically restored whenever the checkbox is re-rendered (overrides any default {{{[x]}}} or {{{[_]}}} value).  If a cookie value is kept, the "_" or "X" character in the tiddler content remains unchanged, and is only applied as the default when a cookie-based value is not currently defined.
//{{{
[x(title|tag)] or [x(title:tag)]
//}}}
Initializes and tracks the current checkbox state by setting or removing a particular tag value from a specified tiddler.  If you omit the tiddler title (and the | or : separator), the specified tag is assigned to the current tiddler.  If you omit the tag value, as in {{{(title|)}}}, the default tag, {{{checked}}}, is assumed.  Omitting both the title and tag, {{{()}}}, tracks the checkbox state by setting the "checked" tag on the current tiddler.  When tag tracking is used, the "_" or "X" character in the tiddler content remains unchanged, and is not used to set or track the checkbox state.  If a tiddler title named in the tag does not exist, the checkbox state defaults to the "inline X" value.  If this value is //checked//, or is subsequently changed to //checked//, it will automatically create the missing tiddler and then add the tag to it.  //''NOTE: beginning with version 2.1.2 of this plugin, the "|" separator is the preferred separator between the title and tag name, as it avoids syntactic ambiguity when ":" is used within tiddler titles or tag names.''//
//{{{
[x(field@tiddler)]
//}}}
Initializes and tracks the current checkbox state by setting a particular custom field value from a specified tiddler.  If you omit the tiddler title (but not the "@" separator), the specified field on the current tiddler is used.  If you omit the field name, as in {{{(@tiddler)}}}, a default fieldname of {{{checked}}} is assumed.  Omitting both the field and the tiddler title, {{{(@)}}}, defaults to setting the "checked" field on the current tiddler.  When field tracking is used, the "_" or "X" character in the tiddler content remains unchanged, and is not used to set or track the checkbox state.  If the tiddler title named in the parameter does not exist, the checkbox state defaults to the "inline X" value.  If this value is //checked// or is subsequently changed to //checked//, it will automatically create the missing tiddler and then add the field to it.
//{{{
[x{javascript}{javascript}{javascript}]
//}}}
You can define optional javascript code segments to add custom initialization and/or 'onClick' handlers to a checkbox.  The current checkbox state (and it's other DOM attributes) can be set or read from within these code segments by reference to a globally-defined context object, "place" (which can also be referenced as "window.place").

The first code segment will be executed when the checkbox is initially displayed, so that you can programmatically determine it's starting checked/unchecked state.  The second code segment (if present) is executed whenever the checkbox is clicked, but //before the regular checkbox processing in performed// ("onClickBefore"), so that you can apply programmed responses or intercept and override the checkbox state based on custom logic.  The third code segment (if present) is executed whenver the checkbox is clicked, //after the regular checkbox processing has completed// ("onClickAfter"), so that you can include "side-effect" processing based on the checkbox state just applied.

>Note: if you want to use the default checkbox initialization processing with a custom onClickBefore/After function, use this syntax:
>{{{[x(tag){}{javascript}]}}} or {{{[x(tag){}{}{javascript}]}}}
<<<
!!!!!Macro usage
<<<
In addition to embedded checkboxes using the wiki syntax described above, a ''macro-based syntax'' is also provided, for use in templates where wiki syntax cannot be directly used.  This macro syntax can also be used in tiddler content, as an alternative to the wiki syntax.  When embedded in [[PageTemplate]], [[ViewTemplate]], or [[EditTemplate]] (or custom alternative templates), use the following macro syntax:
//{{{
<span macro="checkbox target checked id onInit onClickBefore onClickAfter"></span>
//}}}
or, when embedded in tiddler content, use the following macro syntax:
//{{{
<<checkbox target checked id onInit onClickBefore onClickAfter>>
//}}}
where:
''target''
>is either a tag reference (e.g., ''tagname|tiddlername'') or a field reference (e.g. ''fieldname@tiddlername''), as described above.
''checked'' (optional)
>is a keyword that sets the initial state of the checkbox to "checked".  When omitted, the default checkbox state is "unchecked".
''id'' (optional)
>specifies an internal config.options.* ID, as described above.  If the ID begins with "chk", a cookie-based persistent value will be created to track the checkbox state in between sessions.
''onInit'' (optional)
>contains a javascript event handler to be performed when the checkbox is initially rendered (see details above).
''onClickBefore'' and/or ''onClickAfter'' (optional)
>contains a javascript event handler to be performed each time the checkbox is clicked (see details above).  //note: to use the default onInit handler with a custom onClickBefore/After handler, use "" (empty quotes) or {} (empty function) as a placeholder for the onInit and/or onClickBefore parameters//
<<<
!!!!!Examples
<<<
''checked and unchecked static default ("inline X") values:''
//{{{
[X] label
[_] label
//}}}
>[X] label
>[_] label
''document-based value (id='demo', no cookie):''
//{{{
[_=demo] label
//}}}
>[_=demo] label
''cookie-based value  (id='chkDemo'):''
//{{{
[_=chkDemo] label
//}}}
>[_=chkDemo] label
''tag-based value (TogglyTagging):''
//{{{
[_(CheckboxPluginInfo|demotag)]
[_(CheckboxPluginInfo|demotag){place.refresh.tagged=place.refresh.container=false}]
//}}}
>[_(CheckboxPluginInfo|demotag)] toggle 'demotag' (and refresh tiddler display)
>[_(CheckboxPluginInfo|demotag){place.refresh.tagged=place.refresh.container=false}] toggle 'demotag' (no refresh)
''field-based values:''
//{{{
[_(demofield@CheckboxPluginInfo)] demofield@CheckboxPluginInfo
[_(demofield@)] demofield@ (equivalent to demonfield@ current tiddler)
[_(checked@CheckboxPluginInfo)] checked@CheckboxPluginInfo
[_(@CheckboxPluginInfo)] @CheckboxPluginInfo
[_(@)] @ (equivalent to checked@ current tiddler)
//}}}
>[_(demofield@CheckboxPluginInfo)] demofield@CheckboxPluginInfo
>[_(demofield@)] demofield@ (current tiddler)
>[_(checked@CheckboxPluginInfo)] checked@CheckboxPluginInfo
>[_(@CheckboxPluginInfo)] @CheckboxPluginInfo
>[_(@)] toggle field: @ (defaults to "checked@here")
>click to view current: <<toolbar fields>>
''custom init and onClick functions:''
//{{{
[X{place.checked=true}{alert(place.checked?"on":"off")}] message box with checkbox state
//}}}
>[X{place.checked=true}{alert(place.checked?"on":"off")}] message box with checkbox state
''retrieving option values:''
>config.options['demo']=<script>return config.options['demo']?"true":"false";</script>
>config.options['chkDemo']=<script>return config.options['chkDemo']?"true":"false";</script>
<<<
!!!!!Configuration
<<<
Normally, when a checkbox state is changed, the affected tiddlers are automatically re-rendered, so that any checkbox-dependent dynamic content can be updated.  There are three possible tiddlers to be re-rendered, depending upon where the checkbox is placed, and what kind of storage method it is using.
*''container'': the tiddler in which the checkbox is displayed. (e.g., this tiddler)
*''tagged'': the tiddler that is being tagged (e.g., "~MyTask" when tagging "~MyTask:done")
*''tagging'': the "tag tiddler" (e.g., "~done" when tagging "~MyTask:done")
You can set the default refresh handling for all checkboxes in your document by using the following javascript syntax either in a systemConfig plugin, or as an inline script.  (Substitute true/false values as desired):
{{{config.checkbox.refresh = { tagged:true, tagging:true, container:true };}}}

You can also override these defaults for any given checkbox by using an initialization function to set one or more of the refresh options.  For example:
{{{[_{place.refresh.container=false}]}}}
<<<
!!!!!Revisions
<<<
2008.01.08 [*.*.*] plugin size reduction: documentation moved to [[CheckboxPluginInfo]]
2008.01.05 [2.4.0] set global "window.place" to current checkbox element when processing checkbox clicks.  This allows init/beforeClick/afterClick handlers to reference RELATIVE elements, including using "story.findContainingTiddler(place)".  Also, wrap handlers in "function()" so "return" can be used within handler code.
2008.01.02 [2.3.0] split optional custom onClick handling into separate onClickBefore and onClickAfter handlers.  The onClickBefore handler permits interception of the click BEFORE the checkbox is set.  onClickAfter allows follow-on 'side-effect' processing to occur AFTER the checkbox is set.
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.08.06 [2.2.5] supress automatic refresh of any tiddler that is currently being edited.  Ensures that current tiddler edit sessions are not prematurely discarded (losing any changes).  However, if checkbox changes a tag on a tiddler being edited, update the "tags" input field (if any) so that saving the edited tiddler correctly reflects any changes due to checkbox activity... see refreshEditorTagField().
2007.07.13 - 2.2.4 in handler(), fix srctid reference (was "w.tiddler", should have been "w.tiddler.title").  This fixes broken 'inline X' plus fatal macro error when using PartTiddlerPlugin.  Thanks to cmari for reporting the problem and UdoBorkowski for finding the code error.
2007.06.21 - 2.2.3 suppress automatic refresh of tiddler when using macro-syntax to prevent premature end of tiddler editing session.
2007.06.20 - 2.2.2 fixed handling for 'inline X' when checkboxes are contained in a 'trancluded' tiddler.  Now, regardless of where an inline X checkbox appears, the X will be placed in the originating source tiddler, rather than the tiddler in which the checkbox appears.
2007.06.17 - 2.2.1 Refactored code to add checkbox //macro// syntax for use in templates (e.g., {{{macro="checkbox ..."}}}. Also, code cleanup of existing tag handling.
2007.06.16 - 2.2.0 added support for tracking checkbox states using tiddler fields via "(fieldname@tiddlername)" syntax.
2006.05.04 - 2.1.3 fix use of findContainingTiddler() to check for a non-null return value, so that checkboxes won't crash when used outside of tiddler display context (such as in header, sidebar or mainmenu)
2006.03.11 - 2.1.2 added "|" as delimiter to tag-based storage syntax (e.g. "tiddler|tag") to avoid parsing ambiguity when tiddler titles or tag names contain ":".   Using ":" as a delimiter is still supported but is deprecated in favor of the new "|" usage.  Based on a problem reported by JeffMason.
2006.02.25 - 2.1.0 added configuration options to enable/disable forced refresh of tiddlers when toggling tags
2006.02.23 - 2.0.4 when toggling tags, force refresh of the tiddler containing the checkbox.
2006.02.23 - 2.0.3 when toggling tags, force refresh of the 'tagged tiddler' so that tag-related tiddler content (such as "to-do" lists) can be re-rendered.
2006.02.23 - 2.0.2 when using tag-based storage, allow use [[ and ]] to quote tiddler or tag names that contain spaces:
{{{[x([[Tiddler with spaces]]:[[tag with spaces]])]}}}
2006.01.10 - 2.0.1 when toggling tags, force refresh of the 'tagging tiddler'.  For example, if you toggle the "systemConfig" tag on a plugin, the corresponding "systemConfig" TIDDLER will be automatically refreshed (if currently displayed), so that the 'tagged' list in that tiddler will remain up-to-date.
2006.01.04 - 2.0.0 update for ~TW2.0
2005.12.27 - 1.1.2 Fix lookAhead regExp handling for {{{[x=id]}}}, which had been including the "]" in the extracted ID.  
Added check for "chk" prefix on ID before calling saveOptionCookie()
2005.12.26 - 1.1.2 Corrected use of toUpperCase() in tiddler re-write code when comparing {{{[X]}}} in tiddler content with checkbox state. Fixes a problem where simple checkboxes could be set, but never cleared.
2005.12.26 - 1.1.0 Revise syntax so all optional parameters are included INSIDE the [ and ] brackets.  Backward compatibility with older syntax is supported, so content changes are not required when upgrading to the current version of this plugin.   Based on a suggestion by GeoffSlocock
2005.12.25 - 1.0.0 added support for tracking checkbox state using tags ("TogglyTagging")
Revised version number for official post-beta release.
2005.12.08 - 0.9.3 support separate 'init' and 'onclick' function definitions.
2005.12.08 - 0.9.2 clean up lookahead pattern
2005.12.07 - 0.9.1 only update tiddler source content if checkbox state is actually different.  Eliminates unnecessary tiddler changes (and 'unsaved changes' warnings)
2005.12.07 - 0.9.0 initial BETA release
<<<
/%
|Name|CheckboxToggleTag|
|Source|http://www.TiddlyTools.com/#CheckboxToggleTag|
|Version|1.3.2|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|toggle betwen two alternative tag values using HTML checkbox|

Usage:
	<<tiddler CheckboxToggleTag with: tag1 tag2 TiddlerName>> text label goes here
where:
	tag1 is the tag to use when the checkbox is set
	tag2 is the tag to use when the checkbox is cleared
	TiddlerName (optional) is the tiddler to be tagged

%/<html><input type="checkbox" onclick="
	/* ONCLICK: toggle onTag/offTag based on checkbox state */
	store.suspendNotifications();
	var tid=this.getAttribute('tid');
	store.setTiddlerTag(tid,this.checked,this.getAttribute('onTag'));
	store.setTiddlerTag(tid,!this.checked,this.getAttribute('offTag'));
	store.resumeNotifications();
	store.notify(tid,true);
	var here=story.findContainingTiddler(this);
	if (here) story.refreshTiddler(here.getAttribute('tiddler'),null,true);
	return false;
"><hide linebreaks></html><script>
	/* ONINIT: save onTag/offTag and init checkbox based on current tag value (if any) */
	var tid="$3";
	if (tid=="$"+"3") {
		var here=story.findContainingTiddler(place); if (!here) return;
		var tid=here.getAttribute('tiddler');
	}
	if (!store.tiddlerExists(tid)) return;
	var c=place.lastChild.firstChild;
	c.setAttribute('onTag',"$1");
	c.setAttribute('offTag',"$2");
	c.setAttribute('tid',tid);
	c.checked=store.getTiddler(tid).isTagged(c.getAttribute('onTag'));
</script>
/%
|Name|ChecklistScript|
|Source|http://www.TiddlyTools.com/#ChecklistScript|
|Version|1.2.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.4|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|demonstration using InlineJavascriptPlugin to create simple tag-based daily checklist|

IMPORTANT NOTE: for proper display, this tiddler requires either TiddlyWiki version 2.4 or above, or TiddlyTools' [[CoreTweaks]] fix for ticket #578 (trims leading/trailing newlines from tiddler section content).

!toggletag
<html><hide linebreaks><form style="display:inline">
	<input type="checkbox" name='c' onclick="
		var tid=story.findContainingTiddler(this).getAttribute('tiddler');
	 	store.setTiddlerTag(tid,this.checked,'$1');
	">
</form></html><script>
	var t=store.getTiddler(story.findContainingTiddler(place).getAttribute('tiddler'));
	place.lastChild.getElementsByTagName('form')[0].c.checked=t.isTagged('$1');
</script>
!end toggletag

!toggleall
<html><hide linebreaks><form style="display:inline">
	<input type="checkbox" name="c" onclick="
		var tid=story.findContainingTiddler(this).getAttribute('tiddler');
		var tags='$1'.readBracketedList();
		store.suspendNotifications();
		for (var t=0; t<tags.length; t++)
			store.setTiddlerTag(tid,this.checked,tags[t]);
		store.resumeNotifications();
		story.refreshTiddler(tid,null,true);
	">
</form></html><script>
	var t=store.getTiddler(story.findContainingTiddler(place).getAttribute('tiddler'));
	var tags='$1'.readBracketedList(); 
	place.lastChild.getElementsByTagName('form')[0].c.checked=t.tags.containsAll(tags);
</script>
!end toggleall

!resetall
<html><hide linebreaks><form style="display:inline">
	<input type="button" value="$1" onclick="
		var tid=story.findContainingTiddler(this).getAttribute('tiddler');
		var tags='$2'.readBracketedList();
		store.suspendNotifications();
		for (var t=0; t<tags.length; t++)
			store.setTiddlerTag(tid,false,tags[t]);
		store.resumeNotifications();
		story.refreshTiddler(tid,null,true);
"></form></html>
!end resetall

%/Five things to do every day:
<<<
<<tiddler [[ChecklistScript##toggletag]] with: questions>> Ask questions
<<tiddler [[ChecklistScript##toggletag]] with: answers>> Seek Answers
<<tiddler [[ChecklistScript##toggletag]] with: fun>> Have Fun
<<tiddler [[ChecklistScript##toggletag]] with: difference>> Make A Difference
<<tiddler [[ChecklistScript##toggletag]] with: smile>> Smile
----
<<tiddler [[ChecklistScript##toggleall]] with: "questions answers fun difference smile">> //toggle all items//
<<<
<<tiddler [[ChecklistScript##resetall]] with: "reset all items" "questions answers fun difference smile">>
/%
|Name|CloseOtherTiddlers|
|Source|http://www.TiddlyTools.com/#CloseOtherTiddlers|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires||
|Overrides||
|Description|close all other tiddlers when a tiddler is viewed - equivalent to pressing "close others" toolbar command|

Usage: <<tiddler CloseOtherTiddlers>>

%/<script>
	var here=story.findContainingTiddler(place); if (!here) return;
	story.closeAllTiddlers(here.getAttribute("tiddler"));
</script>
/%
|Name|CloseSlider|
|Source|http://www.TiddlyTools.com/#CloseSlider|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin, NestedSlidersPlugin|
|Overrides||
|Description|embed a 'close' link floating in upper right corner of slider.  closes current slider panel.|
%/<script label="<nowiki>[x]</nowiki>" title="hide this panel">
	var panel=place;
	while (panel && !hasClass(panel,'sliderPanel') && !hasClass(panel,'floatingPanel'))
		{ panel=panel.parentNode; }
	if (!panel) { alert('not in a slider'); return false; }
	panel.style.display='none';
	var cookie=panel.button.sliderCookie;
	if (cookie && cookie.length) {
		config.options[cookie]=false;
		if (config.options[cookie]!=panel.button.defOpen)
			saveOptionCookie(cookie);
		else { // remove cookie if slider is in default display state
			var ex=new Date(); ex.setTime(ex.getTime()-1000);
			document.cookie = cookie+"=novalue; path=/; expires="+ex.toGMTString();
		}
	}
	return false;
</script><script>place.lastChild.style.fontWeight="normal"</script>
/***
|Name|CollapseTiddlersPlugin|
|Source|http://gensoft.revhost.net/Collapse.html|
|Version|2008.03.06|
|Author|Bradley Meck (modified by ELS)|
|License|unknown|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|CollapsedTemplate|
|Overrides||
|Description|show/hide content of a tiddler while leaving tiddler title visible|

|ELS 3/6/2008: refactored code for size reduction, readability, and I18N/L10N-readiness.  Also added 'folded' flag to tiddler elements (for use by other plugins that need to know if tiddler is folded (e.g., [[SinglePageModePlugin]]) |
|ELS 10/11/2007: moved [[FoldFirst]] inline script and converted to {{{<<foldFirst>>}}} macro. |
|ELS 9/12/2007: suspend/resume SinglePageMode (SPM/TPM/BPM) when folding/unfolding tiddlers |
|ELS 6/5/2007: add "return false" at the end of each command handler to prevent IE 'page transition' problem. |
|ELS 3/30/2007: add a shadow definition for CollapsedTemplate.  Tweak ViewTemplate shadow so "fold/unfold" and "focus" toolbar items automatically appear when using default templates.  Remove error check for "CollapsedTemplate" existence, since shadow version will now always work as a fallback. |
|ELS 2/24/2006: added fallback to "CollapsedTemplate" if "WebCollapsedTemplate" is not found |
|ELS 2/6/2006: added check for 'readOnly' flag to use alternative "WebCollapsedTemplate" |

***/

//{{{
config.shadowTiddlers.CollapsedTemplate=
	"<!--{{{-->\
	<div class='toolbar' macro='toolbar expandTiddler collapseOthers closeTiddler closeOthers +editTiddler permalink references jump'></div>\
	<div class='title' macro='view title'></div>\
	<!--}}}-->";

// automatically tweak shadow ViewTemplate to add "collapseTiddler collapseOthers" commands
config.shadowTiddlers.ViewTemplate=config.shadowTiddlers.ViewTemplate.replace(/closeTiddler/,"collapseTiddler collapseOthers closeTiddler");

config.commands.collapseTiddler = {
	text: "fold",
	tooltip: "Collapse this tiddler",
	collapsedTemplate: "CollapsedTemplate",
	webCollapsedTemplate: "WebCollapsedTemplate",
	handler: function(event,src,title) {
		var e = story.findContainingTiddler(src); if (!e) return false;
		// don't fold tiddlers that are being edited!
		if(story.isDirty(e.getAttribute("tiddler"))) return false;
		var t=config.commands.collapseTiddler.getCollapsedTemplate();
		config.commands.collapseTiddler.saveTemplate(e);
		config.commands.collapseTiddler.display(title,t);
		e.setAttribute("folded","true");
		return false;
	},
	getCollapsedTemplate: function() {
		if (readOnly&&store.tiddlerExists(this.webCollapsedTemplate))
			return this.webCollapsedTemplate;
		else
			return this.collapsedTemplate
	},
	saveTemplate: function(e) {
		if (e.getAttribute("savedTemplate")==undefined)
			e.setAttribute("savedTemplate",e.getAttribute("template"));

	},
	// fold/unfold tiddler with suspend/resume of single/top/bottom-of-page mode
	display: function(title,t) {
		var opt=config.options;
		var saveSPM=opt.chkSinglePageMode; opt.chkSinglePageMode=false;
		var saveTPM=opt.chkTopOfPageMode; opt.chkTopOfPageMode=false;
		var saveBPM=opt.chkBottomOfPageMode; opt.chkBottomOfPageMode=false;
		story.displayTiddler(null,title,t);
		opt.chkBottomOfPageMode=saveBPM;
		opt.chkTopOfPageMode=saveTPM;
		opt.chkSinglePageMode=saveSPM;
	}
}

config.commands.expandTiddler = {
	text: "unfold",
	tooltip: "Expand this tiddler",
	handler: function(event,src,title) {
		var e = story.findContainingTiddler(src); if (!e) return false;
		var t = e.getAttribute("savedTemplate");
		config.commands.collapseTiddler.display(title,t);
		e.setAttribute("folded","false");
		return false;
	}
}

config.macros.collapseAll = {
	text: "collapse all",
	tooltip: "Collapse all tiddlers",
	handler: function(place,macroName,params,wikifier,paramString,tiddler){
		createTiddlyButton(place,this.text,this.tooltip,function(){
			story.forEachTiddler(function(title,tiddler){
				if(story.isDirty(title)) return;
				var t=config.commands.collapseTiddler.getCollapsedTemplate();
				config.commands.collapseTiddler.saveTemplate(tiddler);
				config.commands.collapseTiddler.display(title,t);
				tiddler.folded=true;
			})
		})
	}
}

config.macros.expandAll = {
	text: "expand all",
	tooltip: "Expand all tiddlers",
	handler: function(place,macroName,params,wikifier,paramString,tiddler){
		createTiddlyButton(place,this.text,this.tooltip,function(){
			story.forEachTiddler(function(title,tiddler){
				var t=config.commands.collapseTiddler.getCollapsedTemplate();
				if(tiddler.getAttribute("template")!=t) return; // re-display only if collapsed
				var t=tiddler.getAttribute("savedTemplate");
				config.commands.collapseTiddler.display(title,t);
				tiddler.folded=false;
			})
		})
	}
}

config.commands.collapseOthers = {
	text: "focus",
	tooltip: "Expand this tiddler and collapse all others",
	handler: function(event,src,title) {
		var e = story.findContainingTiddler(src); if (!e) return false;
		story.forEachTiddler(function(title,tiddler) {
			if(story.isDirty(title)) return;
			var t=config.commands.collapseTiddler.getCollapsedTemplate();
			if (e==tiddler) t=e.getAttribute("savedTemplate");
			config.commands.collapseTiddler.saveTemplate(tiddler);
			config.commands.collapseTiddler.display(title,t);
			tiddler.folded=(e!=tiddler);
		})
		return false;
	}
}

// {{{<<foldFirst>>}}} macro forces tiddler to be folded when *initially* displayed.
// Subsequent re-render does NOT re-fold tiddler, but closing/re-opening tiddler DOES cause it to fold first again.
config.macros.foldFirst = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler){
		var e=story.findContainingTiddler(place);
		if (e.getAttribute("foldedFirst")=="true") return; // already been folded once
		var title=e.getAttribute("tiddler")
		var t=config.commands.collapseTiddler.getCollapsedTemplate();
		config.commands.collapseTiddler.saveTemplate(e);
		config.commands.collapseTiddler.display(title,t);
		e.setAttribute("folded","true");
		e.setAttribute("foldedFirst","true"); // only when tiddler is first rendered
		return false;
	}
}
//}}}
<!--{{{-->
<!--
|Name|CollapsedTemplate|
|Source|http://www.TiddlyTools.com/#CollapsedTemplate|
|Version||
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands|
|Overrides||
|Description|alternative to ViewTemplate, used by CollapseTiddlersPlugin to display tiddler when 'folded'|
-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::CollapsedToolbar]]'></span>
</span>
<span class='title'>
	<span class='floatleft' macro='tiddlerIcons' style='cursor:auto !important;'></span>
	<span macro='view title'></span>
</span>
<div class='tagClear'></div>
<!--}}}-->
/%
|Description|RGB hexadecimal 216-color "Web safe" palette|
%/
Source: Paul Petterson, revised by Eric Shulman
|bgcolor(#FFF):FFF |bgcolor(#CCC):CCC |bgcolor(#999):999 |bgcolor(#666):@@color(white):666@@ |bgcolor(#333):@@color(white):333@@ |bgcolor(#000):@@color(white):000@@ |bgcolor(#FC0):~FC0 |bgcolor(#F90):F90 |bgcolor(#F60):@@color(white):F60@@ |bgcolor(#F30):@@color(white):F30@@ |>|>|>|>|>| |
|bgcolor(#9C0):9C0 |>|>|>| |bgcolor(#C90):C90 |bgcolor(#FC3):~FC3 |bgcolor(#FC6):~FC6 |bgcolor(#F96):F96 |bgcolor(#F63):@@color(white):F63@@ |bgcolor(#C30):@@color(white):C30@@ |>|>|>| |bgcolor(#C03):@@color(white):C03@@ |
|bgcolor(#CF0):~CF0 |bgcolor(#CF3):~CF3 |bgcolor(#330):@@color(white):330@@ |bgcolor(#660):@@color(white):660@@ |bgcolor(#990):990 |bgcolor(#CC0):~CC0 |bgcolor(#FF0):~FF0 |bgcolor(#C93):C93 |bgcolor(#C63):@@color(white):C63@@ |bgcolor(#300):@@color(white):300@@ |bgcolor(#600):@@color(white):600@@ |bgcolor(#900):@@color(white):900@@ |bgcolor(#C00):@@color(white):C00@@ |bgcolor(#F00):@@color(white):F00@@ |bgcolor(#F36):@@color(white):F36@@ |bgcolor(#F03):@@color(white):F03@@ |
|bgcolor(#9F0):9F0 |bgcolor(#CF6):~CF6 |bgcolor(#9C3):9C3 |bgcolor(#663):@@color(white):663@@ |bgcolor(#993):993 |bgcolor(#CC3):~CC3 |bgcolor(#FF3):~FF3 |bgcolor(#960):@@color(white):960@@ |bgcolor(#930):@@color(white):930@@ |bgcolor(#633):@@color(white):633@@ |bgcolor(#933):@@color(white):933@@ |bgcolor(#C33):@@color(white):C33@@ |bgcolor(#F33):@@color(white):F33@@ |bgcolor(#C36):@@color(white):C36@@ |bgcolor(#F69):@@color(white):F69@@ |bgcolor(#F06):@@color(white):F06@@ |
|bgcolor(#6F0):6F0 |bgcolor(#9F6):9F6 |bgcolor(#6C3):6C3 |bgcolor(#690):690 |bgcolor(#996):996 |bgcolor(#CC6):~CC6 |bgcolor(#FF6):~FF6 |bgcolor(#963):@@color(white):963@@ |bgcolor(#630):@@color(white):630@@ |bgcolor(#966):@@color(white):966@@ |bgcolor(#C66):@@color(white):C66@@ |bgcolor(#F66):@@color(white):F66@@ |bgcolor(#903):@@color(white):903@@ |bgcolor(#C39):@@color(white):C39@@ |bgcolor(#F6C):@@color(white):~F6C@@ |bgcolor(#F09):@@color(white):F09@@ |
|bgcolor(#3F0):3F0 |bgcolor(#6F3):6F3 |bgcolor(#390):390 |bgcolor(#6C0):6C0 |bgcolor(#9F3):9F3 |bgcolor(#CC9):~CC9 |bgcolor(#FF9):~FF9 |bgcolor(#C96):C96 |bgcolor(#C60):@@color(white):C60@@ |bgcolor(#C99):C99 |bgcolor(#F99):F99 |bgcolor(#F39):@@color(white):F39@@ |bgcolor(#C06):@@color(white):C06@@ |bgcolor(#906):@@color(white):906@@ |bgcolor(#F3C):@@color(white):~F3C@@ |bgcolor(#F0C):@@color(white):~F0C@@ |
|bgcolor(#0C0):0C0 |bgcolor(#3C0):3C0 |bgcolor(#360):@@color(white):360@@ |bgcolor(#693):693 |bgcolor(#9C6):9C6 |bgcolor(#CF9):~CF9 |bgcolor(#FFC):FFC |bgcolor(#FC9):~FC9 |bgcolor(#F93):F93 |bgcolor(#FCC):FCC |bgcolor(#F9C):~F9C |bgcolor(#C69):@@color(white):C69@@ |bgcolor(#936):@@color(white):936@@ |bgcolor(#603):@@color(white):603@@ |bgcolor(#C09):@@color(white):C09@@ |bgcolor(#303):@@color(white):303@@ |
|bgcolor(#3C3):3C3 |bgcolor(#6C6):6C6 |bgcolor(#0F0):0F0 |bgcolor(#3F3):3F3 |bgcolor(#6F6):6F6 |bgcolor(#9F9):9F9 |bgcolor(#CFC):CFC |>|>| |bgcolor(#C9C):~C9C |bgcolor(#969):@@color(white):969@@ |bgcolor(#939):@@color(white):939@@ |bgcolor(#909):@@color(white):909@@ |bgcolor(#636):@@color(white):636@@ |bgcolor(#606):@@color(white):606@@ |
|bgcolor(#060):@@color(white):060@@ |bgcolor(#363):@@color(white):363@@ |bgcolor(#090):090 |bgcolor(#393):393 |bgcolor(#696):696 |bgcolor(#9C9):9C9 |>|>| |bgcolor(#FCF):FCF |bgcolor(#F9F):~F9F |bgcolor(#F6F):@@color(white):~F6F@@ |bgcolor(#F3F):@@color(white):~F3F@@ |bgcolor(#F0F):@@color(white):~F0F@@ |bgcolor(#C6C):@@color(white):~C6C@@ |bgcolor(#C3C):@@color(white):~C3C@@ |
|bgcolor(#030):@@color(white):030@@ |bgcolor(#0C3):0C3 |bgcolor(#063):@@color(white):063@@ |bgcolor(#396):396 |bgcolor(#6C9):6C9 |bgcolor(#9FC):9FC |bgcolor(#CFF):CFF |bgcolor(#39F):39F |bgcolor(#9CF):9CF |bgcolor(#CCF):CCF |bgcolor(#C9F):~C9F |bgcolor(#96C):@@color(white):96C@@ |bgcolor(#639):@@color(white):639@@ |bgcolor(#306):@@color(white):306@@ |bgcolor(#90C):@@color(white):90C@@ |bgcolor(#C0C):@@color(white):~C0C@@ |
|bgcolor(#0F3):0F3 |bgcolor(#3F6):3F6 |bgcolor(#093):093 |bgcolor(#0C6):0C6 |bgcolor(#3F9):3F9 |bgcolor(#9FF):9FF |bgcolor(#9CC):9CC |bgcolor(#06C):@@color(white):06C@@ |bgcolor(#69C):69C |bgcolor(#99F):99F |bgcolor(#99C):99C |bgcolor(#93F):@@color(white):93F@@ |bgcolor(#60C):@@color(white):60C@@ |bgcolor(#609):@@color(white):609@@ |bgcolor(#C3F):@@color(white):~C3F@@ |bgcolor(#C0F):@@color(white):~C0F@@ |
|bgcolor(#0F6):0F6 |bgcolor(#6F9):6F9 |bgcolor(#3C6):3C6 |bgcolor(#096):096 |bgcolor(#6FF):6FF |bgcolor(#6CC):6CC |bgcolor(#699):699 |bgcolor(#036):@@color(white):036@@ |bgcolor(#369):@@color(white):369@@ |bgcolor(#66F):@@color(white):66F@@ |bgcolor(#66C):@@color(white):66C@@ |bgcolor(#669):@@color(white):669@@ |bgcolor(#309):@@color(white):309@@ |bgcolor(#93C):@@color(white):93C@@ |bgcolor(#C6F):@@color(white):~C6F@@ |bgcolor(#90F):@@color(white):90F@@ |
|bgcolor(#0F9):0F9 |bgcolor(#6FC):6FC |bgcolor(#3C9):3C9 |bgcolor(#3FF):3FF |bgcolor(#3CC):3CC |bgcolor(#399):399 |bgcolor(#366):@@color(white):366@@ |bgcolor(#069):@@color(white):069@@ |bgcolor(#039):@@color(white):039@@ |bgcolor(#33F):@@color(white):33F@@ |bgcolor(#33C):@@color(white):33C@@ |bgcolor(#339):@@color(white):339@@ |bgcolor(#336):@@color(white):336@@ |bgcolor(#63C):@@color(white):63C@@ |bgcolor(#96F):@@color(white):96F@@ |bgcolor(#60F):@@color(white):60F@@ |
|bgcolor(#0FC):0FC |bgcolor(#3FC):3FC |bgcolor(#0FF):0FF |bgcolor(#0CC):0CC |bgcolor(#099):099 |bgcolor(#066):@@color(white):066@@ |bgcolor(#033):@@color(white):033@@ |bgcolor(#39C):39C |bgcolor(#36C):@@color(white):36C@@ |bgcolor(#00F):@@color(white):00F@@ |bgcolor(#00C):@@color(white):00C@@ |bgcolor(#009):@@color(white):009@@ |bgcolor(#006):@@color(white):006@@ |bgcolor(#003):@@color(white):003@@ |bgcolor(#63F):@@color(white):63F@@ |bgcolor(#30F):@@color(white):30F@@ |
|bgcolor(#0C9):0C9 |>|>|>| |bgcolor(#09C):09C |bgcolor(#3CF):3CF |bgcolor(#6CF):6CF |bgcolor(#69F):69F |bgcolor(#36F):@@color(white):36F@@ |bgcolor(#03C):@@color(white):03C@@ |>|>|>| |bgcolor(#30C):@@color(white):30C@@ |
|>|>|>|>|>| |bgcolor(#0CF):0CF |bgcolor(#09F):09F |bgcolor(#06F):@@color(white):06F@@ |bgcolor(#03F):@@color(white):03F@@ |>|>|>|>|>| |
<script>
	place.lastChild.style.width="95%"; // stretch table to fit containing space (leave for border/padding)
</script>
/***
|Name|ColumnCalculatorPlugin|
|Source|http://www.TiddlyTools.com/#ColumnCalculatorPlugin|
|Version|0.6.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|calculate values from table cells in a column|
|Status| ALPHA - DO NOT DISTRIBUTE - USE AT YOUR OWN RISK |

!!!!!Usage
<<<
{{{<<columncalc function startrow endrow>>}}}
where:
''function'' is a keyword:
* "total" or "sum" or //no param// - adds up numeric values for cells above it in the column
* "count" - gives number of cells in column
* "average" or "avg" - gives average of cells in column (i.e., total/count)
''startrow''/''endrow'' are optional, and specify a ONE-based range of rows for limiting the calculation.  Use negative numbers to specify an offset from the current row (e.g., {{{<<calc sum 3 5>>}}} adds up rows 3, 4 and 5, while {{{<<calc sum 1 -1>>}}} adds up all numbers in the column excluding the current row (i.e., the same as the default if no startrow/endrow params are specified)
<<<
!!!!!Examples
<<<
''with numeric values...''
{{{
| foo| 3.2 |
| bar| 1.1 |
| baz| 2.9 |
| gronk| 4.3 |
| snork| 5.5 |
| count| <<columncalc count 1 -1>> |
| total| <<columncalc sum 1 -2>> |
| avg| <<columncalc average 1 -3>> |
}}}
| foo| 3.2 |
| bar| 1.1 |
| baz| 2.9 |
| gronk| 4.3 |
| snork| 5.5 |
| count| <<columncalc count 1 -1>> |
| total| <<columncalc sum 1 -2>> |
| avg| <<columncalc average 1 -3>> |

''with time-formatted values (hh:mm:ss)...''
{{{
| foo| 00:22:15 |
| bar| 00:03:30 |
| baz| 00:01:45 |
| count| <<columncalc count 1 -1>> |
| total| <<columncalc sum 1 -2>> |
| avg| <<columncalc average 1 -3>> |
}}}
| foo| 00:22:15 |
| bar| 00:03:30 |
| baz| 00:01:45 |
| count| <<columncalc count 1 -1>> |
| total| <<columncalc sum 1 -2>> |
| avg| <<columncalc average 1 -3>> |
<<<
!!!!!Revisions
<<<
2007.10.26 [0.6.1] in handler(), using ".textContent" instead of ".innerHTML" when reading values from table cells.  This allows use of values that are transcluded from slices in other tiddlers using the {{{<<tiddler "TiddlerName::slicename">>}}} syntax.
2007.06.29 [0.6.0] added support for handling values in hh:mm:ss format
2007.04.02 [0.5.0] started
<<<
!!!!!Code
***/
//{{{
version.extensions.columncalc = {major: 0, minor: 6, revision: 1, date: new Date(2007,10,26)};
config.macros.columncalc= {
	handler:
	function(place,macroName,params,wikifier,paramString,tiddler) {
		if (place.parentNode.nodeName.toLowerCase()!="tr") return false; // not in a table
		var fn=params.shift(); // first param is function name
		var tbody=place.parentNode.parentNode;
		var row=tbody.childNodes.length-1; // current row #
		var col=place.parentNode.childNodes.length-1; // current column #
		var count=total=0;
		var startrow=0; var endrow=row-1;
		if (params[0]) var startrow=params.shift();
		if (startrow<0) startrow=1*startrow+row; else startrow=startrow-1;
		if (params[0]) var endrow=params.shift();
		if (endrow<0) endrow=1*endrow+row; else endrow=endrow-1;
		var calcTime=false;
		for (r=startrow; r<=endrow; r++) {
			var cell=tbody.childNodes[r].childNodes[col].textContent;
			if (!cell) cell=tbody.childNodes[r].childNodes[col].innerHTML; // fallback for older browsers
			if (!isNaN(cell)) {
				total=total+eval(cell);
				count++;
			} else { // maybe an hh:mm:ss time value?
				var hms=cell.split(":"); var h=hms[0]; var m=hms[1]; var s=hms[2];
				if (hms.length!=3 || isNaN(h) || isNaN(m) || isNaN(s)) continue;  // not a valid time value... skip
				var showTime=true; // found a time value... use time formatting for results.
				total=total+h*3600+m*60+s*1;
				count++;
			}
		}
		switch (fn) {
			case "count":
				var result=count;
				break;
			case "average":
			case "avg":
				var result=Math.floor(total/count*100)/100; // truncate to two decimal places
				break;
			case "total":
			case "sum":
			default:
				var result=total;
				break;
		}
		if (showTime && fn!="count") {
			var h=Math.floor(result/3600);
			var m=Math.floor((result-h*3600)/60);
			var s=Math.floor((result-h*3600-m*60)*100)/100; // truncate to two decimal places
			result=(h<10?'0':'')+h+":"+(m<10?'0':'')+m+":"+(s<10?'0':'')+s;
		}
		createTiddlyText(place,result);
	}
}
//}}}
/***
|Name|CompareTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#CompareTiddlersPlugin|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|show color-coded differences between two selected tiddlers|
!!!!!Usage
<<<
{{{<<compareTiddlers>>}}}
{{smallform small{<<compareTiddlers>>}}}
<<<
!!!!!Revisions
<<<
2007.10.15 [1.0.0] converted from inline script to true plugin
2006.12.27 [0.0.0] inline script.  {{{diff()}}} and {{{diffString()}}} functions written by Bradley Meck.
<<<
!!!!!Code
***/
//{{{
version.extensions.CompareTiddlers= {major: 1, minor: 0, revision: 0, date: new Date(2007,10,15)};
//}}}
//{{{
config.shadowTiddlers.CompareTiddlers="<<compareTiddlers>>";
//}}}
//{{{
config.macros.compareTiddlers= {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		setStylesheet(this.css,"CompareTiddlersStyles");
		var console=createTiddlyElement(place,"span"); console.innerHTML=this.html;
		var form=console.getElementsByTagName("form")[0];
		var target=form.nextSibling;
		this.reset(form,target);
	},
	css: ".compareTiddlersResults \
		{ display:none;clear:both;margin-top:1em;border:1px solid;-moz-border-radius:1em;padding:1em;white-space:normal; }",
	html: "<form><!-- \
		--><select name=list1 size=1 style='width:30%' \
			onchange='config.macros.compareTiddlers.pick(this,this.form.view1,this.form.edit1,this.form.text1)'></select><!-- \
		--><input type=button name=view1 style='width:10%' value='view' disabled \
			onclick='if (this.form.list1.value.length) \
				story.displayTiddler(story.findContainingTiddler(this),this.form.list1.value,DEFAULT_VIEW_TEMPLATE)'><!-- \
		--><input type=button name=edit1 style='width:10%' value='edit' disabled \
			onclick='if (this.form.list1.value.length) \
				story.displayTiddler(story.findContainingTiddler(this),this.form.list1.value,DEFAULT_EDIT_TEMPLATE)'><!-- \
		--><select name=list2 size=1 style='width:30%' \
			onchange='config.macros.compareTiddlers.pick(this,this.form.view2,this.form.edit2,this.form.text2)'></select><!-- \
		--><input type=button name=view2 style='width:10%' value='view' disabled \
			onclick='if (this.form.list2.value.length) \
				story.displayTiddler(story.findContainingTiddler(this),this.form.list2.value,DEFAULT_VIEW_TEMPLATE)'><!-- \
		--><input type=button name=edit2 style='width:10%' value='edit' disabled \
			onclick='if (this.form.list2.value.length) \
				story.displayTiddler(story.findContainingTiddler(this),this.form.list2.value,DEFAULT_EDIT_TEMPLATE)'><br><!-- \
		--><nobr><!-- \
		--><textarea name=text1 style='width:49.5%;display:none' rows='10' readonly></textarea><!-- \
		--><textarea name=text2 style='width:49.5%;display:none' rows='10' readonly></textarea><!-- \
		--></nobr><!-- \
		--><div style='float:left'><!-- \
		-->Additions are shown in <span style='color:green'>GREEN</span>, <!-- \
		-->deletions are shown in <span style='color:red'>RED</span><!-- \
		--></div><!-- \
		--><div style='text-align:right'><!-- \
		--><input type=button name=compare style='width:10%' value='compare' disabled \
			onclick='config.macros.compareTiddlers.compare(this.form,this.form.nextSibling)'><!-- \
		--><input type=button name=done style='width:10%' value='done' disabled \
			onclick='config.macros.compareTiddlers.reset(this.form,this.form.nextSibling)'><!-- \
		--></div><!-- \
		--></form><div class='compareTiddlersResults'>contents to be replaced by results of comparison</div> \
	",
	reset: function(f,target) {
		var tids=store.getTiddlers('title','excludeLists');
		f.text1.style.display="none"; f.text1.value="";
		while (f.list1.options[0]) f.list1.options[0]=null; 
		f.list1.options[0]=new Option("select a tiddler...","",false,false);
		for (i=0; i<tids.length; i++)
			f.list1.options[f.list1.length]=new Option(tids[i].title,tids[i].title,false,false);
		f.text2.style.display="none"; f.text2.value="";
		while (f.list2.options[0]) f.list2.options[0]=null; 
		f.list2.options[0]=new Option("select a tiddler...","",false,false);
		for (i=0; i<tids.length; i++)
			f.list2.options[f.list2.length]=new Option(tids[i].title,tids[i].title,false,false);
		f.view1.disabled=f.view2.disabled=f.edit1.disabled=f.edit2.disabled=f.compare.disabled=f.done.disabled=true;
		target.style.display="none";
		removeChildren(target);
	},
	pick: function(list,view,edit,text) {
		var f=list.form;
		view.disabled=edit.disabled=f.done.disabled=!list.value.length;
		f.compare.disabled=!f.list1.value.length||!f.list2.value.length;
		if (!list.value.length) return;
		f.text1.style.display=f.text2.style.display="inline";
		text.value=store.getTiddlerText(list.value);
	},
	compare: function(f,target) {
		if (!f.list1.value.length) { f.list1.focus(); return alert("select a tiddler"); }
		var t1=store.getTiddlerText(f.list1.value); if (!t1) { displayMessage(f.list1.value+" not found");return false; }
		if (!f.list2.value.length) { f.list2.focus(); return alert("select a tiddler"); }
		var t2=store.getTiddlerText(f.list2.value); if (!t2) { displayMessage(f.list2.value+" not found");return false; }
		var out=this.diffString(t1,t2); if (!out || !out.length) out="no differences";
		removeChildren(target);
		target.innerHTML=out;
		target.style.display="block";
		f.done.disabled=false;
	},
	diffString: function( o, n ) {
		// This function was written by Bradley Meck
		// returns difference between old and new text, color-formatted additions and deletions
		if (o==n) return ""; // simple check, saves time if true
		var error = 5;
		var reg = new RegExp( "\\n|(?:.{0,"+error+"})", "g" );
		var oarr = o.match( reg ); // dices text into chunks
		var narr = n.match( reg );
		var out = this.diff(oarr,narr); // compare the word arrays
		var str = ""; // construct output
		for (i=0; i<out.length; i++) {
			switch (out[i].change) {
				case "ADDED":
					str+="<span style='color:green'>";
					str+=narr.slice(out[i].index,out[i].index+out[i].length).join("");
					str+="</span> ";
					break;
				case "DELETED":
					str+="<span style='color:red'>";
					str+=oarr.slice(out[i].index,out[i].index+out[i].length).join("");
					str+="</span> ";
					break;
				default:
					str+="<span>";
					str+=oarr.slice(out[i].index,out[i].index+out[i].length).join("");
					str+="</span> ";
					break;
			}	
		}
		return str;
	},
	diff: function( oldArray, newArray ) {
		// This function was written by Bradley Meck
		// finds the differences between one set of objects and another.
		// The objects do not need to be Strings.  It outputs an array of objects with the properties value and change.
		// This function is pretty hefty but appears to be rather light for a diff and tops out at O(N^2) for absolute worst cast scenario.
		var newElementHash = { };
		for( var i = 0; i < newArray.length; i++ ) {
			if( ! newElementHash [ newArray [ i ] ] ) {
				newElementHash [ newArray [ i ] ] = [ ];
			}
			newElementHash [ newArray [ i ] ].push( i );
		}
		var substringTable = [ ];
		for( var i = 0; i < oldArray.length; i++ ) {
			if(newElementHash [ oldArray [ i ] ] ) {
				var locations = newElementHash [ oldArray [ i ] ] ;
				for( var j = 0; j < locations.length; j++){
					var length = 1;
					while( i + length < oldArray.length && locations [ j ] + length < newArray.length
						&& oldArray [ i + length ] == newArray [ locations [ j ] + length ] ){
						length++;
					}
					substringTable.push( {
						oldArrayIndex : i,
						newArrayIndex : locations [ j ],
						matchLength : length
					} );
				}
			}
		}
		substringTable.sort( function( a, b ) {
			if ( a.matchLength > b.matchLength /* a is less than b by some ordering criterion */ ) {
				return -1;
			}
			if ( a.matchLength < b.matchLength /* a is greater than b by the ordering criterion */ ) {
				return 1;
			}
			// a must be equal to b
			return 0
		} );
		//displayMessage( substringTable.toSource( ) );
		for( var i = 0; i < substringTable.length; i++) {
			for( var j = 0; j < i; j++) {
				var oldDelta = substringTable [ i ].oldArrayIndex + substringTable [ i ].matchLength - 1 - substringTable [ j ].oldArrayIndex;
				var newDelta = substringTable [ i ].newArrayIndex + substringTable [ i ].matchLength - 1 - substringTable [ j ].newArrayIndex;
				//displayMessage( "oldDelta ::: " + oldDelta );
				//displayMessage( "newDelta ::: " + newDelta );
				//displayMessage( "matchLength ::: " + substringTable [ j ].matchLength );
				if( ( oldDelta >= 0 && oldDelta <= substringTable [ j ].matchLength )
				|| ( newDelta >= 0 && newDelta <= substringTable [ j ].matchLength )
				|| ( oldDelta < 0 && newDelta > 0 )
				|| ( oldDelta > 0 && newDelta < 0 ) ) {
					substringTable.splice( i, 1 );
					i--;
					break;
				}
			}
		}
		//displayMessage( substringTable.toSource(  ) );
		substringTable.sort( function( a, b ) {
			if ( a.oldArrayIndex < b.oldArrayIndex /* a is less than b by some ordering criterion */ ) {
				return -1;
			}
			if ( a.oldArrayIndex > b.oldArrayIndex /* a is greater than b by the ordering criterion */ ) {
				return 1;
			}
			// a must be equal to b
			return 0
		} );
		//displayMessage( substringTable.toSource( ) );
		var oldArrayIndex = 0;
		var newArrayIndex = 0;
		var results = [ ];
		for( var i = 0; i < substringTable.length; i++ ) {
			if( oldArrayIndex != substringTable [ i ].oldArrayIndex ) {
				results.push( {
					change : "DELETED",
					length : substringTable [ i ].oldArrayIndex - oldArrayIndex,
					index : oldArrayIndex
				} );
			}
			if( newArrayIndex != substringTable [ i ].newArrayIndex ) {
				results.push( {
					change : "ADDED",
					length : substringTable [ i ].newArrayIndex - newArrayIndex,
					index : newArrayIndex
				} );
			}
			results.push( {
				change : "STAYED",
				length : substringTable [ i ].matchLength,
				index : substringTable [ i ].oldArrayIndex
			} );
			oldArrayIndex = substringTable [ i ].oldArrayIndex + substringTable [ i ].matchLength;
			newArrayIndex = substringTable [ i ].newArrayIndex + substringTable [ i ].matchLength;
		}
		if( oldArrayIndex != oldArray.length ) {
			results.push( {
				change : "DELETED",
				length : oldArray.length - oldArrayIndex,
				index : oldArrayIndex
			} );
		}
		if( newArrayIndex != newArray.length ) {
			results.push( {
				change : "ADDED",
				length : newArray.length - newArrayIndex,
				index : newArrayIndex
			} );
		}
		return results;
	}
}
//}}}
/***
!!![[CookieJar]] (hard-coded "sticky" cookies)
***/

// 11 cookies saved on Tuesday, April 8th 2008 at 17:30:05 by ELSDesignStudios//
//^^(edit/remove username check and/or individual option settings as desired)^^//
//{{{
if (config.options.txtUserName=="ELSDesignStudios" || config.options.txtUserName=="Eric") {
	config.options.chkSearchByDate=true;
	config.options.chkSearchShadows=true;
	config.options.chkSearchTags=true;
	config.options.chkSearchText=true;
	config.options.chkSearchTitles=true;
	config.options.chkSearchTitlesFirst=true;
	config.options.chkSliderunsaved=true;
	config.options.chkTOCIncludeHidden=true;
	config.options.txtUploadBackupDir="backup";
	config.options.txtUploadStoreUrl="http://www.tiddlytools.com/store.php";
	config.options.txtPrivWizardDefaultStep="2";
}
//}}}
// The following settings are applied to all users: //
//{{{
	config.options.chkSearchIncremental=false;
	config.options.chkInsertTabs=true;
	config.options.chkSearchList=true;
	config.options.txtMaxEditRows=25;
	config.options.txtTiddlerLinkTootip="%0 - %2 (%3 bytes)";
//}}}
/***
|Name|CookieManagerPlugin|
|Source|http://www.TiddlyTools.com/#CookieManagerPlugin|
|Version|2.1.2|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|review/add/delete option cookies and save current option values to CookieJar tiddler for 'sticky' settings|
!!!!!Usage
<<<
View/set/delete your current TiddlyWiki option/cookie values, as well as "bake cookies", which automatically generates the contents of a [[CookieJar]] tiddler for all current cookie-based options.   You can then edit the [[CookieJar]] to remove any lines that set unwanted fixed-value options (so that the normal cookie-based values will still be used for those options).  The code contained in the [[CookieJar]] is wrapped in a conditional so that the fixed-value options are only applied for a specific username.  That way, when you publish or share your document with others, YOUR fixed-value options are not applied, and the normal cookie-based options will still be used for everyone else.

Also, each time you "bake cookies", they are *appended* to the [[CookieJar]], so that any previous values are not automatically discarded, but are instead simply *overridden* by the newer values. After you bake a new batch of cookies, you should edit the [[CookieJar]] to remove any "stale cookies" or merge the old and new options into a single block to simplify code (for readability as well as saving a little tiddler storage space). 
<<<
!!!!!Examples
<<<
{{{<<cookieManager>>}}}
{{center smallform{<<cookieManager>>}}}
<<<
!!!!!Configuration
<<<
<<option chkCookieManagerAddToAdvancedOptions>> display [[CookieManager]] in [[AdvancedOptions]]
<<option chkCookieJarAddToAdvancedOptions>> display [[CookieJar]] in [[AdvancedOptions]]
//note: these settings only take effect after reloading the document//
<<<
!!!!!Revisions
<<<
2008.05.12 [2.1.2] add "cookies" task to backstage (moved from BackstageTasks)
2008.04.09 [2.1.0] added options: chkCookieManagerAddToAdvancedOptions and chkCookieJarAddToAdvancedOptions
2008.04.08 [2.0.1] automatically include CookieManager control panel in AdvancedOptions shadow tiddler
2007.08.02 [2.0.0] converted from inline script
2007.04.29 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.cookieManager= {major: 2, minor: 1, revision: 0, date: new Date(2008,4,9)};
//}}}
//{{{
if (config.options.chkCookieManagerAddToAdvancedOptions===undefined)
	config.options.chkCookieManagerAddToAdvancedOptions=true;
if (config.options.chkCookieJarAddToAdvancedOptions===undefined)
	config.options.chkCookieJarAddToAdvancedOptions=true;

config.shadowTiddlers.CookieManager=
	"!!![[CookieManager]]\n{{center smallform{<<cookieManager>>}}}";
config.annotations.CookieManager=
	"Review, modify, delete, and/or 'bake' option cookies";

if (config.options.chkCookieManagerAddToAdvancedOptions)
	config.shadowTiddlers.AdvancedOptions+="<<tiddler CookieManager>>";
if (config.options.chkCookieJarAddToAdvancedOptions)
	config.shadowTiddlers.AdvancedOptions+="<<tiddler CookieJar>>";

// add "cookies" backstage task
if (config.tasks) { // for TW2.2b3 or above
	config.tasks.cookies = {
		text: "cookies",
		tooltip: "manage plugin-defined option settings",
		content: "{{groupbox{@@display:block;width:50%;<<tiddler CookieManager>>@@\n<<tiddler CookieJar>>}}}"
	}
	config.backstageTasks.push("cookies");
}
//}}}
//{{{
config.macros.cookieManager = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var span=createTiddlyElement(place,"span");
		span.innerHTML=this.html;
		this.setCookieEditorList(span.firstChild.list); 
	},
	html: '<form style="display:inline;margin:0;padding:0" onsubmit="return false"><!--\
		--><select style="width:99%" name="list" \
			onchange="this.form.val.value=this.value.length?config.options[this.value]:\'\';"><!--\
		--></select><br>\
		<input type="text" style="width:98%;margin:0;" name="val" title="enter an option value"><br>\
		<input type="button" style="width:33%;margin:0;" value="get" title="refresh list" \
			onclick="config.macros.cookieManager.setCookieEditorList(this.form.list);"><!--\
		--><input type="button" style="width:33%;margin:0;" value="set" title="save cookie value" \
			onclick="var opt=this.form.list.value; var v=this.form.val.value; \
				config.options[opt]=opt.substr(0,3)==\'txt\'?v:(v.toLowerCase()==\'true\'); \
				saveOptionCookie(opt);config.macros.cookieManager.setCookieEditorList(this.form.list);"><!--\
		--><input type="button" style="width:33%;margin:0;" value="del" title="remove cookie" \
			onclick="var ex=new Date(); ex.setTime(ex.getTime()-1000); \
				document.cookie=this.form.list.value+\'=novalue; path=/; expires=\'+ex.toGMTString(); \
				config.macros.cookieManager.setCookieEditorList(this.form.list);"><br>\
		<input type="button" style="width:50%;margin:0;" value="bake cookies" \
			title="save current cookie-based option values into the CookieJar tiddler" \
			onclick="return config.macros.cookieManager.bakeCookies(this,false)"><!--\
		--><input type="button" style="width:50%;margin:0;" value="bake all options" \
			title="save ALL option values (including NON-COOKIE values) into the CookieJar tiddler" \
			onclick="return config.macros.cookieManager.bakeCookies(this,true)"><!--\
		--></form>\
	',
	bakeCookies: function(here,all) {
		var title='CookieJar';
		var tid=store.getTiddler(title);
		var who=config.options.txtUserName;
		var when=new Date();
		var tags=['systemConfig'];
		if (all) { 
			var opts=new Array();
			for (var i in config.options) if (i.substr(0,3)=='chk'||i.substr(0,3)=='txt') opts.push(i);
			opts.sort();
		}
		else var opts=this.getCookieList();
		var text=tid?tid.text:"/***\n!!![[CookieJar]] (hard-coded 'sticky' cookies)\n***/\n";
		text+='\n// '+opts.length+(all?' options':' cookies')+' saved ';
		text+=when.formatString('on DDD, MMM DDth YYYY at 0hh:0mm:0ss');
		text+=' by '+who+'//\n';
		text+='//^^(edit/remove username check and/or individual option settings as desired)^^//\n';
		text+='//{{{\n';
		text+='if (config.options.txtUserName=="'+who+'") {\n';
		for (i=0; i<opts.length; i++) {
			if (opts[i].substr(0,3)=='chk')
				text+='\tconfig.options.'+opts[i]+'='+config.options[opts[i]]+';\n';
			if (opts[i].substr(0,3)=='txt')
				text+='\tconfig.options.'+opts[i]+'="'+config.options[opts[i]]+'";\n';
		}
		text+='}\n//}}}\n';
		store.saveTiddler(title,title,text,who,when,tags,tid?tid.fields:null);
		story.displayTiddler(story.findContainingTiddler(this),title);
		story.refreshTiddler(title,null,true);
		displayMessage(opts.length+(all?' options':' cookies')+' have been saved in '+title+'.  Please review all stored settings.');
		return false;
	},
	getCookieList: function() {
		var cookies = { };
		if (document.cookie != "") {
			var p = document.cookie.split("; ");
			for (var i=0; i < p.length; i++) {
				var pos=p[i].indexOf("=");
				if (pos==-1) cookies[p[i]]="";
				else cookies[p[i].substr(0,pos)]=unescape(p[i].slice(pos+1));
			}
		}
		var opt=new Array(); for (var i in config.options) if (cookies[i]) opt.push(i); opt.sort();
		return opt;
	},
	setCookieEditorList: function(list) {
		var opt=this.getCookieList();
		var sel=list.selectedIndex;
		while (list.options.length > 1) { list.options[1]=null; } // clear list (except for header item)
		list.options[0]=new Option("There are "+opt.length+" cookies...","",false,false);
		if (!opt.length) { list.form.val.value=""; return; } // no cookies
		var c=1;
		for(var i=0; i<opt.length; i++) {
			var txt="";
			if  (opt[i].substr(0,3)=="chk")
				txt+="["+(config.options[opt[i]]?"x":"_")+"] ";
			txt+=opt[i];
			list.options[c++]=new Option(txt,opt[i],false,false);
		}
		list.selectedIndex=sel>0?sel:0;
		list.form.val.value=sel>0?config.options[list.options[sel].value]:"";
	}
}
//}}}
/***
|Name|CopyTiddlerPlugin|
|Source|http://www.TiddlyTools.com/#CopyTiddlerPlugin|
|Version|3.0.3|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Quickly create a copy of any existing tiddler|
!!!!!Usage
<<<
View a tiddler and select the "copy" toolbar item.  A new tiddler editor is opened with a title of "Copy of TiddlerName" containing copies of the text/tags from the original tiddler.  Note: If select the "copy" toolbar item while //editing// a tiddler, the current values of the text/tags that are displayed in the existing tiddler editor are used (including any unsaved changes you may have made to those values).
* When using the default (shadow) EditTemplate, the plugin automatically updates the template to include the ''copyTiddler'' toolbar command.
* If you have created a custom EditTemplate tiddler, you will need to manually add the ''copyTiddler'' toolbar command to your existing template toolbar definition.
* If you add ''copyTiddler'' to the ViewTemplate toolbar definition, the ''copy'' toolbar command will also appear when viewing a tiddler.
{{{
<!-- add 'copyTiddler' command to existing toolbar definition -->
<div class='toolbar' macro='toolbar ... copyTiddler ... '>
}}}
<<<
!!!!!Revisions
<<<
2008.05.20 [3.0.3] in handler, when copying from VIEW mode, create duplicate array from existing tags array before saving new tiddler.  Fixes "linked tags" problem whereby changes in newly created copy were affecting original tiddler tags as well.
2007.12.19 [3.0.2] in handler, when copying from VIEW mode, duplicate custom fields before saving new tiddler.  Fixes "linked fields" problem whereby changes in newly created copy were affecting original tiddler values as well.  Thanks to bug report from Ken Girard.
2007.09.26 [3.0.1] in handler, use findContainingTiddler(src) to get tiddlerElem (and title).  Allows 'copy' command to find correct tiddler when transcluded using {{{<<tiddler>>}}} macro or enhanced toolbar inclusion (see [[CoreTweaks]])
2007.06.28 [3.0.0] complete re-write to handle custom fields and alternative view/edit templates
2007.05.17 [2.1.2] use store.getTiddlerText() to retrieve tiddler content, so that SHADOW tiddlers can be copied correctly when in VIEW mode
2007.04.01 [2.1.1] in copyTiddler.handler(), fix check for editor fields by ensuring that found field actually has edit=="text" attribute
2007.02.05 [2.1.0] in copyTiddler.handler(), if editor fields (textfield and/or tagsfield) can't be found (i.e., tiddler is in VIEW mode, not EDIT mode), then get text/tags values from stored tiddler instead of active editor fields.  Allows use of COPY toolbar directly from VIEW mode (based on a request from LaurentCharles)
2006.12.12 [2.0.0] completely rewritten so plugin just creates a new tiddler EDITOR with a copy of the current tiddler EDITOR contents, instead of creating the new tiddler in the STORE by copying the current tiddler values from the STORE.
2005.xx.xx [1.0.0] original version by Tim Morgan
<<<
!!!!!Code
***/
//{{{
version.extensions.copyTiddler= {major: 3, minor: 0, revision: 3, date: new Date(2008,5,20)};

// automatically tweak shadow EditTemplate to add "copyTiddler" toolbar command (following "cancelTiddler")
config.shadowTiddlers.EditTemplate=config.shadowTiddlers.EditTemplate.replace(/cancelTiddler/,"cancelTiddler copyTiddler");

config.commands.copyTiddler = {
	text: 'copy',
	hideReadOnly: true,
	tooltip: 'Make a copy of this tiddler',
	prefix: "Copy of ",
	handler: function(event,src,title) {
		var tiddlerElem=story.findContainingTiddler(src);
		if (!tiddlerElem) return; // get tiddler... if no tiddler, do nothing.
		title=tiddlerElem.getAttribute("tiddler"); // current tiddler title
		var template=tiddlerElem.getAttribute("template") // current tiddler template
		var newTitle = this.prefix+title; // add "copy of" to create new tiddler title
		if (!story.isDirty(title)) { // if existing tiddler is being VIEWED (not EDITED)
			// duplicate existing stored tiddler (and clear "changecount")
			var tid=store.getTiddler(title);
			var newtags=[]; for (var t=0; t<tid.tags.length; t++) newtags.push(tid.tags[t]);
			var newfields={}; store.forEachField(tid,function(t,f,v){newfields[f]=v;},true);
	                store.saveTiddler(newTitle,newTitle,tid.text,
				config.options.txtUserName,new Date(),newtags, newfields, true);
			// display new tiddler using same view template as current tiddler
			story.displayTiddler(story.findContainingTiddler(src),newTitle,template);
		} else {
			// display new tiddler editor using same editor template as current tiddler
			story.displayTiddler(story.findContainingTiddler(src),newTitle,template);
			// get fields from current tiddler editor
			var fields=config.commands.copyTiddler.gatherFields(tiddlerElem);
			// set fields in new editor
			var newTiddlerElem = document.getElementById(story.idPrefix+newTitle);
			for (var f=0; f<fields.length; f++) { 
				if (fields[f].name=="title") fields[f].value=newTitle; // rename title in new tiddler
				var fieldElem=config.commands.copyTiddler.findField(newTiddlerElem,fields[f].name);
				if (fieldElem) {
					if (fieldElem.getAttribute("type")=="checkbox")
						fieldElem.checked=fields[f].value;
					else 
						fieldElem.value=fields[f].value;
				}
			}
		}
		story.focusTiddler(newTitle,"title");
		return false;
	},
	findField: function(tiddlerElem,field) {
		var inputs=tiddlerElem.getElementsByTagName("input");
		for (var i=0; i<inputs.length; i++) {
			if (inputs[i].getAttribute("type")=="checkbox" && inputs[i].field == field) return inputs[i];
			if (inputs[i].getAttribute("type")=="text" && inputs[i].getAttribute("edit") == field) return inputs[i];
		}
		var tas=tiddlerElem.getElementsByTagName("textarea");
		for (var i=0; i<tas.length; i++) if (tas[i].getAttribute("edit") == field) return tas[i];
		var sels=tiddlerElem.getElementsByTagName("select");
		for (var i=0; i<sels.length; i++) if (sels[i].getAttribute("edit") == field) return sels[i];
		return null;
	},
	gatherFields: function(tiddlerElem) { // get field names and values from current tiddler editor
		var fields=[];
		// get checkboxes and edit fields
		var inputs=tiddlerElem.getElementsByTagName("input");
		for (var i=0; i<inputs.length; i++) {
			if (inputs[i].getAttribute("type")=="checkbox")
				if (inputs[i].field) fields.push({name:inputs[i].field,value:inputs[i].checked});
			if (inputs[i].getAttribute("type")=="text")
				if (inputs[i].getAttribute("edit")) fields.push({name:inputs[i].getAttribute("edit"),value:inputs[i].value});
		}
		// get textareas (multi-line edit fields)
		var tas=tiddlerElem.getElementsByTagName("textarea");
		for (var i=0; i<tas.length; i++)
			if (tas[i].getAttribute("edit")) fields.push({name:tas[i].getAttribute("edit"),value:tas[i].value});
		// get selection lists (droplist or listbox)
		var sels=tiddlerElem.getElementsByTagName("select");
		for (var i=0; i<sels.length; i++)
			if (sels[i].getAttribute("edit")) fields.push({name:sels[i].getAttribute("edit"),value:sels[i].value});
		return fields;
	}
};
//}}}
/***
|Name|DatePlugin|
|Source|http://www.TiddlyTools.com/#DatePlugin|
|Documentation|http://www.TiddlyTools.com/#DatePluginInfo|
|Version|2.7.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|formatted dates plus popup menu with 'journal' link, changes and (optional) reminders|
There are quite a few calendar generators, reminders, to-do lists, 'dated tiddlers' journals, blog-makers and GTD-like schedule managers that have been built around TW.  While they all have different purposes, and vary in format, interaction, and style, in one way or another each of these plugins displays and/or uses date-based information to make finding, accessing and managing relevant tiddlers easier.  This plugin provides a general approach to embedding dates and date-based links/menus within tiddler content.
!!!!!Documentation
>see [[DatePluginInfo]]
!!!!!Configuration
<<<
<<option chkDatePopupHideCreated>> omit 'created' section from date popups
<<option chkDatePopupHideChanged>> omit 'changed' section from date popups
<<option chkDatePopupHideTagged>> omit 'tagged' section from date popups
<<option chkDatePopupHideReminders>> omit 'reminders' section from date popups
<<option chkShowJulianDate>> display Julian day number (1-365) below current date

see [[DatePluginConfig]] for additional configuration settings, for use in calendar displays, including:
*date formats
*color-coded backgrounds
*annual fixed-date holidays
*weekends
<<<
!!!!!Revisions
<<<
2008.03.08 [2.7.0] in addModifiedsToPopup(), if a tiddler was created on the specified date, don't list it in the 'changed' section of the popup.  Based on a request from Kashgarinn.
|please see [[DatePluginInfo]] for additional revision details|
2005.10.30 [0.9.0] pre-release
<<<
!!!!!Code
***/
//{{{
version.extensions.date = {major: 2, minor: 7, revision: 0, date: new Date(2008,3,8)};

config.macros.date = {
	format: "YYYY.0MM.0DD", // default date display format
	linkformat: "YYYY.0MM.0DD", // 'dated tiddler' link format
	linkedbg: "#babb1e", // "babble"
	todaybg: "#ffab1e", // "fable"
	weekendbg: "#c0c0c0", // "cocoa"
	holidaybg: "#ffaace", // "face"
	createdbg: "#bbeeff", // "beef"
	modifiedsbg: "#bbeeff", // "beef"
	remindersbg: "#c0ffee", // "coffee"
	holidays: [ "01/01", "07/04", "07/24", "11/24" ], // NewYearsDay, IndependenceDay(US), Eric's Birthday (hooray!), Thanksgiving(US)
	weekend: [ 1,0,0,0,0,0,1 ] // [ day index values: sun=0, mon=1, tue=2, wed=3, thu=4, fri=5, sat=6 ]
};

config.macros.date.handler = function(place,macroName,params)
{
	// do we want to see a link, a popup, or just a formatted date?
	var mode="display";
	if (params[0]=="display") { mode=params[0]; params.shift(); }
	if (params[0]=="popup") { mode=params[0]; params.shift(); }
	if (params[0]=="link") { mode=params[0]; params.shift(); }
	// get the date
	var now = new Date();
	var date = now;
	if (!params[0] || params[0]=="today")
		{ params.shift(); }
	else if (params[0]=="filedate")
		{ date=new Date(document.lastModified); params.shift(); }
	else if (params[0]=="tiddler")
		{ date=store.getTiddler(story.findContainingTiddler(place).id.substr(7)).modified; params.shift(); }
	else if (params[0].substr(0,8)=="tiddler:")
		{ var t; if ((t=store.getTiddler(params[0].substr(8)))) date=t.modified; params.shift(); }
	else {
		var y = eval(params.shift().replace(/Y/ig,(now.getYear()<1900)?now.getYear()+1900:now.getYear()));
		var m = eval(params.shift().replace(/M/ig,now.getMonth()+1));
		var d = eval(params.shift().replace(/D/ig,now.getDate()+0));
		date = new Date(y,m-1,d);
	}
	// date format with optional custom override
	var format=this.format; if (params[0]) format=params.shift();
	var linkformat=this.linkformat; if (params[0]) linkformat=params.shift();
	showDate(place,date,mode,format,linkformat);
}

window.showDate=showDate;
function showDate(place,date,mode,format,linkformat,autostyle,weekend)
{
	if (!mode) mode="display";
	if (!format) format=config.macros.date.format;
	if (!linkformat) linkformat=config.macros.date.linkformat;
	if (!autostyle) autostyle=false;

	// format the date output
	var title = date.formatString(format);
	var linkto = date.formatString(linkformat);

	// just show the formatted output
	if (mode=="display") { place.appendChild(document.createTextNode(title)); return; }

	// link to a 'dated tiddler'
	var link = createTiddlyLink(place, linkto, false);
	link.appendChild(document.createTextNode(title));
	link.title = linkto;
	link.date = date;
	link.format = format;
	link.linkformat = linkformat;

	// if using a popup menu, replace click handler for dated tiddler link
	// with handler for popup and make link text non-italic (i.e., an 'existing link' look)
	if (mode=="popup") {
		link.onclick = onClickDatePopup;
		link.style.fontStyle="normal";
	}
	// format the popup link to show what kind of info it contains (for use with calendar generators)
	if (autostyle) setDateStyle(place,link,weekend);
}
//}}}

//{{{
// NOTE: This function provides default logic for setting the date style when displayed in a calendar
// To customize the date style logic, please see[[DatePluginConfig]]
function setDateStyle(place,link,weekend) {
	// alias variable names for code readability
	var date=link.date;
	var fmt=link.linkformat;
	var linkto=date.formatString(fmt);
	var cmd=config.macros.date;

	if ((weekend!==undefined?weekend:isWeekend(date))&&(cmd.weekendbg!=""))
		{ place.style.background = cmd.weekendbg; }
	if (hasModifieds(date)||hasCreateds(date)||hasTagged(date,fmt))
		{ link.style.fontStyle="normal"; link.style.fontWeight="bold"; }
	if (hasReminders(date))
		{ link.style.textDecoration="underline"; }
	if (isToday(date))
		{ link.style.border="1px solid black"; }
	if (isHoliday(date)&&(cmd.holidaybg!=""))
		{ place.style.background = cmd.holidaybg; }
	if (hasCreateds(date)&&(cmd.createdbg!=""))
		{ place.style.background = cmd.createdbg; }
	if (hasModifieds(date)&&(cmd.modifiedsbg!=""))
		{ place.style.background = cmd.modifiedsbg; }
	if ((hasTagged(date,fmt)||store.tiddlerExists(linkto))&&(cmd.linkedbg!=""))
		{ place.style.background = cmd.linkedbg; }
	if (hasReminders(date)&&(cmd.remindersbg!=""))
		{ place.style.background = cmd.remindersbg; }
	if (isToday(date)&&(cmd.todaybg!=""))
		{ place.style.background = cmd.todaybg; }
	if (config.options.chkShowJulianDate) { // optional display of Julian date numbers
		var m=[0,31,59,90,120,151,181,212,243,273,304,334];
		var d=date.getDate()+m[date.getMonth()];
		var y=date.getFullYear();
		if (date.getMonth()>1 && (y%4==0 && y%100!=0) || y%400==0)
			d++; // after February in a leap year
		wikify("@@font-size:80%;<br>"+d+"@@",place);
	}

}
//}}}

//{{{
function isToday(date) // returns true if date is today
	{ var now=new Date(); return ((now-date>=0) && (now-date<86400000)); }

function isWeekend(date) // returns true if date is a weekend
	{ return (config.macros.date.weekend[date.getDay()]); }

function isHoliday(date) // returns true if date is a holiday
{
	var longHoliday = date.formatString("0MM/0DD/YYYY");
	var shortHoliday = date.formatString("0MM/0DD");
	for(var i = 0; i < config.macros.date.holidays.length; i++) {
		var holiday=config.macros.date.holidays[i];
		if (holiday==longHoliday||holiday==shortHoliday) return true;
	}
	return false;
}
//}}}

//{{{
// Event handler for clicking on a day popup
function onClickDatePopup(e)
{
	if (!e) var e = window.event;
	var theTarget = resolveTarget(e);
	var popup = Popup.create(this);
	if(popup) {
		// always show dated tiddler link (or just date, if readOnly) at the top...
		if (!readOnly || store.tiddlerExists(this.date.formatString(this.linkformat)))
			createTiddlyLink(popup,this.date.formatString(this.linkformat),true);
		else
			createTiddlyText(popup,this.date.formatString(this.linkformat));
		if (!config.options.chkDatePopupHideCreated)
			addCreatedsToPopup(popup,this.date,this.format);
		if (!config.options.chkDatePopupHideChanged)
			addModifiedsToPopup(popup,this.date,this.format);
		if (!config.options.chkDatePopupHideTagged)
			addTaggedToPopup(popup,this.date,this.linkformat);
		if (!config.options.chkDatePopupHideReminders)
			addRemindersToPopup(popup,this.date,this.linkformat);
	}
	Popup.show(popup,false);
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
	return(false);
}
//}}}

//{{{
function indexCreateds() // build list of tiddlers, hash indexed by creation date
{
	var createds= { };
	var tiddlers = store.getTiddlers("title","excludeLists");
	for (var t = 0; t < tiddlers.length; t++) {
		var date = tiddlers[t].created.formatString("YYYY0MM0DD")
		if (!createds[date])
			createds[date]=new Array();
		createds[date].push(tiddlers[t].title);
	}
	return createds;
}
function hasCreateds(date) // returns true if date has created tiddlers
{
	if (!config.macros.date.createds) config.macros.date.createds=indexCreateds();
	return (config.macros.date.createds[date.formatString("YYYY0MM0DD")]!=undefined);
}

function addCreatedsToPopup(popup,when,format)
{
	var force=(store.isDirty() && when.formatString("YYYY0MM0DD")==new Date().formatString("YYYY0MM0DD"));
	if (force || !config.macros.date.createds) config.macros.date.createds=indexCreateds();
	var indent=String.fromCharCode(160)+String.fromCharCode(160);
	var createds = config.macros.date.createds[when.formatString("YYYY0MM0DD")];
	if (createds) {
		createds.sort();
		var e=createTiddlyElement(popup,"div",null,null,"created ("+createds.length+")");
		for(var t=0; t<createds.length; t++) {
			var link=createTiddlyLink(popup,createds[t],false);
			link.appendChild(document.createTextNode(indent+createds[t]));
			createTiddlyElement(popup,"br",null,null,null);
		}
	}
}
//}}}

//{{{
function indexModifieds() // build list of tiddlers, hash indexed by modification date
{
	var modifieds= { };
	var tiddlers = store.getTiddlers("title","excludeLists");
	for (var t = 0; t < tiddlers.length; t++) {
		var date = tiddlers[t].modified.formatString("YYYY0MM0DD")
		if (!modifieds[date])
			modifieds[date]=new Array();
		modifieds[date].push(tiddlers[t].title);
	}
	return modifieds;
}
function hasModifieds(date) // returns true if date has modified tiddlers
{
	if (!config.macros.date.modifieds) config.macros.date.modifieds = indexModifieds();
	return (config.macros.date.modifieds[date.formatString("YYYY0MM0DD")]!=undefined);
}

function addModifiedsToPopup(popup,when,format)
{
	var date=when.formatString("YYYY0MM0DD");
	var force=(store.isDirty() && date==new Date().formatString("YYYY0MM0DD"));
	if (force || !config.macros.date.modifieds) config.macros.date.modifieds=indexModifieds();
	var indent=String.fromCharCode(160)+String.fromCharCode(160);
	var mods = config.macros.date.modifieds[date];
	if (mods) {
		// if a tiddler was created on this date, don't list it in the 'changed' section
		if (config.macros.date.createds && config.macros.date.createds[date]) {
			var temp=[];
			for(var t=0; t<mods.length; t++)
				if (!config.macros.date.createds[date].contains(mods[t]))
					temp.push(mods[t]);
			mods=temp;
		}
		mods.sort();
		var e=createTiddlyElement(popup,"div",null,null,"changed ("+mods.length+")");
		for(var t=0; t<mods.length; t++) {
			var link=createTiddlyLink(popup,mods[t],false);
			link.appendChild(document.createTextNode(indent+mods[t]));
			createTiddlyElement(popup,"br",null,null,null);
		}
	}
}
//}}}

//{{{
function hasTagged(date,format) // returns true if date is tagging other tiddlers
{
	return store.getTaggedTiddlers(date.formatString(format)).length>0;
}

function addTaggedToPopup(popup,when,format)
{
	var indent=String.fromCharCode(160)+String.fromCharCode(160);
	var tagged=store.getTaggedTiddlers(when.formatString(format));
	if (tagged.length) var e=createTiddlyElement(popup,"div",null,null,"tagged ("+tagged.length+")");
	for(var t=0; t<tagged.length; t++) {
		var link=createTiddlyLink(popup,tagged[t].title,false);
		link.appendChild(document.createTextNode(indent+tagged[t].title));
		createTiddlyElement(popup,"br",null,null,null);
	}
}
//}}}

//{{{
function indexReminders(date,leadtime) // build list of tiddlers with reminders, hash indexed by reminder date
{
	var reminders = { };
	if(window.findTiddlersWithReminders!=undefined) { // reminder plugin is installed
		// DEBUG var starttime=new Date();
		var t = findTiddlersWithReminders(date, [0,leadtime], null, null, 1);
		for(var i=0; i<t.length; i++) reminders[t[i].matchedDate]=true;
		// DEBUG var out="Found "+t.length+" reminders in "+((new Date())-starttime+1)+"ms\n";
		// DEBUG out+="startdate: "+date.toLocaleDateString()+"\n"+"leadtime: "+leadtime+" days\n\n";
		// DEBUG for(var i=0; i<t.length; i++) { out+=t[i].matchedDate.toLocaleDateString()+" "+t[i].params.title+"\n"; }
		// DEBUG alert(out);
	}
	return reminders;
}

function hasReminders(date) // returns true if date has reminders
{
	if (window.reminderCacheForCalendar)
		return window.reminderCacheForCalendar[date]; // use calendar cache
	if (!config.macros.date.reminders)
		config.macros.date.reminders = indexReminders(date,90); // create a 90-day leadtime reminder cache
	return (config.macros.date.reminders[date]);
}

function addRemindersToPopup(popup,when,format)
{
	if(window.findTiddlersWithReminders==undefined) return; // reminder plugin not installed

	var indent = String.fromCharCode(160)+String.fromCharCode(160);
	var reminders=findTiddlersWithReminders(when, [0,31],null,null,1);
	createTiddlyElement(popup,"div",null,null,"reminders ("+(reminders.length||"none")+")");
	for(var t=0; t<reminders.length; t++) {
		link = createTiddlyLink(popup,reminders[t].tiddler,false);
		var diff=reminders[t].diff;
		diff=(diff<1)?"Today":((diff==1)?"Tomorrow":diff+" days");
		var txt=(reminders[t].params["title"])?reminders[t].params["title"]:reminders[t].tiddler;
		link.appendChild(document.createTextNode(indent+diff+" - "+txt));
		createTiddlyElement(popup,"br",null,null,null);
	}
	if (readOnly) return;	// omit "new reminder..." link
	var link = createTiddlyLink(popup,indent+"new reminder...",true); createTiddlyElement(popup,"br");
	var title = when.formatString(format);
	link.title="add a reminder to '"+title+"'";
	link.onclick = function() {
		// show tiddler editor
		story.displayTiddler(null, title, 2, null, null, false, false);
		// find body 'textarea'
		var c =document.getElementById("tiddler" + title).getElementsByTagName("*");
		for (var i=0; i<c.length; i++) if ((c[i].tagName.toLowerCase()=="textarea") && (c[i].getAttribute("edit")=="text")) break;
		// append reminder macro to tiddler content
		if (i<c.length) {
			if (store.tiddlerExists(title)) c[i].value+="\n"; else c[i].value="";
			c[i].value += "<<reminder";
			c[i].value += " day:"+when.getDate();
			c[i].value += " month:"+(when.getMonth()+1);
			c[i].value += " year:"+when.getFullYear();
			c[i].value += ' title:"Enter a title" >>';
		}
	};
}
//}}}
/***
|Name|DatePluginConfig|
|Source|http://www.TiddlyTools.com/#DatePluginConfig|
|Documentation|http://www.TiddlyTools.com/#DatePluginInfo|
|Version|2.6.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|formats, background colors and other optional settings for DatePlugin|
***/
// // Default popup content display options (can be overridden by cookies)
//{{{
if (config.options.chkDatePopupHideCreated===undefined)
	config.options.chkDatePopupHideCreated=false;
if (config.options.chkDatePopupHideChanged===undefined)
	config.options.chkDatePopupHideChanged=false;
if (config.options.chkDatePopupHideTagged===undefined)
	config.options.chkDatePopupHideTagged=false;
if (config.options.chkDatePopupHideReminders===undefined)
	config.options.chkDatePopupHideReminders=false;
//}}}

// // show Julian date number below regular date
//{{{
if (config.options.chkShowJulianDate===undefined)
	config.options.chkShowJulianDate=false;
//}}}

// // fixed-date annual holidays
//{{{
config.macros.date.holidays=[
	"01/01", // NewYearsDay, 
	"07/04", // US Independence Day
	"07/24"  // Eric's Birthday (hooray!)
];
//}}}

// // weekend map (1=weekend, 0=weekday)
//{{{
config.macros.date.weekend=[ 1,0,0,0,0,0,1 ]; // day index values: sun=0, mon=1, tue=2, wed=3, thu=4, fri=5, sat=6
//}}}

// // date display/link formats
//{{{
config.macros.date.format="YYYY.0MM.0DD"; // default date display format
config.macros.date.linkformat="YYYY.0MM.0DD"; // 'dated tiddler' link format
//}}}

// // When displaying a calendar (see [[CalendarPlugin]]), you can customize the colors/styles that are applied to the calendar dates by modifying the values and/or functions below:
//{{{
// default calendar colors
config.macros.date.weekendbg="#c0c0c0";
config.macros.date.holidaybg="#ffaace";
config.macros.date.createdbg="#bbeeff";
config.macros.date.modifiedsbg="#bbeeff";
config.macros.date.linkedbg="#babb1e";
config.macros.date.remindersbg="#c0ffee";

// apply calendar styles
function setDateStyle(place,link,weekend) {
	// alias variable names for code readability
	var date=link.date;
	var fmt=link.linkformat;
	var linkto=date.formatString(fmt);
	var cmd=config.macros.date;

	if ((weekend!==undefined?weekend:isWeekend(date))&&(cmd.weekendbg!=""))
		{ place.style.background = cmd.weekendbg; }
	if (hasModifieds(date)||hasCreateds(date)||hasTagged(date,fmt))
		{ link.style.fontStyle="normal"; link.style.fontWeight="bold"; }
	if (hasReminders(date))
		{ link.style.textDecoration="underline"; }
	if (isToday(date))
		{ link.style.border="1px solid black"; }
	if (isHoliday(date)&&(cmd.holidaybg!=""))
		{ place.style.background = cmd.holidaybg; }
	if (hasCreateds(date)&&(cmd.createdbg!=""))
		{ place.style.background = cmd.createdbg; }
	if (hasModifieds(date)&&(cmd.modifiedsbg!=""))
		{ place.style.background = cmd.modifiedsbg; }
	if ((hasTagged(date,fmt)||store.tiddlerExists(linkto))&&(cmd.linkedbg!=""))
		{ place.style.background = cmd.linkedbg; }
	if (hasReminders(date)&&(cmd.remindersbg!=""))
		{ place.style.background = cmd.remindersbg; }
	if (isToday(date)&&(cmd.todaybg!=""))
		{ place.style.background = cmd.todaybg; }
	if (config.options.chkShowJulianDate) {
		var m=[0,31,59,90,120,151,181,212,243,273,304,334];
		var d=date.getDate()+m[date.getMonth()];
		var y=date.getFullYear();
		if (date.getMonth()>1 && (y%4==0 && y%100!=0) || y%400==0) d++; // after February in a leap year
		wikify("@@font-size:80%;<br>"+d+"@@",place);
	}
}
//}}}
|Name|DatePluginInfo|
|Source|http://www.TiddlyTools.com/#DatePlugin|
|Documentation|http://www.TiddlyTools.com/#DatePluginInfo|
|Version|2.7.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for DatePlugin|
There are quite a few calendar generators, reminders, to-do lists, 'dated tiddlers' journals, blog-makers and GTD-like schedule managers that have been built around TW.  While they all have different purposes, and vary in format, interaction, and style, in one way or another each of these plugins displays and/or uses date-based information to make finding, accessing and managing relevant tiddlers easier.  This plugin provides a general approach to embedding dates and date-based links/menus within tiddler content.
!!!!!Usage
<<<
This plugin display formatted dates, for the specified year, month, day using number values or mathematical expressions such as (Y+1) or (D+30).  Optionally, you can create a link from the formatted output to a 'dated tiddler' for quick blogging or create a popup menu that includes the dated tiddler link plus links to tiddlers that were created/changed on that date, or are tagged with that date, as well as links to any pending reminders for the coming 31 days (if the RemindersPlugin is installed).  This plugin also provides a public API for easily incorporating formatted date output (with or without the links/popups) into other plugins, such as calendar generators, etc.

This plugin defines a macro: {{{<<date [mode] [date] [format] [linkformat]>>}}}.  All of the macro parameters are optional and, in it's simplest form, {{{<<date>>}}}, it is equivalent to the ~TiddlyWiki core macro, {{{<<today>>}}}.

However, where {{{<<today>>}}} simply inserts the current date/time in a predefined format (or custom format, using {{{<<today [format]>>}}}), the {{{<<date>>}}} macro's parameters take it much further than that:
* [mode] is either ''display'', ''link'' or ''popup''.  If omitted, it defaults to ''display''.  This param let's you select between simply displaying a formatted date, or creating a link to a specific 'date titled' tiddler or a popup menu containing a dated tiddler link, plus links to changes and reminders.
* [date] lets you enter ANY date (not just today) as ''year, month, and day values or simple mathematical expressions'' using pre-defined variables, Y, M, and D for the current year, month and day, repectively.  You can display the modification date of the current tiddler by using the keyword: ''tiddler'' in place of the year, month and day parameters.  Use ''tiddler://name-of-tiddler//'' to display the modification date of a specific tiddler.  You can also use keywords ''today'' or ''filedate'' to refer to these //dynamically changing// date/time values.  
* [format] and [linkformat] uses standard ~TiddlyWiki date formatting syntax.  The default is "YYYY.0MM.0DD"
>^^''DDD'' - day of week in full (eg, "Monday"), ''DD'' - day of month, ''0DD'' - adds leading zero^^
>^^''MMM'' - month in full (eg, "July"), ''MM'' - month number, ''0MM'' - adds leading zero^^
>^^''YYYY'' - full year, ''YY'' - two digit year, ''hh'' - hours, ''mm'' - minutes, ''ss'' - seconds^^
>^^//note: use of hh, mm or ss format codes is only supported with ''tiddler'', ''today'' or ''filedate'' values//^^
* [linkformat] - specify an alternative date format so that the title of a 'dated tiddler' link can have a format that differs from the date's displayed format

In addition to the macro syntax, DatePlugin also provides a public javascript API so that other plugins that work with dates (such as calendar generators, etc.) can quickly incorporate date formatted links or popups into their output:

''{{{showDate(place, date, mode, format, linkformat, autostyle, weekend)}}}'' 

Note that in addition to the parameters provided by the macro interface, the javascript API also supports two optional true/false parameters:
* [autostyle] - when true, the font/background styles of formatted dates are automatically adjusted to show the date's status:  'today' is boxed, 'changes' are bold, 'reminders' are underlined, while weekends and holidays (as well as changes and reminders) can each have a different background color to make them more visibly distinct from each other.
* [weekend] - true indicates a weekend, false indicates a weekday.  When this parameter is omitted, the plugin uses internal defaults to automatically determine when a given date falls on a weekend.
<<<
!!!!!Examples
<<<
The current date: <<date>>
The current time: <<date today "0hh:0mm:0ss">>
Today's blog: <<date link today "DDD, MMM DDth, YYYY">>
Recent blogs/changes/reminders: <<date popup Y M D-1 "yesterday">> <<date popup today "today">> <<date popup Y M D+1 "tomorrow">>
The first day of next month will be a <<date Y M+1 1 "DDD">>
This tiddler (DatePlugin) was last updated on: <<date tiddler "DDD, MMM DDth, YYYY">>
The SiteUrl was last updated on: <<date tiddler:SiteUrl "DDD, MMM DDth, YYYY">>
This document was last saved on <<date filedate "DDD, MMM DDth, YYYY at 0hh:0mm:0ss">>
<<date 2006 07 24 "MMM DDth, YYYY">> will be a <<date 2006 07 24 "DDD">>
<<<
!!!!!Revisions
<<<
2008.03.08 [2.7.0] in addModifiedsToPopup(), if a tiddler was created on the specified date, don't list it in the 'changed' section of the popup.  Based on a request from Kashgarinn
2008.01.31 [2.6.0] refactored date style logic into separate setDateStyle() function so it can be overridden by a custom definition.  See [[DatePluginConfig]].
2008.01.11 [2.5.0] added options to selectively suppress created/changes/tagged/reminders popup content 
2008.01.08 [*.*.*] plugin size reduction: documentation moved to DatePluginInfo
2007.11.21 [2.4.0] added hasTagged() and addTaggedToPopup() to list any tiddlers that has been tagged using the title of the dated journal tiddler asa tag value (i.e., the tiddlers that will be listed in the standard "tagging" display when viewing the journal tiddler itself).  Based on a request from Coby.
2007.06.20 [2.3.1] in onClickDatePopup(), use Popup.show() instead of deprecated ScrollToTiddlerPopup().  Fixes fatal error that prevents popups from being properly displayed
2007.05.31 [2.3.0] list "created" tiddlers in date popup.  Also, force re-cache of created/modified indices when displaying current date and store.isDirty(), so that popup is kept in sync with tiddler changes.
2006.05.09 [2.2.1] added "todaybg" handling to set background color of current date.  Also, honor excludeLists tag when getting lists of tiddlers.  Based on suggestions by Mark Hulme.
2006.05.05 [2.2.0] added "linkedbg" handling to set background color when a 'dated tiddler' exists.  Based on a suggestion by Mark Hulme.
2006.03.08 [2.1.2] add 'override leadtime' flag param in call to findTiddlersWithReminders(), and add "Enter a title" default text to new reminder handler.  Thanks to Jeremy Sheeley for these additional tweaks.
2006.03.06 [2.1.0] hasReminders() nows uses window.reminderCacheForCalendar[] when present.  If calendar cache is not present, indexReminders() now uses findTiddlersWithReminders() with a 90-day look ahead to check for reminders.  Also, switched default background colors for autostyled dates: reminders are now greenish ("c0ffee") and holidays are now reddish ("ffaace").
2006.02.14 [2.0.5] when readOnly is set (by TW core), omit "new reminders..." popup menu item and, if a "dated tiddler" does not already exist, display the date as simple text instead of a link.
2006.02.05 [2.0.4] added var to variables that were unintentionally global.  Avoids FireFox 1.5.0.1 crash bug when referencing global variables
2006.01.18 [2.0.3] In 1.2.x the tiddler editor's text area control was given an element ID=("tiddlerBody"+title), so that it was easy to locate this field and programmatically modify its content.  With the addition of configuration templates in 2.x, the textarea no longer has an ID assigned.  To find this control we now look through all the child nodes of the tiddler editor to locate a "textarea" control where attribute("edit") equals "text", and then append the new reminder to the contents of that control.
2006.01.11 [2.0.2] correct 'weekend' override detection logic in showDate()
2006.01.10 [2.0.1] allow custom-defined weekend days (default defined in config.macros.date.weekend[] array)
added flag param to showDate() API to override internal weekend[] array
2005.12.27 [2.0.0] Update for TW2.0
Added parameter handling for 'linkformat'
2005.12.21 [1.2.2] FF's date.getYear() function returns 105 (for the current year, 2005).  When calculating a date value from Y M and D expressions, the plugin adds 1900 to the returned year value get the current year number.  But IE's date.getYear() already returns 2005.  As a result, plugin calculated date values on IE were incorrect (e.g., 3905 instead of 2005).  Adding +1900 is now conditional so the values will be correct on both browsers.
2005.11.07 [1.2.1] added support for "tiddler" dynamic date parameter
2005.11.06 [1.2.0] added support for "tiddler:title" dynamic date parameter
2005.11.03 [1.1.2] when a reminder doesn't have a specified title parameter, use the title of the tiddler that contains the reminder as "fallback" text in the popup menu.  Based on a suggestion from BenjaminKudria.
2005.11.03 [1.1.1] Temporarily bypass hasReminders() logic to avoid excessive overhead from generating the indexReminders() cache.  While reminders can still appear in the popup menu, they just won't be indicated by auto-styling the date number that is displayed.  This single change saves approx. 60% overhead (5 second delay reduced to under 2 seconds).
2005.11.01 [1.1.0] corrected logic in hasModifieds() and hasReminders() so caching of indexed modifieds and reminders is done just once, as intended.  This should hopefully speed up calendar generators and other plugins that render multiple dates...
2005.10.31 [1.0.1] documentation and code cleanup
2005.10.31 [1.0.0] initial public release
2005.10.30 [0.9.0] pre-release
<<<
/%
|Name|DigitalClock|
|Source|http://www.TiddlyTools.com/#DigitalClock|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|display current time with automatic LIVE update|

Usage: <<tiddler DigitalClock with: format tick>>

where 'format' is any TiddlyWiki date/time formatting string
and 'tick' is the time in seconds between display updates (default=1sec)

For example, use:
   << ... "0hh:0mm" 60>>
to show hours and minutes only, updated once per minute

%/<script>
	window.DigitalClock_tick=function(id){
		var e=document.getElementById(id); if (!e) return;
		e.title='click to '+(e.paused?'RESUME':'PAUSE')+' clock display';
		if (e.paused) return;
		e.innerHTML=new Date().formatString(e.fmt);
		setTimeout('window.DigitalClock_tick('+id+')',e.tick*1000);
	}
	var e=createTiddlyElement(place,'a',new Date().getTime()+Math.random());
	e.onclick=function(){this.paused=!this.paused;window.DigitalClock_tick(this.id);}
	e.style.cursor='pointer';
	e.fmt=('$1'=='$'+'1')?'hh12:0mm:0ss am':'$1';
	e.tick=('$2'=='$'+'2')?'1':'$2';
	window.DigitalClock_tick(e.id);
</script>
TiddlyWiki FireFox TiddlyTools TiddlyTech HowTo
/***
|Name|DisableWikiLinksPlugin|
|Source|http://www.TiddlyTools.com/#DisableWikiLinksPlugin|
|Version|1.5.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Tiddler.prototype.autoLinkWikiWords, 'wikiLink' formatter|
|Options|##Configuration|
|Description|selectively disable TiddlyWiki's automatic ~WikiWord linking behavior|
This plugin allows you to disable TiddlyWiki's automatic ~WikiWord linking behavior, so that WikiWords embedded in tiddler content will be rendered as regular text, instead of being automatically converted to tiddler links.  To create a tiddler link when automatic linking is disabled, you must enclose the link text within {{{[[...]]}}}.
!!!!!Usage
<<<
You can block automatic WikiWord linking behavior for any specific tiddler by ''tagging it with<<tag excludeWikiWords>>'' (see configuration below) or, check a plugin option to disable automatic WikiWord links to non-existing tiddler titles, while still linking WikiWords that correspond to existing tiddlers titles or shadow tiddler titles.  You can also block specific selected WikiWords from being automatically linked by listing them in [[DisableWikiLinksList]] (see configuration below), separated by whitespace.  This tiddler is optional and, when present, causes the listed words to always be excluded, even if automatic linking of other WikiWords is being permitted.  

Note: WikiWords contained in default ''shadow'' tiddlers will be automatically linked unless you select an additional checkbox option lets you disable these automatic links as well, though this is not recommended, since it can make it more difficult to access some TiddlyWiki standard default content (such as AdvancedOptions or SideBarTabs)
<<<
!!!!!Configuration
<<<
<<option chkDisableWikiLinks>> Disable ALL automatic WikiWord tiddler links
<<option chkAllowLinksFromShadowTiddlers>> ... except for WikiWords //contained in// shadow tiddlers
<<option chkDisableNonExistingWikiLinks>> Disable automatic WikiWord links for non-existing tiddlers
Disable automatic WikiWord links for words listed in: <<option txtDisableWikiLinksList>>
Disable automatic WikiWord links for tiddlers tagged with: <<option txtDisableWikiLinksTag>>
<<<
!!!!!Revisions
<<<
2006.06.09 [1.5.0] added configurable txtDisableWikiLinksTag (default value: "excludeWikiWords") to allows selective disabling of automatic WikiWord links for any tiddler tagged with that value.
2006.12.31 [1.4.0] in formatter, test for chkDisableNonExistingWikiLinks
2006.12.09 [1.3.0] in formatter, test for excluded wiki words specified in DisableWikiLinksList
2006.12.09 [1.2.2] fix logic in autoLinkWikiWords() (was allowing links TO shadow tiddlers, even when chkDisableWikiLinks is TRUE).  
2006.12.09 [1.2.1] revised logic for handling links in shadow content
2006.12.08 [1.2.0] added hijack of Tiddler.prototype.autoLinkWikiWords so regular (non-bracketed) WikiWords won't be added to the missing list
2006.05.24 [1.1.0] added option to NOT bypass automatic wikiword links when displaying default shadow content (default is to auto-link shadow content)
2006.02.05 [1.0.1] wrapped wikifier hijack in init function to eliminate globals and avoid FireFox 1.5.0.1 crash bug when referencing globals
2005.12.09 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.disableWikiLinks= {major: 1, minor: 5, revision: 0, date: new Date(2007,6,9)};

if (config.options.chkDisableNonExistingWikiLinks==undefined) config.options.chkDisableNonExistingWikiLinks= false;
if (config.options.chkDisableWikiLinks==undefined) config.options.chkDisableWikiLinks=false;
if (config.options.txtDisableWikiLinksList==undefined) config.options.txtDisableWikiLinksList="DisableWikiLinksList";
if (config.options.chkAllowLinksFromShadowTiddlers==undefined) config.options.chkAllowLinksFromShadowTiddlers=true;
if (config.options.txtDisableWikiLinksTag==undefined) config.options.txtDisableWikiLinksTag="excludeWikiWords";

// find the formatter for wikiLink and replace handler with 'pass-thru' rendering
initDisableWikiLinksFormatter();
function initDisableWikiLinksFormatter() {
	for (var i=0; i<config.formatters.length && config.formatters[i].name!="wikiLink"; i++);
	config.formatters[i].coreHandler=config.formatters[i].handler;
	config.formatters[i].handler=function(w) {
		// supress any leading "~" (if present)
		var skip=(w.matchText.substr(0,1)==config.textPrimitives.unWikiLink)?1:0;
		var title=w.matchText.substr(skip);
		var exists=store.tiddlerExists(title);
		var inShadow=w.tiddler && store.isShadowTiddler(w.tiddler.title);

		// check for excluded Tiddler
		if (w.tiddler && w.tiddler.isTagged(config.options.txtDisableWikiLinksTag))
			{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }
		
		// check for specific excluded wiki words
		var t=store.getTiddlerText(config.options.txtDisableWikiLinksList)
		if (t && t.length && t.indexOf(w.matchText)!=-1)
			{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }

		// if not disabling links from shadows (default setting)
		if (config.options.chkAllowLinksFromShadowTiddlers && inShadow)
			return this.coreHandler(w);

		// check for non-existing non-shadow tiddler
		if (config.options.chkDisableNonExistingWikiLinks && !exists)
			{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }

		// if not enabled, just do standard WikiWord link formatting
		if (!config.options.chkDisableWikiLinks)
			return this.coreHandler(w);

		// just return text without linking
		w.outputText(w.output,w.matchStart+skip,w.nextMatch)
	}
}

Tiddler.prototype.coreAutoLinkWikiWords = Tiddler.prototype.autoLinkWikiWords;
Tiddler.prototype.autoLinkWikiWords = function()
{
	// DEBUG alert("processing: "+this.title);
	// if all automatic links are not disabled, just return results from core function
	if (!config.options.chkDisableWikiLinks)
		return this.coreAutoLinkWikiWords.apply(this,arguments);
	return false;
}
//}}}
''horizontal:''
{{{
* menu #1
** [[item #1-1]]
** [[item #1-2]]
** [[item #1-3]]
* menu #2
** [[item #2-1]]
** [[item #2-2]]
** [[menu #2-3]]
* menu #3
** [[item #2-1]]
** [[item #2-2]]
** [[menu #2-3]]
<<dropMenu>>
}}}
* menu #1
** [[item #1-1]]
** [[item #1-2]]
** [[item #1-3]]
* menu #2
** [[item #2-1]]
** [[item #2-2]]
** [[menu #2-3]]
* menu #3
** [[item #2-1]]
** [[item #2-2]]
** [[menu #2-3]]
<<dropMenu>>

''vertical:''
{{{
* menu #1
** [[item #1-1]]
** [[item #1-2]]
** [[item #1-3]]
* menu #2
** [[item #2-1]]
** [[item #2-2]]
** [[menu #2-3]]
<<dropMenu vertical>>
}}}

* menu #1
** [[item #1-1]]
** [[item #1-2]]
** [[item #1-3]]
* menu #2
** [[item #2-1]]
** [[item #2-2]]
** [[menu #2-3]]
<<dropMenu vertical>>


/% %/
/***
|''Name:''|DropDownMenuPlugin|
|''Description:''|Create dropdown menus from unordered lists|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#DropDownMenuPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.1|
|''Date:''|11/04/2007|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.5|

!!Usage:
* create a two-level unordered list using wiki syntax, and place {{{<<dropMenu>>}}} on the line after it.
* to create a vertical menu use {{{<<dropMenu vertical>>}}} instead.
* to assign custom classes to the list, just pass them as parameters to the macro {{{<<dropMenu className1 className2 className3>>}}}

!!Features:
*Supports just a single level of drop-downs, as anything more usually provides a poor experience for the user.
* Very light weight, about 1.5kb of JavaScript and 4kb of CSS.
* Comes with two built in css 'themes', the default horizontal and vertical. 

!!Customizing:
* to customize the appearance of the menu's, you can either add a custom class as described above or, you can edit the CSS via the StyleSheetDropDownMenu shadow tiddler.

!!Examples:
* [[DropDownMenuDemo]]

***/
// /%
//!BEGIN-PLUGIN-CODE
config.macros.dropMenu={

	dropdownchar: "\u25bc",

	handler : function(place,macroName,params,wikifier,paramString,tiddler){
		list = findRelated(place.lastChild,"UL","tagName","previousSibling");
		if (!list)
			return;
		addClass(list,"suckerfish");
		if (params.length){
			addClass(list,paramString);
		}
		this.fixLinks(list);
	},
	
	fixLinks : function(el){
		var els = el.getElementsByTagName("li");
		for(var i = 0; i < els.length; i++) {
			if(els[i].getElementsByTagName("ul").length>0){
				var link = findRelated(els[i].firstChild,"A","tagName","nextSibling");
				if(!link){
					var ih = els[i].firstChild.data;
					els[i].removeChild(els[i].firstChild);
					var d = createTiddlyElement(null,"a",null,null,ih+this.dropdownchar,{href:"javascript:;"});
					els[i].insertBefore(d,els[i].firstChild);
				}
				else{
					link.firstChild.data = link.firstChild.data + this.dropdownchar;
					removeClass(link,"tiddlyLinkNonExisting");
				}
			}
			els[i].onmouseover = function() {
				addClass(this, "sfhover");
			};
			els[i].onmouseout = function() {
				removeClass(this, "sfhover");
			};
		}
	}	
};

config.shadowTiddlers["StyleSheetDropDownMenuPlugin"] = 
	 "/*{{{*/\n"+
	 "/***** LAYOUT STYLES -  DO NOT EDIT! *****/\n"+
	 "ul.suckerfish, ul.suckerfish ul {\n"+
	 "	margin: 0;\n"+
	 "	padding: 0;\n"+
	 "	list-style: none;\n"+
	 "	line-height:1.4em;\n"+
	 "}\n\n"+
	 "ul.suckerfish  li {\n"+
	 "	display: inline-block; \n"+
	 "	display: block;\n"+
	 "	float: left; \n"+
	 "}\n\n"+
	 "ul.suckerfish li ul {\n"+
	 "	position: absolute;\n"+
	 "	left: -999em;\n"+
	 "}\n\n"+
	 "ul.suckerfish li:hover ul, ul.suckerfish li.sfhover ul {\n"+
	 "	left: auto;\n"+
	 "}\n\n"+
	 "ul.suckerfish ul li {\n"+
	 "	float: none;\n"+
	 "	border-right: 0;\n"+
	 "	border-left:0;\n"+
	 "}\n\n"+
	 "ul.suckerfish a, ul.suckerfish a:hover {\n"+
	 "	display: block;\n"+
	 "}\n\n"+
	 "ul.suckerfish li a.tiddlyLink, ul.suckerfish li a, #mainMenu ul.suckerfish li a {font-weight:bold;}\n"+
	 "/**** END LAYOUT STYLES *****/\n"+
	 "\n\n"+
	 "/**** COLORS AND APPEARANCE - DEFAULT *****/\n"+
	 "ul.suckerfish li a {\n"+
	 "	padding: 0.5em 1.5em;\n"+
	 "	color: #FFF;\n"+
	 "	background: #0066aa;\n"+
	 "	border-bottom: 0;\n"+
	 "	font-weight:bold;\n"+
	 "}\n\n"+
	 "ul.suckerfish li:hover a, ul.suckerfish li.sfhover a{\n"+
	 "	background: #00558F;\n"+
	 "}\n\n"+
	 "ul.suckerfish li:hover ul a, ul.suckerfish li.sfhover ul a{\n"+
	 "	color: #000;\n"+
	 "	background: #eff3fa;\n"+
	 "	border-top:1px solid #FFF;\n"+
	 "}\n\n"+
	 "ul.suckerfish ul li a:hover {\n"+
	 "	background: #e0e8f5;\n"+
	 "}\n\n"+
	 "ul.suckerfish li a{\n"+
	 "	width:9em;\n"+
	 "}\n\n"+
	 "ul.suckerfish ul li a, ul.suckerfish ul li a:hover{\n"+
	 "	display:inline-block;\n"+
	 "	width:9em;\n"+
	 "}\n\n"+
	 "ul.suckerfish li {\n"+
	 "	border-left: 1px solid #00558F;\n"+
	 "}\n"+
	 "/***** END COLORS AND APPEARANCE - DEFAULT *****/\n"+
	 "\n\n"+
	 "/***** LAYOUT AND APPEARANCE: VERTICAL *****/\n"+
	 "ul.suckerfish.vertical li{\n"+
	 "	width:10em;\n"+
	 "	border-left: 0px solid #00558f;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical ul li, ul.suckerfish.vertical li a, ul.suckerfish.vertical li:hover a, ul.suckerfish.vertical li.sfhover a {\n"+
	 "	border-left: 0.8em solid #00558f;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical li a, ul.suckerfish.vertical li:hover a, ul.suckerfish.vertical li.sfhover a,  ul.suckerfish.vertical li.sfhover a:hover{\n"+
	 "	width:8em;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical {\n"+
	 "	width:10em; text-align:left;\n"+
	 "	float:left;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical li a {\n"+
	 "	padding: 0.5em 1em 0.5em 1em;\n"+
	 "	border-top:1px solid  #fff;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical, ul.suckerfish.vertical ul {\n"+
	 "	line-height:1.4em;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical li:hover ul, ul.suckerfish.vertical li.sfhover ul { \n"+
	 "	margin: -2.4em 0 0 10.9em;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical li:hover ul li a, ul.suckerfish.vertical li.sfhover ul li a {\n"+
	 "	border: 0px solid #FFF;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical li:hover a, ul.suckerfish.vertical li.sfhover a{\n"+
	 "	padding-right:1.1em;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical li:hover ul li, ul.suckerfish.vertical li.sfhover ul li {\n"+
	 "	border-bottom:1px solid  #fff;\n"+
	 "}\n\n"+
	 "/***** END LAYOUT AND APPEARANCE: VERTICAL *****/\n"+
	 "/*}}}*/";
store.addNotification("StyleSheetDropDownMenuPlugin",refreshStyles);
//!END-PLUGIN-CODE
// %/
/***
| Name:|''dropTagging''|
| Created by:|SaqImtiaz|
| Location:|http://tw.lewcid.org/|
| Version:|0.1 (06-Apr-2006)|
| Requires:|~TW2.07|

!About
*provides a drop down list of tiddlers tagged with the specified tag, a replacement for the core tagging macro.

!Demonstration
*<<dropTagging Saq>>
''I recommend using either TaggerPlugin or monkeyTagger, with dropTags and dropTagging in the toolbar:''


!Usage
{{{<<dropTagging>>}}} for tiddlers tagged by current tiddler/tag
{{{<<dropTagging 'Saq'>>}}} for tiddlers tagged by the tag 'Saq' <<dropTagging 'Saq'>>
{{{<<dropTagging 'Saq' 'custom label'>>}}} for tiddlers tagged by the tag 'Saq' with a custom label. <<dropTagging 'Saq' 'custom label'>>

!Installation:
*Copy this tiddler to your TW with the systemConfig tag
* copy the following to your ViewTemplate:
#either {{{<div class='tagging' macro='dropTagging'></div>}}} to add next to or replace tagging macro, or
#{{{<div class='toolbar' >
<span style="padding-right:1.75em;" macro='dropTagging''></span>
<span macro='toolbar -closeTiddler closeOthers +editTiddler permalink references jump'></span>
</div>}}}(adjust padding to taste)

!To Do
*tweak popup css to optimize placement and colors.
*''optimize code to use core onClickTag function, can cut code size by half!''

!Code
***/
//{{{
config.macros.dropTagging={};
config.macros.dropTagging.dropdownchar = (document.all?"â–¼":"â–¾"); // the fat one is the only one that works in IE
config.macros.dropTagging.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
 var arrow=': '+ config.macros.dropTagging.dropdownchar;
 if(params[0] && store.tiddlerExists(params[0]))
 tiddler = store.getTiddler(params[0]);



 var droptagginglabel= (params[1] && params[1] !='.')? params[1]: 'tagging'+arrow;
 var droptaggingtooltip="tiddlers tagged with '"+tiddler.title+"'";
 
 if(params[0] && store.tiddlerExists(params[0]))
 tiddler = store.getTiddler(params[0]);
 var tagged = store.getTaggedTiddlers(tiddler.title);

 if(tagged.length==0)
 return false; 
 
 var droptagging = function(e)
 { if (!e) var e = window.event;
 var popup = Popup.create(this);
 


 for(var t=0; t<tagged.length; t++)
 createTiddlyLink(createTiddlyElement(popup,"li"),tagged[t].title,true);

 Popup.show(popup,false);
 e.cancelBubble = true;
 if (e.stopPropagation)
 e.stopPropagation();
 return(false);
 };
 
var createdropperButton = function(place){
var sp = createTiddlyElement(place,"span",null,"taggingdropbutton");
var theDropDownBtn = createTiddlyButton(sp,droptagginglabel,droptaggingtooltip,droptagging);
 };
createdropperButton(place);
};

setStylesheet(
 ".toolbar .taggingdropbutton {margin-right:0em; border:0px solid #eee; padding:0px; padding-right:0px; padding-left:0px; }\n"+
 ".taggingdropbutton a.button {padding:2px; padding-left:2px; padding-right:2px;}\n"+
// ".taggingdropbutton {font-size:150%;}\n"+
".popup .highlight{background: #fe8; color:#000;}\n"+
 "",
"DropTaggingStyles");

//}}}
/***
|''Name:''|''dropTags''|
|''Version:''|0.5 (12-May-2006)|
|''Created by:''|SaqImtiaz|
|''Location:''|http://tw.lewcid.org/#DropTagsMacro|
|''Description:''|provides a drop down list of tags in the current tiddler,<<br>> a replacement for the core tags macro.|
|''Documentation:''|DropTagsMacroDocumentation |
|''Source Code:''|[[DropTagsMacroSource|DropTagsMacroDocumentation]] |
|''Requires:''|~TW2.07|

***/
// /%
config.macros.dropTags={};config.macros.dropTags.dropdownchar=(document.all?"â–¼":"â–¾");config.macros.dropTags.handler=function(_1,_2,_3,_4,_5,_6){var _7=config.macros.dropTags.dropdownchar;var _8=(_3[0]&&_3[0]!=".")?_3[0]+_7:"tags"+_7;var _9="current tags for this tiddler";var _a=function(e){if(!e){var e=window.event;}var _d=Popup.create(this);var _e=config.views.wikified.tag;if(_6.tags.length==0){createTiddlyElement(_d,"li",null,"listTitle",_e.labelNoTags);}else{for(var t=0;t<_6.tags.length;t++){createTagButton(createTiddlyElement(_d,"li"),_6.tags[t],_6.title);}}if(version.extensions.IntelliTaggerPlugin){createTiddlyElement(createTiddlyElement(_d,"li"),"hr");abego.IntelliTagger.createEditTagsButton(_6,createTiddlyElement(_d,"li"),"[IntelliEdit]","Edit tags with Intellitagger");}Popup.show(_d,false);e.cancelBubble=true;if(e.stopPropagation){e.stopPropagation();}return (false);};createTiddlyButton(_1,_8,_8,_a,"button","dropTagBtn");};setStylesheet(".popup .highlight{background: #fe8; color:#000;}\n"+"#nestedtagger {background:#2E5ADF; border: 1px solid #0331BF;}\n"+"","DropTagsStyles");if(!config.macros.tagger){window.onClickTag=function(e){if(!e){var e=window.event;}var _12=resolveTarget(e);var _13=(!isNested(_12));if((Popup.stack.length>1)&&(_13==true)){Popup.removeFrom(1);}else{if(Popup.stack.length>0&&_13==false){Popup.removeFrom(0);}}var _14=(_13==false)?"popup":"nestedtagger";var _15=createTiddlyElement(document.body,"ol",_14,"popup",null);Popup.stack.push({root:this,popup:_15});var tag=this.getAttribute("tag");var _17=this.getAttribute("tiddler");if(_15&&tag){var _18=store.getTaggedTiddlers(tag);var _19=[];var li,r;for(r=0;r<_18.length;r++){if(_18[r].title!=_17){_19.push(_18[r].title);}}var _1b=config.views.wikified.tag;if(_19.length>0){var _1c=createTiddlyButton(createTiddlyElement(_15,"li"),_1b.openAllText.format([tag]),_1b.openAllTooltip,onClickTagOpenAll);_1c.setAttribute("tag",tag);createTiddlyElement(createTiddlyElement(_15,"li"),"hr");for(r=0;r<_19.length;r++){createTiddlyLink(createTiddlyElement(_15,"li"),_19[r],true);}}else{createTiddlyText(createTiddlyElement(_15,"li",null,"disabled"),_1b.popupNone.format([tag]));}createTiddlyElement(createTiddlyElement(_15,"li"),"hr");var h=createTiddlyLink(createTiddlyElement(_15,"li"),tag,false);createTiddlyText(h,_1b.openTag.format([tag]));}Popup.show(_15,false);e.cancelBubble=true;if(e.stopPropagation){e.stopPropagation();}return (false);};}if(!window.isNested){window.isNested=function(e){while(e!=null){var _1f=document.getElementById("contentWrapper");if(_1f==e){return true;}e=e.parentNode;}return false;};};config.shadowTiddlers.DropTagsMacroDocumentation="The documentation is available [[here.|http://tw.lewcid.org/#DropTagsMacroDocumentation]]";config.shadowTiddlers.DropTagsMacroSource="The documentation is available [[here.|http://tw.lewcid.org/#DropTagsMacroDocumentation]]";
// %/
/***
|''Name:''|''dropTags''|
|''Version:''|0.5 (12-May-2006)|
|''Created by:''|SaqImtiaz|
|''Location:''|http://tw.lewcid.org/#DropTagsMacro|
|''Description:''|provides a drop down list of tags in the current tiddler,<<br>> a replacement for the core tags macro.|
|''Documentation:''|DropTagsMacroDocumentation |
|''Source Code:''|DropTagsMacroSource |
|''Requires:''|~TW2.07|

!About
*provides a drop down list of tags in the current tiddler, a replacement for the core tags macro.

''I recommend using either TaggerPlugin or monkeyTagger, with dropTags and dropTagging in the toolbar:''


!Usage
{{{<<dropTags>>}}} for <<dropTags>>
or {{{<<dropTags 'custom label'>>}}} for <<dropTags 'custom label'>>

!Installation:
*Copy this tiddler to your TW with the systemConfig tag
* copy the following to your ViewTemplate:
#either {{{<div class='tagged' macro='dropTags'></div>}}} to add to next to the tags macro in the viewer area, or
#{{{<div class='toolbar' >
<span style="padding-right:8.75em;" macro='dropTags "current tags: "+config.macros.dropTags.dropdownchar}}'></span>
<span macro='toolbar -closeTiddler closeOthers +editTiddler permalink references jump'></span>
</div>}}}


!History
*May 12th, version 0.5, fixed some nesting bugs, added support for IntellitaggerPlugin.
*May 3rd, version 0.41, made compatible with CustomPopups.

!Source Code
***/
//{{{
config.macros.dropTags={};
config.macros.dropTags.dropdownchar = (document.all?"â–¼":"â–¾"); // the fat one is the only one that works in IE
config.macros.dropTags.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
    var arrow=config.macros.dropTags.dropdownchar;
    var droptaglabel= (params[0] && params[0] !='.')? params[0]+arrow: 'tags'+arrow;
    var droptagtooltip="current tags for this tiddler";

    var droptag = function(e){
        if (!e) var e = window.event;
        var popup = Popup.create(this);
        var lingo = config.views.wikified.tag;
        if (tiddler.tags.length==0)
           createTiddlyElement(popup,"li",null,"listTitle",lingo.labelNoTags);
        else
            for(var t=0; t<tiddler.tags.length; t++)
                    {createTagButton(createTiddlyElement(popup,"li"),tiddler.tags[t],tiddler.title);}
        if (version.extensions.IntelliTaggerPlugin)
            {createTiddlyElement(createTiddlyElement(popup,"li"),"hr");
             abego.IntelliTagger.createEditTagsButton(tiddler, createTiddlyElement(popup,"li"),"[IntelliEdit]","Edit tags with Intellitagger");}
        Popup.show(popup,false);
        e.cancelBubble = true;
        if (e.stopPropagation)
           e.stopPropagation();
        return(false);
        };
    createTiddlyButton(place,droptaglabel,droptaglabel,droptag,"button","dropTagBtn");
};

setStylesheet(
".popup .highlight{background: #fe8; color:#000;}\n"+
"#nestedtagger {background:#2E5ADF; border: 1px solid #0331BF;}\n"+
 "",
"DropTagsStyles");

if (!config.macros.tagger)
   window.onClickTag=function(e){
	if (!e) var e = window.event;
	var theTarget = resolveTarget(e);

        var nested = (!isNested(theTarget));
        if ((Popup.stack.length > 1)&&(nested==true)) {Popup.removeFrom(1);}
        else if(Popup.stack.length > 0 && nested==false) {Popup.removeFrom(0);};

        var theId = (nested==false)? "popup" : "nestedtagger";
        var popup = createTiddlyElement(document.body,"ol",theId,"popup",null);
        Popup.stack.push({root: this, popup: popup});

	var tag = this.getAttribute("tag");
	var title = this.getAttribute("tiddler");
	if(popup && tag)
		{
		var tagged = store.getTaggedTiddlers(tag);
		var titles = [];
		var li,r;
		for(r=0;r<tagged.length;r++)
			if(tagged[r].title != title)
				titles.push(tagged[r].title);
		var lingo = config.views.wikified.tag;
		if(titles.length > 0)
			{
			var openAll = createTiddlyButton(createTiddlyElement(popup,"li"),lingo.openAllText.format([tag]),lingo.openAllTooltip,onClickTagOpenAll);
			openAll.setAttribute("tag",tag);
			createTiddlyElement(createTiddlyElement(popup,"li"),"hr");
			for(r=0; r<titles.length; r++)
				{
				createTiddlyLink(createTiddlyElement(popup,"li"),titles[r],true);
				}
			}
		else
			createTiddlyText(createTiddlyElement(popup,"li",null,"disabled"),lingo.popupNone.format([tag]));
		createTiddlyElement(createTiddlyElement(popup,"li"),"hr");
		var h = createTiddlyLink(createTiddlyElement(popup,"li"),tag,false);
		createTiddlyText(h,lingo.openTag.format([tag]));
		}
	Popup.show(popup,false);
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
	return(false);
   }

if (!window.isNested)
   window.isNested = function(e) {
        while (e != null) {
                var contentWrapper = document.getElementById("contentWrapper");
                if (contentWrapper == e) return true;
                e = e.parentNode;
                }
        return false;
   };

config.shadowTiddlers.DropTagsMacroDocumentation="The documentation is available [[here.|http://tw.lewcid.org/#DropTagsMacroDocumentation]]";

config.shadowTiddlers.DropTagsMacroSource="The documentation is available [[here.|http://tw.lewcid.org/#DropTagsMacroDocumentation]]";

//}}}
/***
|Name|Edge of Night|
|Source|http://www.TiddlyTools.com/#Edge of Night|
|Version||
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|CSS|
|Requires||
|Overrides||
|Description|theme: dark blue sunset photo background|
|StyleSheet|Edge of Night|
|PageTemplateReadOnly|PageTemplateReadOnly|
|EditTemplateReadOnly|EditTemplateReadOnly|
***/

[[StyleSheetAdjustments]]
[[BrightText]]
/* ==== Edge of Night ==== */
/*{{{*/
body
	{ background-image: url('[[Edge of Night Background]]'); background-color:#113; }
.menubox
	{ background-image: none; background-color: #002; }
.viewer
	{ background-image: url('[[TexturesMarbleBlack]]'); background-color:#111; border: 1px solid #999; -moz-border-radius:1em; padding:1em; }
.header
	{ background-image: none; background-color:transparent; color:#ccf; border-bottom:0px solid #036; }
.siteSubtitle
	{ color:#0c0; }
.floatingPanel, .attachPanel, #importPanel, #exportPanel
	{ background: #eee; background-image: url('[[TexturesParchmentGray]]');}
.floatingPanel a, .attachPanel a, #importPanel a, #exportPanel a, 
.floatingPanel .button, .attachPanel .button, #importPanel .button, #exportPanel .button,
.floatingPanel .tiddlyLinkExisting, .attachPanel .tiddlyLinkExisting, #importPanel .tiddlyLinkExisting, #exportPanel .tiddlyLinkExisting,
	{ color:#009; }
#messageArea 
	{ background: #ddf; }
.siteMenu .floatingPanel
	{ background-image: url('[[TexturesParchmentGray]]'); }
.groupbox { background:#ddf; }

.viewer h1,.viewer h2,.viewer h3,.viewer h4,.viewer h5 { background: #666; color:#fff; }

.tabContents
	{ background-color:#ddf; color:#000; background-image: url('[[TexturesParchmentGray]]'); }
.viewer .tabContents, #sidebarTabs .tabContents
	{ background-image:none; background-color:#002; color:#fff; }
#tiddlerWelcome .viewer .tabContents
	{ background-image: url('[[TexturesMarbleBlack]]'); }
.tabContents a, .tabContents .button, .tabContents .tiddlyLinkExisting
	{ color:#99f; }
/*}}}*/
| source file|{{{...images\sunset.jpg}}}|
| attached on|20 May 2006 by ELSDesignStudios|
| embedded data|//none//|
| local link|//none//|
| remote link|/%REMOTE_LINK%/[[images/sunset.jpg|images/sunset.jpg]]|
image
<<<
usage: {{{[img[tooltip|Edge of Night Background]] or [img[tooltip|Edge of Night Background][link]]}}}
[img[tooltip|Edge of Night Background]]
<<<
/***
|Name|EditFieldPlugin|
|Source|http://www.TiddlyTools.com/#EditFieldPlugin|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|extend core edit macro for use in ViewTemplates or direct embedding in tiddler content|
This plugin extends the core {{{<<edit fieldname #OfLines>>}}} macro for use in a ViewTemplate or directly embedded in tiddler content.
!!!!!Usage
<<<
Normally, when you edit a tiddler, any changes you make are saved (or discarded) when you press the "done" (or "cancel") command in the tiddler editor's toolbar.  However, when in a 'view mode' context, these command items are not available, and so the TiddlyWiki core commands cannot be used to trigger the 'save/discard' handling once you have decided that your input activities are complete.

This plugin extends the core's input field handling, so that when:
{{{
<<edit fieldname numberOfLines>>
}}}
is used in tiddler content, or:
{{{
<span macro='edit fieldname numberOfLines'></span>
}}}
is used in a ViewTemplate definition, you will be automatically prompted to save/discard your changes (if any) as soon as you press ENTER or move away ('onBlur' handling) from that input field (if the content has been changed).  You can also abandon your changes to input field content by pressing ESCAPE (you will be asked to confirm before discarding changes).

You can change the browser-defined default width of an input field by surrounding the edit field by using custom CSS class wrappers, defined in the StyleSheet tiddler.  For example:
{{{
.stretch input { width:99%; }
.stretch textarea { width:99%; }
.onechar input { width:1em; }
.twochar input { width:2em; }
.threechar input { width:3em; }
.fourchar input { width:4em; }
.fivechar input { width:5em; }
}}}
>Note: the 'fixed' width values in the above example are only approximate.  The actual width rendered by your browser will vary based on the current font-family and font-size that is applied to the field.
<<<
!!!!!Examples
<<<
*"""<<edit foobar>>"""<br>&nbsp;&nbsp;<<edit foobar>>
*"""{{threechar{<<edit foobar>>}}}"""<br>&nbsp;&nbsp;{{threechar{<<edit foobar>>}}}
*"""<<edit tags>>"""<br>&nbsp;&nbsp;<<edit tags>>
*"""{{stretch{<<edit text 10>>}}}"""<br>&nbsp;&nbsp;{{stretch{<<edit text 10>>}}}
<<<
!!!!!Revisions
<<<
2007.08.22 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.editFieldPlugin= {major: 1, minor: 0, revision: 0, date: new Date(2007,8,22)};

config.macros.edit.editFieldPlugin_savedHandler=config.macros.edit.handler;
config.macros.edit.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
	// let core create edit field
	config.macros.edit.editFieldPlugin_savedHandler.apply(this,arguments);
	// get edit field or textarea
	var fieldType=params[0]=="text"||params[1]?'textarea':'input';
	var ins=place.getElementsByTagName(fieldType);
	var e=ins[ins.length-1];
	if (fieldType=="textarea" && params[1]) e.style.height=params[1]+"em"; // force height for textarea field
	// if viewing tiddler, add autosave handlers
	var here=story.findContainingTiddler(place);
	if (here && here.getAttribute("template").indexOf("ViewTemplate")!=-1) {
		story.setDirty(tiddler.title,false); // clear tiddler ("dirty") flag set by core when field was created
		var field=e.getAttribute("edit");
		var val=store.getValue(tiddler.title,field); if (!val) val="";
		e.setAttribute("currval",val); // remember starting value
		e.setAttribute("tiddler",tiddler.title); // remember target tiddler
		e.onkeydown=function(ev) { // ENTER key=save (for single-line edit fields only)
			var event=ev?ev:window.event;
			this.setAttribute("keyCode",event.keyCode); // save last keyCode for blur() handler
			if (event.keyCode==13 && this.nodeName.toUpperCase()!="TEXTAREA")
				this.saveField(); // save input to tiddler field
		}
		e.onblur=function(ev) { // accept or reject input when focus moves away from field
			var event=ev?ev:window.event;
			var tid=this.getAttribute("tiddler"); if (!tid || !tid.length) return;
			var field=this.getAttribute("edit");
			if (this.value!=this.getAttribute("currval")) { // if value has changed
				if (this.getAttribute("keyCode")=="27") { // if user pressed ESC
					var msg="Abandon changes to %0@%1?".format([field,tid]);
					if (confirm(msg)) this.value=this.getAttribute("currval"); // reset to starting value
					this.id=new Date().getTime(); // set unique ID
					setTimeout("document.getElementById('"+this.id+"').focus()",1); // restore focus (after blur completes)
				} else { // other focus change events
					var msg="Save changes to %0@%1?".format([field,tid]);
					if (confirm(msg)) this.saveField(); // save input to tiddler field, then continue blur
					else this.value=this.getAttribute("currval"); // reset to starting value, then continue blur
				}
			}
		};
		e.saveField=function() { // save input value to tiddler field (create, touch or rename tiddler as needed)
			var tid=this.getAttribute("tiddler"); if (!tid || !tid.length) return;
			var field=this.getAttribute("edit");
			var title=(field=="title")?this.value:tid;
			if (!title.length) { // prevent blank tiddler title from being used
				this.value=this.getAttribute("currval"); // reset to starting value
				this.id=new Date().getTime(); // set unique ID
				setTimeout("displayMessage('Please enter a non-blank value')",1); // notify user
				setTimeout("document.getElementById('"+this.id+"').focus()",2); // set focus to continue editing
				return;
			}
			var t=store.getTiddler(tid);
			store.suspendNotifications();
			var anim=config.options.chkAnimate; config.options.chkAnimate=false; // suspend animation
			var who=t&&config.options.chkForceMinorUpdate?t.modifier:config.options.txtUserName;
			var when=t&&config.options.chkForceMinorUpdate?t.modified:new Date();
			store.saveTiddler(t?tid:title,title,t?t.text:"",who,when,t?t.tags:[],t?t.fields:null);
			store.setValue(title,field,this.value); // save value in tiddler field
			this.setAttribute("currval",this.value); // remember new starting value
			if (tid!=title) // if title changed, display renamed tiddler in place of current one
				{ story.displayTiddler(story.findContainingTiddler(this),title); story.closeTiddler(tid); }
			if (field=="text") // if tiddler content changed, refresh tiddler display
				{ story.refreshTiddler(title,null,true); }
			config.options.chkAnimate=anim; // resume animation
			store.resumeNotifications();
			store.notify(title,true);
		};
	}
}
//}}}
<!--{{{-->
<!--
|Name|EditTemplate|
|Source|http://www.TiddlyTools.com/#EditTemplate|
|Version||
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands|
|Overrides||
|Description|custom version of shadow template used to display tiddler for normal editing|
-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></span>
<div class='title' macro='view title'></div>
<div style='clear:both'></div>
<div class='editor' macro='edit title'></div>
<div macro='tiddler QuickEditToolbar'></div>
<div class='editor' macro='edit text'></div>
<span macro='resizeEditor'></span><span macro='setUserName'></span>
<div class='editor' macro='preview hide text'></div>
<div class='editor' macro='edit tags'></div>
<div class='toolbar editorFooter' style='text-align:left !important;float:left !important'>
	<span macro='message views.editor.tagPrompt'></span>
	<span macro='tagChooser'></span>
</div>
<div style='clear:both'></div>
<!--}}}-->
<!--{{{-->
<!--
|Name|EditTemplate|
|Source|http://www.TiddlyTools.com/#EditTemplate|
|Version||
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands|
|Overrides||
|Description|custom version of shadow template used to display tiddler for normal editing|
-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbarReadOnly]]'></span>
<div class='title' macro='view title'></div>
<div style='clear:both'></div>
<div class='editor' macro='edit title'></div>
<div class='editor' macro='edit text'></div>
<span macro='resizeEditor'></span>
<div class='editor' macro='preview hide text'></div>
<div class='editor' macro='edit tags'></div>
<div class='toolbar editorFooter' style='text-align:left !important;float:left !important'>
	<span macro='message views.editor.tagPrompt'></span>
	<span macro='tagChooser'></span>
</div>
<div style='clear:both'></div>
<!--}}}-->
/***
|Name|EditTiddlerPlugin|
|Source|http://www.TiddlyTools.com/#EditTiddlerPlugin|
|Version|1.2.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|embed an 'edit' link in tiddler content to invoke edit on any specified tiddler title|

!!!!!Usage:
<<<
{{{<<editTiddler TiddlerName linktext>>}}}
If no tiddler title is specified (or the special keyword "here" is used), the tiddler containing the rendered macro is assumed.  You can also specify optional alternative "link text" to be displayed. The default link text is "edit".
<<<
!!!!!Revisions:
<<<
2007.03.22 1.2.0 added support for 'here' keyword and optional 2nd param to specify label text
2007.03.15 1.1.1 fixed 'get tiddler ID' logic so it actually works! D'oh! 
2007.03.11 1.1.0 changed 'get tiddler ID' logic so that macro can be used outside a tiddler (i.e., in mainMenu) by specifying the ID
2006.10.04 1.0.1 invoke findContainingTiddler() as fallback when 'tiddler' param is null
2006.04.28 1.0.0 Initial release
<<<
!!!Code:
***/
//{{{
config.macros.editTiddler={
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var tid=params.shift(); // use specified tiddler ID (or "here")
		if (!tid || tid=="here") {
			if (tiddler)
				tid=tiddler.title; // use current tiddler, fallback to find tiddler if none provided
			else { 
				var here=story.findContainingTiddler(place);
				if (!here) return; // not in a tiddler, do nothing
				tid=here.getAttribute('tiddler'); // get ID from tiddler element
			}
		}
		var label="edit"; if (params[0]) label=params.shift();
		createTiddlyButton(place,label,'edit tiddler: '+tid,this.onclick).setAttribute('which',tid);
	},
	onclick: function(e) {
		story.displayTiddler(null,this.getAttribute('which'),DEFAULT_EDIT_TEMPLATE);
	}
}
//}}}
/%
|Name|EmbedTiddlers|
|Source|http://www.TiddlyTools.com/#EmbedTiddlers|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|transclude a list of tiddlers in a specific order|

usage:
   <<tiddler EmbedTiddlers with: "TiddlerName [[TiddlerName with spaces]] TiddlerName ...">>

or
   <<tiddler EmbedTiddlers with: @TiddlerName>>

where @TiddlerName specifies a //separate// tiddler containing the space-separated, bracketed list of tiddlers to transclude (e.g., DefaultTiddlers).

%/<script>
	var list='$1';
	if (list.substr(0,1)=='@') list=store.getTiddlerText(list.substr(1),'');
	var tids=list.readBracketedList();
	var out='';
	for (var i=0; i<tids.length; i++) out+='<<tiddler %0>>'.format([tids[i]]);
	return out;
</script>
/%
|Name|ExpandSlidersScript|
|Source|http://www.TiddlyTools.com/#ExpandSlidersScript|
|Version|1.0.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin, NestedSlidersPlugin|
|Overrides||
|Description|simulateously expand/collapse all nested sliders in a tiddler (or ID'd DOM element)|

Usage:
	<<tiddler ExpandSlidersScript with: elementID expandlabel collapselabel>>

%/<script label="expand">
	// if 'in a tiddler', expand all sliders... otherwise, expand based on passed in element ID
	var here=story.findContainingTiddler(place);
	if (!here) {
		if ("$1"=="$"+"1")
			{ alert("ExpandSlidersScript: not in a tiddler, use 'with: elementID' syntax"); return; }
		var here=document.getElementById("$1");
		if (!here) { alert("ExpandSlidersScript: unknown elementID: '$1'"); return false; }
	}
	var expandlabel="expand"; if ("$2"!="$"+"2") var expandlabel="$2";
	var collapselabel="collapse"; if ("$3"!="$"+"3") var collapselabel="$3";
	var elems=here.getElementsByTagName("*");
	var state=(place.innerHTML.toLowerCase()==expandlabel)?"none":"block";
	for (var e=0; e<elems.length; e++) {
		var p=elems[e].sliderPanel;
		if (p && p.className=="sliderPanel") {
			if (p.style.display==state) window.onClickNestedSlider({target:elems[e]});
		}
	}
	place.innerHTML=state=="none"?collapselabel:expandlabel;
	return false;
</script><script>
	place.lastChild.style.fontWeight="normal";
	var expandlabel="expand"; if ("$2"!="$"+"2") var expandlabel="$2";
	var collapselabel="collapse"; if ("$3"!="$"+"3") var collapselabel="$3";
	var currlabel=place.lastChild.innerHTML.toLowerCase();
	place.lastChild.innerHTML=expandlabel;
</script>
/***
|Name|ExportTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#ExportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ExportTiddlersPluginInfo|
|Version|2.6.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|select and extract tiddlers from your ~TiddlyWiki documents and save them to a separate file|
ExportTiddlersPlugin lets you select and extract tiddlers from your ~TiddlyWiki documents using interactive control panel lets you specify a destination, and then select which tiddlers to export. Tiddler data can be output as complete, stand-alone TiddlyWiki documents, or just the selected tiddlers ("~PureStore" format -- smaller files!) that can be imported directly into another ~TiddlyWiki, or as an ~RSS-compatible XML file that can be published for RSS syndication.
!!!!!Documentation
>see [[ExportTiddlersPluginInfo]]
!!!!!Inline control panel (live):
><<exportTiddlers inline>>
!!!!!Revisions
<<<
2008.05.12 [2.6.1] automatically add 'export' task to backstage (moved from BackstageTweaks)
2008.03.10 [2.6.0] added "delete tiddlers" button
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.11.10 [2.5.1] removed debugging alert messages from promptForExportFilename()
|please see [[ExportTiddlersPluginInfo]] for additional revision details|
2005.10.09 [0.0.0] development started
<<<
!!!!!Code
***/
//{{{
// version
version.extensions.exportTiddlers = {major: 2, minor: 6, revision: 1, date: new Date(2008,5,12)};

// default shadow definition
config.shadowTiddlers.ExportTiddlers="<<exportTiddlers inline>>";

// add 'export' backstage task (following built-in import task)
if (config.tasks) { // TW2.2 or above
	config.tasks.exportTask = {
		text:"export",
		tooltip:"Export selected tiddlers to another file",
		content:"<<exportTiddlers inline>>"
	}
	config.backstageTasks.splice(config.backstageTasks.indexOf("importTask")+1,0,"exportTask");
}

// macro handler
config.macros.exportTiddlers = {
	label: "export tiddlers",
	prompt: "Copy selected tiddlers to an export document",
	newdefault: "export.html",
	datetimefmt: "0MM/0DD/YYYY 0hh:0mm:0ss" // for "filter date/time" edit fields
};

config.macros.exportTiddlers.handler = function(place,macroName,params) {
	if (params[0]!="inline")
		{ createTiddlyButton(place,this.label,this.prompt,onClickExportMenu); return; }
	var panel=createExportPanel(place);
	panel.style.position="static";
	panel.style.display="block";
}

function createExportPanel(place) {
	var panel=document.getElementById("exportPanel");
	if (panel) { panel.parentNode.removeChild(panel); }
	setStylesheet(config.macros.exportTiddlers.css,"exportTiddlers");
	panel=createTiddlyElement(place,"span","exportPanel",null,null)
	panel.innerHTML=config.macros.exportTiddlers.html;
	exportInitFilter();
	refreshExportList(0);
	var fn=document.getElementById("exportFilename");
	if (window.location.protocol=="file:" && !fn.value.length) {
		// get new target path/filename
		var newPath=getLocalPath(window.location.href);
		var slashpos=newPath.lastIndexOf("/"); if (slashpos==-1) slashpos=newPath.lastIndexOf("\\"); 
		if (slashpos!=-1) newPath=newPath.substr(0,slashpos+1); // trim filename
		fn.value=newPath+config.macros.exportTiddlers.newdefault;
	}
	return panel;
}

function onClickExportMenu(e)
{
	if (!e) var e = window.event;
	var parent=resolveTarget(e).parentNode;
	var panel = document.getElementById("exportPanel");
	if (panel==undefined || panel.parentNode!=parent)
		panel=createExportPanel(parent);
	var isOpen = panel.style.display=="block";
	if(config.options.chkAnimate)
		anim.startAnimating(new Slider(panel,!isOpen,e.shiftKey || e.altKey,"none"));
	else
		panel.style.display = isOpen ? "none" : "block" ;
	if (panel.style.display!="none") { // update list and set focus when panel is made visible
		refreshExportList(0);
		var fn=document.getElementById("exportFilename"); fn.focus(); fn.select();
	}
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
	return(false);
}
//}}}

// // IE needs explicit scoping for functions called by browser events
//{{{
window.onClickExportMenu=onClickExportMenu;
window.onClickExportButton=onClickExportButton;
window.exportShowFilterFields=exportShowFilterFields;
window.refreshExportList=refreshExportList;
//}}}

// // CSS for floating export control panel
//{{{
config.macros.exportTiddlers.css = '\
#exportPanel {\
	display: none; position:absolute; z-index:12; width:35em; right:105%; top:6em;\
	background-color: #eee; color:#000; font-size: 8pt; line-height:110%;\
	border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;\
	padding: 0.5em; margin:0em; -moz-border-radius:1em;\
}\
#exportPanel a, #exportPanel td a { color:#009; display:inline; margin:0px; padding:1px; }\
#exportPanel table { width:100%; border:0px; padding:0px; margin:0px; font-size:8pt; line-height:110%; background:transparent; }\
#exportPanel tr { border:0px;padding:0px;margin:0px; background:transparent; }\
#exportPanel td { color:#000; border:0px;padding:0px;margin:0px; background:transparent; }\
#exportPanel select { width:98%;margin:0px;font-size:8pt;line-height:110%;}\
#exportPanel input  { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%; }\
#exportPanel textarea  { width:98%;padding:0px;margin:0px;overflow:auto;font-size:8pt; }\
#exportPanel .box { border:1px solid black; padding:3px; margin-bottom:5px; background:#f8f8f8; -moz-border-radius:5px; }\
#exportPanel .topline { border-top:2px solid black; padding-top:3px; margin-bottom:5px; }\
#exportPanel .rad { width:auto;border:0 }\
#exportPanel .chk { width:auto;border:0 }\
#exportPanel .btn { width:auto; }\
#exportPanel .btn1 { width:98%; }\
#exportPanel .btn2 { width:48%; }\
#exportPanel .btn3 { width:32%; }\
#exportPanel .btn4 { width:24%; }\
#exportPanel .btn5 { width:19%; }\
';
//}}}

// // HTML for export control panel interface
//{{{
config.macros.exportTiddlers.html = '\
<!-- target path/file  -->\
<div>\
export to path/filename:<br>\
<input type="text" id="exportFilename" size=40 style="width:93%"><input \
	type="button" id="exportBrowse" value="..." title="select or enter a local folder/file..." style="width:5%" \
	onclick="var fn=window.promptForExportFilename(this); if (fn.length) this.previousSibling.value=fn; ">\
</div>\
\
<!-- output format -->\
<div>\
output file format:\
<select id="exportFormat" size=1>\
<option value="TW">TiddlyWiki document (includes core code)</option>\
<option value="DIV">TiddlyWiki export file (tiddler data only)</option>\
<option value="XML">XML (for RSS newsfeed)</option>\
</select>\
</div>\
\
<!-- notes -->\
<div>\
notes:<br>\
<textarea id="exportNotes" rows=3 cols=40 style="height:4em;margin-bottom:5px;" onfocus="this.select()"></textarea> \
</div>\
\
<!-- list of tiddlers -->\
<table><tr align="left"><td>\
	select:\
	<a href="JavaScript:;" id="exportSelectAll"\
		onclick="onClickExportButton(this)" title="select all tiddlers">\
		&nbsp;all&nbsp;</a>\
	<a href="JavaScript:;" id="exportSelectChanges"\
		onclick="onClickExportButton(this)" title="select tiddlers changed since last save">\
		&nbsp;changes&nbsp;</a> \
	<a href="JavaScript:;" id="exportSelectOpened"\
		onclick="onClickExportButton(this)" title="select tiddlers currently being displayed">\
		&nbsp;opened&nbsp;</a> \
	<a href="JavaScript:;" id="exportSelectRelated"\
		onclick="onClickExportButton(this)" title="select all tiddlers related (by link or transclusion) to the currently selected tiddlers">\
		&nbsp;related&nbsp;</a> \
	<a href="JavaScript:;" id="exportToggleFilter"\
		onclick="onClickExportButton(this)" title="show/hide selection filter">\
		&nbsp;filter&nbsp;</a>  \
</td><td align="right">\
	<a href="JavaScript:;" id="exportListSmaller"\
		onclick="onClickExportButton(this)" title="reduce list size">\
		&nbsp;&#150;&nbsp;</a>\
	<a href="JavaScript:;" id="exportListLarger"\
		onclick="onClickExportButton(this)" title="increase list size">\
		&nbsp;+&nbsp;</a>\
</td></tr></table>\
<select id="exportList" multiple size="10" style="margin-bottom:5px;"\
	onchange="refreshExportList(this.selectedIndex)">\
</select><br>\
</div><!--box-->\
\
<!-- selection filter -->\
<div id="exportFilterPanel" style="display:none">\
<table><tr align="left"><td>\
	selection filter\
</td><td align="right">\
	<a href="JavaScript:;" id="exportHideFilter"\
		onclick="onClickExportButton(this)" title="hide selection filter">hide</a>\
</td></tr></table>\
<div class="box">\
<input type="checkbox" class="chk" id="exportFilterStart" value="1"\
	onclick="exportShowFilterFields(this)"> starting date/time<br>\
<table cellpadding="0" cellspacing="0"><tr valign="center"><td width="50%">\
	<select size=1 id="exportFilterStartBy" onchange="exportShowFilterFields(this);">\
		<option value="0">today</option>\
		<option value="1">yesterday</option>\
		<option value="7">a week ago</option>\
		<option value="30">a month ago</option>\
		<option value="site">SiteDate</option>\
		<option value="file">file date</option>\
		<option value="other">other (mm/dd/yyyy hh:mm)</option>\
	</select>\
</td><td width="50%">\
	<input type="text" id="exportStartDate" onfocus="this.select()"\
		onchange="document.getElementById(\'exportFilterStartBy\').value=\'other\';">\
</td></tr></table>\
<input type="checkbox" class="chk" id="exportFilterEnd" value="1"\
	onclick="exportShowFilterFields(this)"> ending date/time<br>\
<table cellpadding="0" cellspacing="0"><tr valign="center"><td width="50%">\
	<select size=1 id="exportFilterEndBy" onchange="exportShowFilterFields(this);">\
		<option value="0">today</option>\
		<option value="1">yesterday</option>\
		<option value="7">a week ago</option>\
		<option value="30">a month ago</option>\
		<option value="site">SiteDate</option>\
		<option value="file">file date</option>\
		<option value="other">other (mm/dd/yyyy hh:mm)</option>\
	</select>\
</td><td width="50%">\
	<input type="text" id="exportEndDate" onfocus="this.select()"\
		onchange="document.getElementById(\'exportFilterEndBy\').value=\'other\';">\
</td></tr></table>\
<input type="checkbox" class="chk" id=exportFilterTags value="1"\
	onclick="exportShowFilterFields(this)"> match tags<br>\
<input type="text" id="exportTags" onfocus="this.select()">\
<input type="checkbox" class="chk" id=exportFilterText value="1"\
	onclick="exportShowFilterFields(this)"> match titles/tiddler text<br>\
<input type="text" id="exportText" onfocus="this.select()">\
</div> <!--box-->\
</div> <!--panel-->\
\
<!-- action buttons -->\
<div style="text-align:center">\
<input type=button class="btn4" onclick="onClickExportButton(this)"\
	id="exportFilter" value="apply filter">\
<input type=button class="btn4" onclick="onClickExportButton(this)"\
	id="exportStart" value="export tiddlers">\
<input type=button class="btn4" onclick="onClickExportButton(this)"\
	id="exportDelete" value="delete tiddlers">\
<input type=button class="btn4" onclick="onClickExportButton(this)"\
	id="exportClose" value="close">\
</div><!--center-->\
';
//}}}

// // initialize interface

// // exportInitFilter()
//{{{
function exportInitFilter() {
	// start date
	document.getElementById("exportFilterStart").checked=false;
	document.getElementById("exportStartDate").value="";
	// end date
	document.getElementById("exportFilterEnd").checked=false;
	document.getElementById("exportEndDate").value="";
	// tags
	document.getElementById("exportFilterTags").checked=false;
	document.getElementById("exportTags").value="";
	// text
	document.getElementById("exportFilterText").checked=false;
	document.getElementById("exportText").value="";
	// show/hide filter input fields
	exportShowFilterFields();
}
//}}}

// // exportShowFilterFields(which)
//{{{
function exportShowFilterFields(which) {
	var show;

	show=document.getElementById('exportFilterStart').checked;
	document.getElementById('exportFilterStartBy').style.display=show?"block":"none";
	document.getElementById('exportStartDate').style.display=show?"block":"none";
	var val=document.getElementById('exportFilterStartBy').value;
	document.getElementById('exportStartDate').value
		=getFilterDate(val,'exportStartDate').formatString(config.macros.exportTiddlers.datetimefmt);
	 if (which && (which.id=='exportFilterStartBy') && (val=='other'))
		document.getElementById('exportStartDate').focus();

	show=document.getElementById('exportFilterEnd').checked;
	document.getElementById('exportFilterEndBy').style.display=show?"block":"none";
	document.getElementById('exportEndDate').style.display=show?"block":"none";
	var val=document.getElementById('exportFilterEndBy').value;
	document.getElementById('exportEndDate').value
		=getFilterDate(val,'exportEndDate').formatString(config.macros.exportTiddlers.datetimefmt);
	 if (which && (which.id=='exportFilterEndBy') && (val=='other'))
		document.getElementById('exportEndDate').focus();

	show=document.getElementById('exportFilterTags').checked;
	document.getElementById('exportTags').style.display=show?"block":"none";

	show=document.getElementById('exportFilterText').checked;
	document.getElementById('exportText').style.display=show?"block":"none";
}
//}}}

// // onClickExportButton(which): control interactions
//{{{
function onClickExportButton(which)
{
	// DEBUG alert(which.id);
	var theList=document.getElementById('exportList'); if (!theList) return;
	var count = 0;
	var total = store.getTiddlers('title').length;
	switch (which.id)
		{
		case 'exportFilter':
			count=filterExportList();
			var panel=document.getElementById('exportFilterPanel');
			if (count==-1) { panel.style.display='block'; break; }
			document.getElementById("exportStart").disabled=(count==0);
			document.getElementById("exportDelete").disabled=(count==0);
			clearMessage(); displayMessage("filtered "+formatExportMessage(count,total));
			if (count==0) { alert("No tiddlers were selected"); panel.style.display='block'; }
			break;
		case 'exportStart':
			exportTiddlers();
			break;
		case 'exportDelete':
			exportDeleteTiddlers();
			break;
		case 'exportHideFilter':
		case 'exportToggleFilter':
			var panel=document.getElementById('exportFilterPanel')
			panel.style.display=(panel.style.display=='block')?'none':'block';
			break;
		case 'exportSelectChanges':
			var lastmod=new Date(document.lastModified);
			for (var t = 0; t < theList.options.length; t++) {
				if (theList.options[t].value=="") continue;
				var tiddler=store.getTiddler(theList.options[t].value); if (!tiddler) continue;
				theList.options[t].selected=(tiddler.modified>lastmod);
				count += (tiddler.modified>lastmod)?1:0;
			}
			document.getElementById("exportStart").disabled=(count==0);
			document.getElementById("exportDelete").disabled=(count==0);
			clearMessage(); displayMessage(formatExportMessage(count,total));
			if (count==0) alert("There are no unsaved changes");
			break;
		case 'exportSelectAll':
			for (var t = 0; t < theList.options.length; t++) {
				if (theList.options[t].value=="") continue;
				theList.options[t].selected=true;
				count += 1;
			}
			document.getElementById("exportStart").disabled=(count==0);
			document.getElementById("exportDelete").disabled=(count==0);
			clearMessage(); displayMessage(formatExportMessage(count,count));
			break;
		case 'exportSelectOpened':
			for (var t = 0; t < theList.options.length; t++) theList.options[t].selected=false;
			var tiddlerDisplay = document.getElementById("tiddlerDisplay"); // for TW2.1-
			if (!tiddlerDisplay) tiddlerDisplay = document.getElementById("storyDisplay"); // for TW2.2+
			for (var t=0;t<tiddlerDisplay.childNodes.length;t++) {
				var tiddler=tiddlerDisplay.childNodes[t].id.substr(7);
				for (var i = 0; i < theList.options.length; i++) {
					if (theList.options[i].value!=tiddler) continue;
					theList.options[i].selected=true; count++; break;
				}
			}
			document.getElementById("exportStart").disabled=(count==0);
			document.getElementById("exportDelete").disabled=(count==0);
			clearMessage(); displayMessage(formatExportMessage(count,total));
			if (count==0) alert("There are no tiddlers currently opened");
			break;
		case 'exportSelectRelated':
			// recursively build list of related tiddlers
			function getRelatedTiddlers(tid,tids) {
				var t=store.getTiddler(tid); if (!t || tids.contains(tid)) return tids;
				tids.push(t.title);
				if (!t.linksUpdated) t.changed();
				for (var i=0; i<t.links.length; i++)
					if (t.links[i]!=tid) tids=getRelatedTiddlers(t.links[i],tids);
				return tids;
			}
			// for all currently selected tiddlers, gather up the related tiddlers (including self) and select them as well
			var tids=[];
			for (var i=0; i<theList.options.length; i++)
				if (theList.options[i].selected) tids=getRelatedTiddlers(theList.options[i].value,tids);
			// select related tiddlers (includes original selected tiddlers)
			for (var i=0; i<theList.options.length; i++)
				theList.options[i].selected=tids.contains(theList.options[i].value);
			clearMessage(); displayMessage(formatExportMessage(tids.length,total));
			break;
		case 'exportListSmaller':	// decrease current listbox size
			var min=5;
			theList.size-=(theList.size>min)?1:0;
			break;
		case 'exportListLarger':	// increase current listbox size
			var max=(theList.options.length>25)?theList.options.length:25;
			theList.size+=(theList.size<max)?1:0;
			break;
		case 'exportClose':
			document.getElementById('exportPanel').style.display='none';
			break;
		}
}
//}}}

// // promptForFilename(msg,path,file) uses platform/browser specific functions to get local filespec
//{{{
window.promptForExportFilename=function(here)
{
	var msg=here.title; // use tooltip as dialog box message
	var path=getLocalPath(document.location.href);
	var slashpos=path.lastIndexOf("/"); if (slashpos==-1) slashpos=path.lastIndexOf("\\"); 
	if (slashpos!=-1) path = path.substr(0,slashpos+1); // remove filename from path, leave the trailing slash
	var file=config.macros.exportTiddlers.newdefault;
	var result="";
	if(window.Components) { // moz
		try {
			netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
			var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
			var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
			picker.init(window, msg, nsIFilePicker.modeSave);
			var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
			thispath.initWithPath(path);
			picker.displayDirectory=thispath;
			picker.defaultExtension='html';
			picker.defaultString=file;
			picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
			if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.persistentDescriptor;
		}
		catch(e) { alert('error during local file access: '+e.toString()) }
	}
	else { // IE
		try { // XPSP2 IE only
			var s = new ActiveXObject('UserAccounts.CommonDialog');
			s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
			s.FilterIndex=3; // default to HTML files;
			s.InitialDir=path;
			s.FileName=file;
			if (s.showOpen()) var result=s.FileName;
		}
		catch(e) {  // fallback
			var result=prompt(msg,path+file);
		}
	}
	return result;
}
//}}}

// // list display
//{{{
function formatExportMessage(count,total)
{
	var txt=total+' tiddler'+((total!=1)?'s':'')+" - ";
	txt += (count==0)?"none":(count==total)?"all":count;
	txt += " selected for export";
	return txt;
}

function refreshExportList(selectedIndex)
{
	var theList  = document.getElementById("exportList");
	var sort;
	if (!theList) return;
	// get the sort order
	if (!selectedIndex)   selectedIndex=0;
	if (selectedIndex==0) sort='modified';
	if (selectedIndex==1) sort='title';
	if (selectedIndex==2) sort='modified';
	if (selectedIndex==3) sort='modifier';
	if (selectedIndex==4) sort='tags';

	// unselect headings and count number of tiddlers actually selected
	var count=0;
	for (var t=5; t < theList.options.length; t++) {
		if (!theList.options[t].selected) continue;
		if (theList.options[t].value!="")
			count++;
		else { // if heading is selected, deselect it, and then select and count all in section
			theList.options[t].selected=false;
			for ( t++; t<theList.options.length && theList.options[t].value!=""; t++) {
				theList.options[t].selected=true;
				count++;
			}
		}
	}

	// disable "export" and "delete" buttons if no tiddlers selected
	document.getElementById("exportStart").disabled=(count==0);
	document.getElementById("exportDelete").disabled=(count==0);
	// show selection count
	var tiddlers = store.getTiddlers('title');
	if (theList.options.length) { clearMessage(); displayMessage(formatExportMessage(count,tiddlers.length)); }

	// if a [command] item, reload list... otherwise, no further refresh needed
	if (selectedIndex>4)  return;

	// clear current list contents
	while (theList.length > 0) { theList.options[0] = null; }
	// add heading and control items to list
	var i=0;
	var indent=String.fromCharCode(160)+String.fromCharCode(160);
	theList.options[i++]=
		new Option(tiddlers.length+" tiddlers in document", "",false,false);
	theList.options[i++]=
		new Option(((sort=="title"        )?">":indent)+' [by title]', "",false,false);
	theList.options[i++]=
		new Option(((sort=="modified")?">":indent)+' [by date]', "",false,false);
	theList.options[i++]=
		new Option(((sort=="modifier")?">":indent)+' [by author]', "",false,false);
	theList.options[i++]=
		new Option(((sort=="tags"	)?">":indent)+' [by tags]', "",false,false);
	// output the tiddler list
	switch(sort)
		{
		case "title":
			for(var t = 0; t < tiddlers.length; t++)
				theList.options[i++] = new Option(tiddlers[t].title,tiddlers[t].title,false,false);
			break;
		case "modifier":
		case "modified":
			var tiddlers = store.getTiddlers(sort);
			// sort descending for newest date first
			tiddlers.sort(function (a,b) {if(a[sort] == b[sort]) return(0); else return (a[sort] > b[sort]) ? -1 : +1; });
			var lastSection = "";
			for(var t = 0; t < tiddlers.length; t++)
				{
				var tiddler = tiddlers[t];
				var theSection = "";
				if (sort=="modified") theSection=tiddler.modified.toLocaleDateString();
				if (sort=="modifier") theSection=tiddler.modifier;
				if (theSection != lastSection)
					{
					theList.options[i++] = new Option(theSection,"",false,false);
					lastSection = theSection;
					}
				theList.options[i++] = new Option(indent+indent+tiddler.title,tiddler.title,false,false);
				}
			 break;
		case "tags":
			var theTitles = {}; // all tiddler titles, hash indexed by tag value
			var theTags = new Array();
			for(var t=0; t<tiddlers.length; t++) {
				var title=tiddlers[t].title;
				var tags=tiddlers[t].tags;
				if (!tags || !tags.length) {
					if (theTitles["untagged"]==undefined) { theTags.push("untagged"); theTitles["untagged"]=new Array(); }
					theTitles["untagged"].push(title);
				}
				else for(var s=0; s<tags.length; s++) {
					if (theTitles[tags[s]]==undefined) { theTags.push(tags[s]); theTitles[tags[s]]=new Array(); }
					theTitles[tags[s]].push(title);
				}
			}
			theTags.sort();
			for(var tagindex=0; tagindex<theTags.length; tagindex++) {
				var theTag=theTags[tagindex];
				theList.options[i++]=new Option(theTag,"",false,false);
				for(var t=0; t<theTitles[theTag].length; t++)
					theList.options[i++]=new Option(indent+indent+theTitles[theTag][t],theTitles[theTag][t],false,false);
			}
			break;
		}
	theList.selectedIndex=selectedIndex;		  // select current control item
	document.getElementById("exportStart").disabled=true;
	document.getElementById("exportDelete").disabled=true;
	clearMessage(); displayMessage(formatExportMessage(0,tiddlers.length));
}
//}}}

// // list filtering
//{{{
function getFilterDate(val,id)
{
	var result=0;
	switch (val) {
		case 'site':
			var timestamp=store.getTiddlerText("SiteDate");
			if (!timestamp) timestamp=document.lastModified;
			result=new Date(timestamp);
			break;
		case 'file':
			result=new Date(document.lastModified);
			break;
		case 'other':
			result=new Date(document.getElementById(id).value);
			break;
		default: // today=0, yesterday=1, one week=7, two weeks=14, a month=31
			var now=new Date(); var tz=now.getTimezoneOffset()*60000; now-=tz;
			var oneday=86400000;
			if (id=='exportStartDate')
				result=new Date((Math.floor(now/oneday)-val)*oneday+tz);
			else
				result=new Date((Math.floor(now/oneday)-val+1)*oneday+tz-1);
			break;
	}
	// DEBUG alert('getFilterDate('+val+','+id+')=='+result+"\nnow="+now);
	return result;
}

function filterExportList()
{
	var theList  = document.getElementById("exportList"); if (!theList) return -1;

	var filterStart=document.getElementById("exportFilterStart").checked;
	var val=document.getElementById("exportFilterStartBy").value;
	var startDate=getFilterDate(val,'exportStartDate');

	var filterEnd=document.getElementById("exportFilterEnd").checked;
	var val=document.getElementById("exportFilterEndBy").value;
	var endDate=getFilterDate(val,'exportEndDate');

	var filterTags=document.getElementById("exportFilterTags").checked;
	var tags=document.getElementById("exportTags").value;

	var filterText=document.getElementById("exportFilterText").checked;
	var text=document.getElementById("exportText").value;

	if (!(filterStart||filterEnd||filterTags||filterText)) {
		alert("Please set the selection filter");
		document.getElementById('exportFilterPanel').style.display="block";
		return -1;
	}
	if (filterStart&&filterEnd&&(startDate>endDate)) {
		var msg="starting date/time:\n"
		msg+=startDate.toLocaleString()+"\n";
		msg+="is later than ending date/time:\n"
		msg+=endDate.toLocaleString()
		alert(msg);
		return -1;
	}

	// scan list and select tiddlers that match all applicable criteria
	var total=0;
	var count=0;
	for (var i=0; i<theList.options.length; i++) {
		// get item, skip non-tiddler list items (section headings)
		var opt=theList.options[i]; if (opt.value=="") continue;
		// get tiddler, skip missing tiddlers (this should NOT happen)
		var tiddler=store.getTiddler(opt.value); if (!tiddler) continue; 
		var sel=true;
		if ( (filterStart && tiddler.modified<startDate)
		|| (filterEnd && tiddler.modified>endDate)
		|| (filterTags && !matchTags(tiddler,tags))
		|| (filterText && (tiddler.text.indexOf(text)==-1) && (tiddler.title.indexOf(text)==-1)))
			sel=false;
		opt.selected=sel;
		count+=sel?1:0;
		total++;
	}
	return count;
}
//}}}

//{{{
function matchTags(tiddler,cond)
{
	if (!cond||!cond.trim().length) return false;

	// build a regex of all tags as a big-old regex that 
	// OR's the tags together (tag1|tag2|tag3...) in length order
	var tgs = store.getTags();
	if ( tgs.length == 0 ) return results ;
	var tags = tgs.sort( function(a,b){return (a[0].length<b[0].length)-(a[0].length>b[0].length);});
	var exp = "(" + tags.join("|") + ")" ;
	exp = exp.replace( /(,[\d]+)/g, "" ) ;
	var regex = new RegExp( exp, "ig" );

	// build a string such that an expression that looks like this: tag1 AND tag2 OR NOT tag3
	// turns into : /tag1/.test(...) && /tag2/.test(...) || ! /tag2/.test(...)
	cond = cond.replace( regex, "/$1\\|/.test(tiddlerTags)" );
	cond = cond.replace( /\sand\s/ig, " && " ) ;
	cond = cond.replace( /\sor\s/ig, " || " ) ;
	cond = cond.replace( /\s?not\s/ig, " ! " ) ;

	// if a boolean uses a tag that doesn't exist - it will get left alone 
	// (we only turn existing tags into actual tests).
	// replace anything that wasn't found as a tag, AND, OR, or NOT with the string "false"
	// if the tag doesn't exist then /tag/.test(...) will always return false.
	cond = cond.replace( /(\s|^)+[^\/\|&!][^\s]*/g, "false" ) ;

	// make a string of the tags in the tiddler and eval the 'cond' string against that string 
	// if it's TRUE then the tiddler qualifies!
	var tiddlerTags = (tiddler.tags?tiddler.tags.join("|"):"")+"|" ;
	try { if ( eval( cond ) ) return true; }
	catch( e ) { displayMessage("Error in tag filter '" + e + "'" ); }
	return false;
}
//}}}

// // OUTPUT FORMATTING AND FILE I/O

// // exportHeader(format)
//{{{
function exportHeader(format)
{
	switch (format) {
		case "TW":	return exportTWHeader();
		case "DIV":	return exportDIVHeader();
		case "XML":	return exportXMLHeader();
	}
}
//}}}

// // exportFooter(format)
//{{{
function exportFooter(format)
{
	switch (format) {
		case "TW":	return exportTWFooter();
		case "DIV":	return exportDIVFooter();
		case "XML":	return exportXMLFooter();
	}
}
//}}}

// // exportTWHeader()
//{{{
function exportTWHeader()
{
	// get the TiddlyWiki core code source
	var sourcefile=getLocalPath(document.location.href);
	var source=loadFile(sourcefile);
	if(source==null) { alert(config.messages.cantSaveError); return null; }
	// reset existing HTML source markup
	source=updateMarkupBlock(source,"PRE-HEAD");
	source=updateMarkupBlock(source,"POST-HEAD");
	source=updateMarkupBlock(source,"PRE-BODY");
	source=updateMarkupBlock(source,"POST-BODY");
	// find store area
	var posOpeningDiv=source.indexOf(startSaveArea);
	var posClosingDiv=source.lastIndexOf(endSaveArea);
	if((posOpeningDiv==-1)||(posClosingDiv==-1)) { alert(config.messages.invalidFileError.format([sourcefile])); return; }
	// return everything up to store area
	return source.substr(0,posOpeningDiv+startSaveArea.length);
}
//}}}

// // exportTWFooter()
//{{{
function exportTWFooter()
{
	// get the TiddlyWiki core code source
	var sourcefile=getLocalPath(document.location.href);
	var source=loadFile(sourcefile);
	if(source==null) { alert(config.messages.cantSaveError); return null; }
	// reset existing HTML source markup
	source=updateMarkupBlock(source,"PRE-HEAD");
	source=updateMarkupBlock(source,"POST-HEAD");
	source=updateMarkupBlock(source,"PRE-BODY");
	source=updateMarkupBlock(source,"POST-BODY");
	// find store area
	var posOpeningDiv=source.indexOf(startSaveArea);
	var posClosingDiv=source.lastIndexOf(endSaveArea);
	if((posOpeningDiv==-1)||(posClosingDiv==-1)) { alert(config.messages.invalidFileError.format([sourcefile])); return; }
	// return everything after store area
	return source.substr(posClosingDiv);
}
//}}}

// // exportDIVHeader()
//{{{
function exportDIVHeader()
{
	var out=[];
	var now = new Date();
	var title = convertUnicodeToUTF8(wikifyPlain("SiteTitle").htmlEncode());
	var subtitle = convertUnicodeToUTF8(wikifyPlain("SiteSubtitle").htmlEncode());
	var user = convertUnicodeToUTF8(config.options.txtUserName.htmlEncode());
	var twver = version.major+"."+version.minor+"."+version.revision;
	var pver = version.extensions.exportTiddlers.major+"."
		+version.extensions.exportTiddlers.minor+"."+version.extensions.exportTiddlers.revision;
	out.push("<html><body>");
	out.push("<style type=\"text/css\">");
	out.push("#storeArea {display:block;margin:1em;}");
	out.push("#storeArea div");
	out.push("{padding:0.5em;margin:1em;border:2px solid black;height:10em;overflow:auto;}");
	out.push("#javascriptWarning");
	out.push("{width:100%;text-align:left;background-color:#eeeeee;padding:1em;}");
	out.push("</style>");
	out.push("<div id=\"javascriptWarning\">");
	out.push("TiddlyWiki export file<br>");
	out.push("Source"+": <b>"+convertUnicodeToUTF8(document.location.href)+"</b><br>");
	out.push("Title: <b>"+title+"</b><br>");
	out.push("Subtitle: <b>"+subtitle+"</b><br>");
	out.push("Created: <b>"+now.toLocaleString()+"</b> by <b>"+user+"</b><br>");
	out.push("TiddlyWiki "+twver+" / "+"ExportTiddlersPlugin "+pver+"<br>");
	out.push("Notes:<hr><pre>"+document.getElementById("exportNotes").value.replace(/\n/g,"<br>")+"</pre>");
	out.push("</div>");
	out.push("<div id=\"storeArea\">");
	return out;
}
//}}}

// // exportDIVFooter()
//{{{
function exportDIVFooter()
{
	return ["</div><!--POST-BODY-START-->\n<!--POST-BODY-END--></body></html>"];
}
//}}}

// // exportXMLHeader()
//{{{
function exportXMLHeader()
{
	var out=[];
	var now = new Date();
	var u = store.getTiddlerText("SiteUrl",null);
	var title = convertUnicodeToUTF8(wikifyPlain("SiteTitle").htmlEncode());
	var subtitle = convertUnicodeToUTF8(wikifyPlain("SiteSubtitle").htmlEncode());
	var user = convertUnicodeToUTF8(config.options.txtUserName.htmlEncode());
	var twver = version.major+"."+version.minor+"."+version.revision;
	var pver = version.extensions.exportTiddlers.major+"."
		+version.extensions.exportTiddlers.minor+"."+version.extensions.exportTiddlers.revision;
	out.push("<" + "?xml version=\"1.0\"?" + ">");
	out.push("<rss version=\"2.0\">");
	out.push("<channel>");
	out.push("<title>" + title + "</title>");
	if(u) out.push("<link>" + convertUnicodeToUTF8(u.htmlEncode()) + "</link>");
	out.push("<description>" + subtitle + "</description>");
	out.push("<language>en-us</language>");
	out.push("<copyright>Copyright " + now.getFullYear() + " " + user + "</copyright>");
	out.push("<pubDate>" + now.toGMTString() + "</pubDate>");
	out.push("<lastBuildDate>" + now.toGMTString() + "</lastBuildDate>");
	out.push("<docs>http://blogs.law.harvard.edu/tech/rss</docs>");
	out.push("<generator>TiddlyWiki "+twver+" plus ExportTiddlersPlugin "+pver+"</generator>");
	return out;
}
//}}}

// // exportXMLFooter()
//{{{
function exportXMLFooter()
{
	return ["</channel></rss>"];
}
//}}}

// // exportData()
//{{{
function exportData(theList,theFormat)
{
	// scan export listbox and collect DIVs or XML for selected tiddler content
	var out=[];
	for (var i=0; i<theList.options.length; i++) {
		// get item, skip non-selected items and section headings
		var opt=theList.options[i]; if (!opt.selected||(opt.value=="")) continue;
		// get tiddler, skip missing tiddlers (this should NOT happen)
		var thisTiddler=store.getTiddler(opt.value); if (!thisTiddler) continue; 
		switch (theFormat) {
			case "TW":
				out.push(convertUnicodeToUTF8(store.getSaver().externalizeTiddler(store,thisTiddler)));
				break;
			case "DIV":
				out.push(convertUnicodeToUTF8(thisTiddler.title+"\n"+store.getSaver().externalizeTiddler(store,thisTiddler)));
				break;
			case "XML":
				out.push(convertUnicodeToUTF8(thisTiddler.saveToRss(store.getTiddlerText("SiteUrl",""))));
				break;
		}
	}
	return out;
}
//}}}

// // exportTiddlers(): output selected data to local file
//{{{
function exportTiddlers()
{
	var theList  = document.getElementById("exportList"); if (!theList) return;
	var theFormat = document.getElementById("exportFormat").value;
	var theData=exportData(theList,theFormat);
	var count=theData.length;
	var out=[]; var txt=out.concat(exportHeader(theFormat),theData,exportFooter(theFormat)).join("\n");
	var msg="";
	var theTarget = document.getElementById("exportFilename").value.trim();
	if (theTarget.length) {
		if (saveFile(theTarget,txt))
			msg=count+" tiddler"+((count!=1)?"s":"")+" exported to "+theTarget;
		else
			msg+="An error occurred while saving to "+theTarget;
		theTarget="file:///"+theTarget; // URL link for newly created file
	}
	else
		msg = "A local target path/filename is required";
	clearMessage(); displayMessage(msg,theTarget);
}
//}}}

// // exportDeleteTiddlers(): delete selected tiddlers from file
//{{{
function exportDeleteTiddlers()
{
	var list=document.getElementById("exportList"); if (!list) return;
	var tids=[];
	for (i=0;i<list.length;i++)
		if (list.options[i].selected && list.options[i].value.length)
			tids.push(list.options[i].value);
	if (!confirm("Are you sure you want to delete these tiddlers:\n\n"+tids.join(', '))) return;
	store.suspendNotifications();
	for (t=0;t<tids.length;t++) {
		var tid=store.getTiddler(tids[t]); if (!tid) continue;
		if (tid.tags.contains("systemConfig"))
			if (!confirm("'"+tid.title+"' is tagged with 'systemConfig'.\n\nRemoving this tiddler may cause unexpected results.  Are you sure?"))
				continue;
		store.removeTiddler(tid.title);
		story.closeTiddler(tid.title);
	}
	store.resumeNotifications();
	alert(tids.length+" tiddlers deleted");
	refreshExportList(0); // reload listbox
	store.notifyAll(); // update page display
}
//}}}
/***
|Name|ExportTiddlersPluginInfo|
|Source|http://www.TiddlyTools.com/#ExportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ExportTiddlersPluginInfo|
|Version|2.6.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|Documentation for ExportTiddlersPlugin|
ExportTiddlersPlugin lets you select and extract tiddlers from your ~TiddlyWiki documents using interactive control panel lets you specify a destination, and then select which tiddlers to export. Tiddler data can be output as complete, stand-alone TiddlyWiki documents, or just the selected tiddlers ("~PureStore" format -- smaller files!) that can be imported directly into another ~TiddlyWiki, or as an ~RSS-compatible XML file that can be published for RSS syndication.
!!!!!Usage
<<<
{{{
<<exportTiddlers>> (sidebar menu item)
<<exportTiddlers inline>> (embedded control panel)
}}}

Inline control panel (live):
<<exportTiddlers inline>>

Optional "special tiddlers" used by this plugin:
* SiteUrl<br>URL for official server-published version of document being viewed (used in XML export). Ddefault: //none//
* SiteDate<br>stored date/time stamp for most recent published version of document.  Default: current document.modified value (i.e., the 'file date')
<<<
!!!!!Revisions
<<<
2008.03.10 [2.6.0] added "delete tiddlers" button
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.11.10 [2.5.1] removed debugging alert messages from promptForExportFilename()
2007.10.31 [2.5.0] code reduction: removed incomplete/unused interface and supporting functions for exporting directly to http, https or ftp servers.  Plugin now supports exporting to local file only.  Transferring that file is now left to other mechanisms, such as email attachments, FTP uploads, portable media (USB,CD,DVD,...), etc.  Also, updated "save as TiddlyWiki document" output to correctly generate TW2.2 compatible file format.
2007.10.30 [2.4.2] added automatic shadow tiddler definition for [[ExportTiddlers]]
2007.07.16 [2.4.1] in exportTWHeader(), reset HTML source 'markup' so installed markup is NOT copied to new file.
2007.06.30 [2.4.0] added "select related tiddlers" feature.  Recursively scans the tiddler links[] info to find all tiddlers referenced by any of the currently selected tiddler, and then selects them all (including the original tiddlers).  //Theoretically//, selecting all related tiddlers should ensure that the exported file contains all tiddlers needed to properly render all of the originally selected tiddlers.
2007.04.19 [2.3.0] in exportData(), pass SiteURL value as param to saveToRss().  Fixes 'undefined' appearing in tiddler link in XML output.  Also, in refreshExportList(), added 'sort by tags'.  Also, added 'group select'... selecting a heading (date,author,tag) auto-selects all tiddlers in that group.
2007.03.02 [2.2.6] in onClickExportButton(), when selecting open tiddlers for TW2.2, look for "storyDisplay" instead of "tiddlerDisplay" but keep fallback to "tiddlerDisplay" for TW2.1 or earlier
2007.03.01 [2.2.5] removed hijack of store.saveChanges() (was catching save on http:, but there are other solutions that do a much better job of handling save to server.
2006.11.08 [2.2.4] added promptForExportFilename() and replaced type="file" control with edit field + browse button ("...").
2006.10.12 [2.2.3] in exportDIVFooter(), write POST-BODY-START/END markers for compatibility with TW2.1 core file format.  Based on report from Jose Gonzalez.
2006.05.11 [2.2.2] in createExportPanel, removed call to addNotification() to no longer auto-refresh the list every time a tiddler is changed.  Instead, call refreshExportList(0) only when the panel is first rendered and each time it is made visible.  Prevents unneeded feedback messages from being displayed and increases overall document performance, since the listbox is no longer being updated each time a tiddler is saved.
2006.05.02 [2.2.1] Use displayMessage() to show number of selected tiddlers instead of updating listbox 'header' item after each selection.  Prevents awkward 'scroll-to-top' behavior that made multi-select via ctrl-click nearly impossible.  Reported by Paul Reiber.
2006.04.29 [2.2.0] New features: "Notes" are free-form text that is inserted in the header of a TWDIV export file.  When exporting to a server, the "notify" checkbox indicates that server-side script processing should send an email message when the export file is stored on the server.  Comma-separated addresses may be typed in, or pre-defined in the SiteNotify tiddler.
2006.03.29 [2.1.3] added calls to convertUnicodeToUTF8() for generated output, so it better handles international characters.
2006.02.12 [2.1.2] added var to unintended global 'tags' in matchTags(). Avoids FF1501 bug when filtering by tags.  (based on report by TedPavlic)
2006.02.04 [2.1.1] added var to variables that were unintentionally global.  Avoids FireFox 1.5.0.1 crash bug when referencing global variables
2006.02.02 [2.1.0] Added support for output of complete TiddlyWiki documents.  Let's you use ExportTiddlers to generate 'starter' documents from selected tiddlers.
2006.01.21 [2.0.1] Defer initial panel creation and only register a notification function when panel first is created
in saveChanges 'hijack', create panel as needed.  Note: if window.event is not available to identify the click location, the export panel is positioned relative to the 'tiddlerDisplay' element of the TW document.
2005.12.27 [2.0.0] Update for TW2.0
Defer initial panel creation and only register a notification function when panel first is created
2005.12.24 [0.9.5] Minor adjustments to CSS to force correct link colors regardless of TW stylesheet selection
2005.12.16 [0.9.4] Dynamically create/remove exportPanel as needed to ensure only one instance of interface elements exists, even if there are multiple instances of macro embedding.
2005.11.15 [0.9.2] added non-Ajax post function to bypass javascript security restrictions on cross-domain I/O.  Moved AJAX functions to separate tiddler (no longer needed here).  Generalized HTTP server to support UnaWiki servers
2005.11.08 [0.9.1] moved HTML, CSS and control initialization into exportInit() function and call from macro handler instead of at load time.  This allows exportPanel to be placed within the same containing element as the "export tiddlers" button, so that relative positioning can be achieved.
2005.10.28 [0.9.0] added 'select opened tiddlers' feature. Based on a suggestion by Geoff Slocock
2005.10.24 [0.8.3] Corrected hijack of 'save changes' when using http:
2005.10.18 [0.8.2] added AJAX functions
2005.10.18 [0.8.1] Corrected timezone handling when filtering for date ranges. Improved error checking/reporting for invalid filter values and filters that don't match any tiddlers. Exporting localfile-to-localfile is working for IE and FF.  Exporting server-to-localfile works in IE (after ActiveX warnings), but has security issues in FF. Cross-domain exporting (localfile/server-to-server) is under development.  More style tweaks, minor text changes and some assorted layout cleanup.
2005.10.17 [0.8.0] First pre-release.
2005.10.16 [0.7.0] filter by tags
2005.10.15 [0.6.0] filter by title/text
2005.10.14 [0.5.0] export to local file (DIV or XML)
2005.10.14 [0.4.0] filter by start/end date
2005.10.13 [0.3.0] panel interaction
2005.10.11 [0.2.0] panel layout
2005.10.10 [0.1.0] code framework
2005.10.09 [0.0.0] development started
<<<
/***
|Name|ExternalTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#ExternalTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ExternalTiddlersPluginInfo|
|Version|1.3.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|TemporaryTiddlersPlugin (optional, recommended)|
|Overrides|config.macros.tiddler.handler|
|Options|##Configuration|
|Description|retrieve and wikify content from external files or remote URLs|
This plugin extends the {{{<<tiddler>>}}} macro syntax so you can retrieve and wikify content directly from external files or remote URLs.  You can also define alternative "fallback" sources to provide basic "import on demand" handling by automatically creating/importing tiddler content from external sources when the specified ~TiddlerName does not already exist in your document.
!!!!!Documentation
>see [[ExternalTiddlersPluginInfo]]
!!!!!Configuration
<<<
<<option chkExternalTiddlersImport>> automatically create/import tiddlers when using external fallback references
{{{usage: <<option chkExternalTiddlersImport>>}}}
<<option chkExternalTiddlersQuiet>> don't display messages when adding tiddlers ("quiet mode")
{{{usage: <<option chkExternalTiddlersQuiet>>}}}
<<option chkExternalTiddlersTemporary>> tag retrieved tiddlers as 'temporary'(requires [[TemporaryTiddlersPlugin]])
{{{usage: <<option chkExternalTiddlersTemporary>>}}}
tag retrieved tiddlers with: <<option txtExternalTiddlersTags>>
{{{usage: <<option txtExternalTiddlersTags>>}}}

__password-protected server settings //(optional, if needed)//:__
>username: <<option txtRemoteUsername>> password: <<option txtRemotePassword>>
>{{{usage: <<option txtRemoteUsername>> <<option txtRemotePassword>>}}}
>''note: these settings are also used by [[LoadTiddlersPlugin]] and [[ImportTiddlersPlugin]]''
<<<
!!!!!Revisions
<<<
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ExternalTiddlersPluginInfo
2008.01.03 [1.3.0] use lower-level doHttp() instead loadRemoteFile() so that optional username/password values can be used in XMLHttpRequest
2007.12.22 [1.2.2] in handler(), when reading from local file with relative path fixup, use decodeURIComponent() instead of decodeURI 
2007.11.30 [1.2.1] lots of code/docmentation cleanup.  renamed option cookies.  changed auto tag value to "external".
2007.11.27 [1.2.0] added support for automatically importing external tiddlers
2007.11.26 [1.1.1] improved XMLHttpRequest() error reporting for cross-domain security issues
2007.11.26 [1.1.0] added support for multiple alternative fallback references
2007.11.25 [1.0.0] initial release - moved from CoreTweaks
<<<
!!!!!Code
***/
//{{{
version.extensions.ExternalTiddlers= {major: 1, minor: 3, revision: 0, date: new Date(2008,1,3)};

// optional automatic import/create for missing tiddlers
if (config.options.chkExternalTiddlersImport==undefined) config.options.chkExternalTiddlersImport=true;
if (config.options.chkExternalTiddlersTemporary==undefined) config.options.chkExternalTiddlersTemporary=true;
if (config.options.chkExternalTiddlersQuiet==undefined) config.options.chkExternalTiddlersQuiet=false;
if (config.options.txtExternalTiddlersTags==undefined) config.options.txtExternalTiddlersTags="external";
if (config.options.txtRemoteUsername==undefined) config.options.txtRemoteUsername="";
if (config.options.txtRemotePassword==undefined) config.options.txtRemotePassword="";

config.macros.tiddler.externalTiddlers_handler = config.macros.tiddler.handler;
config.macros.tiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	params = paramString.parseParams("name",null,true,false,true);
	var names = params[0]["name"];
	var list = names[0];
	var items = list.split("|"); 
	var className = names[1] ? names[1] : null;
	var args = params[0]["with"];

	// UTILITY FUNCTIONS
	function extract(text,tids) { // get tiddler source content from plain text or TW doc
		if (!text || !tids || !tids.length) return text; // no text or no tiddler list... return text as-is
		var remoteStore=new TiddlyWiki();
		if (!remoteStore.importTiddlyWiki(text)) return text; // not a TW document... return text as-is
		var out=[]; for (var t=0;t<tids.length;t++)
			{ var txt=remoteStore.getTiddlerText(tids[t]); if (txt) out.push(txt); }
		return out.join("\n");
	}
	function substitute(text,args) { // replace "substitution markers" ($1-$9) with macro param values (if any)
		if (!text || !args || !args.length) return text;
		var n=args.length; if (n>9) n=9;
		for(var i=0; i<n; i++) { var re=new RegExp("\\$" + (i + 1),"mg"); text=text.replace(re,args[i]); }
		return text;
	}
	function addTiddler(src,text,tids) { // extract tiddler(s) from text and create local copy
		if (!config.options.chkExternalTiddlersImport) return; // not enabled... do nothing
		if (!text || !tids || !tids.length) return; // no text or no tiddler list... do nothing
		var remoteStore=new TiddlyWiki();
		if (!remoteStore.importTiddlyWiki(text)) // not a TW document... create a single tiddler from text
			makeTiddler(src,text,tids[0]);
		else // TW document with "permaview-like" suffix... copy tiddler(s) from remote store
			for (var t=0;t<tids.length;t++)
				insertTiddler(src,remoteStore.getTiddler(tids[t]));
		return;
	}
	function makeTiddler(src,text,title) { // create a new tiddler object from text
		var who=config.options.txtUserName; var when=new Date();
		var msg="/%\n\nThis tiddler was automatically created using ExternalTiddlersPlugin\n";
		msg+="by %0 on %1\nsource: %2\n\n%/";
		var tags=config.options.txtExternalTiddlersTags.readBracketedList();
		if (config.options.chkExternalTiddlersTemporary) tags.pushUnique(config.options.txtTemporaryTag); 
		store.saveTiddler(null,title,msg.format([who,when,src])+text,who,when,tags,{});
		if (!config.options.chkExternalTiddlersQuiet) displayMessage("Created new tiddler '"+title+"' from text file "+src);
	}
	function insertTiddler(src,t) { // import a single tiddler object into the current document store
		if (!t) return;
		var who=config.options.txtUserName; var when=new Date();
		var msg="/%\n\nThis tiddler was automatically imported using ExternalTiddlersPlugin\n";
		msg+="by %0 on %1\nsource: %2\n\n%/";
		var newtags=Array.concat(t.tags,config.options.txtExternalTiddlersTags.readBracketedList());
		if (config.options.chkExternalTiddlersTemporary) newtags.push(config.options.txtTemporaryTag);
		store.saveTiddler(null,t.title,msg.format([who,when,src])+t.text,t.modifier,t.modified,newtags,t.fields);
		if (!config.options.chkExternalTiddlersQuiet) displayMessage("Imported tiddler '"+t.title+"' from "+src);
	}
	function getGUID()  // create a Globally Unique ID (for async reference to DOM elements)
		 { return new Date().getTime()+Math.random().toString(); }

	// loop through "|"-separated list of alternative tiddler/file/URL references until successful
	var fallback="";
	for (var i=0; i<items.length; i++) { var src=items[i];
		// if tiddler (or shadow) exists, replace reference list with current source name and apply core handler
		if (store.getTiddlerText(src)) {
			arguments[2][0]=src; // params[] array
			var p=arguments[4].split(list); arguments[4]=p[0]+src+p[1]; // paramString
			this.externalTiddlers_handler.apply(this,arguments);
			break; // stop processing alternatives
		}
		// tiddler doesn't exist, and not an external file/URL reference... skip it
		if (!config.formatterHelpers.isExternalLink(src)) {
			if (!fallback.length) fallback=src; // title to use when importing external tiddler
			continue;
		}
		// separate 'permaview' list of tiddlers (if any) from file/URL (i.e., '#name name name..." suffix)
		var p=src.split("#"); src=p[0]; var tids=p[1]?p[1].readBracketedList(false):[];
		// if reference is to a remotely hosted document or the current document is remotely hosted...
		if (src.substr(0,4)=="http" || document.location.protocol.substr(0,4)=="http") {
			if (src.substr(0,4)!="http") // fixup URL for relative remote references
				{ var h=document.location.href; src=h.substr(0,h.lastIndexOf("/")+1)+src; }
			var wrapper = createTiddlyElement(place,"span",getGUID(),className); // create placeholder for async rendering
			var callback=function(success,params,text,src,xhr) { // ASYNC CALLBACK
				if (!success) { displayMessage(xhr.status); return; } // couldn't read remote file... report the error 
				if (params.fallback.length)
					addTiddler(params.url,text,params.tids.length?params.tids:[params.fallback]); // import tiddler
				var wrapper=document.getElementById(params.id); if (!wrapper) return; 
				wikify(substitute(extract(text,params.tids),params.args),wrapper); // ASYNC RENDER
			};
			var callbackparams={ url:src, id:wrapper.id, args:args, tids:tids, fallback:fallback }  // ASYNC PARAMS
			var name=config.options.txtRemoteUsername; // optional value
			var pass=config.options.txtRemotePassword; // optional value
			var x=doHttp("GET",src,null,null,name,pass,callback,callbackparams,null)
			if (typeof(x)=="string") // couldn't start XMLHttpRequest... report error
				{ displayMessage("error: cannot access "+src); displayMessage(x); }
			break; // can't tell if async read will succeed.... stop processing alternatives anyway.
		}
		else { // read file from local filesystem
			var text=loadFile(getLocalPath(src));
			if (!text) { // couldn't load file... fixup path for relative reference and retry...
				var h=document.location.href;
				var text=loadFile(getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf("/")+1)))+src);
			}
			if (text) { // test it again... if file was loaded OK, render it in a class wrapper
				if (fallback.length) // create new tiddler using primary source name (if any)
					addTiddler(src,text,tids.length?tids:[fallback]);
				var wrapper=createTiddlyElement(place,"span",null,className);
				wikify(substitute(extract(text,tids),args),wrapper); // render
				break; // stop processing alternatives
			}
		}
	}
};
//}}}
|Name|ExternalTiddlersPluginInfo|
|Source|http://www.TiddlyTools.com/#ExternalTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ExternalTiddlersPluginInfo|
|Version|1.3.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 ExternalTiddlersPlugin|
This plugin extends the {{{<<tiddler>>}}} macro syntax so you can retrieve and wikify content directly from external files or remote URLs.  You can also define alternative "fallback" sources to provide basic "import on demand" handling by automatically creating/importing tiddler content from external sources when the specified ~TiddlerName does not already exist in your document.
!!!!!Configuration
>see ExternalTiddlersPlugin
!!!!!Usage
<<<
The standard TiddlyWiki core syntax for the {{{<<tiddler>>}}} macro is:
>{{{<<tiddler TiddlerName with: param param param ...>>}}}
where the optional {{{with: param param param...}}} values are used to replace any corresponding "substitution markers" ($1 to $9) that may be embedded in the referenced tiddler content.

This plugin allows the {{{<<tiddler>>}}} macro to ''use external file/URL references in place of the usual ~TiddlerName parameter'', so that you can render wiki-formatted source content retrieved from an external file/URL reference (as determined by the core's isExternalLink() test function), ''//as if// it had come from a tiddler in the current document''.  The external file/URL can be either ''a relative or absolute reference'' and can contain ''"plain text" or a full TiddlyWiki document''.  When using a TiddlyWiki document, you must specify which tiddlers should be included in the output by appending a permaview-like suffix to the file or URL reference, e.g.:
>{{{<<tiddler "myfile.txt" with: param param param...>>}}}
>or
>{{{<<tiddler "myfile.html#TiddlerName TiddlerName..." with: param param param...>>}}}
>or
>{{{<<tiddler "http://www.TiddlyWiki.com/index.html#HelloThere" with: param param param...>>}}}
If the plugin-enhanced {{{<<tiddler>>}}} macro is unable to retrieve the external content --  perhaps because the file doesn't exist or doesn't contain the requested tiddler(s), or cross-domain security blocked file access, or the network/server "timed out", etc., -- then it produces no output (i.e., just as when the standard {{{<<tiddler>>}}} macro is given a ~TiddlerName does not exist in the current document.)
<<<
!!!!!Using alternative "fallback" references
<<<
In addition to using external file/URL references in place of the usual ~TiddlerName, the plugin also allows you to use a ''fallback list'' consisting of a combination of alternative sources: tiddlers, local files, and/or URL references, each separated by "|".  The first reference in a fallback list is the "primary source"; the remaining references are "fallback sources".  The plugin will attempt to retrieve content from each fallback source until one is successfully retrieved or all alternatives have been tried.

For example, if you create a tiddler called [[HelloThere]], as well as a remotely-hosted TW document containing a published tiddler, also called [[HelloThere]], then you can write:
>{{{<<tiddler [[HelloThere|http://www.TiddlyWiki.com/#HelloThere]]>>}}}
When [[HelloThere]] is present in the local document, it is processed in the normal manner.  However, if you delete the  local [[HelloThere]] tiddler, the plugin will attempt to retrieve the [[HelloThere]] tiddler from the indicated remote URL.

Please note: although you can list any number of alternative sources, in whatever order you prefer, retrieval from a remote URL occurs asynchronously via XMLHttpRequest() processing.  As a consequence, there can be ''no more than one remote URL reference in the fallback list'', and any alternatives that follow a remote URL reference will not be processed.
<<<
!!!!!Automatically import/create missing tiddlers
<<<
When content is retrieved from an external fallback source, the plugin can automatically import/create tiddler(s) containing that content into your document, allowing you to display, modify, save and/or search for text in that tiddler from within your own document, without needing to retrieve it again from the external source.

If no local ~TiddlerName(s) are specified in the fallback list (i.e., only direct file/URL references are present), then a tiddler will NOT be created, so that each time you render the tiddler display the external source will be re-read in order to render the most recently saved external file content.  To illustrate using the example from above:
>&nbsp;&nbsp;&nbsp;{{{<<tiddler [[HelloThere|http://www.TiddlyWiki.com/#HelloThere]]>>}}}
will automatically create a locally-stored [[HelloThere]] tiddler, so that the external source is only accessed the first time the content is rendered, while:
>&nbsp;&nbsp;&nbsp;{{{<<tiddler [[http://www.TiddlyWiki.com/#HelloThere]]>>}}}
will re-load the content from the external source each time the display is rendered.

For easy identification, any tiddlers that are automatically created/imported are tagged with <<tag external>> (or other custom-defined tag values).  These tiddlers can also be automatically tagged with <<tag temporary>> for use with [[TemporaryTiddlersPlugin]], which will skip over those tiddlers when saving changes to your document so that when you reload the document, the temporary tiddlers will no longer be present and will be retrieved anew from the external source, on demand, when (or if) they are needed.  Important reminder: ''If you modify a temporary tiddler and want to retain it in your local document, be sure to remove the <<tag temporary>> tag from the tiddler before saving.''
<<<
!!!!!~XMLHttpRequest: performance and security issues
<<<
This plugin uses asynchronous XMLHttpRequest() processing to access external content directly from URLs hosted on remote web servers.  This often creates delays ranging from mere moments to many minutes while waiting for the remote web server to transfer the requested file.  This performance can vary greatly depending upon the size of the remote file, how the remote server responds to repeated requests for the same URL (e.g, with a //"304 - no change"// response code), as well as how your ''browser's cache mechanism'' has been configured (to avoid repeated downloads).

In addition to server-originated delays, ''cross-domain access from one remote domain to another using XMLHttpRequest() processing is generally restricted for security reasons''.  As a result, if you publish your document to a remote web server, then external file/URL references contained in that document will not work if they are not located on the same server as the hosted document.

Fortunately, this security restriction does NOT usually apply when accessing remote URLs rendered into a locally-viewed document, since blocking such access would interfere with normal browser functions!  As a "rule of thumb", in order to ensure that external content included in server-hosted documents will be displayed as intended, you should ''always use either a relative path/file reference or an http: reference located on the same domain as the published document.'' for any document you intend to publish.

Note: Some hosting providers, such as http://www.TiddlySpot.com/ offer ''"proxy" services that may allow you to bypass the security restrictions'' for certain designated remote web sites.  Consult your hosting service for information regarding their proxy arrangments (if any).
<<<
/***
|Name|FAQViewerPlugin|
|Source|http://www.TiddlyTools.com/#FAQViewerPlugin|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|select and display FAQ tiddlers from a droplist, sorted by date|
!!!!!Usage
<<<
{{{<<faqViewer tagname>>}}}
where ''tagname'' is optional and specifies the set of tiddlers to include in the FAQ list (default='faq')

example: {{{<<faqViewer>>}}}
{{smallform small{<<faqViewer>>}}}
<<<
!!!!!Revisions
<<<
2008.01.20 [1.1.0] added support for alternative 'target' tag instead of "faq" (default)
2007.10.15 [1.0.0] converted to true plugin
2007.02.01 [0.0.0] inline script
<<<
!!!!!Code
***/
//{{{
version.extensions.FAQViewer={major: 1, minor: 1, revision: 0, date: new Date(2006,1,20)};
//}}}
//{{{
config.shadowTiddlers.FAQViewer="{{smallform{<<faqViewer>>}}}";
//}}}
//{{{
config.macros.faqViewer= {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		// create form
		var console=createTiddlyElement(place,"span");
		console.innerHTML=this.html;
		this.go(console.getElementsByTagName("form")[0],params[0]); // initialize droplist
	},
	go: function(f,targetType) {
		targetType=targetType||"faq";
		f.targetType.value=targetType;
		var lists=f.getElementsByTagName("select"); if (!lists.length) return;
		var FAQList=lists[0]; var taglist=lists[1];
		while (FAQList.options[0]) FAQList.options[0]=null; // empty FAQList
		if (f.search.value!=f.search.defaultValue) var find=f.search.value;
		var tiddlers=store.getTaggedTiddlers(targetType,"modified");
		var matchcount=0; var tags=[];
		FAQList.options[0]=new Option("select an item...","",false,false);
		for (var i=tiddlers.length-1; i>=0; i--) {
			for (var t=0; t<tiddlers[i].tags.length; t++) tags.pushUnique(tiddlers[i].tags[t]); // collect other tags
			if (find && find.length && tiddlers[i].text.indexOf(find)==-1) continue;
			if (taglist.value && taglist.value.length && !tiddlers[i].tags.contains(taglist.value)) continue;
			matchcount++;
			var descr=store.getTiddlerSlice(tiddlers[i].title,"Description")
			var date=tiddlers[i].modified.formatString("YYYY.0MM.0DD 0hh:0mm");
			FAQList.options[FAQList.options.length]=new Option(date+' - '+descr,tiddlers[i].title,false,false);
		}
		FAQList.options[0].text="select an item... ["+tiddlers.length+" item"+(tiddlers.length!=1?"s":"");
		if (find && find.length || taglist.value.length)
			FAQList.options[0].text+=", "+matchcount+" match"+(matchcount!=1?"es":"");
		FAQList.options[0].text+="]";

		if (!taglist.options.length) { // only load tag list the first time, since it doesn't change
			while (taglist.options[0]) taglist.options[0]=null; // empty taglist
			taglist.options[0]=new Option("filter by tag...","",false,false);
			var tagcount=0;
			for (var t=0; t<tags.length; t++) {
				if (tags[t].toLowerCase()==targetType) continue;
				if (tags[t].indexOf("exclude")!=-1) continue;
				taglist.options[taglist.options.length]
					=new Option(tags[t],tags[t],false,false);
				tagcount++;
			}
			if (!tagcount) taglist.options[taglist.options.length]
				=new Option("no category tags found","",false,false);
		}
	},
	faqlayout:
		"{{borderleft{\n{{toolbar floatright fine{//now viewing: //[[%0]] &nbsp;}}}<<tiddler [[%0]]>>}}}",
	html:
		"<form onsubmit='return false;' style='display:inline;margin:0;padding:0;'><!-- \
		--><input type='hidden' name='targetType' value='faq'><!-- \
		--><select name='list' size=1 style='width:50%' \
			onchange='var target=this.form.nextSibling; removeChildren(target); \
				wikify(config.macros.faqViewer.faqlayout.format([this.value]),target); \
				target.style.display=this.value.length?\"block\":\"none\"; \
				this.form.done.disabled=!this.value.length;'><!-- \
		--></select><!-- \
		--><select name='taglist' size=1 style='width:15%' \
			title='list only items that have a specific category tag' \
			onchange='var f=this.form; f.done.onclick(); \
				config.macros.faqViewer.go(this.form,this.form.targetType.value)'><!-- \
		--></select><!-- \
		--><input type='text' name='search' value='enter search text...' style='width:16%' \
			title='list only items that contain the search text (use blank to match all)' \
			onfocus='this.select()' \
			onkeyup=' if (event.keyCode==13) this.form.find.onclick(); \
				if (!this.value.length) {this.value=this.defaultValue; this.select(); this.form.find.onclick();}'><!-- \
		--><input type='button' name='find' value='find' style='width:6%' \
			title='list only items that contain the search text ' \
			onclick='this.form.done.onclick(); \
				config.macros.faqViewer.go(this.form,this.form.targetType.value)'><!-- \
		--><input type='button' name='reset' value='reset' style='width:6%' \
			title='reset FAQViewer to default ' \
			onclick='var f=this.form; f.done.onclick(); \
				f.search.value=f.search.defaultValue; f.taglist.selectedIndex=0; \
				config.macros.faqViewer.go(f,f.targetType.value)'><!-- \
		--><input type='button' name='done' value='done' disabled style='width:6%' \
			title='hide current item display' \
			onclick='var target=this.form.nextSibling; removeChildren(target); \
				target.style.display=\"none\"; this.form.list.selectedIndex=0; this.disabled=true;'><!-- \
		--></form><div style=\"display:none;white-space:normal;\"></div> \
	"
}
//}}}
/%
|Description|Configuring browser security settings in FireFox...|
%/
{{small{
__Configuring browser security settings in FireFox...__

Certain javascript features (most notably functions that perform local filesystem I/O) require expanded "cross-domain" privileges.  These permissions are normally restricted for use with ''signed'' scripts, and FireFox can be configured to allow or disallow these privileges based on the digital signature of the originator (or ''principal'') of the signed script.

However, ''unsigned'' scripts, such as TiddlyWiki, do not contain a digital signature and are not normally allowed access to filesystem functions.  Fortunately, an //''unsigned''// script can still be granted expanded filesystem privileges through use of a ''codebase principal'', which relies upon the originating URL of the script (it's "codebase") to identify the "trusted source", rather than verifying a digital signature of a certificate.

''In FireFox (and other 'mozilla-based' browsers) use of codebase principals is disabled by default''
>To enable use of codebase principals, go to "about:config" in your browser, and set:
>&nbsp;&nbsp;''{{{signed.applets.codebase_principal_support}}}'' to ''{{{true}}}''
>note: other browsers' settings may vary...  if applicable, try adding
>&nbsp;&nbsp;''{{{user_pref("signed.applets.codebase_principal_support", true);}}}''
>to your browser's "preferences" file (prefs.js), which is typically located in a sub-folder that is created as part of the browser application installation process.
After you have enabled codebase principals, you will begin receiving security notices whenever you invoke a TiddlyWiki operation that requires use of privileged functions.  These notices report that the script has not been digitally signed, and asks for permission to grant privileges based on the URL (the 'codebase principal') rather than signed/verified author information.  You can press the "allow" button to permit the processing to continue, or press "deny" to prevent the privileged functions from being used by that document.  You may receive several of security notices in a row before TiddlyWiki processing is done.  These messages are normal, and you should ALLOW each of them, so that the process can continue to completion.  

Once you are confident that the document you are using is a ''trusted source'', you can mark the "remember this decision" checkbox to automatically grant security priviledges and eliminate additional notices so that the process can proceed without further interruptions.  This setting will only be applied to the specific web domain in question, so you will still receive security notices when using privileged functions from any other web sites.

When codebase principals are enabled, in addition to displaying security notices for remotely-stored TiddlyWiki documents (i.e., via {{{http://}}}), notices are also displayed when accessing TiddlyWiki documents locally (i.e., via {{{file://}}}).  This is a result of TiddlyWiki's normal filesystem I/O processing and should generally be considered safe to allow.
>Note: you can use the [[ShowFirefoxPermissions]] inline 'onclick' script (requires InlineJavascriptPlugin) to review the codebase principle permissions that are currently in effect.
!!!!!Technical information for developers:
The following table defines the various privileges that a script can request:
| Privilege |Description |
| ~UniversalBrowserRead|Allows reading of privileged data from the browser. This allows the script to pass the ''same origin'' check for any document.|
| ~UniversalBrowserWrite|Allows modification of privileged data in a browser. This allows the script to pass the same origin check for any document.|
| ~UniversalBrowserAccess|Allows both reading and modification of privileged data from the browser. This allows the script to pass the same origin check for any document.|
| ~UniversalFileRead|Allows a script to read any files stored on hard disks or other storage media connected to your computer.|
| ~UniversalPreferencesRead|Allows the script to read preferences using the navigator.preference method.|
| ~UniversalPreferencesWrite|Allows the script to set preferences using the navigator.preference method.|
| ~UniversalSendMail|Allows the program to send mail in the user's name.|
To programmatically request a privilege, you will typically use code like this:
{{{
if (typeof(netscape)!="undefined") { /* note: this check prevents errors in Internet Explorer */
	try { netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); }
	catch (e) { alert(e.description||e.toString()); }
}
}}}
>Note: you can request several privileges in a single function call by specifying them using a space-separated text string, e.g., {{{enablePrivilege("UniversalBrowserRead UniversalBrowserWrite")}}}
__Browser features requiring expanded privileges__
<<<
*Setting a file upload widget (~UniversalFileRead)
*Submitting a form to a mailto: or news: URL (~UniversalSendMail)
*Using an about: URL (other than about:blank or about:config) (~UniversalBrowserRead)
<<<
__Object properties requiring expanded privileges__
<<<
*event object
**Setting any property (~UniversalBrowserWrite)
*~DragDrop event
**Getting the value of the data property (~UniversalBrowserRead)
*history object
**Getting the value of any property (~UniversalBrowserRead)
*navigator object
**Getting the value of a preference using the preference method (~UniversalPreferencesRead)
**Setting the value of a preference using the preference method (~UniversalPreferencesWrite)
*window object (~UniversalBrowserWrite)
**Adding or removing the directory bar, location bar, menu bar, personal bar, scroll bar, status bar, or toolbar
**Setting the innerWidth or innerHeight of a window to a size smaller than 100 x 100 or larger than the screen can accommodate
<<<
__Methods (functions) requiring expanded privileges__
<<<
*window.enableExternalCapture()
**capture events in pages loaded from different servers. Follow this method with window.captureEvents().
*window.close()
**unconditionally close a browser window
*window.moveBy() or window.moveTo()
**move a window off the screen.
*window.resizeTo() or window.resizeBy()
**set a window smaller than 100 x 100 pixels or larger than the screen can accommodate.
*window.open()
**create a window smaller than 100 x 100 pixels or larger than the screen can accommodate by using innerWidth, innerHeight, outerWidth, and outerHeight
**place a window off screen by using screenX and screenY
**create a window without a titlebar by using titlebar.<br>To use alwaysRaised, alwaysLowered, or z-lock for any setting
<<<
}}}
/%
|Description|Creating tiddlers from HTML forms|
%/
{{small{
__Create tiddlers using custom-built HTML forms__

The following HTML demonstrates a technique for using an HTML form, rendered in a tiddler, to input and create tiddlers with custom-formatted content
!!!!Example HTML
{{{
<html><hide linebreaks><!-- see HTMLFormattingPlugin --><form action="javascript:;"
	onsubmit="
		/* validate new title */
		var t=this.title.value;
		if (!t.length || t==this.title.defaultValue)
			{ alert('A title is required'); this.title.focus(); return false; }
		if (store.tiddlerExists(t) && !confirm(config.messages.overwriteWarning.format([t])))
			{ this.title.focus(); return false; }
		/* extract field values and construct new tiddler text */
		var txt='|%0|%1|\n%2'.format([this.field1.value,this.field2.value,this.field3.value]);
		/* extract and parse space-separated, bracketed tags into array of strings */
		var tags=this.tagsfield.value.readBracketedList();
		/* create and show new tiddler */
		store.saveTiddler(t,t,txt, config.options.txtUserName, new Date(), tags, {});
		story.displayTiddler(story.findContainingTiddler(this),t);
		return false;">
Title <input name="title" value="enter a title" onfocus="this.select()">
Field1 <input name="field1" value="field1 value" onfocus="this.select()">
Field2 <input name="field2" value="field2 value" onfocus="this.select()"><br>
<textarea name="field3" rows=5 style="width:100%;">field3 value goes here</textarea><br>
<input name="tagsfield" value="space-separated tags go here" style="width:100%;"><br>
<input type="submit" value="create tiddler">
</form></html>
}}}
!!!!Try it:
{{smallform{
<html><hide linebreaks><!-- see HTMLFormattingPlugin --><form action="javascript:;"
	onsubmit="
		/* validate new title */
		var t=this.title.value;
		if (!t.length || t==this.title.defaultValue)
			{ alert('A title is required'); this.title.focus(); return false; }
		if (store.tiddlerExists(t) && !confirm(config.messages.overwriteWarning.format([t])))
			{ this.title.focus(); return false; }
		/* extract field values and construct new tiddler text */
		var txt='|%0|%1|\n%2'.format([this.field1.value,this.field2.value,this.field3.value]);
		/* extract and parse space-separated, bracketed tags into array of strings */
		var tags=this.tagsfield.value.readBracketedList();
		/* create and show new tiddler */
		store.saveTiddler(t,t,txt, config.options.txtUserName, new Date(), tags, {});
		story.displayTiddler(story.findContainingTiddler(this),t);
		return false;">
Title <input name="title" value="enter a title" onfocus="this.select()">
Field1 <input name="field1" value="field1 value" onfocus="this.select()">
Field2 <input name="field2" value="field2 value" onfocus="this.select()"><br>
<textarea name="field3" rows=5 style="width:100%;">field3 value goes here</textarea><br>
<input name="tagsfield" value="space-separated tags go here" style="width:100%;"><br>
<input type="submit" value="create tiddler">
</form></html>
}}}
}}}
/%
|Description|Is there a "Developer's Guide to TiddlyWiki?"|
%/
{{small{
__Is there a "Developer's Guide to TiddlyWiki?"__

As you might imagine, once you get past the basics of TiddlyWiki, there is SO much more that you can do when you write your own javascript code.  However, because TiddlyWiki has been evolving so quickly and in such great leaps, the developer documentation has been lagging behind the development of core API functions and plugin coding methodologies.

Unfortunately, there *currently* isn't really any official "developer's guide".  Mostly, people have been digging through other people's code to learn how it's done.  Picking which bit of code to start with is an important question.  Start with a simple macro whose use and purpose you understand.... then, climb inside the code... if the plugin writer has well-written code (or at least well-documented via embedded comments), you should be able to figure out what they've done.

That having been said, there are several bits and pieces that have been put together by various individuals that might offer some help getting started:
* http://bradleymeck.tiddlyspot.com/#HelloWorld
* http://doc.tiddlywiki.org/#CoreFunction%20%5B%5BTiddlyWiki%20API%20Doc%20Thoughts%5D%5D
* http://tiddlywikiguides.org/
* http://mptw2.tiddlyspot.com/#HijackingHowto

In addition, I am working on a new book: "TiddlyTech: An Author's Guide to TiddlyWiki", which I hope to have in 'real-world' print later this year.  In the interim, I will be periodically posting short FAQ/HowTo articles on TiddlyTools, and will probably release the initial chapters for review and comment before finalizing their content for printing.
}}}
/%
|Description|Reduce working memory usage in FireFox|
%/
{{small{
__Use FireFox config setting to reduce working memory when browser is minimized__

To reduce memory usage by Firefox, try this:
# Type 'about:config' in Firefox address bar and press Enter.
# Right click in the page and select 'New > Boolean'.
# Type 'config.trim_on_minimize' in the box that pops up. Press Enter.
# Select 'True' and then press Enter.
# Restart Firefox.

What this does is cause FireFox to automatically its reduce working memory whenever the  browser window is minimized.  I tested this under FF2002 on WinXPSP2 using a local copy of TiddlyTools, and the browser's memory usage (as shown by the Task Manager "Processes" tab) went from around 38Mb down to around 5Mb, just by minimizing the window!!  

In addition, not only does this setting dramatically reduce the memory used by FireFox while it is minimized, but after you restore the browser window, it appears that FireFox continues to use significantly less memory than before (though more than when minimized).  I've also noticed that FireFox seems to run a bit quicker after a minimize/restore, especially if it has been running all day with an actively edited TW document. 

These side-effects are most likely the result of some *global* garbage collection process that is apparently being performed to reclaim wasted memory space each time the window is minimized.  

Original source of this 'tweak':
http://www.cypherhackz.net/archives/2006/11/20/reduce-firefox-memory-usage-when-minimize/
}}}
/%
|Description|Display a tiddler in a floating, moveable, sizeable panel|
%/
{{small{
__Display a tiddler in a floating, moveable, sizeable panel__

Using a combination of NestedSlidersPlugin and MoveablePanelPlugin, you can quickly turn any tiddler into a floating panel that can be moved/sized/folded/maximized in response to simple mouse actions (drag, shift-drag, double-click) and/or menu commands.

!!!!! example
{{{
syntax:
+++^width^[label]
	<<moveablePanel>>TiddlerTitle
----
	<<tiddler TiddlerTitle>>
===
}}}
+++^30em^[click here to see SiteURL in a floating panel]
	<<moveablePanel>>SiteURL
----
	This is the site URL:

	<<tiddler SiteUrl>>
===
{{{
+++^30em^[click here to see SiteURL in a floating panel]
	<<moveablePanel>>SiteURL
----
	This is the site URL:

	<<tiddler SiteUrl>>
===
}}}
*the {{{^width^}}} portion of the slider syntax declares the start of a "floating slider" panel, where //width// is any valid CSS measurement (e.g., "30em", "200px", "60%", "3in", etc.).  Use ^auto^, {{{^^}}}, or just {{{^}}} to allow the panel to resize as needed to fit the contents.
>{{fine{hint: if you use 'auto' sizing, the panel width can change unexpectedly due to the 'float:right' properties of the moveable panel dynamic menus.  To bypass this behavior, always specify a fixed panel size when including the {{{<<moveablePanel>>}}} macro}}}
*The {{{<<moveablePanel>>}}} macro adds move/size functions (mouse actions and menus) to the floating slider panel, and should be the first item in the slider panel contents, immediately following the "start slider" syntax.
>{{fine{hint: you can follow the {{{<<moveablePanel>>}}} macro with some "title text" for the panel and then a horizontal line (----) to create a "titlebar" appearance for the panel.  When appropriate, this panel "title" should include a link to the tiddler containing the source for the panel content, so that the reader can easily view that content using a standard tiddler display.}}}
*Use the {{{<<tiddler TiddlerName>>}}} macro to insert contents from another tiddler.  You can put //any// tiddler content you want inside a floating panel: e.g. ''add formatting or other content //surrounding// the included tiddler'', or just ''enter content directly, without including another tiddler'' at all...
}}}
/%
|Description|TiddlyWiki documents don't pass W3C HTML validation|
%/
{{small{
__TiddlyWiki documents don't pass W3C HTML validation__

When your browser requests a page from a webserver (or file system if "file://..." is used), the source HTML delivered back to your browser is a simple block of //human-readable text//.  The browser then parses the HTML syntax in this text and uses it like a recipe to generate the DOM (Document Object Model) *data* elements that correspond to the HTML syntax and then uses the DOM elements to actually render the visible portion of the web page on your screen.

However, unlike a typical web page which just contains 'static HTML' stored as text, most of the ''content in a ~TiddlyWiki document is kept as tiddler //data// in a hidden "store area"'' which has to be processed by the ~TiddlyWiki core programming before it can be rendered by the browser.

''~TiddlyWiki does NOT generate HTML'' from this tiddler data.  Instead, it bypasses the browser's normal HTML parser and, using it's own "wikify()" parser, converts tiddler source content directly into the DOM data elements that the browser uses to render the page.

As a result of this processing, most HTML validators aren't very useful or informative for analyzing ~TiddlyWiki documents, since they typically only examine the statically-defined source content of the document, without actually running any javascript processing.  Since ~TiddlyWiki doesn't contain much actual HTML in its source file, there's simply not much for an HTML validator to sink it's teeth into.
}}}
/%
|Description|Improving TiddlyWiki processing speed when editing/saving tiddler changes|
%/
{{small{
__Improving TiddlyWiki processing speed when editing/saving tiddler changes__

The performance of the TiddlyTools plugins depends on several factors: the performance of your overall system, which is affected by the CPU speed, amount of RAM, disk access rates,  etc. and, even more important: which browser you are using.  Internet Explorer is significantly slower than other browsers at processing certain pieces of javascript code.  Except for 'animation' effects, FireFox seems to be consistently faster than IE, and often produces a very noticeable improvement in response time for many activities.

However, if your document is performing "too slow" even with FireFox running on a fast system, you can also try eliminating some of the plugins that are installed in your document to see what effect that has.  Look for plugins that 'hijack' the saveTiddler() function, since that adds overhead each time you press "done" after editing a tiddler.

There are, of course, many other reasons that various TiddlyWiki actions can take a long time finish, such as slow upload/download speeds, browser "memory leaks", and even the occasional programming bug //(gasp! "... say it ain't so, Joe!")//.
}}}
/%
|Description|Installing Plugins: some suggested 'best practices'|
%/
{{small{
__Installing Plugins: some suggested 'best practices'__

Most plugins are actively maintained and many are updated fairly often with bug fixes, performance improvements, new features, etc.  I get *lots* of feedback every day from users of my TiddlyTools plugins, with ideas for new features, requests for help, bug reports, and even "fan mail" (I love getting those... about 3-5 per week!... feels really nice... send more!!! :-)

Of course, once someone has installed some of my plugins in their document, they typically start building their content around those features, so that correctly processing the tiddler content now depends upon that specific set of plugins.  Obviously, if you copy an *entire* TW document from somewhere else, you should use the plugins it contains, as installed by that document's author, so that you are assured that everything in THAT document will work together properly.

However... if you are copying just a few plugins to incorporate into *your own* document, then you probably should TRY using the newest version of a plugin, whenever possible.  By convention, most plugin authors include a "Revisions" section that describes the important changes that have occurred in the plugin, and assign a "revision number" to each of those sets of changes.

When you copy a plugin from another document, you should always check to see if there any notes in the tiddler content indicating it has been *modified* for use in that specific document.  If so, you might not want to use that copy of the plugin, since it could produce output or interactions that differ greatly from the offical version.  This could make your tiddler content less "shareable" with other TW documents, because those tiddlers would be dependent upon having the altered, non-standard plugins installed.

Always check for a link back to an "official" distribution source URL. Go there and check the plugin documentation to find out the current plugin revision number.  Compare that with the one you copied from the other document.  If they are not the same, you should review the revision histories to determine what has changed.  If they are the same, you are *probably* OK (though this is not assured, since an author might have modified the plugin source without documenting their changes).

Even if the revision numbers ARE different, the plugin changes may be completely backward compatible with the earlier revision, so that there would be nearly no downside to installing the latest version into your document.  Of course, sometimes a newer feature will require other changes that you might not want/need, or will make the plugin significantly larger, so you can still choose to go with the older/modified version you have already copied, IF it actually does what you need.

Lastly, once you have installed the most up-to-date revision in your document, you should avoid altering it unless absolutely necessary, so that your copy can be easily shared with others while not contributing more complexity to the whole "revision skew/custom code changes" situation.
}}}
/%
|Description|Select a local file and display it in an IFRAME embedded in a tiddler|
%/
{{small{
__Select a local file and display it in an IFRAME embedded in a tiddler__
Here's an embedded form that lets you to select and view almost any local file in an IFRAME.  It uses the browser-provided platform-specific "select a file" dialog box to fill the "whichfile" input field (which you can also type into, if you like).  A //hidden// IFRAME that follows the form has a specified name/id (use both attributes for compatibility with older browsers), which is also used as the form's //target//.  When you click the "open" button, it sets the form //action// to refer to the selected path/file (pre-pending {{{file:///}}} so it can be seen as a URL by the browser).  Then, it displays the IFRAME and triggers the form's submit() handler, causing the URL to be loaded and displayed in the target IFRAME. 

{{fine{
Notes:
* This technique only works when the form and iframe are being viewed from a local (file:) document.  If you try to open a locally-stored file while viewing a document on a remote server, you will receive a security error.
* This form may also work with file types other than "text"... it all depends upon your browser's support for those file types...
}}}
Try it now:
<html><hide linebreaks> <!-- note: extra psuedo-tag from HTMLFormattingPlugin suppresses newlines -->
	<form target="theFrameID">
	<input type=file name=whichfile>
	<input type=button value="view"
		onclick="var frame=document.getElementById(this.form.target);
			this.form.action='file:///'+this.form.whichfile.value;
			try { frame.style.display='block'; this.form.done.disabled=false; this.form.submit(); }
			catch(e) { alert(e.description?e.description:e.toString()); }">
	<input type=button name=done value="done" disabled 
		onclick="var frame=document.getElementById(this.form.target);
			frame.style.display='none'; this.disabled=true;">
	</form>
	<iframe src="" name="theFrameID" id="theFrameID"
		style="display:none;background:#fff;width:100%;height:500px">
	</iframe>
</html>
{{{
<html>
	<form target="theFrameID">
	<input type=file name=whichfile>
	<input type=button value="View"
		onclick="var frame=document.getElementById(this.form.target);
			this.form.action='file:///'+this.form.whichfile.value;
			try { frame.style.display='block'; this.form.done.disabled=false; this.form.submit(); }
			catch(e) { alert(e.description?e.description:e.toString()); }">
	<input type=button name=done value="Done" disabled 
		onclick="var frame=document.getElementById(this.form.target);
			frame.style.display='none'; this.disabled=true;">
	</form>
	<iframe src="" name="theFrameID" id="theFrameID"
		style="display:none;background:#fff;width:100%;height:500px">
	</iframe>
</html>
}}}
----
As an alternative to using a "select a file" dialog as shown above, you could simply load the IFRAME directly from a link that contains a hard-coded reference to a specific directory path and/or filename:

Try it now: <html><hide linebreaks> <!-- note: extra psuedo-tag from HTMLFormattingPlugin suppresses newlines -->
	<a href="file:///C:/"
		onclick="var f=document.getElementById('anotherFrameID');
			try { f.src=this.href; f.style.display='block'; }
			catch(e) { f.style.display='none'; alert(e.description?e.description:e.toString()); }
			return false;">view local filesystem...</a>
	<iframe src="" id="anotherFrameID"
		style="display:none;background:#fff;width:100%;height:500px"></iframe>
</html>
{{{
<html>
	<a href="file:///C:/"
		onclick="var f=document.getElementById('anotherFrameID');
			try { f.src=this.href; f.style.display='block'; }
			catch(e) { f.style.display='none'; alert(e.description?e.description:e.toString()); }
			return false;">view local filesystem...</a>
	<iframe src="" id="anotherFrameID"
		style="display:none;background:#fff;width:100%;height:500px"></iframe>
</html>
}}}
}}}
/%
|Description|Requirements for modifying TiddlyTools plugins|
%/
{{small{
__Requirements for modifying TiddlyTools plugins, scripts, templates, etc.__

Whenever you make modifications to a TiddlyTools component (plugin, scripts, stylesheet, etc. -- anything that carries a reference to the [[TiddlyTools LegalStatements|LegalStatements]] and/or the [[Creative Commons License|http://creativecommons.org/licenses/by-sa/2.5/]] terms -- you MUST make sure your alterations are: ''"clearly identified as a derivative work that is easily distinguished from the original version"''.

To achieve this, three basic steps should be taken:

*{{block{
''Rename the altered tiddler.''
This is VERY important.  It ensures that YOUR variant plugin does not get confused with the original, officially-published TiddlyTools component.  Keep in mind that, because people can import plugins from anyone's TiddlyWiki document, as soon as you share you document with just ONE other person, you become a "re-distributor" of the plugins you have installed in that document, including those that you have modified.
<br>}}}
*{{block{
''Add comments in the "Revisions" section explaining what you have done.''
As with renaming the tiddler, this helps ensure that your variant plugin is not confused with the official version.  By doing so, if someone mistakenly installed your variant and then has problems, they can at least read a summary of changes to discover what you did to the code, instead of simply reporting a problem, without giving any indication that there is variant code involved.
<br>}}}
*{{block{
''Add a comment (e.g., {{{/* ELS */}}}) on each line of modified code (or surrounding a section of added code)''. 
By adding a distinct //marker// that is easily searched for, each specific change can be quickly located, so that when (or if) someone else is attempting to debug your code changes, they won't have to spend a lot of time trying to determine what you've changed.
<br>}}}
By following these three simple steps, you can make things much easier for everyone, and vastly increase the chances that you may actually get some help with your problem.  However, while I will probably take a look at your changes, and will gladly suggest a fix if one is readily apparent, I will not take on the responsibility for debugging other people's changes to my code!  

One of the most frustrating experiences is to spend hours (or even days) trying to debug problems that have been reported about TiddlyTools plugins that were, in fact, due to unofficial variants of my code that had been has modified by others and then shared, albeit unintentionally.  

As a matter of principle, if you can //make// changes to code, you should be able to //debug// them as well... and if //you// create a variant plugin, //you// must be prepared to support it.  Otherwise, ''the best approach is often to make a "feature request" to the original plugin author, and leave it up to them to determine the best way to modify their own code.''

In fact, as a TiddlyTools general policy, ''problems with variant plugins should always be reported first to the person who modified that plugin'', and then only reported to TiddlyTools if it can be shown that the problem also occurs in TiddlyTools' officially-published version of the plugin.

In addition, in order to encourage proper differentiation of variant plugins, ''problems that are reported for //undifferentiated// variant plugins won't receive //any// help'' (once they are determined to be variants, of course!), except perhaps to direct the inquirer to seek help from wherever they got the variant plugin in the first place.

Having said all this, I want to also emphasize that you //are// permitted to make whatever code changes you need to TiddlyTools components to suit your specific purposes... and you are also allowed to share those altered plugins with others, ''as long as they are clearly differentiated from the originals'', as described above.  Of course, if some particular changes have a wider application than just your specific use-case, you are always welcome to ''submit your modifications back to TiddlyTools'' for possible inclusion in an official update.
/%
|Description|Override cookie-based option settings with 'hard-coded' values|
%/
{{small{
__Override cookie-based option settings with 'hard-coded' values__

You can override //any// cookie-based config.option.* setting by ''hard-coding'' the desired value into a systemConfig tiddler (i.e., a plugin).

For example, suppose you prefer to set EnableAnimations to false by default, so that the first time your readers visit your document, they won't have to disable it themselves... all you need to do is to create a tiddler containing the following line of javascript:
{{{
config.options.chkAnimate=false;
}}}
then, tag that tiddler with<<tag systemConfig>>to make it a plugin... the javascript it contains will be invoked //after// you save and reload the document.  At "load-time", option values are initialized in this order:
<<<
# hard-coded values in the TiddlyWiki core code.
# values from cookies (read from the browser)
# values set by plugins
<<<
Because plugins are executed last, any values they set supercede the values loaded from the browser's cookies or set by the core code.
>{{fine{note: plugins are executed in //alphanumeric// order (based on tiddler title).  Most of the time this does not cause any problems.  However, if a plugin references an option value during it's load-time initialization, you will need to make sure that the tiddler containing the overridden cookie values is executed //first// by giving it a tiddler title that is sorted ahead of the dependent plugin's title.}}}
example: ConfigTweaks
}}}
/%
|Description|Printing tiddler content formatted to fit 3x5 index cards|
%/
{{small{
__Printing tiddler content formatted to fit 3x5 index cards__

To print tiddler content in a format that fits on 3x5 index card stock generally requires a specialized set of PageTemplate and ViewTemplate definitions, combined with CSS stylesheet definitions for printed media (see StyleSheetPrint), that are all optimized for the 3x5 presentation format.

The most active interest in printing to 3x5 cards has been from people who are using David Allen's "GTD" (Getting Things Done) method of time management.  There is a thriving community of TiddlyWiki-based GTD-ers (see http://groups.google.com/group/GTD-TiddlyWiki) who are using TiddlyWiki documents that have been (such as the popular MonkeyGTD and d-Cubed (d^^3^^) varieties, both of which can be found at http://www.TiddlySpot.com)

Even for non-GTD use, the 3x5 card format could be very helpful, inasmuch as the "cards in a box" metaphor maps very well to explain the basic idea of tiddlers contained in a TiddlyWiki document (and especially for those people who are not familiar with the wiki concept or are not frequent computer users).

Currently, TiddlyTools does not currently offer a 3x5 display/print "theme"... but check back soon for the new IndexCards stylesheet/template theme.
}}}
/%
|Description|Reposition slider panels within a tiddler|
%/
{{small{
__Reposition slider panels within a tiddler__

When you select a slider button, everything following that slider button is 'pushed down' the page so that the corresponding slider panel can be displayed.  However, when several slider buttons are on the same line (e.g. to create a horizontal 'menubar'), opening one of these sliders 'splits' the menubar, so that any menu items following the open slider are pushed down below that slider.

To preserve the single-row layout of slider buttons, you can use the {{{#panelID:}}} syntax of NestedSlidersPlugin to ''set a specific element ID for each slider panel'', and then ''move the identified elements'' using the {{{<<DOM move id>>}}} macro (see DOMTweaksPlugin), so that all panels //follow// the slider buttons, instead of being placed //in-between// them.
!!!!! example
without stacking:
+++[label1]
	stuff1
===
+++[label2]
	stuff2
===
+++[label3]
	stuff3
===
+++[label4]
	stuff4
===
{{{
+++[label1]
	stuff1
===
+++[label2]
	stuff2
===
+++[label3]
	stuff3
===
+++[label4]
	stuff4
===
}}}
----
with stacking:
+++[label1]#panel1:
	stuff1
===
+++[label2]#panel2:
	stuff2
===
+++[label3]#panel3:
	stuff3
===
+++[label4]#panel4:
	stuff4
===
<<DOM move panel1>><<DOM move panel2>><<DOM move panel3>><<DOM move panel4>>
{{{
+++[label1]#panel1:
	stuff1
===
+++[label2]#panel2:
	stuff2
===
+++[label3]#panel3:
	stuff3
===
+++[label4]#panel4:
	stuff4
===
<<DOM move panel1>><<DOM move panel2>><<DOM move panel3>><<DOM move panel4>>
}}}
}}}
/%
|Description|Reposition tag display below the tiddler content|
%/
{{small{
__How to move the tiddler tag display so that tags appear below the tiddler content__

You can move a tiddler's tag display so that the tags appear in a line below the tiddler rather than as a list that 'floats' along the right side of the tiddler content.

In ViewTemplate, move this line:
{{{
   <div class='tagged' macro='tags'></div>
}}}
so that occurs just before this line:
{{{
   <div class='tagClear'></div>
}}}
in StyleSheet, add the following CSS to override the default appearance of the .tagged class (defined in StyleSheetLayout):
{{{
   .tagged { float:left !important; }
   .tagged li { display:inline; }
}}}
The first line makes the tag display appear left-aligned with the tiddler content.  The second line eliminates the 'newlines' between tag values, so that they all appear on a single line instead of one-per-line (note: if you have a LOT of tags, they may still wrap onto additional lines if the line gets wider than the tiddler display area).  You may also want to change or eliminate the background for the .tagged area:
{{{
   .tagged { background:transparent !important; border:0 !important; }
}}}
}}}
/%
|Description|Saving changes for online documents if the network goes down|
%/
{{small{
__Saving changes to online documents if your network connection goes down while editing__

If you have been editing a document online (e.g., using an account on http://www.TiddlySpot.com with [[UploadPlugin]]), and your internet connection has gone down while editing, it is not possible to save your changes in the usual manner because, without the internet, the remotely-stored document is //inaccessible//.

Unfortunately, you also cannot save the document locally because of security restrictions that prevent access to your local filesystem when working with a server-hosted document (i.e., viewed via http:).

Fortunately, there is a ''manual work-around that will let you 'rescue' TiddlyWiki's internal //storeArea// for the current document, including your unsaved changes to tiddler content'' by using the following command link:

{{big center{<<tiddler RescueStoreAreaCommand with: "rescue storeArea">>}}}
When clicked, this link ''opens a new window and writes a copy of the storeArea into that window.''  The content in that window is displayed as plain-text, and includes //only the storeArea DIVs that define the tiddlers, without any of the surrounding TiddlyWiki core code.//  To preserve this storeArea, ''select and copy/paste the displayed content into a local text file for safe-keeping.''

Then, to merge this 'rescued store area' with the rest of the TW core, use a plain-text editor (not the browser) to open a ''copy'' of any locally-stored TW document.  If a locally-stored TiddlyWiki document is not available, you will have to wait until your network connection has been re-established, so that you can download your TiddlyWiki document from the server, or [[obtain an empty TiddlyWiki document from http://www.TiddlyWiki.com|http://www.TiddlyWiki.com/empty.html]].

Then, find the 'storeArea' in that document, which looks like this:
{{{
<!--POST-SHADOWAREA-->
<div id="storeArea">
.... *** replace this part *** ...
</div>
<!--POST-STOREAREA-->
}}}
Select everything //inside the storeArea DIV//, and replace it with the rescued store area content, and then save the file.  If all goes well, the saved file can then be opened in your browser as a complete TW document, *with* all the saved content in place!

Note: The command link shown above may also be installed directly into your browser as an [[InstantBookmarklet|InstantBookmarklets]]. To create a bookmarklet, simply ''//drag-and-drop the command link directly onto your browser's toolbar//'' or right-click and use 'bookmark this link' (or 'add to favorites') to add the bookmarklet to your browser's bookmarks menu.  Once installed, you can use this command with //any// TiddlyWiki document, even when [[RescueStoreAreaCommand]] and [[InlineJavascriptPlugin]] have not been installed in that document!
}}}
/%
|Description|Inline scripts and plugins: some basic differences|
%/
{{small{
__A brief summary of some of the differences between "inline scripts" and "plugins":__

!!!!Standard TiddlyWiki feature vs. plugin-supported feature
* Plugins are a TiddlyWiki ''core-supported feature''
* Inline scripts depend upon http://www.TiddlyTools.com/#InlineJavascriptPlugin, a plugin that must be present in your document for the {{{<script>...</script>}}} syntax to be recognized.
!!!!Code-only vs. mixed code-and-content
* Plugins are ''special tiddlers, tagged with <<tag systemConfig>>, that contain ONLY "pure" javascript'' code.  Any wiki syntax they contains must be wrapped inside a javascript comment block.
* Scripts are ''regular tiddlers that can contain a mix of wiki syntax PLUS javascript code'', embedded "inline", in between {{{<script>...</script>}}} markers.
!!!!Run at startup vs. run when rendered
* Plugins are tagged with "systemConfig", which tells TW to run them ''each time the document is loaded (or reloaded) into your browser'', which can add significant overhead to the document's startup time.  Once the document is loaded, //displaying// a plugin tiddler does //not// run its code again.  Installing a new plugin (or changing the code definition in an existing plugin) requires that you save-and-reload the document for the changes to take effect.
* Scripts are ''run each time the tiddler in which they are embedded is rendered.''  However, scripts are //not// run until the tiddler that contains them is rendered, and so do //not// add to the document's startup time.  Newly installed or modified scripts can be invoked immediately, without saving and reloading the document.
!!!!Macro and function //definitions// vs. dynamically-generated //output//
* Plugins typically ''install macro definitions or other internal functions'' that are then triggered later on, often by rendering another tiddler that uses the plugin-defined macro, or as a side-effect of performing some other activity.
* Scripts are typically used to ''generate and return wiki-syntax output'' that then is immediately rendered to insert dynamic content into the tiddler display.
!!!!Other features of inline scripts
* Scripts can also ''make small 'on-the-'fly' adjustments to the attributes of rendered elements'' contained within the same tiddler using the specially-defined 'place' variable for //relative DOM references// (e.g., place.lastChild, place.parentNode, etc.)
* Scripts can also be used to ''create "onclick" command links to invoke javascript code'' in response to a user action (i.e., clicking on the link text).
* "Onclick" scripts can also be used to create "[[instant bookmarklets|InstantBookmarklets]]" (small pieces of javascript that can be ''invoked directly from your browser's toolbar or bookmarket menu''.  Once installed in your browser, the bookmarklet can be invoked for //any// TiddlyWiki document, even if InlineJavascriptPlugin is not installed in that document!

}}}
/%
|Description|Online TiddlyWiki documents appear blank and/or report server-side PHP errors|
%/
{{small{
__Problem: Online TiddlyWiki documents (on some servers) appear blank and/or report server-sde PHP errors__

The TW wikify() parser matches the {{{[<img[...]]}}} syntax by using a regular expression pattern that contains this specific character sequence: <?. Unfortunately, the presence of the <? sequence is also used to mark the beginning of embedded PHP syntax.

Normally, this isn't a problem, since most servers that pre-process embedded PHP only do so for files with specific filename extensions (e.g., ".php").  However, your web server seems to be configured to pre-process embedded PHP in *all* file types, including ".html".  Of course, files containing pure HTML are just passed through the server-side processing unchanged.  But, since the TW core just happens to use that same sequence, it is getting stuck in the server-side PHP pre-processor, which spits out an error instead of the unchanged .html file.

Assuming you are on an Apache-based system and you are allowed to use directory-level configuration directives, then you might try adding the following in an .htaccess file that you should put in the directory containing your TW documents:
{{{
SetHandler none
}}}
This //should// disable the default PHP pre-processing for all files in that directory.  However, if this doesn't work, or causes a "server error" page to appear when you try to access your documents, then you probably don't have the permissions to use the {{{SetHandler}}} directive or {{{.htaccess}}} files.  In that case, you will probably have to request your system admin to make a change in the overall server configuration.
}}}
/%
|Description|Add ToggleLeftSidebar/ToggleRightSidebar to a fixed-position "StoryMenu"|
%/
__How to add ToggleLeftSidebar/ToggleRightSidebar to a fixed-position "StoryMenu"__

{{small{
First, you will need to create a fixed-location page element that will always be displayed at the top of the "story column" (which is where the open tiddlers are rendered).  Let's call that fixed element the "story menu"...

# {{block{From the sidebar, open the more>shadowed tab.  A list of built-in default definitions (called "shadow tiddlers") is displayed. Click on [[PageTemplate]] to open and then edit that tiddler.

}}}
# {{block{Find this part of the template definition:
{{{
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
}}}
and change it to:
{{{
<div id='displayArea'>
<div id='messageArea'></div>
<div id='storyMenu' refresh='content' tiddler='StoryMenu'></div>
<div id='tiddlerDisplay'></div>
</div>
}}}
Press 'done' to create a "real" [[PageTemplate]] tiddler that overrides the default "shadow" [[PageTemplate]] tiddler.  If you subsequently delete (or rename) this tiddler, the default shadow definition will be re-applied (i.e., it 'emerges from the shadows'... hence the name)

}}}
# {{block{Next, create a new tiddler called [[StoryMenu]], whose contents will be automatically rendered into the 'storyMenu' element you just added to the customized [[PageTemplate]].  Enter the following into the [[StoryMenu]] definition, all on one line, (without any newlines):
{{{
{{floatleft{<<tiddler ToggleLeftSidebar>>}}}{{floatright{<<tiddler ToggleRightSidebar>>}}}
}}}
The """<<tiddler>>""" macro is used to render the content from those other tiddlers into the [[StoryMenu]] tiddler (this is called 'transclusion').  Press 'done'.  The [[ToggleLeftSidebar]] and [[ToggleRightSidebar]] arrows will then appear in the story column.

}}}
# {{block{The """{{floatleft{...}}}""" and """{{floatright{...}}}""" syntax is used to apply custom  'CSS class wrappers' to the transcluded content, so the arrows will be suitably positioned at the margins of the [[StoryMenu]] display. To declare these custom CSS classnames, create/edit a tiddler called [[StyleSheet]], and enter the following:
{{{
.floatleft { float:left; }
.floatright { float:right; }
}}}
and press 'done' to apply the [[StyleSheet]] definitions. Note: these CSS classnames are also defined as part of a set of 'formatting shortcuts' contained in [[StyleSheetShortcuts]].  To include //all// of these shortcuts in your [[StyleSheet]], simply enter:
{{{
[[StyleSheetShortcuts]]
}}}
into your [[StyleSheet]] tiddler and press 'done' to apply those definitions.

}}}
/%
|Description|How to use a checkbox to toggle between two tag values|
%/
{{small{
__How to use a checkbox to toggle between two tag values__

''//PJO asks: I would like to tag new (user created) tiddlers with either of two mutually exclusive tags, ideally via a drop down list with two values, or with one and a check box. In effect: a two state radio button.  Not, "Tag" or "", but "Tag1" or "Tag2".  Any suggestions on the best / easiest way to do this?//''

Normally, a checkbox created by [[CheckboxPlugin]] adds a tag when checked, and removes the tag when cleared.  In contrast, a checkbox created using the [[CheckboxToggleTag]] inline script can //toggle between two different tags//, one tag value for when it is checked, and another tag value for when it is cleared.  This tiddler uses """$1""" and """$2""" 'substitution parameters' to designate the desired tags to use, so it can be quickly and easily 'transcluded' into other tiddler content via the {{{<<tiddler>>}}} macro, like this:
><<tiddler CheckboxToggleTag with: ON OFF>> toggle on/off
{{{
<<tiddler CheckboxToggleTag with: ON OFF>> toggle on/off
}}}
where //ON// is the tag to use when the checkbox is set, and //OFF// is the tag to use when the checkbox is cleared.

Also, to display this checkbox in //every// tiddler, you could add the following to the [[ViewTemplate]]:
{{{
<span macro='tiddler CheckboxToggleTag with: ON OFF'></span><span>toggle on/off</span>
}}}
}}}
/%
|Description|Using images to create custom bullet items|
%/
{{small{
__Using images to create custom bullet items__

Suppose you want to have your own bullet points using small graphic images instead of the standard bullets, and you also want to be able to use a different image for each individual bullet item.

Using a combination of [[InlineJavascriptPlugin]] and [[AliasPlugin]] you can write the following to define macros that set the individual custom bullet styles:
{{{
<<alias b_smiley "<script>place.style.listStyleImage='url(images/silk/icons/emoticon_smile.png)';</script>">>
<<alias b_frowny "<script>place.style.listStyleImage='url(images/silk/icons/emoticon_unhappy.png)';</script>">>
<<alias b_winky "<script>place.style.listStyleImage='url(images/silk/icons/emoticon_wink.png)';</script>">>
<<alias b_dopey "<script>place.style.listStyleImage='url(images/silk/icons/emoticon_tongue.png)';</script>">>
<<alias b_normal "<script>place.style.listStyleImage='none !important';</script>">>
}}}
Then, you can use these macros within your bullet items, like this:
{{{
*plain bullet
**nested plain bullet
**<<b_smiley>>nested bullet using smiley
***nested bullet using smiley by default
**nested plain bullet
*<<b_smiley>>bullet using smiley
**nested bullet using smiley by default
*<<b_frowny>>bullet using frowny
**<<b_winky>>nested bullet using winky
**<<b_normal>>nested plain bullet
**nested bullet using frowny by default
*<<b_winky>>bullet using winky
*<<b_dopey>>bullet using dopey
}}}
Which looks like this when rendered:
<<alias b_smiley "<script>place.style.listStyleImage='url(images/silk/icons/emoticon_smile.png)';</script>">>/%
%/<<alias b_frowny "<script>place.style.listStyleImage='url(images/silk/icons/emoticon_unhappy.png)';</script>">>/%
%/<<alias b_winky "<script>place.style.listStyleImage='url(images/silk/icons/emoticon_wink.png)';</script>">>/%
%/<<alias b_dopey "<script>place.style.listStyleImage='url(images/silk/icons/emoticon_tongue.png)';</script>">>/%
%/<<alias b_normal "<script>place.style.listStyleImage='none !important';</script>">>
*plain bullet
**nested plain bullet
**<<b_smiley>>nested bullet using smiley
***nested bullet using smiley by default
**nested plain bullet
*<<b_smiley>>bullet using smiley
**nested bullet using smiley by default
*<<b_frowny>>bullet using frowny
**<<b_winky>>nested bullet using winky
**<<b_normal>>nested plain bullet
**nested bullet using frowny by default
*<<b_winky>>bullet using winky
*<<b_dopey>>bullet using dopey
}}}
/***
|FileDropPlugin|h
|author : BradleyMeck|
|version : 0.1.1|
|date : Nov 13 2006|
|usage : drag a file onto the TW to have it be made into a tiddler|
|browser(s) supported : Mozilla|

Note: this version has been 'tweaked' by Eric Shulman (http://www.TiddlyTools.com) to add suspend/resume notification handling to improve performance when multiple files are dropped at once.

!Trouble Shooting
*If the plugin does not seem to work, open up the page "about:config" (just type it in the address bar) and make sure @@color(blue):signed.applets.codebase_principal_support@@ is set to @@color(blue):true@@

!Revisions
*Multiple File Dropping API updated, to end all capturing events after yours return a value that makes if(myFunctionsReturnValue) evaluate to true
*Added support for multiple file drop handlers
**Use the config.macros.fileDrop.addEventListener(@@color(green):String Flavor@@, @@color(green):Function handler(nsiFile){}@@, @@color(green):Boolean addToFront@@) function
***Standard Flavor is "application/x-moz-file"
***addToFront gives your handler priority over all others at time of add
*Old plugin would disallow drops of text vetween applications because it didn't check if the transfer was a file.

!Example Handler
*Adds simple file import control, add this to a tiddler tagged {{{systemConfig}}} to make file dropping work
{{{
config.macros.fileDrop.addEventListener("application/x-moz-file",function(nsiFile)
{
 if(
    confirm("You have dropped the file \""+nsiFile.path+"\" onto the page, it will be imported as a tiddler. Is that ok?")
    )
 {
 var newDate = new Date();
 var title = prompt("what would you like to name the tiddler?");
 store.saveTiddler(title,title,loadFile(nsiFile.path),config.options.txtUserName,newDate,[]);
 }
 return true;
})
}}}

!Example Handler without popups and opening the tiddler on load
*Adds simple file import control, add this to a tiddler tagged {{{systemConfig}}} to make file dropping work
{{{
config.macros.fileDrop.addEventListener("application/x-moz-file",function(nsiFile)
{
 var newDate = new Date();
 store.saveTiddler(nsiFile.path,nsiFile.path,loadFile(nsiFile.path),config.options.txtUserName,newDate,[]);
 story.displayTiddler(null,nsiFile.path)
 return true;
})
}}}
!Code
***/

//{{{
config.macros.fileDrop = {version : {major : 0, minor : 0, revision: 1}};
config.macros.fileDrop.customDropHandlers = [];

config.macros.fileDrop.dragDropHandler = function(evt) {

 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 // Load in the native DragService manager from the browser.
 var dragService = Components.classes["@mozilla.org/widget/dragservice;1"].getService(Components.interfaces.nsIDragService);

 // Load in the currently-executing Drag/drop session.
 var dragSession = dragService.getCurrentSession();

 // Create an instance of an nsITransferable object using reflection.
 var transferObject = Components.classes["@mozilla.org/widget/transferable;1"].createInstance();

 // Bind the object explicitly to the nsITransferable interface. We need to do this to ensure that
 // methods and properties are present and work as expected later on.
 transferObject = transferObject.QueryInterface(Components.interfaces.nsITransferable);

 // I've chosen to add only the x-moz-file MIME type. Any type can be added, and the data for that format
 // will be retrieved from the Drag/drop service.
 transferObject.addDataFlavor("application/x-moz-file");

 // Get the number of items currently being dropped in this drag/drop operation.
 var numItems = dragSession.numDropItems;
// ELS 2007.12.03: performance improvement when dropping multiple files
if (numItems>1) {
	clearMessage();
	displayMessage("Reading "+numItems+" files...");
	store.suspendNotifications();
}
 for (var i = 0; i < numItems; i++)
 {
 // Get the data for the given drag item from the drag session into our prepared
 // Transfer object.
 dragSession.getData(transferObject, i);

 // We need to pass in Javascript 'Object's to any XPConnect method which
 // requires OUT parameters. The out value will then be saved as a new
 // property called Object.value.
 var dataObj = {};
 var dropSizeObj = {};

for(var ind = 0; ind < config.macros.fileDrop.customDropHandlers.length; ind++)
{
  var item = config.macros.fileDrop.customDropHandlers[ind];
  if(dragSession.isDataFlavorSupported(item.flavor))
  {
    transferObject.getTransferData(item.flavor, dataObj, dropSizeObj);
    var droppedFile = dataObj.value.QueryInterface(Components.interfaces.nsIFile);
    // Display all of the returned parameters with an Alert dialog.
    var result = item.handler.call(item,droppedFile);
 // Since the event is handled, prevent it from going to a higher-level event handler.
	 evt.stopPropagation();
	 evt.preventDefault();
    if(result){break;}
  }
}
 }
// ELS 2007.12.03: performance improvement and feedback after dropping multiple files
if (numItems>1) {
	store.resumeNotifications();
	store.notifyAll();
	displayMessage(numItems+" files have been processed");
}
}

if(!window.event)
{
 // Register the event handler, and set the 'capture' flag to true so we get this event
 // before it bubbles up through the browser.
 window.addEventListener("dragdrop", config.macros.fileDrop.dragDropHandler , true);
}

config.macros.fileDrop.addEventListener = function(paramflavor,func,inFront)
{
var obj = {};
obj.flavor = paramflavor;
obj.handler = func;
if(!inFront)
{config.macros.fileDrop.customDropHandlers.push(obj);}
else{config.macros.fileDrop.customDropHandlers.shift(obj);}
}
//}}}
/***
|Name|FileDropPluginConfig|
|Source|http://www.TiddlyTools.com/#FileDropPluginConfig|
|Version|1.5.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|FileDropPlugin, AttachFilePlugin|
|Overrides||
|Options|##Configuration|
|Description|Adds drag-and-drop handlers for creating binary attachments or directory lists|

__TiddlyTools FileDrop+AttachFile extended handler:__
* use just filename instead of whole path as tiddler title
* check for existing tiddler and prompt for new name
* handle folder drops (drops each file or creates a file list in a tiddler)
* use AttachFilePlugin if MIME type is not text/plain
* autotag created tiddlers (e.g., "temporary", "dropped", etc.)
* option to suppress automatic display of newly created tiddlers
* suspend/resume notifications when handling multiple files (performance improvement)
!!!!!Configuration
<<<
<<option chkFileDropTrimFilename>> Omit file extensions from tiddler titles when creating new tiddlers
&nbsp;&nbsp;{{{usage: <<option chkFileDropTrimFilename>> }}}
<<option chkFileDropDisplay>> Automatically display newly created tiddlers
&nbsp;&nbsp;{{{usage: <<option chkFileDropDisplay>> }}}
Tag newly created tiddlers with: <<option txtFileDropTags>>
&nbsp;&nbsp;{{{usage: <<option txtFileDropTags>>}}}

__FileDrop+AttachFile configuration options:__
<<option chkFileDropAttachEncodeData>> Encode binary file data as embedded "base64" text
&nbsp;&nbsp;{{{usage: <<option chkFileDropAttachEncodeData>> }}}
...for binary files smaller than: <<option txtFileDropAttachDataLimit>> bytes
&nbsp;&nbsp;{{{usage: <<option txtFileDropAttachDataLimit>>}}}

See [[FileDropPlugin]] for more documentation on handler implementation specifics, including sample code for default drop handlers.
<<<
!!!!!Code
***/
//{{{
if (config.options.chkFileDropAttachEncodeData==undefined)
	config.options.chkFileDropAttachEncodeData=true;
if (config.options.txtFileDropAttachDataLimit==undefined)
	config.options.txtFileDropAttachDataLimit=32768;
if (config.options.txtFileDropTags==undefined)
	config.options.txtFileDropTags="";
if (config.options.chkFileDropDisplay==undefined)
	config.options.chkFileDropDisplay=true;
if (config.options.chkFileDropTrimFilename==undefined)
	config.options.chkFileDropTrimFilename=false;

config.macros.fileDrop.addEventListener("application/x-moz-file",function(nsiFile)
{
	var header="Index of %0\n^^(as of %1)^^\n|!filename| !size | !modified |\n";
	var item="|[[%0|%1]]| %2|%3|\n";
	var footer="Total of %0 bytes in %1 files\n";

	var now=new Date();
	var files=[nsiFile];
	if (nsiFile.isDirectory()) {
		var folder=nsiFile.directoryEntries;
		var files=[];
		while (folder.hasMoreElements()) {
			var f=folder.getNext().QueryInterface(Components.interfaces.nsILocalFile);
			if (f instanceof Components.interfaces.nsILocalFile && !f.isDirectory()) files.push(f);
		}
		var msg=nsiFile.path.replace(/\\/g,"/")+"\n\n";
		msg+="contains "+files.length+" files... ";
		msg+="select OK to attach all files or CANCEL to create a list...";
		if (!confirm(msg)) { // create a list in a tiddler
			var title=nsiFile.leafName; // tiddler name is last directory name in path
			while (title && title.length && store.tiddlerExists(title)) {
				if (confirm(config.messages.overwriteWarning.format([title]))) break; // use existing title
				title=prompt("Please enter a different tiddler title for this file",nsiFile.path.replace(/\\/g,"/"));
			}
			if (!title || !title.length) return true; // aborted by user... we're done!
			var text=header.format([nsiFile.path.replace(/\\/g,"/"),now.toLocaleString()]);
			var total=0;
			for (var i=0; i<files.length; i++) { var f=files[i];
				var name=f.leafName;
				if (config.options.chkFileDropTrimFilename)
					{ var p=name.split("."); if (p.length>1) p.pop(); name=p.join("."); }
				var path="file:///"+f.path.replace(/\\/g,"/");
				var size=f.fileSize; total+=size;
				var when=new Date(f.lastModifiedTime).formatString("YYYY.0MM.0DD 0hh:0mm:0ss");
				text+=item.format([name,path,size,when]);
			}
			text+=footer.format([total,files.length]);
			var newtags=config.options.txtFileDropTags?config.options.txtFileDropTags.readBracketedList():[];
			store.saveTiddler(null,title,text,config.options.txtUserName,now,newtags);
			if (config.options.chkFileDropDisplay) story.displayTiddler(null,title);
			return true;
		}
	}
	if (files.length>1) store.suspendNotifications();
	for (i=0; i<files.length; i++) {
		var file=files[i];
		if (file.isDirectory()) continue; // skip over nested directories
		var type="text/plain";
		var title=file.leafName; // tiddler name is file name
		if (config.options.chkFileDropTrimFilename)
			{ var p=title.split("."); if (p.length>1) p.pop(); title=p.join("."); }
		var path=file.path;
		var size=file.fileSize;
		while (title && title.length && store.tiddlerExists(title)) {
			if (confirm(config.messages.overwriteWarning.format([title]))) break; // use existing title
			title=prompt("Please enter a different tiddler title for this file",path.replace(/\\/g,"/"));
		}
		if (!title || !title.length) continue; // cancelled by user... skip this file
		if (config.macros.attach) {
			type=config.macros.attach.getMIMEType(file.leafName,"");
			if (!type.length)
				type=prompt("Unrecognized file type.  Please enter a MIME type for this file","text/plain");
			if (!type||!type.length) continue; // cancelled by user... skip this file
		}
		var newtags=config.options.txtFileDropTags?config.options.txtFileDropTags.readBracketedList():[];
		if (type=="text/plain")
			store.saveTiddler(null,title,loadFile(path),config.options.txtUserName,now,newtags);
		else {
			// only encode data if enabled and file is smaller than limit.  Default is 32768 (32K) bytes.
			var embed=config.options.chkFileDropAttachEncodeData
				&& file.fileSize<config.options.txtFileDropAttachDataLimit;
			newtags.push("attachment"); newtags.push("excludeMissing");
			// if file is in current document folder, remove path prefix and use relative reference
			var localfile=path;
			var h=document.location.href; folder=getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf("/")+1)));
			if (localfile.substr(0,folder.length)==folder) localfile='./'+localfile.substr(folder.length);
			config.macros.attach.createAttachmentTiddler(path,
				now.formatString(config.macros.timeline.dateFormat),
				"attached by FileDropPlugin", newtags,
				title, embed, true, false, localfile, "", type,!config.options.chkFileDropDisplay);
		}
		if (config.options.chkFileDropDisplay) story.displayTiddler(null,title);
	}
	if (files.length>1) { store.resumeNotifications(); store.notifyAll(); }
	if (window.FFDEBUG) console.log(new Date()-now);
	return true;
})
//}}}
/***
|Name|FoldHeadingsPlugin|
|Source|http://www.TiddlyTools.com/#FoldHeadingsPlugin|
|Version|1.0.2|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|automatically turn headings into slider-like panels that can be folded/unfolded with a single click|
This plugin defines a macro that automatically converts heading-formatted content into sliders that let you expand/collapse their content by clicking on individual headings.
!!!!!Usage
<<<
{{{
<<foldHeadings opened|closed tag tag tag...>>
}}}
where: ''opened'' or ''closed'' is a keyword indicating the initial state of the sections (default: opened), and ''tag tag tag...'' is an optional list of tags to match, so that the foldable effect is only applied to tiddlers that contain one (or more) of the indicated tags.  

When you place the macro in a tiddler, any heading-formatted content (i.e, "!" through "!!!!!") in that tiddler will automatically become //'fold-able'//, allowing you to expand/collapse the content that follows each heading simply by clicking on that heading.  Each content section begins with the first element following a heading, and continues until either another heading is found or the end of the tiddler is reached.  For example:
{{{
<<foldHeadings closed>>
}}}
is embedded in ''this'' tiddler in order to make all the headings it contains 'fold-able'.  Note that the macro has been placed at the //end// of the tiddler because it only operates on *rendered* content.  Thus, only headings that //precede// it in the same tiddler will become fold-able, as any headings that //follow// it are not actually rendered until //after// the macro has been processed.

You can further limit the effect of the macro within the tiddler by surrounding several headings in a "CSS class wrapper" ("""{{classname{...}}}""") or other containing DOM element (e.g., """@@display:inline;...@@""") and then embedding the {{{<<foldHeadings>>}}} macro inside that container (at the end)... only those headings that are also within that container will be made fold-able, instead of converting ''all'' the headings in that tiddler.

Conversely, if you want the fold-able ability to apply to the headings in //all// tiddlers, ''without having to alter //any// of those individual tiddlers'', you can add the macro to the end of your [[ViewTemplate]], so that it will be invoked after the content in each tiddler has been rendered, causing all headings they contain to automatically become fold-able.  For example:
{{{
<span macro="foldHeadings closed"></span>
}}}
You can also limit this effect to selected tiddlers by specifying one or more tags as additional macro parameters.  For example:
{{{
<span macro="foldHeadings closed systemConfig"></span>
}}}
is only applied to headings contained in //plugin tiddlers// (i.e., tiddlers tagged with <<tag systemConfig>>), while headings in other tiddlers remain unaffected by the macro, even though it is embedded in the common [[ViewTemplate]] definition.
<<<
!!!!!Revisions
<<<
2007.12.06 [1.0.2] fix handling for empty sections when checking for sliderPanel/floatingPanel
2007.12.02 [1.0.1] fix handling when content following a heading is already a sliderPanel/floatingPanel
2007.12.01 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.FoldHeadings= {major: 1, minor: 0, revision: 2, date: new Date(2007,12,6)};

config.macros.foldHeadings = {
	guideText: "opened|closed className",
	showtip: "click to show '%0'",
	hidetip: "click to hide '%0'",
	showlabel: "more...",
	hidelabel: "[x]",
	html: "<span style='float:right;text-weight:normal;font-size:80%;' class='TiddlyLinkExisting'>%0&nbsp;</span>",
	handler: function(place,macroName,params) {
		var show=params[0] && params.shift().toLowerCase()!="closed";
		if (params.length) { // if filtering by tag(s)
			var here=story.findContainingTiddler(place);
			if (here) var tid=store.getTiddler(here.getAttribute("tiddler"));
			if (!tid || !tid.tags.containsAny(params)) return; // in a tiddler and not tagged... do nothing...
		}
		var elems=place.parentNode.getElementsByTagName("*");
		var heads=[]; for (var i=0; i<elems.length; i++) { // get non-foldable heading elements
			var n=elems[i].nodeName; var foldable=hasClass(elems[i],"foldable");
			if ((n=="H1"||n=="H2"||n=="H3"||n=="H4"||n=="H5")&&!foldable)
				heads.push(elems[i]);
			}
		for (var i=0; i<heads.length; i++) { var h=heads[i]; // for each heading element...
			// find start/end of section content (up to next heading or end of content)
			var start=end=h.nextSibling; while (end && end.nextSibling) {
				var n=end.nextSibling.nodeName.toUpperCase();
				if (n=="H1"||n=="H2"||n=="H3"||n=="H4"||n=="H5") break;
				end=end.nextSibling;
			}
			if (start && hasClass(start,"sliderPanel")||hasClass(start,"floatingPanel")) continue; // heading is already a slider!
			var span=createTiddlyElement(null,"span",null,"sliderPanel"); // create container
			span.style.display=show?"inline":"none"; // set initial display state
			h.parentNode.insertBefore(span,start); // and insert it following the heading element
			// move section elements into container...
			var e=start; while (e) { var next=e.nextSibling; span.insertBefore(e,null); if (e==end) break; e=next; }
			// set heading label/tip/cursor...
			h.title=(show?this.hidetip:this.showtip).format([h.textContent])
			h.innerHTML=this.html.format([show?this.hidelabel:this.showlabel])+h.innerHTML;
			h.style.cursor='pointer';
			addClass(h,"foldable"); // so we know it been done (and to add extra styles)
			h.onclick=function() {
				var panel=this.nextSibling; var show=panel.style.display=="none";
				// update panel display state
				if (config.options.chkAnimate) anim.startAnimating(new Slider(panel,show));
				else panel.style.display = show?"inline":"none";
				// update heading label/tip
				this.removeChild(this.firstChild); // remove existing label
				var fh=config.macros.foldHeadings; // abbreviation for readability...
				this.title=(show?fh.hidetip:fh.showtip).format([this.textContent])
				this.innerHTML=fh.html.format([show?fh.hidelabel:fh.showlabel])+this.innerHTML;
			}
		}		
	}
}
//}}}
// //<<foldHeadings closed>>
/%
|Name|FoldOtherTiddlers|
|Source|http://www.TiddlyTools.com/#FoldOtherTiddlers|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires||
|Overrides||
|Description|fold all other tiddlers when a tiddler is viewed - equivalent to pressing "focus" toolbar command|

Usage: <<tiddler FoldOtherTiddlers>>

%/<script>
	if (!config.commands.collapseTiddler) return;
	var here=story.findContainingTiddler(place); if (!here) return;
	config.commands.collapseOthers.handler(null,here,here.getAttribute('tiddler'));
</script>
/***
|Name|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 has been updated to prevent double clicks of the button from triggering editing of the containing tiddler.
''Creating a footnote is very easy. Just put the text of the footnote inside triple backticks.''
{{{``` text of footnote ```}}}

''Try clicking on the red numbers, in the paragraphs below, to see the footnotes. 
Edit this tiddler, to see how easy it is, to create footnotes.''

Lorem ipsum dolor sit amet, consectetuer adipiscing elit```This is my first footnote```. Duis eleifend. Phasellus id orci. Suspendisse quis elit pharetra arcu fringilla vulputate. Nullam et orci. In vel dolor quis eros euismod vehicula. Mauris eros lectus, imperdiet id, aliquet quis, mollis bibendum, libero. Suspendisse turpis diam, lobortis id, consectetuer a, porta a, nisl. Morbi tristique, tellus ac mollis suscipit, dolor dui convallis massa, a tristique ligula nisl ac turpis. Pellentesque in elit sit amet urna mattis vulputate. Cras convallis gravida nulla. Integer luctus ante et velit. In vel urna. Donec in sapien.

Ut elementum egestas nibh. Sed at urna non lectus```You can have as many footnotes as you like``` accumsan lobortis. Ut risus nibh, commodo non, blandit sit amet, consequat id, nisl. Nulla facilisi. Curabitur massa magna, vulputate sed, porttitor accumsan, eleifend sit amet, dui. Curabitur risus. Integer id enim vel ligula porttitor laoreet. Vivamus congue lorem id urna. Donec viverra. Donec et massa non arcu sollicitudin bibendum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque velit mauris, lacinia eget, lobortis vitae, aliquam a, lectus. Donec pulvinar, libero sit amet auctor volutpat, mauris est posuere nisi, vel aliquet enim nisi in ipsum. Nullam at eros ac leo convallis blandit```Clicking on a footnote link, takes you to the footnote```.

Aliquam erat volutpat. Nam congue. Maecenas vitae tortor. In enim leo, rutrum non, tincidunt at, adipiscing in, lectus. Donec bibendum, lacus a ultricies ultricies, lacus erat rhoncus augue, sit amet vehicula libero massa eget sem. Donec quis felis. Nullam auctor interdum purus. Mauris mauris. Integer interdum blandit erat. Nulla facilisi. Integer fermentum gravida nunc. Maecenas vitae justo ut tortor ultrices dictum. Maecenas purus magna, pellentesque vel, luctus vel, commodo a, enim. Ut convallis, metus in consectetuer dapibus, nisi mi malesuada justo, nec feugiat leo magna et orci. In hendrerit enim eget sem sollicitudin auctor```Footnotes are numbered automatically```. Donec hendrerit, lorem id tincidunt bibendum, dolor dui dignissim velit, eu aliquet dolor sapien tincidunt nunc. Duis condimentum leo laoreet nibh. Proin in lacus quis ante lacinia vestibulum.

Donec pharetra diam at massa. Aliquam ut eros in odio malesuada euismod. Nam interdum. Sed quis quam sed justo hendrerit facilisis. Morbi euismod. Fusce urna lacus, lobortis vitae, feugiat quis, commodo eu, dui. Nunc dui lacus, ultricies sed, pharetra ac, feugiat id, velit. Sed accumsan, metus at pharetra accumsan, nisl ante vulputate lectus, in pretium dui sem nec dui. Quisque mattis arcu eget nulla. Mauris turpis. Donec elementum lacinia turpis. Donec enim diam, feugiat id, feugiat gravida, mollis non, magna```Each footnote, has a back button, to take you to where you came from```. 
/***
|''Name:''|FootnotesPlugin|
|''Description:''|Create automated tiddler footnotes.|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#FootnotesPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.01|
|''Date:''|10/25/07|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.2|

!!Usage:
*To create a footnote, just put the footnote text inside triple backticks.
*Footnotes are numbered automatically, and listed at the bottom of the tiddler.
*{{{Creating a footnote is easy. ```This is the text for my footnote```}}}
*[[Example|FootnotesDemo]]
***/
// /%
//!BEGIN-PLUGIN-CODE
config.footnotesPlugin = {
	backLabel: "back",
	prompt:"show footnote"
};

config.formatters.unshift( {
    name: "footnotes",
    match: "```",
    lookaheadRegExp: /```((?:.|\n)*?)```/g,
    handler: function(w)
    {
        this.lookaheadRegExp.lastIndex = w.matchStart;
        var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
        if(lookaheadMatch && lookaheadMatch.index == w.matchStart )
            {
			var tiddler = story.findContainingTiddler(w.output);
			if (!tiddler.notes)
				tiddler.notes = [];
			var title = tiddler.getAttribute("tiddler");
			tiddler.notes.pushUnique(lookaheadMatch[1]);
			var pos = tiddler.notes.indexOf(lookaheadMatch[1]) + 1;
			createTiddlyButton(w.output,pos,config.footnotesPlugin.prompt,function(){var x = document.getElementById(title+"ftn"+pos);window.scrollTo(0,ensureVisible(x)+(ensureVisible(x)<findScrollY()?(findWindowHeight()-x.offsetHeight):0));return false;},"ftnlink",title+"ftnlink"+pos);			
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
            }
    }
});

old_footnotes_refreshTiddler = Story.prototype.refreshTiddler;
Story.prototype.refreshTiddler = function(title,template,force)
{
    var tiddler = old_footnotes_refreshTiddler.apply(this,arguments);
	if (tiddler.notes && tiddler.notes.length)
	{
		var holder = createTiddlyElement(null,"div",null,"footnoteholder");
		var list = createTiddlyElement(holder,"ol",title+"footnoteholder");
		for (var i=0; i<tiddler.notes.length; i++)
		{
			var ftn = createTiddlyElement(list,"li",title+"ftn"+(i+1),"footnote");
			wikify(tiddler.notes[i]+" ",ftn);
			createTiddlyButton(ftn,"["+config.footnotesPlugin.backLabel+"]",config.footnotesPlugin.backLabel,function(){window.scrollTo(0,ensureVisible(document.getElementById(this.parentNode.id.replace("ftn","ftnlink"))));return false;},"ftnbklink");
		}
		var count = tiddler.childNodes.length;
		for (var j=0; j<count; j++){
			if(hasClass(tiddler.childNodes[j],"viewer")){
				var viewer = tiddler.childNodes[j];	
			}
		}
		viewer.appendChild(holder);
		tiddler.notes = [];
	}
    return tiddler;
};

setStylesheet(
".tiddler a.ftnlink {vertical-align: super; font-size: 0.8em; color:red;}\n"+
".tiddler a.ftnlink:hover, .tiddler .footnoteholder a.ftnbklink:hover{color:#fff;background:red;}\n"+
".tiddler div.footnoteholder{margin:1.8em 1.0em; padding:0.1em 1.0em 0.1em 1.0em ;border-left: 1px solid #ccc;}"+
".tiddler footnoteholder ol {font-size: 0.9em; line-height: 1.2em;}\n"+
".tiddler .footnoteholder li.footnote {margin: 0 0 5px 0;}\n"+
".tiddler .footnoteholder a.ftnbklink{color:red;}\n","FootNotesStyles");
//!END-PLUGIN-CODE
// %/
/***
|''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.
***/

/***
|Name|FramedLinksPlugin|
|Source|http://www.TiddlyTools.com/#FramedLinksPlugin|
|Version|1.0.5|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|createExternalLink|
|Options|##Configuration|
|Description|clicking an external link opens an IFRAME following the link instead of opening a new tab/window|
This plugin causes clicks on external links to be rendered into inline frames (~IFRAMEs) instead of opening them in new browser tabs/windows.
!!!!!Usage
<<<
Just place an external link into your tiddler content using standard TiddlyWiki syntax.  When this plugin is enabled (see Configuration), an IFRAME will be created dynamically whenever you click the external link.  Clicking on the link again removes the IFRAME.  You can hold down a modifier key (shift, control, or alt) while clicking a specific link to ''temporarily'' bypass the plugin-enhanced IFRAME handling and use the standard link handling behavior for that link.
<<<
!!!!!Configuration
<<<
<<option chkFramedLinks>> display external links using inline frames
{{{usage: <<option chkFramedLinks>>}}}

IFRAME size  (use CSS units: %, em, px, cm, in):
>width: <<option txtFrameWidth>> height: <<option txtFrameHeight>>
>{{{usage: <<option txtFrameWidth>> <<option txtFrameHeight>>}}}
<<<
!!!!!Examples
<<<
Enable the plugin (see Configuration)... then try these links:
*http://www.TiddlyWiki.com
*http://www.TiddlyTools.com
*http://groups.google.com/group/TiddlyWiki/topics
<<<
!!!!!Revisions
<<<
2007.11.29 [1.0.5] added slider animation and improved CSS handling for IFRAME height/width to maximize display area
2007.11.29 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.FramedLinks= {major: 1, minor: 0, revision: 5, date: new Date(2007,11,29)};

if (config.options.chkFramedLinks==undefined) config.options.chkFramedLinks=false;
if (config.options.txtFrameWidth==undefined) config.options.txtFrameWidth="100%";
if (config.options.txtFrameHeight==undefined) config.options.txtFrameHeight="80%";

window.framedLinks_createExternalLink=createExternalLink;
window.createExternalLink=function(place,url)
{
	var link=this.framedLinks_createExternalLink.apply(this,arguments);
	link.onclick=function(ev) { var e=ev?ev:window.event;
		if (!config.options.chkFramedLinks || e.ctrlKey || e.shiftKey || e.altKey) return; // BYPASS
		var p=this.parentNode; 
		var f=this.nextSibling?this.nextSibling.firstChild:null; // get the IFRAME... maybe...
		var w=config.options.txtFrameWidth; if (!w || !w.length) w="100%";
		var h=config.options.txtFrameHeight; if (!h || !h.length) h="80%";
		if (h.indexOf("%")) h=(findWindowHeight()*h.replace(/%/,"")/100)+"px"; // calc height as % of window
		var showing=f && f.nodeName.toUpperCase()=="IFRAME"; // does IFRAME really exist?
		var stretchCell=p.nodeName.toUpperCase()=="TD" && w.indexOf("%")!=-1 && w.replace(/%/,"")>=100;
		if (!showing) { // create an iframe
			link.style.display="block"; // force IFRAME onto line following link
			if (stretchCell) { p.setAttribute("savedWidth",p.style.width); p.style.width="100%"; } // adjust TD so IFRAME stretches
			var wrapper=createTiddlyElement(null,"span"); // wrapper for slider animation
			wrapper.setAttribute("url",this.href); // for async loading of frame after animation completes
			var f=createTiddlyElement(wrapper,"iframe"); // create IFRAME
			f.style.backgroundColor="#fff"; f.style.width=w; f.style.height=h;
			p.insertBefore(wrapper,this.nextSibling);
			function loadURL(wrapper) { var f=wrapper.firstChild; var url=wrapper.getAttribute("url");
				var d=f.contentDocument?f.contentDocument:(f.contentWindow?f.contentWindow.document:f.document);
				d.open(); d.writeln("<html>connecting to "+url+"</html>"); d.close();
				try { f.src=url; } // if the iframe can't handle the href
				catch(e) { alert(e.description?e.description:e.toString()); } // ... then report the error
				window.scrollTo(0,ensureVisible(wrapper));
			}
			if (!config.options.chkAnimate) loadURL(wrapper);
			else {
				var morph=new Slider(wrapper,true);
				morph.callback=loadURL;
				morph.properties.push({style: 'width', start: 0, end: 100, template: '%0%'});
				anim.startAnimating(morph);
			}
		} else { // remove iframe
			link.style.display="inline"; // restore link style
			if (stretchCell) p.style.width=p.getAttribute("savedWidth"); // restore previous width of TD
			if (!config.options.chkAnimate) p.removeChild(f.parentNode);
			else {
				var morph=new Slider(f.parentNode,false,false,"all");
				morph.properties.push({style: 'width', start: 100, end: 0, template: '%0%'});
				anim.startAnimating(morph);
			}
		}
		e.cancelBubble=true; if (e.stopPropagation) e.stopPropagation(); return false;
	}
	return link;
}
//}}}
/***
|Name|FullScreenPlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#FullScreenPlugin|
|Version|1.1|
|Requires|~TW2.x|
!Description:
Toggle between viewing tiddlers fullscreen and normally. Very handy for when you need more viewing space.

!Demo:
Click the ↕ button in the toolbar for this tiddler. Click it again to turn off fullscreen.

!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.
Edit the ViewTemplate to add the fullscreen command to the toolbar.

!History:
*25-07-06: ver 1.1
*20-07-06: ver 1.0

!Code
***/
//{{{
var lewcidFullScreen = false;

config.commands.fullscreen =
{
            text:" ↕ ",
            tooltip:"Fullscreen mode"
};

config.commands.fullscreen.handler = function (event,src,title)
{
            if (lewcidFullScreen == false)
               {
                lewcidFullScreen = true;
                setStylesheet('#sidebar, .header, #mainMenu{display:none;} #displayArea{margin:0em 0 0 0 !important;}',"lewcidFullScreenStyle");
               }
            else
               {
                lewcidFullScreen = false;
                setStylesheet(' ',"lewcidFullScreenStyle");
               }
}

config.macros.fullscreen={};
config.macros.fullscreen.handler =  function(place,macroName,params,wikifier,paramString,tiddler)
{
        var label = params[0]||" ↕ ";
        var tooltip = params[1]||"Fullscreen mode";
        createTiddlyButton(place,label,tooltip,config.commands.fullscreen.handler);
}

var lewcid_fullscreen_closeTiddler = Story.prototype.closeTiddler;
Story.prototype.closeTiddler =function(title,animate,slowly)
{
           lewcid_fullscreen_closeTiddler.apply(this,arguments);
           if (story.isEmpty() && lewcidFullScreen == true)
              config.commands.fullscreen.handler();
}


Slider.prototype.lewcidStop = Slider.prototype.stop;
Slider.prototype.stop = function()
{
           this.lewcidStop();
           if (story.isEmpty() && lewcidFullScreen == true)
              config.commands.fullscreen.handler();
}
//}}}
/%
|''URL:''|http://gimcrackd.com/etc/src/|
|''Description:''|Gimcrack'd: Code and Other Oddments|
|''Author:''|ChrisKlimas|
%/
/%
|''URL:''|http://groups.google.com/group/TiddlyWiki/topics|
|''Description:''|TiddlyWiki discussions, help, announcments, etc.|
|''Author:''|everyone!|
%/
This is a good place to ask questions... people are friendly and helpful!
/***
|Name|GotoPlugin|
|Source|http://www.TiddlyTools.com/#GotoPlugin|
|Documentation|http://www.TiddlyTools.com/#GotoPluginInfo|
|Version|1.5.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|view any tiddler by entering it's title - displays list of possible matches|
''View a tiddler by typing its title and pressing //enter//.''  As you type, a list of possible matches is displayed.  You can scroll-and-click (or use arrows+enter) to select/view a tiddler, or press //escape// to close the listbox to resume typing.  When the listbox is ''//not//'' being displayed, press //escape// to clear the current text input and start over.
!!!!!Documentation
>see [[GotoPluginInfo]]
!!!!!Revisions
<<<
2008.02.17 [1.5.0] ENTER key always displays tiddler based on current input regardless of whether input matches any existing tiddler
|please see [[GotoPluginInfo]] for additional revision details|
2006.05.05 [0.0.0] started
<<<
!!!!!Code
***/
//{{{
version.extensions.gotoTiddler = {major: 1, minor: 5, revision: 0, date: new Date(200,2,17)};

// automatically tweak shadow SideBarOptions to add <<gotoTiddler>> macro above <<search>>
config.shadowTiddlers.SideBarOptions=config.shadowTiddlers.SideBarOptions.replace(/<<search>>/,"{{button{goto}}}\n<<gotoTiddler>><<search>>");

config.macros.gotoTiddler= { 
	handler:
	function(place,macroName,params) {
		var quiet=(params[0] && params[0]=="quiet"); if (quiet) params.shift();
		var insert=(params[0] && params[0]=="insert"); if (insert) params.shift();
		var instyle=params.shift(); if (!instyle) instyle="";
		var liststyle=params.shift(); if (!liststyle) liststyle="";
		var keyevent=window.event?"onkeydown":"onkeypress";
		createTiddlyElement(place,"span").innerHTML
			=this.html.replace(/%keyevent%/g,keyevent).replace(/%insert%/g,insert).replace(/%quiet%/g,quiet).replace(/%instyle%/g,instyle).replace(/%liststyle%/g,liststyle);
	},

	html:
	'<form onsubmit="return false" style="display:inline;margin:0;padding:0">\
		<input name=gotoTiddler type=text autocomplete="off" accesskey="G" style="%instyle%"\
			title="enter a tiddler title"\
			onclick="this.form.list.style.display=\'none\';"\
			onfocus="this.select(); this.setAttribute(\'accesskey\',\'G\');"\
			%keyevent%="return config.macros.gotoTiddler.inputEscKeyHandler(event,this,this.form.list);"\
			onkeyup="return config.macros.gotoTiddler.inputKeyHandler(event,this,this.form.list,%quiet%,%insert%);">\
		<select name=list style="%liststyle%;display:none;position:absolute"\
			onchange="if (!this.selectedIndex) this.selectedIndex=1;"\
			onblur="this.style.display=\'none\';"\
			%keyevent%="return config.macros.gotoTiddler.selectKeyHandler(event,this,this.form.gotoTiddler,%insert%);"\
			onclick="return config.macros.gotoTiddler.processItem(this.value,this.form.gotoTiddler,this,%insert%);">\
		</select>\
	</form>',

	getItems:
	function(val) {
		if (!this.items.length || val.length<2) { // starting new search, refresh cached list of tiddlers/shadows/tags
			this.items=new Array();
			var tiddlers=store.getTiddlers("title","excludeLists");
			for(var t=0; t<tiddlers.length; t++) this.items.push(tiddlers[t].title);
			for (var t in config.shadowTiddlers) this.items.pushUnique(t);
			var tags=store.getTags();
			for(var t=0; t<tags.length; t++) this.items.pushUnique(tags[t][0]);
		}
		var found = [];
		var match=val.toLowerCase();
		for(var i=0; i<this.items.length; i++)
			if (this.items[i].toLowerCase().indexOf(match)!=-1) found.push(this.items[i]);
		return found;
	},
	items: [], // cached list of tiddlers/shadows/tags

	getItemSuffix:
	function(t) {
		if (store.tiddlerExists(t)) return "";  // tiddler
		if (store.isShadowTiddler(t)) return " (shadow)"; // shadow
		return " (tag)"; // tag 
	},

	keyProcessed:
	function(ev) { // utility function: exits handler and prevents browser from processing the keystroke
		ev.cancelBubble=true; // IE4+
		try{event.keyCode=0;}catch(e){}; // IE5
		if (window.event) ev.returnValue=false; // IE6
		if (ev.preventDefault) ev.preventDefault(); // moz/opera/konqueror
		if (ev.stopPropagation) ev.stopPropagation(); // all
		return false;
	},

	inputEscKeyHandler:
	function(event,here,list) {
		var key=event.keyCode;
		// escape... hide list (2nd esc=clears input)
		if (key==27) {
			if (list.style.display=="none")
				here.value=here.defaultValue;
			list.style.display="none";
			return this.keyProcessed(event);
		}
		return true; // key bubbles up
	},

	inputKeyHandler:
	function(event,here,list,quiet,insert) {
		var key=event.keyCode;
		// non-printing chars... bubble up, except: backspace=8, enter=13, space=32, down=40, delete=46
		if (key<48) switch(key) { case 8: case 13: case 32: case 40: case 46: break; default: return true; }
		// blank input... if down/enter... fall through (list all)... else, and hide list
		if (!here.value.length && !(key==40 || key==13))
			{ list.style.display="none"; return this.keyProcessed(event); }
		// find matching items...
		var found = this.getItems(here.value);
		// non-blank input... enter key... show/create tiddler
		if (key==13) return this.processItem(here.value,here,list,insert);
		// make sure list is shown/hidden
		list.style.display=(!quiet && found.length)?"block":"none";
		// no matches, key bubbles up
		if (!found.length) return true;
		// down key... shows/moves to list...
		if (key==40)  { list.style.display="block"; list.focus(); }
		// finally, if list is showing, fill it with found results...
		if (list.style.display!="none") {
			while (list.length > 0) list.options[0]=null; // clear list
			found.sort(); // alpha by title
			var hdr=this.listHeading.format([found.length,found.length==1?"":"s"]);
			list.options[0]=new Option(hdr,"",false,false);
			for (var t=0; t<found.length; t++)  // fill list...
				list.options[list.length]=new Option(found[t]+this.getItemSuffix(found[t]),found[t],false,false);
			list.size=(found.length<this.listMaxSize?found.length:this.listMaxSize)+1; // resize list...
			list.selectedIndex=(key==40 || key==13)?1:0;
		}
		return true; // key bubbles up
	},
	listMaxSize: 10,
	listHeading: 'Found %0 matching title%1:',

	selectKeyHandler:
	function(event,list,editfield,insert) {
		if (event.keyCode==27) // escape... hide list, move to edit field
			{ editfield.focus(); list.style.display="none"; return this.keyProcessed(event); }
		if (event.keyCode==13 && list.value.length) // enter... view selected item
			{ this.processItem(list.value,editfield,list,insert); return this.keyProcessed(event); }
		return true; // key bubbles up
	},

	processItem:
	function(title,here,list,insert) {
		if (!title.length) return; here.value=title; list.style.display='none';
		if (insert) {
			var tidElem=story.findContainingTiddler(here); if (!tidElem) { here.focus(); return false; }
			var e=story.getTiddlerField(tidElem.getAttribute("tiddler"),"text");
			if (!e||e.getAttribute("edit")!="text") return false;
			var txt=prompt(this.askForText,title); if (!txt||!txt.length) { here.focus(); return false; }
			e.focus(); // put focus on target field before setting selection
			replaceSelection(e,"[["+txt+"|"+title+"]]"); // insert selected tiddler as a PrettyLink
		}
		else
			story.displayTiddler(null,title); // show selected tiddler
		return false;
	},
	askForText: "Enter the text to display for this link"
}
//}}}
/***
|Name|GotoPluginInfo|
|Source|http://www.TiddlyTools.com/#GotoPlugin|
|Documentation|http://www.TiddlyTools.com/#GotoPluginInfo|
|Version|1.5.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 GotoPlugin|
''View a tiddler by typing its title and pressing //enter//.''  As you type, a list of possible matches is displayed.  You can scroll-and-click (or use arrows+enter) to select/view a tiddler, or press //escape// to close the listbox to resume typing.  When the listbox is ''//not//'' being displayed, press //escape// to clear the current text input and start over.
!!!!!Usage/Examples
<<<
| //IMPORTANT NOTE:// ''As of version 1.4.0 (2007.04.25),<br>to avoid conflict with javascript reserved keywords<br>the {{{<<goto>>}}} macro has been renamed to {{{<<gotoTiddler>>}}}'' |
syntax: {{{<<gotoTiddler quiet insert inputstyle liststyle>>}}}
All parameters are optional.
* ''quiet'' prevents //automatic// display of the list as each character is typed.  To view the list when ''quiet'', use //down// or //enter//.
* ''insert'' causes the selected tiddler title to be inserted into the tiddler source currently being edited (use with EditTemplate)
* ''inputstyle'' and ''liststyle'' are CSS declarations that modify the default input and listbox styles.  Note: styles containing spaces must be surrounded by ({{{"..."}}} or {{{'...'}}}) or ({{{[[...]]}}}).
{{{<<gotoTiddler>>}}}
<<gotoTiddler>>
{{{<<gotoTiddler quiet>>}}}
<<gotoTiddler quiet>>
{{{<<goto width:20em width:20em>>}}}
<<gotoTiddler width:20em width:20em>>

You can also invoke the macro with the "insert" keyword.  When used in the [[EditTemplate]], like this:
{{{
<span macro="gotoTiddler insert"></span>
}}}
it allows you to type/select a tiddler title, and instantly insert a link to that title (e.g. {{{[[TiddlerName]]}}}) into the tiddler source being edited.
<<<
!!!!!Configuration
<<<
You can create a tiddler tagged with <<tag systemConfig>> to control the maximum height of the listbox of tiddlers/shadows/tags. //The default values are shown below://
//{{{
config.macros.gotoTiddler.listMaxSize=10;
//}}}
<<<
!!!!!Revisions
<<<
2008.02.17 [1.5.0] ENTER key always displays tiddler based on current input regardless of whether input matches any existing tiddler
2007.10.31 [1.4.3] removed extra trailing comma on last property of config.macros.gotoTiddler object.  This fixes an error under InternetExplorer that was introduced 6 days ago... sure, I should have found it sooner, but... WHY DON'T PEOPLE TELL ME WHEN THINGS ARE BROKEN!!!!
2007.10.25 [1.4.2] added onclick handler for input field, so that clicking in field hides the listbox.
2007.10.25 [1.4.1] re-wrote getItems() to cache list of tiddlers/shadows/tags and use case-folded simple text match instead of regular expression to find matching tiddlers.  This *vastly* reduces processing overhead between keystrokes, especially for documents with many (>1000) tiddlers.  Also, removed local definition of replaceSelection(), now supported directly by the TW2.2+ core, as well as via backward-compatible plugin
2007.04.25 [1.4.0] renamed macro from "goto" to "gotoTiddler".  This was necessary to avoid a fatal syntax error in Opera (and other browsers) that require strict adherence to ECMAScript 1.5 standards which defines the identifier "goto" as "reserved for FUTURE USE"... *sigh*
2007.04.21 [1.3.2] in html definition, removed DIV around droplist (see 1.2.6 below).  It created more layout problems then it solved. :-(
2007.04.01 [1.3.1] in processItem(), ensure that correct textarea field is found by checking for edit=="text" attribute
2007.03.30 [1.3.0] tweak SideBarOptions shadow to automatically add {{{<<goto>>}}} when using default sidebar content
2007.03.30 [1.2.6] in html definition, added DIV around droplist to fix IE problem where list appears next to input field instead of below it.  
2007.03.28 [1.2.5] in processItem(), set focus to text area before setting selection (needed for IE to get correct selection 'range')
2007.03.28 [1.2.4] added prompt for 'pretty text' when inserting a link into tiddler content
2007.03.28 [1.2.3] added local copy of core replaceSelection() and modified for different replace logic
2007.03.27 [1.2.2] in processItem(), use story.getTiddlerField() to retrieve textarea control
2007.03.26 [1.2.1] in html, use either 'onkeydown' (IE) or 'onkeypress' (Moz) event to process <esc> key sooner, to prevent <esc> from 'bubbling up' to the tiddler (which will close the current editor).
2007.03.26 [1.2.0] added support for optional "insert" keyword param. When used in [[EditTemplate]], (e.g. {{{<span macro="goto insert"></span>}}}) it triggers alternative processing: instead of displaying the selected tiddler, that tiddler's title is inserted into a tiddler's textarea edit field surrounded by {{{[[...]]}}}.
2006.05.10 [1.1.2] when filling listbox, set selection to 'heading' item... auto-select first tiddler title when down/enter moves focus into listbox
2006.05.08 [1.1.1] added accesskey ("G") to input field html (also set when field gets focus).  Also, inputKeyHandler() skips non-printing/non-editing keys. 
2006.05.08 [1.1.0] added heading to listbox for better feedback (also avoids problems with 1-line droplist)
2006.05.07 [1.0.0] list matches against tiddlers/shadows/tags.  input field auto-completion... 1st enter=complete matching input (or show list)... 2nd enter=view tiddler.  optional "quiet" param controls when listbox appears.
2006.05.06 [0.5.0] added handling for enter (13), escape(27), and down(40) keys.   Change 'ondblclick' to 'onclick' for list handler to view tiddlers (suggested by Florian Cauvin - prevents unintended trigger of tiddler editor).  shadow titles inserted into list instead of appended to the end.
2006.05.05 [0.0.0] started
<<<
/***
|Name|HTMLFormattingPlugin|
|Source|http://www.TiddlyTools.com/#HTMLFormattingPlugin|
|Documentation|http://www.TiddlyTools.com/#HTMLFormattingPluginInfo|
|Version|2.1.5|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|'HTML' formatter|
|Description|embed wiki syntax formatting inside of HTML content|
The ~HTMLFormatting plugin allows you to ''mix wiki-style formatting syntax within HTML formatted content'' by extending the action of the standard TiddlyWiki formatting handler.
!!!!!Documentation
>see [[HTMLFormattingPluginInfo]]
!!!!!Revisions
<<<
2008.04.26 [*.*.*] plugin size reduction: more documentation moved to HTMLFormattingInfo
2008.01.08 [*.*.*] plugin size reduction: documentation moved to HTMLFormattingInfo
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.06.14 [2.1.5] in formatter, removed call to e.normalize().  Creates an INFINITE RECURSION error in Safari!!!!
| see [[HTMLFormattingPluginInfo]] for additional revision details |
2005.06.26 [1.0.0] Initial Release (as code adaptation - pre-dates TiddlyWiki plugin architecture!!)
<<<
!!!!!Code
***/
//{{{
version.extensions.HTMLFormatting = {major: 2, minor: 1, revision: 5, date: new Date(2007,6,14)};

// find the formatter for HTML and replace the handler
initHTMLFormatter();
function initHTMLFormatter()
{
	for (var i=0; i<config.formatters.length && config.formatters[i].name!="html"; i++);
	if (i<config.formatters.length)	config.formatters[i].handler=function(w) {
		if (!this.lookaheadRegExp)  // fixup for TW2.0.x
			this.lookaheadRegExp = new RegExp(this.lookahead,"mg");
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var html=lookaheadMatch[1];
			// optionally suppress wiki-style literal handling of newlines
			if (html.indexOf('<hide linebreaks>')!=-1) html=html.replace(/\n/g,' ');
			// remove carriage returns (\r) added by IE textarea
			html=html.replace(/\r/g,'');
			// encode newlines (\n) and macro brackets (<< and >>)
			html=html.replace(/\n/g,'\\n').replace(/<</g,'%%(').replace(/>>/g,')%%');
			// create span to hold HTML
			var e = createTiddlyElement(w.output,"span");
			// let browser parse HTML
			e.innerHTML=html;
			// walk node tree and call wikify() on each text node
			wikifyTextNodes(e);
			// continue wiki parsing
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
}

// wikify text nodes remaining after HTML content is processed (pre-order recursion)
function wikifyTextNodes(theNode)
{
	// textarea node doesn't get wikified, just decoded... 
	if (theNode.nodeName.toLowerCase()=='textarea')
		theNode.value=theNode.value.replace(/\%%\(/g,'<<').replace(/\)\%%/g,'>>').replace(/\\n/g,'\n');
	else for (var i=0;i<theNode.childNodes.length;i++) {
		var theChild=theNode.childNodes.item(i);
		if (theChild.nodeName.toLowerCase()=='option') continue;
		if (theChild.nodeName.toLowerCase()=='select') continue;
		wikifyTextNodes(theChild);
		if (theChild.nodeName=='#text') {
			var txt=theChild.nodeValue;
			// decode macro brackets and newlines
			txt=txt.replace(/\%%\(/g,'<<').replace(/\)\%%/g,'>>').replace(/\\n/g,'\n');
			// replace text node with wikified() span
			var newNode=createTiddlyElement(null,"span");
			theNode.replaceChild(newNode,theChild);
			wikify(txt,newNode);
		}
	}
}
//}}}
|Name|HTMLFormattingPluginInfo|
|Source|http://www.TiddlyTools.com/#HTMLFormattingPlugin|
|Documentation|http://www.TiddlyTools.com/#HTMLFormattingPluginInfo|
|Version|2.1.5|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for HTMLFormattingPlugin|
The ~HTMLFormatting plugin allows you to freely ''mix wiki-style formatting syntax within HTML formatted content'' by extending the action of the standard TiddlyWiki formatting handler.
!!!!!Usage
<<<
The shorthand Wiki-style formatting syntax of ~TiddlyWiki is very convenient and enables most content to be reasonably well presented. However, there are times when tried-and-true HTML formatting syntax allows more more precise control of the content display.

When a tiddler is about to be displayed, ~TiddlyWiki looks for tiddler content contained within {{{<html>}}} and {{{</html>}}} markers.  When present, the TiddlylWiki core simply passes this content directly to the browser's internal "rendering engine" to process as ~HTML-formatted content.  However, TiddlyWiki does not also process the HTML source content for any embedded wiki-formatting syntax it may contain.  This means that while you can use HTML formatted content, you cannot mix wiki-formatted content within the HTML formatting.

This plugin extends the TiddlyWiki core processing so that, after the HTML formatting has been processed, all the pieces of text occuring within the HTML block are then processed one piece at a time, so that normal wiki-style formatting can be applied to the individual text pieces.
<<<
!!!!!Line breaks
<<<
One major difference between Wiki formatting and HTML formatting is how "line breaks" are processed. Wiki formatting treats all line breaks as literal content to be displayed //as-is//. However, because HTML normally ignores line breaks and actually processes them as simple "word separators" instead, many people who write HTML include extra line breaks in their documents, just to make the "source code" easier to read.

Even though you can use HTML tags within your tiddler content, the default treatment for line breaks still follows the Wiki-style rule (i.e., all new lines are displayed as-is). When adding HTML content to a tiddler (especially if you cut-and-paste it from another web page), you should take care to avoid adding extra line breaks to the text.

If removing all the extra line breaks from your HTML content would be a big hassle, you can quickly //override the default Wiki-style line break rule// so that the line breaks use the standard HTML rules instead.  Placing a ''<{{{hide linebreaks}}}>'' tag within the tiddler's HTML content changes all line breaks to spaces before rendering the content, so that the literal line breaks will be processed as simple word-breaks instead.

Note: this does //not// alter the actual tiddler content that is stored in the document, just the manner in which it is displayed. Any line breaks contained in the tiddler will still be there when you edit its content. Also, to include a literal line break when the ''<{{{hide linebreaks}}}>'' tag is present, you will need to use a ''<{{{br}}}>'' or ''<{{{p}}}>'' HTML tag instead of simply typing a line break.
<<<
!!!!!How it works
<<<
The TW core support for HTML does not let you put ANY wiki-style syntax (including TW macros) *inside* the {{{<html>...</html>}}} block.  Everything between {{{<html>}}} and {{{</html>}}} is handed to the browser for processing and that is it.

However, not all wiki syntax can be safely passed through the browser's parser. Specifically, any TW macros inside the HTML will get 'eaten' by the browser since the macro brackets, {{{<<...>>}}} use the "<" and ">" that normally delimit the HTML/XML syntax recognized by the browser's parser.

Similarly, you can't use InlineJavascript within the HTML because the {{{<script>...</script>}}} syntax will also be consumed by the browser and there will be nothing left to process afterward.  Note: unfortunately, even though the browser removes the {{{<script>...</script>}}} sequence, it doesn't actually execute the embedded javascript code that it removes, so any scripts contained inside of <html> blocks in TW are currently being ignored. :-(

As a work-around to allow TW *macros* (but not inline scripts) to exist inside of <html> formatted blocks of content, the plugin first converts the {{{<<}}} and {{{>>}}} into "%%(" and ")%%", making them "indigestible" so they can pass unchanged through the belly of the beast (the browser's HTML parser).

After the browser has done its job, the wiki syntax sequences (including the "undigested" macros) are contained in #text nodes in the browser-generated DOM elements.  The plugin then recursively locates and processes each #text node, converts the %%( and )%% back into {{{<<}}} and {{{>>}}}, passes the result to wikify() for further rendering of the wiki-formatted syntax into a containing SPAN that replaces the previous #text node.  At the end of this process, none of the encoded %%( and )%% sequences remain in the rendered tiddler output.
<<<
!!!!!Revisions
<<<
2008.04.26 [*.*.*] plugin size reduction: more documentation moved to HTMLFormattingInfo
2008.01.08 [*.*.*] plugin size reduction: documentation moved to HTMLFormattingInfo
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.06.14 [2.1.5] in formatter, removed call to e.normalize().  Creates an INFINITE RECURSION error in Safari!!!!
2006.09.10 [2.1.4] update formatter for 2.1 compatibility (use this.lookaheadRegExp instead of temp variable)
2006.05.28 [2.1.3] in wikifyTextNodes(), decode the *value* of TEXTAREA nodes, but don't wikify() its children.  (thanks to "ayj" for bug report)
2006.02.19 [2.1.2] in wikifyTextNodes(), put SPAN element into tiddler DOM (replacing text node), BEFORE wikifying the text content.  This ensures that the 'place' passed to any macros is correctly defined when the macro is evaluated, so that calls to story.findContainingTiddler(place) will work as expected. (Thanks for bug report from GeoffSlocock)
2006.02.05 [2.1.1] wrapped wikifier hijack in init function to eliminate globals and avoid FireFox 1.5.0.1 crash bug when referencing globals
2005.12.01 [2.1.0] don't wikify #TEXT nodes inside SELECT and TEXTAREA elements
2005.11.06 [2.0.1] code cleanup
2005.10.31 [2.0.0] replaced hijack wikify() with hijack config.formatters["html"] and simplified recursive WikifyTextNodes() code
2005.10.09 [1.0.2] combined documentation and code into a single tiddler
2005.08.05 [1.0.1] moved HTML and CSS definitions into plugin code instead of using separate tiddlers
2005.07.26 [1.0.1] Re-released as a plugin. Added <{{{html}}}>...</{{{nohtml}}}> and <{{{hide newlines}}}> handling
2005.06.26 [1.0.0] Initial Release (as code adaptation - pre-dates TiddlyWiki plugin architecture!!)
<<<
/%
|Name|HideTiddlerBackground|
|Source|http://www.TiddlyTools.com/#HideTiddlerBackground|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|hide a tiddler's background and border (if any)|

Usage: <<tiddler HideTiddlerBackground>>

%/<script>
	var t=story.findContainingTiddler(place);
	if (!t || t.id=="HideTiddlerBackground") return;
	var nodes=t.getElementsByTagName("*");
	for (var i=0; i<nodes.length; i++) if (hasClass(nodes[i],"viewer")) {
		var s=nodes[i].style;
		s.backgroundImage="none";
		s.backgroundColor="transparent"
		s.borderColor="transparent";
		s.borderWidth=0;
		s.margin=0;
		s.padding=0;
		break;
	}
</script>
/%
|Name|HideTiddlerSubtitle|
|Source|http://www.TiddlyTools.com/#HideTiddlerSubtitle|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|hide a tiddler's subtitle (dates/created by) display|

Usage: <<tiddler HideTiddlerSubtitle>>

%/<script>
	var t=story.findContainingTiddler(place);
	if (!t || t.id=="tiddlerHideTiddlerSubtitle") return;
	var nodes=t.getElementsByTagName("*");
	for (var i=0; i<nodes.length; i++)
		if (hasClass(nodes[i],"subtitle"))
			nodes[i].style.display="none";
</script>
/%
|Name|HideTiddlerTags|
|Source|http://www.TiddlyTools.com/#HideTiddlerTags|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|hide a tiddler's tagged/tagging display elements|

Usage: <<tiddler HideTiddlerTags>>

%/<script>
	var t=story.findContainingTiddler(place);
	if (!t || t.id=="tiddlerHideTiddlerTags") return;
	var nodes=t.getElementsByTagName("div");
	for (var i=0; i<nodes.length; i++)
		if (hasClass(nodes[i],"tagging")||hasClass(nodes[i],"tagged"))
			nodes[i].style.display="none";
</script>
/%
|Name|HideTiddlerTitle|
|Source|http://www.TiddlyTools.com/#HideTiddlerTitle|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|hide a tiddler's title display elements (name, dates, and author)|

Usage: <<tiddler HideTiddlerTitle>>

%/<script>
	var t=story.findContainingTiddler(place);
	if (!t || t.id=="tiddlerHideTiddlerTitle") return;
	var nodes=t.getElementsByTagName("*");
	for (var i=0; i<nodes.length; i++)
		if (hasClass(nodes[i],"title")||hasClass(nodes[i],"subtitle"))
			nodes[i].style.display="none";
</script>
/%
|Name|HideTiddlerToolbar|
|Source|http://www.TiddlyTools.com/#HideTiddlerToolbar|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|hide a tiddler's toolbar display|

Usage: <<tiddler HideTiddlerToolbar>>

%/<script>
	var t=story.findContainingTiddler(place);
	if (!t || t.id=="tiddlerHideTiddlerToolbar") return;
	var nodes=t.getElementsByTagName("*");
	for (var i=0; i<nodes.length; i++)
		if (hasClass(nodes[i],"toolbar"))
			nodes[i].style.display="none";
</script>
<<top>><<icon top.bmp 16 16>>
<<toggleSideBar '' '' hide>><<icon toggle.bmp 16 16>>
<<jump j '' top>><<icon jump.bmp 16 16>>
<<fullscreen f>><<icon full.bmp 16 16>>
<<saveChanges>><<icon save.bmp 16 16>>
<<newTiddler>><<icon new.bmp 16 16>>
/***
|Name|HoverMenuPlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#HoverMenuPlugin|
|Version|1.11|
|Requires|~TW2.x|
!Description:
Provides a hovering menu on the edge of the screen for commonly used commands, that scrolls with the page.

!Demo:
Observe the hovering menu on the right edge of the screen.

!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.
To customize your HoverMenu, edit the HoverMenu shadow tiddler.

To customize whether the menu sticks to the right or left edge of the screen, and its start position, edit the HoverMenu configuration settings part of the code below. It's well documented, so don't be scared!

The menu has an id of hoverMenu, in case you want to style the buttons in it using css.

!Notes:
Since the default HoverMenu contains buttons for toggling the side bar and jumping to the top of the screen and to open tiddlers, the ToggleSideBarMacro, JumpMacro and the JumpToTopMacro are included in this tiddler, so you dont need to install them separately. Having them installed separately as well could lead to complications.

If you dont intend to use these three macros at all, feel free to remove those sections of code in this tiddler.

!To Do:
* rework code to allow multiple hovering menus in different positions, horizontal etc.
* incorporate code for keyboard shortcuts that correspond to the buttons in the hovermenu

!History:
*03-08-06, ver 1.1.2: compatibility fix with SelectThemePlugin
*03-08-06,  ver 1.11: fixed error with button tooltips
*27-07-06, ver 1.1 : added JumpMacro to hoverMenu
*23-07-06

!Code
***/

/***
start HoverMenu plugin code
***/
//{{{
config.hoverMenu={};
//}}}

/***
HoverMenu configuration settings
***/
//{{{
config.hoverMenu.settings={
               align: 'right',    //align menu to right or left side of screen, possible values are 'right' and 'left'               
               x: 1,              // horizontal distance of menu from side of screen, increase to your liking.
               y: 158            //vertical distance of menu from top of screen at start, increase or decrease to your liking
               };
//}}}

//{{{
//continue HoverMenu plugin code
config.hoverMenu.handler=function()
{              
               if (!document.getElementById("hoverMenu"))
               {
               var theMenu = createTiddlyElement(document.getElementById("contentWrapper"), "div","hoverMenu");
               theMenu.setAttribute("refresh","content");
               theMenu.setAttribute("tiddler","HoverMenu");
               var menuContent = store.getTiddlerText("HoverMenu");
               wikify(menuContent,theMenu);
              }

	       var Xloc = this.settings.x;
	       Yloc =this.settings.y;
	       var ns = (navigator.appName.indexOf("Netscape") != -1);
	       function SetMenu(id)
                        {
		        var GetElements=document.getElementById?document.getElementById(id):document.all?document.all[id]:document.layers[id];
		        if(document.layers)GetElements.style=GetElements;
		        GetElements.sP=function(x,y){this.style[config.hoverMenu.settings.align]=x +"px";this.style.top=y +"px";};
		        GetElements.x = Xloc;
		        GetElements.y = findScrollY();
		        GetElements.y += Yloc;
		        return GetElements;
	                }
               window.LoCate_XY=function()
                        {
		        var pY =  findScrollY();
                        ftlObj.y += (pY + Yloc - ftlObj.y)/15;
		        ftlObj.sP(ftlObj.x, ftlObj.y);
		        setTimeout("LoCate_XY()", 10);
	                }
               ftlObj = SetMenu("hoverMenu");
	       LoCate_XY();
};

window.old_lewcid_hovermenu_restart = restart;
restart = function()
{
               window.old_lewcid_hovermenu_restart();
               config.hoverMenu.handler();
};

setStylesheet(
"#hoverMenu .imgLink, #hoverMenu .imgLink:hover {border:none; padding:0px; float:right; margin-bottom:2px; margin-top:0px;}\n"+
"#hoverMenu  .button, #hoverMenu  .tiddlyLink {border:none; font-weight:bold; background:#18f; color:#FFF; padding:0 5px; float:right; margin-bottom:4px;}\n"+
"#hoverMenu .button:hover, #hoverMenu .tiddlyLink:hover {font-weight:bold; border:none; color:#fff; background:#000; padding:0 5px; float:right; margin-bottom:4px;}\n"+
"#hoverMenu .button {width:100%; text-align:center}"+
"#hoverMenu { position:absolute; width:7px;}\n"+
"\n","hoverMenuStyles");


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

               if (place.lastChild.tagName!="BR")
                     {
                      place.lastChild.firstChild.data = params[0];
                      if (params[1]) {place.lastChild.title = params[1];}
                     }
};

config.shadowTiddlers["HoverMenu"]="<<top>>\n<<toggleSideBar>><<renameButton '>' >>\n<<jump j '' top>>\n<<saveChanges>><<renameButton s 'Save TiddlyWiki'>>\n<<newTiddler>><<renameButton n>>\n";
//}}}
//end HoverMenu plugin code

//Start ToggleSideBarMacro code
//{{{
config.macros.toggleSideBar={};

config.macros.toggleSideBar.settings={
         styleHide :  "#sidebar { display: none;}\n"+"#contentWrapper #displayArea { margin-right: 1em;}\n"+"",
         styleShow : " ",
         arrow1: "«",
         arrow2: "»"
};

config.macros.toggleSideBar.handler=function (place,macroName,params,wikifier,paramString,tiddler)
{
          var tooltip= params[1]||'toggle sidebar';
          var mode = (params[2] && params[2]=="hide")? "hide":"show";
          var arrow = (mode == "hide")? this.settings.arrow1:this.settings.arrow2;
          var label= (params[0]&&params[0]!='.')?params[0]+" "+arrow:arrow;
          var theBtn = createTiddlyButton(place,label,tooltip,this.onToggleSideBar,"button HideSideBarButton");
          if (mode == "hide")
             { 
             (document.getElementById("sidebar")).setAttribute("toggle","hide");
              setStylesheet(this.settings.styleHide,"ToggleSideBarStyles");
             }
};

config.macros.toggleSideBar.onToggleSideBar = function(){
          var sidebar = document.getElementById("sidebar");
          var settings = config.macros.toggleSideBar.settings;
          if (sidebar.getAttribute("toggle")=='hide')
             {
              setStylesheet(settings.styleShow,"ToggleSideBarStyles");
              sidebar.setAttribute("toggle","show");
              this.firstChild.data= (this.firstChild.data).replace(settings.arrow1,settings.arrow2);
              }
          else
              {    
               setStylesheet(settings.styleHide,"ToggleSideBarStyles");
               sidebar.setAttribute("toggle","hide");
               this.firstChild.data= (this.firstChild.data).replace(settings.arrow2,settings.arrow1);
              }

     return false;
}

setStylesheet(".HideSideBarButton .button {font-weight:bold; padding: 0 5px;}\n","ToggleSideBarButtonStyles");
//}}}
//end ToggleSideBarMacro code

//start JumpToTopMacro code
//{{{
config.macros.top={};
config.macros.top.handler=function(place,macroName)
{
               createTiddlyButton(place,"^","jump to top",this.onclick);
}
config.macros.top.onclick=function()
{
               window.scrollTo(0,0);
};

config.commands.top =
{
               text:" ^ ",
               tooltip:"jump to top"
};

config.commands.top.handler = function(event,src,title)
{
               window.scrollTo(0,0);
}
//}}}
//end JumpToStartMacro code

//start JumpMacro code
//{{{
config.macros.jump= {};
config.macros.jump.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
        var label = (params[0] && params[0]!=".")? params[0]: 'jump';
        var tooltip = (params[1] && params[1]!=".")? params[1]: 'jump to an open tiddler';
        var top = (params[2] && params[2]=='top') ? true: false;        

        var btn =createTiddlyButton(place,label,tooltip,this.onclick);
        if (top==true)
              btn.setAttribute("top","true")
}

config.macros.jump.onclick = function(e)
{
        if (!e) var e = window.event;
        var theTarget = resolveTarget(e);
        var top = theTarget.getAttribute("top");
	var popup = Popup.create(this);
	if(popup)
		{
                 if(top=="true")
                                {createTiddlyButton(createTiddlyElement(popup,"li"),'Top ↑','Top of TW',config.macros.jump.top);
                                 createTiddlyElement(popup,"hr");}
		
		story.forEachTiddler(function(title,element) {
			createTiddlyLink(createTiddlyElement(popup,"li"),title,true);
			});
                }
	Popup.show(popup,false);
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
	return false;
}

config.macros.jump.top = function()
{
       window.scrollTo(0,0);
}
//}}}
//end JumpMacro code

//utility functions
//{{{
Popup.show = function(unused,slowly)
{
	var curr = Popup.stack[Popup.stack.length-1];
	var rootLeft = findPosX(curr.root);
	var rootTop = findPosY(curr.root);
	var rootHeight = curr.root.offsetHeight;
	var popupLeft = rootLeft;
	var popupTop = rootTop + rootHeight;
	var popupWidth = curr.popup.offsetWidth;
	var winWidth = findWindowWidth();
        if (isChild(curr.root,'hoverMenu'))
              var x = config.hoverMenu.settings.x;
        else
              var x = 0;
	if(popupLeft + popupWidth+x > winWidth)
		popupLeft = winWidth - popupWidth -x;
        if (isChild(curr.root,'hoverMenu'))
  	        {curr.popup.style.right = x + "px";}
        else
                curr.popup.style.left = popupLeft + "px";
	curr.popup.style.top = popupTop + "px";
	curr.popup.style.display = "block";
	addClass(curr.root,"highlight");
	if(config.options.chkAnimate)
		anim.startAnimating(new Scroller(curr.popup,slowly));
	else
		window.scrollTo(0,ensureVisible(curr.popup));
}

window.isChild = function(e,parentId) {
        while (e != null) {
                var parent = document.getElementById(parentId);
                if (parent == e) return true;
                e = e.parentNode;
                }
        return false;
};
//}}}


HoverMenuPlugin updated to fix error with SelectThemePlugin
HoverMenuPlugin has been updated to include a jump macro, that allows jumping to any open tiddler. Also, the jump macro dropdown can optionally include a button to jump to the top of the screen.
//{{{
// version: beta 1.1
//replace macro buttons with icons
// params[0] = image location
//params[1] = image width
//params[2] = image height
//params[3] = image title (optional)
config.macros.icon={};
config.macros.icon.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{

               if (place.lastChild.tagName!="BR")
                     {
                     var tempTitle = place.lastChild.firstChild.title;
                     removeChildren(place.lastChild);
                     place.lastChild.className = "imgLink";
                     var img = createTiddlyElement(place.lastChild,"img");
                     img.src = params[0];
                     if (params[3])
                         img.title = params[3];
                     img.width= params[1];
                     img.height =params[2];
                     }
};

//use icons for toolbar commands.
// used in view template like:
// <span macro='commandIcon jump jump.bmp'></span>
//params[0] = command name
//params[1] = image location
config.macros.commandIcon={};
config.macros.commandIcon.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{if(!e) var e = window.event;
    var img = createTiddlyElement(place,"img",null,"toolbarImg");
    img.src = params[1];
    img.onclick = function(){config.commands[params[0]].handler(e,place,story.findContainingTiddler(place).getAttribute("tiddler"));};
    img.title = config.commands[params[0]].tooltip;
}

setStylesheet(".toolbarImg {vertical-align: middle; cursor:pointer;}\n","commandIconStyles"); 

//}}}
Tentative version of IconMacro, meant to replace buttons created by macros with images. Will only work for some macros and not at all for commands.... In use in the HoverMenu on the right.

Update: commandIcon macro added, that can be used to create Image icons that launch toolbar commands
This package defines a set of small icons appear adjacent to the title of each tiddler and indicate various information about the tiddler, such as whether it has unsaved changes, or has been changed recently, or has been tagged as<<tag Trash>>.  Additional icons indicate important categories of tiddlers (based on tags), such as plugins, scripts, templates, attachments, bookmarks, tasks, etc.

----
<<tiddler ShowAllIcons>>
----

{{fine italic{
Note: this package includes icons that are part of the "Silk" icon set: http://www.famfamfam.com/lab/icons/silk/ containing 1000 16-by-16 pixel icons in PNG format, created by Mark James, a part-time web developer, part-time student currently living in Birmingham, UK, and is licensed under a Creative Commons Attribution 2.5 License. Please visit http://www.famfamfam.com/ for further information and licensing details.}}}
http://www.TiddlyTools.com/images/
http://www.TiddlyTools.com/images/silk/icons/
/***
|Name|ImagePathPlugin|
|Source|http://www.TiddlyTools.com/#ImagePathPlugin|
|Version|0.7.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin,formatter|
|Requires||
|Overrides|'image' formatter|
|Description|Tell TiddlyWiki where to look for image files.  Permits multiple 'fallback' locations|
|Status|ALPHA - initial development/testing only - may be unstable - do not distribute|

!!!!!Usage
<<<
This plugin adds "resolvePath()" fallback processing to the {{{[img[...]]}}} formatter's handler, so that local image file references can be successfully resolved, even if the files cannot be located on the local filesystem.

The plugin tries alternative file "paths" that are listed, one per line, in an optional tiddler, [[ImagePathList]].  Each path in the list is combined with the image filename, which is then checked for existence, until the file is located.  If no alternative is found, or [[ImagePathList]] is not present, then a 'last-ditch' fallback is attempted using the remote system and path specified in [[SiteUrl]] (if present).

If no fallback attempt is successful (i.e., because no [[ImagePathList]] OR [[SiteUrl]] tiddlers have been defined), the plugin simply passes the original image file value along for default handling by the browser without any "path resolution" being applied.(i.e, the current TW core behavior occurs).

| ''Important note: This plugin may cause one or more security alert messages to appear, because it uses browser-specific functions that can require security permission in order to access the local filesystem to check for the existence of a given image file.  If you block local access, the 'last-ditch' fallback using the remote [[SiteUrl]] (if present) will be attempted.'' |

Note: the image formatter code contained here also includes support for AttachFilePlugin extensions (if installed).  AttachFilePlugin includes its own fallback mechanism for handling embedded vs. local file vs. remote URL references to the attached binary file.  Both methods may be used: ImagePathPlugin provides fallback for images contained in tiddler content, while AttachFilePlugin works well for access to non-image binary files (or images used in CSS as backgrounds, textures, etc.)
<<<
!!!!!Examples
<<<
coming soon...
<<<
!!!!!Revisions
<<<
''2007.04.13 [0.7.1]'' in testFile(), convert any file:// references to local native format before checking for existence.
''2007.03.26 [0.7.0]'' for IE, use onError handling to trigger call to resolvePath() so it will only be invoked if the original path/file is not found by the browser-native lookup.  This avoids an unneeded call to fileExists() and the accompanying ActiveX security alert message box (as well as being slightly more efficient...)
''2007.03.25 [0.6.0]'' code cleanup (moved global functions into config.formatterHelpers) plus documentation re-write
''2007.03.24 [0.5.0]'' initial implementation - ALPHA - do not distribute
<<<
!!!!!Code
***/
//{{{
version.extensions.imagePath = {major: 0, minor: 7, revision: 1, date: new Date(2007,4,13)};
//}}}
//{{{
// name of path definition tiddler
if (config.options.txtPathTiddler==undefined) config.options.txtPathTiddler="ImagePathList";
//}}}
//{{{
// low-level wrapper for platform-specific tests for local file existence
// returns true/false without visible error display
// Uses Components for FF and ActiveX FSO object for MSIE
// NOTE: this can cause a security warning on some browsers
config.formatterHelpers.fileExists=function(theFile) {
	var found=false;
	// DEBUG: alert('testing fileExists('+theFile+')...');
	if(window.Components) {
		try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
		catch(e) { return false; } // security access denied
		var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
		try { file.initWithPath(theFile); }
		catch(e) { return false; } // invalid directory
		found = file.exists();
	}
	else { // use ActiveX FSO object for MSIE 
		var fso = new ActiveXObject("Scripting.FileSystemObject");
		found = fso.FileExists(theFile)
	}
	// DEBUG: alert(theFile+" "+(found?"exists":"not found"));
	return found;
}
//}}}
//{{{
// higher-level logic for checking local file existence.
// with secondary check for finding relative file references
// and automatic OK of http-based references without checking local filesystem
config.formatterHelpers.testFile=function(theFile) {
	if (document.location.protocol!="file:") return true; // viewing remote document, can't test local filesystem... assume OK
	if (theFile.substr(0,5)=="http:") return true; // remote HTTP reference... assume OK
	if (theFile.substr(0,5)=="file:") theFile=getLocalPath(theFile); // convert local FILE reference to native format
	if (this.fileExists(theFile)) return true; // file exists locally... OK to use!
	// file might have been relative, add path from current document and try again
	var docPath=document.location.href;
	var slashpos=docPath.lastIndexOf("/"); if (slashpos==-1) slashpos=docPath.lastIndexOf("\\"); 
	if (slashpos!=-1 && slashpos!=docPath.length-1) docPath=docPath.substr(0,slashpos+1); // trim off filename
	if (this.fileExists(getLocalPath(docPath+theFile)))
		return true; // ah ha!... file exists relative to current document... OK to use!
	return false; // file not found on local system
}
//}}}
//{{{
// given a path/file string, check for existence and
// try alternatives (if any) defined in a tiddler
// with last-ditch using system/path from SiteUrl (if any)
config.formatterHelpers.resolvePath=function(theFile,testoriginal) {
	if (testoriginal && this.testFile(theFile)) return theFile; // FOUND FILE - use specified path/file without modification
	// get the filename portion only
	var slashpos=theFile.lastIndexOf("/"); if (slashpos==-1) slashpos=theFile.lastIndexOf("\\"); 
	var theName=(slashpos==-1)?theFile:theFile.substr(slashpos+1);
	// get list of fallbacks (if any)
	var pathText=store.getTiddlerText(config.options.txtPathTiddler);
	if (pathText && pathText.length) {
		var paths=pathText.split("\n");
		for (p=0; p<paths.length; p++) // combine path+filename until one works...
			if (this.testFile(paths[p]+theName))
				return paths[p]+theName; // FOUND FILE - use alternative path+filename
	}
	// try "last ditch" fallback using SiteURL - assumes that original path/file was relative to document location
	var siteURL=store.getTiddlerText("SiteUrl");
	if (!siteURL||!siteURL.length) return theFile; // NO FALLBACK - use original path/file and hope for the best
	// trim filename (if any) from site URL
	var slashpos=siteURL.lastIndexOf("/"); if (slashpos==-1) slashpos=siteURL.lastIndexOf("\\"); 
	if (slashpos!=-1 && slashpos!=siteURL.length-1) siteURL=siteURL.substr(0,slashpos+1);
	return siteURL+theFile; // LAST DITCH: use system/path from SiteUrl combined with original file/path
}
//}}}
//{{{
// replace standard handler for image formatter
// adds call to resolvePath() to handle fallback processing
// includes support for AttachFilePlugin as well
config.formatters[config.formatters.findByField("name","image")].handler=function(w) {
	if (!this.lookaheadRegExp)  // fixup for TW2.0.x
		this.lookaheadRegExp = new RegExp(this.lookahead,"mg");
	this.lookaheadRegExp.lastIndex = w.matchStart;
	var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
	if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
		// Simple bracketted link
		var e = w.output;
		if(lookaheadMatch[5]) {
			var link = lookaheadMatch[5];
			if (!config.formatterHelpers.isExternalLink) // fixup for TW2.0.x
				var external=!store.tiddlerExists(link)&&!store.isShadowTiddler(link);
			else
				var external=config.formatterHelpers.isExternalLink(link);
			if (external) {
				if (config.macros.attach && config.macros.attach.isAttachment(link)) { // ELS - attachments
					e = createExternalLink(w.output,link);
					e.href=config.macros.attach.getAttachment(link);
					e.title = config.macros.attach.linkTooltip + link;
				} else
					e = createExternalLink(w.output,link);
			} else 
				e = createTiddlyLink(w.output,link,false,null,w.isStatic);
			addClass(e,"imageLink");
		}
		var img = createTiddlyElement(e,"img");
		if(lookaheadMatch[1])
			img.align = "left";
		else if(lookaheadMatch[2])
			img.align = "right";
		if(lookaheadMatch[3])
			img.title = lookaheadMatch[3];
		if (config.macros.attach!=undefined && config.macros.attach.isAttachment(lookaheadMatch[4])) // ELS - attachments
			img.src=config.macros.attach.getAttachment(lookaheadMatch[4]);
		else {
			if (config.browser.isIE || config.browser.isSafari) { // ELS - path processing
				// IE and Safari use browser's onError handling to check the original file...
				// avoids extra security alert messages due to use of Components/ActiveX for filesystem access
				img.onerror=(function(){this.src=config.formatterHelpers.resolvePath(this.src,false);return false;});
				img.src=lookaheadMatch[4]; // ELS - path processing
			} else {
				// if NOT IE or Safari, always check the original path/file before rendering
				img.src=config.formatterHelpers.resolvePath(lookaheadMatch[4],true);
			}
		}
		w.nextMatch = this.lookaheadRegExp.lastIndex;
	}
}
//}}}
/***
|Name|ImageSizePlugin|
|Source|http://www.TiddlyTools.com/#ImageSizePlugin|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin,formatter|
|Requires||
|Overrides|'image' formatter|
|Description|extends image syntax to add optional CSS width/height values|
!!!!!Usage
<<<
Extends standard TiddlyWiki image syntax, ''{{{[img[...]]}}}'', so you can specify CSS width/height values.

The extended syntax is:
>''{{{[img(x,y)[...]]}}}''
>where x and y are the desired width and height of the image, specified using CSS units of measurement (e.g., px, em, cm, in, or %).  Use ''auto'' for either the width or height to scale image proportionally (i.e., maintain aspect ratio).  You may also calculate a CSS value on-the-fly by using //evaluated javascript//, enclosed between """{{""" and """}}""", e.g, {{{({{widthFunction()}},{{heightFunction()}})}}}.

Note: this plugin also includes enhancements to support:
*[[AttachFilePluginFormatters]] (embed image files as text-encoded tiddlers)
* [[ImagePathPlugin]] (fallback locations for missing images)
Please refer to those plugins for details...
<<<
!!!!!Examples
<<<
{{{
[<img(34%,auto)[images/meow.gif]]
[<img(21%,auto)[images/meow.gif]]
[<img(13%,auto)[images/meow.gif]]
[<img(8%,auto)[images/meow.gif]]
[<img(5%,auto)[images/meow.gif]]
[<img(3%,auto)[images/meow.gif]]
[<img(2%,auto)[images/meow.gif]]
[img(1%,auto)[images/meow.gif]]
}}}
[<img(34%,auto)[images/meow.gif]]
[<img(21%,auto)[images/meow.gif]]
[<img(13%,auto)[images/meow.gif]]
[<img(8%,auto)[images/meow.gif]]
[<img(5%,auto)[images/meow.gif]]
[<img(3%,auto)[images/meow.gif]]
[<img(2%,auto)[images/meow.gif]]
[img(1%,auto)[images/meow.gif]]
{{clear block{}}}
<<<
!!!!!Revisions
<<<
2008.01.19 [1.1.0] added support for evaluated width/height values!!
2008.01.18 [1.0.1] code cleanup plus improved regexp for matching "(width,height)" by eliminating hard-coded recognition of [px,em,cm,in,%] CSS units.  Syntax now accepts ANY values for width/height, and leaves it to the browser's CSS processing to handle any invalid values.
2008.01.17 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.imageSize = {major: 1, minor: 1, revision: 0, date: new Date(2008,1,19)};

// replace standard handler for image formatter
// note: includes modifications for [[AttachFilePluginFormatters]] AND [[ImagePathPlugin]]
var f=config.formatters.findByField("name","image");
config.formatters[f].match="\\[[<>]?[Ii][Mm][Gg](?:\\([^,]*,[^\\)]*\\))?\\[";
config.formatters[f].lookaheadRegExp=/\[([<]?)(>?)[Ii][Mm][Gg](\([^,]*,[^\)]*\))?\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg;
config.formatters[f].handler=function(w) {
	this.lookaheadRegExp.lastIndex = w.matchStart;
	var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
	if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
		var floatLeft=lookaheadMatch[1];
		var floatRight=lookaheadMatch[2];
		var XY=lookaheadMatch[3];
		var tooltip=lookaheadMatch[4];
		var src=lookaheadMatch[5];
		var link=lookaheadMatch[6];
		// Simple bracketted link
		var e = w.output;
		if(link) { // LINKED IMAGE
			if (config.formatterHelpers.isExternalLink(link)) {
				if (config.macros.attach && config.macros.attach.isAttachment(link)) {
					// see [[AttachFilePluginFormatters]]
					e = createExternalLink(w.output,link);
					e.href=config.macros.attach.getAttachment(link);
					e.title = config.macros.attach.linkTooltip + link;
				} else
					e = createExternalLink(w.output,link);
			} else 
				e = createTiddlyLink(w.output,link,false,null,w.isStatic);
			addClass(e,"imageLink");
		}
		var img = createTiddlyElement(e,"img");
		if(floatLeft) img.align="left"; else if(floatRight) img.align="right"; // FLOAT LEFT/RIGHT
		if(XY) { // CUSTOM SIZE with optional EVAL'ED width/height ({{...}},{{...}})
			var parts=XY.replace(/[\(\)]/g,'').split(","); var x=parts[0]; var y=parts[1];
			if (x.substr(0,2)=="{{") {
				try{img.style.width=eval(x.substr(2,x.length-4));}
				catch(e){displayMessage(e.description||e.toString())}
			} else img.style.width=x;

			if (y.substr(0,2)=="{{") {
				try{img.style.height=eval(y.substr(2,y.length-4));}
				catch(e){displayMessage(e.description||e.toString())}
			} else img.style.height=y;
		}
		if(tooltip) img.title = tooltip; // TOOLTIP
		// GET IMAGE SOURCE (get attachment or resolve fallback path as needed)
		if (config.macros.attach && config.macros.attach.isAttachment(src))
			src=config.macros.attach.getAttachment(src); // see [[AttachFilePluginFormatters]]
		else if (config.formatterHelpers.resolvePath) { // see [[ImagePathPlugin]]
			// Note: IE and Safari use onError to call resolvePath() only if initial lookup fails
			// (avoids security messages for initial filesystem access)... otherwise, attempt to
			// resolve the original path/file before initial rendering
			if (config.browser.isIE || config.browser.isSafari) {
				img.onerror=(function(){
					this.src=config.formatterHelpers.resolvePath(this.src,false);
					return false;
				});
			} else
				src=config.formatterHelpers.resolvePath(lookaheadMatch[5],true);
		}
		img.src=src; // RENDER IMAGE
		w.nextMatch = this.lookaheadRegExp.lastIndex;
	}
}
//}}}
/***
|Name|InlineJavascriptPlugin|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.9.2|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Insert Javascript executable code directly into your tiddler content.|
''Call directly into TW core utility routines, define new functions, calculate values, add dynamically-generated TiddlyWiki-formatted output'' into tiddler content, or perform any other programmatic actions each time the tiddler is rendered.
!!!!!Documentation
>see [[InlineJavascriptPluginInfo]]
!!!!!Revisions
<<<
2008.03.03 [1.9.2] corrected declaration of wikifyPlainText() for 'TW 2.1.x compatibility fallback' (fixes Safari "parse error")
2008.02.23 [1.9.1] in onclick function, use string instead of array for 'bufferedHTML' attribute on link element (fixes IE errors)
2008.02.21 [1.9.0] 'onclick' scripts now allow returned text (or document.write() calls) to be wikified into a span that immediately follows the onclick link.  Also, added default 'return false' handling if no return value provided (prevents HREF from being triggered -- return TRUE to allow HREF to be processed).  Thanks to Xavier Verges for suggestion and preliminary code.
|please see [[InlineJavascriptPluginInfo]] for additional revision details|
2005.11.08 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.inlineJavascript= {major: 1, minor: 9, revision: 2, date: new Date(2008,3,3)};

config.formatters.push( {
	name: "inlineJavascript",
	match: "\\<script",
	lookahead: "\\<script(?: src=\\\"((?:.|\\n)*?)\\\")?(?: label=\\\"((?:.|\\n)*?)\\\")?(?: title=\\\"((?:.|\\n)*?)\\\")?(?: key=\\\"((?:.|\\n)*?)\\\")?( show)?\\>((?:.|\\n)*?)\\</script\\>",

	handler: function(w) {
		var lookaheadRegExp = new RegExp(this.lookahead,"mg");
		lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = lookaheadRegExp.exec(w.source)
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var src=lookaheadMatch[1];
			var label=lookaheadMatch[2];
			var tip=lookaheadMatch[3];
			var key=lookaheadMatch[4];
			var show=lookaheadMatch[5];
			var code=lookaheadMatch[6];
			if (src) { // load a script library
				// make script tag, set src, add to body to execute, then remove for cleanup
				var script = document.createElement("script"); script.src = src;
				document.body.appendChild(script); document.body.removeChild(script);
			}
			if (code) { // there is script code
				if (show) // show inline script code in tiddler output
					wikify("{{{\n"+lookaheadMatch[0]+"\n}}}\n",w.output);
				if (label) { // create a link to an 'onclick' script
					// add a link, define click handler, save code in link (pass 'place'), set link attributes
					var link=createTiddlyElement(w.output,"a",null,"tiddlyLinkExisting",wikifyPlainText(label));
					var fixup=code.replace(/document.write\s*\(/gi,'place.bufferedHTML+=(');
					link.code="function _out(place){"+fixup+"\n};_out(this);"
					link.tiddler=w.tiddler;
					link.onclick=function(){
						this.bufferedHTML="";
						try{ var r=eval(this.code);
							if(this.bufferedHTML.length || (typeof(r)==="string")&&r.length)
								var s=this.parentNode.insertBefore(document.createElement("span"),this.nextSibling);
							if(this.bufferedHTML.length)
								s.innerHTML=this.bufferedHTML;
							if((typeof(r)==="string")&&r.length) {
								wikify(r,s,null,this.tiddler);
								return false;
							} else return r!==undefined?r:false;
						} catch(e){alert(e.description||e.toString());return false;}
					};
					link.setAttribute("title",tip||"");
					var URIcode='javascript:void(eval(decodeURIComponent(%22(function(){try{';
					URIcode+=encodeURIComponent(encodeURIComponent(code.replace(/\n/g,' ')));
					URIcode+='}catch(e){alert(e.description||e.toString())}})()%22)))';
					link.setAttribute("href",URIcode);
					link.style.cursor="pointer";
					if (key) link.accessKey=key.substr(0,1); // single character only
				}
				else { // run inline script code
					var fixup=code.replace(/document.write\s*\(/gi,'place.innerHTML+=(');
					var code="function _out(place){"+fixup+"\n};_out(w.output);"
					try { var out=eval(code); } catch(e) { out=e.description?e.description:e.toString(); }
					if (out && out.length) wikify(out,w.output,w.highlightRegExp,w.tiddler);
				}
			}
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
	}
} )
//}}}

// // Backward-compatibility for TW2.1.x and earlier
//{{{
if (typeof(wikifyPlainText)=="undefined") window.wikifyPlainText=function(text,limit,tiddler) {
	if(limit > 0) text = text.substr(0,limit);
	var wikifier = new Wikifier(text,formatter,null,tiddler);
	return wikifier.wikifyPlain();
}
//}}}
/***
|Name|InlineJavascriptPluginInfo|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.9.2|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|Documentation for InlineJavascriptPlugin|
''Call directly into TW core utility routines, define new functions, calculate values, add dynamically-generated TiddlyWiki-formatted output'' into tiddler content, or perform any other programmatic actions each time the tiddler is rendered.
!!!!!Usage
<<<
This plugin adds wiki syntax for surrounding tiddler content with {{{<script>}}} and {{{</script>}}} markers, so that it can be recognized as embedded javascript code.
<script show>
	/* javascript code goes here... */
</script>Every time the tiddler content is rendered, the javascript code is automatically evaluated, allowing you to invoke 'side-effect' processing and/or produce dynamically-generated content that is then inserted into the tiddler content, immediately following the script (see below).  By including the optional ''show'' keyword as the final parameter in a {{{<script>}}} marker, the plugin will also include the script source code in the output that it displays in the tiddler.  This is helpful when creating examples for documentation purposes (such as used in this tiddler!)

__''Deferred execution from an 'onClick' link''__
<script label="click here" title="mouseover tooltip text" key="X" show>
	/* javascript code goes here... */
	alert('you clicked on the link!');
</script>
By including a {{{label="..."}}} parameter in the initial {{{<script>}}} marker, the plugin will create a link to an 'onclick' script that will only be executed when that specific link is clicked, rather than running the script each time the tiddler is rendered.  You may also include a {{{title="..."}}} parameter to specify the 'tooltip' text that will appear whenever the mouse is moved over the onClick link text, and a {{{key="X"}}} parameter to specify an //access key// (which must be a //single// letter or numeric digit only).

__''Loading scripts from external source files''__
<script src="URL" show>
	/* optional javascript code goes here... */
</script>You can also load javascript directly from an external source URL, by including a src="..." parameter in the initial {{{<script>}}} marker (e.g., {{{<script src="demo.js"></script>}}}).  This is particularly useful when incorporating third-party javascript libraries for use in custom extensions and plugins.  The 'foreign' javascript code remains isolated in a separate file that can be easily replaced whenever an updated library file becomes available.

In addition to loading the javascript from the external file, you can also use this feature to invoke javascript code contained within the {{{<script>...</script>}}} markers.  This code is invoked //after// the external script file has been processed, and can make immediate use of the functions and/or global variables defined by the external script file.
>Note: To ensure that your javascript functions are always available when needed, you should load the libraries from a tiddler that is rendered as soon as your TiddlyWiki document is opened, such as MainMenu.  For example: put your {{{<script src="..."></script>}}} syntax into a separate 'library' tiddler (e.g., LoadScripts), and then add {{{<<tiddler LoadScripts>>}}} to MainMenu so that the library is loaded before any other tiddlers that rely upon the functions it defines. 
>
>Normally, loading external javascript in this way does not produce any direct output, and should not have any impact on the appearance of your MainMenu.  However, if your LoadScripts tiddler contains notes or other visible content, you can suppress this output by using 'inline CSS' in the MainMenu, like this: {{{@@display:none;<<tiddler LoadScripts>>@@}}}
<<<
!!!!!Creating dynamic tiddler content and accessing the ~TiddlyWiki DOM
<<<
An important difference between TiddlyWiki inline scripting and conventional embedded javascript techniques for web pages is the method used to produce output that is dynamically inserted into the document: in a typical web document, you use the {{{document.write()}}} (or {{{document.writeln()}}}) function to output text sequences (often containing HTML tags) that are then rendered when the entire document is first loaded into the browser window.

However, in a ~TiddlyWiki document, tiddlers (and other DOM elements) are created, deleted, and rendered "on-the-fly", so writing directly to the global 'document' object does not produce the results you want (i.e., replacing the embedded script within the tiddler content), and instead will //completely replace the entire ~TiddlyWiki document in your browser window (which is clearly not a good thing!)//.  In order to allow scripts to use {{{document.write()}}}, the plugin automatically converts and buffers all HTML output so it can be safely inserted into your tiddler content, immediately following the script.

''Note that {{{document.write()}}} can only be used to output "pure HTML" syntax.  To produce //wiki-formatted// output, your script should instead return a text value containing the desired wiki-syntax content'', which will then be automatically rendered immediately following the script.  If returning a text value is not sufficient for your needs, the plugin also provides an automatically-defined variable, 'place', that gives the script code ''direct access to the //containing DOM element//'' into which the tiddler output is being rendered.  You can use this variable to ''perform direct DOM manipulations'' that can, for example:
* generate wiki-formatted output using {{{wikify("...content...",place)}}}
* vary the script's actions based upon the DOM element in which it is embedded
* access 'tiddler-relative' DOM information using {{{story.findContainingTiddler(place)}}}
Note:
''When using an 'onclick' script, the 'place' element actually refers to the onclick //link text// itself, instead of the containing DOM element.''  This permits you to directly reference or modify the link text to reflect any 'stateful' conditions that might set by the script.  To refer to the containing DOM element from within an 'onclick' script, you can use "place.parentNode" instead.
<<<
!!!!!Instant "bookmarklets"
<<<
You can also use an 'onclick' link to define a "bookmarklet": a small piece of javascript that can be ''invoked directly from the browser without having to be defined within the current document.''  This allows you to create 'stand-alone' commands that can be applied to virtually ANY TiddlyWiki document... even remotely-hosted documents that have been written by others!!  To create a bookmarklet, simply define an 'onclick' script and then grab the resulting link text and drag-and-drop it onto your browser's toolbar (or right-click and use the 'bookmark this link' command to add it to the browser's menu).

Notes:
*When writing scripts intended for use as bookmarklets, due to the ~URI-encoding required by the browser, ''you cannot not use ANY double-quotes (") within the bookmarklet script code.''
*All comments embedded in the bookmarklet script must ''use the fully-delimited {{{/* ... */}}} comment syntax,'' rather than the shorter {{{//}}} comment syntax.
*Most importantly, because bookmarklets are invoked directly from the browser interface and are not embedded within the TiddlyWiki document, there is NO containing 'place' DOM element surrounding the script.  As a result, ''you cannot use a bookmarklet to generate dynamic output in your document,''  and using {{{document.write()}}} or returning wiki-syntax text or making reference to the 'place' DOM element will halt the script and report a "Reference Error" when that bookmarklet is invoked.  
Please see [[InstantBookmarklets]] for many examples of 'onclick' scripts that can also be used as bookmarklets.
<<<
!!!!!Special reserved function name
<<<
The plugin 'wraps' all inline javascript code inside a function, {{{_out()}}}, so that any return value you provide can be correctly handled by the plugin and inserted into the tiddler.  To avoid unpredictable results (and possibly fatal execution errors), this function should never be redefined or called from ''within'' your script code.
<<<
!!!!!Examples
<<<
simple dynamic output:
><script show>
	document.write("The current date/time is: "+(new Date())+"<br>");
	return "link to current user: [["+config.options.txtUserName+"]]\n";
</script>
dynamic output using 'place' to get size information for current tiddler:
><script show>
	if (!window.story) window.story=window;
	var title=story.findContainingTiddler(place).getAttribute("tiddler");
	var size=store.getTiddlerText(title).length;
	return title+" is using "+size+" bytes";
</script>
dynamic output from an 'onclick' script, using {{{document.write()}}} and/or {{{return "..."}}}
><script label="click here" show>
	document.write("<br>The current date/time is: "+(new Date())+"<br>");
	return "link to current user: [["+config.options.txtUserName+"]]\n";
</script>
creating an 'onclick' button/link that accesses the link text AND the containing tiddler:
><script label="click here" title="clicking this link will show an 'alert' box" key="H" show>
	if (!window.story) window.story=window;
	var txt=place.firstChild.data;
	var tid=story.findContainingTiddler(place).getAttribute('tiddler');
	alert('Hello World!\nlinktext='+txt+'\ntiddler='+tid);
</script>
dynamically setting onclick link text based on stateful information:
>{{block{
{{{
<script label="click here">
	/* toggle "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.innerHTML=on?"enable":"disable";
	config.txtSomething=on?"OFF":"ON";
	return "\nThe current value is: "+config.txtSomething;
</script><script>
	/* initialize onclick link text based on current "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.lastChild.previousSibling.innerHTML=on?"disable":"enable";
</script>
}}}
<script label="click here">
	/* toggle "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.innerHTML=on?"enable":"disable";
	config.txtSomething=on?"OFF":"ON";
	return "\nThe current value is: "+config.txtSomething;
</script><script>
	/* initialize onclick link text based on current "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.lastChild.innerHTML=on?"enable":"disable";
</script>
}}}
loading a script from a source url:
>http://www.TiddlyTools.com/demo.js contains:
>>{{{function inlineJavascriptDemo() { alert('Hello from demo.js!!') } }}}
>>{{{displayMessage('InlineJavascriptPlugin: demo.js has been loaded');}}}
>note: When using this example on your local system, you will need to download the external script file from the above URL and install it into the same directory as your document.
>
><script src="demo.js" show>
	return "inlineJavascriptDemo() function has been defined"
</script>
><script label="click to invoke inlineJavascriptDemo()" key="D" show>
	inlineJavascriptDemo();
</script>
<<<
!!!!!Revisions
<<<
2008.03.03 [1.9.2] corrected declaration of wikifyPlainText() for 'TW 2.1.x compatibility fallback' (fixes Safari "parse error")
2008.02.23 [1.9.1] in onclick function, use string instead of array for 'bufferedHTML' attribute on link element (fixes IE errors)
2008.02.21 [1.9.0] 'onclick' scripts now allow returned text (or document.write() calls) to be wikified into a span that immediately follows the onclick link.  Also, added default 'return false' handling if no return value provided (prevents HREF from being triggered -- return TRUE to allow HREF to be processed).  Thanks to Xavier Verges for suggestion and preliminary code.
2008.02.14 [1.8.1] added backward-compatibility for use of wikifyPlainText() in TW2.1.3 and earlier
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.28 [1.8.0] added support for key="X" syntax to specify custom access key definitions
2007.12.15 [1.7.0] autogenerate URI encoded HREF on links for onclick scripts.  Drag links to browser toolbar to create bookmarklets.  IMPORTANT NOTE: place is NOT defined when scripts are used as bookmarklets.  In addition, double-quotes will cause syntax errors.  Thanks to PaulReiber for debugging and brainstorming.
2007.11.26 [1.6.2] when converting "document.write()" function calls in inline code, allow whitespace between "write" and "(" so that "document.write ( foobar )" is properly converted.
2007.11.16 [1.6.1] when rendering "onclick scripts", pass label text through wikifyPlainText() to parse any embedded wiki-syntax to enable use of HTML entities or even TW macros to generate dynamic label text.
2007.02.19 [1.6.0] added support for title="..." to specify mouseover tooltip when using an onclick (label="...") script
2006.10.16 [1.5.2] add newline before closing '}' in 'function out_' wrapper.  Fixes error caused when last line of script is a comment.
2006.06.01 [1.5.1] when calling wikify() on script return value, pass hightlightRegExp and tiddler params so macros that rely on these values can render properly
2006.04.19 [1.5.0] added 'show' parameter to force display of javascript source code in tiddler output
2006.01.05 [1.4.0] added support 'onclick' scripts.  When label="..." param is present, a button/link is created using the indicated label text, and the script is only executed when the button/link is clicked.  'place' value is set to match the clicked button/link element.
2005.12.13 [1.3.1] when catching eval error in IE, e.description contains the error text, instead of e.toString().  Fixed error reporting so IE shows the correct response text.  Based on a suggestion by UdoBorkowski
2005.11.09 [1.3.0] for 'inline' scripts (i.e., not scripts loaded with src="..."), automatically replace calls to 'document.write()' with 'place.innerHTML+=' so script output is directed into tiddler content.  Based on a suggestion by BradleyMeck
2005.11.08 [1.2.0] handle loading of javascript from an external URL via src="..." syntax
2005.11.08 [1.1.0] pass 'place' param into scripts to provide direct DOM access 
2005.11.08 [1.0.0] initial release
<<<
/%
|Name|InstantBookmarklets|
|Source|http://www.TiddlyTools.com/#InstantBookmarklets|
|Version|2.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|instantly create bookmarklets by dragging onclick links to the browser toolbar|

See [[InlineJavascriptPluginInfo]] for bookmarklet authoring documentation

%/{{nowrap{
__[[InstantBookmarklets:|InstantBookmarklets]]__{{fine{__// drag these links to your browser toolbar!//__ <script label="(help...)">
alert("To create a bookmarklet, simply drag-and-drop any command link below directly onto your browser's toolbar or right-click and use 'bookmark this link' (or 'add to favorites') to add the bookmarklet to your browser's bookmarks menu.  Once installed, you can use the bookmarklet with ANY TiddlyWiki document, even if the command script (and InlineJavascriptPlugin) has not been installed in that document!");
</script>}}}

//~TiddlyWiklets: {{fine{(TiddlyWiki "tear-off" utilities)}}}///%

========================== TOGGLE SITE TITLES %/
*<script label="&#x25b2; - Toggle site titles" title="show/hide SiteTitle and SiteSubtitle (header) content">
	var c=document.getElementById('contentWrapper');  if (!c) return;
	for (var i=0; i<c.childNodes.length; i++)
		if (hasClass(c.childNodes[i],'header')) { var h=c.childNodes[i]; break; }
	if (!h) return;
	config.options.chkHideSiteTitles=h.style.display!='none';
	h.style.display=config.options.chkHideSiteTitles?'none':'block';
	saveOptionCookie('chkHideSiteTitles');
	return false;
</script>/%

========================== TOGGLE LEFT SIDEBAR %/
*<<tiddler ToggleLeftSidebar with: "&#x25c4; - Toggle left sidebar">>/%

========================== TOGGLE RIGHT SIDEBAR %/
*<<tiddler ToggleRightSidebar with: "&#x25ba; - Toggle right sidebar">>/%

========================== TOGGLE ANIMATION EFFECTS %/
*<<tiddler ToggleAnimations with: "&infin; - Toggle animation effects">>/%

========================== TOGGLE SINGLE PAGE MODE %/
*<<tiddler ToggleSinglePageMode with: "1 - Toggle single-page mode">>/%

========================== TOGGLE "FULLSCREEN" (SIDEBARS AND TITLES) %/
*<<tiddler ToggleFullScreen with: "&loz; - Toggle fullscreen">>/%

========================== TOGGLE TIDDLER TITLES (and SUBTITLES) %/
*<<tiddler ToggleTiddlerTitles with: "T - Toggle tiddler titles">>/%

========================== TOGGLE TIDDLER TAGS %/
*<<tiddler ToggleTiddlerTags with: "# - Toggle tiddler tags">>/%

========================== RESTART WITHOUT RELOADING %/
*<script label="&#x2302; - Home" title="Restart initial page content WITHOUT RELOADING!">
	story.closeAllTiddlers(); restart(); refreshPageTemplate(); 
 	return false;
</script>/%

========================== REFRESH WITHOUT RESTARTING %/
*<<tiddler RefreshPageDisplay with: "&asymp; - Refresh current display">>/%

========================== SHOW CURRENT VERSION, TIMESTAMP, and TIDDLER INFO %/
*<<tiddler ShowDocumentInfo>>/%

========================== RESET TIDDLYWIKI OPTION COOKIES (WITH CONFIRM) %/
*<<tiddler ResetOptionCookies>>/%

========================== CLEAR CHANGE COUNTERS %/
*<<tiddler ResetChangeCounters>>/%

========================== RESCUE STORE AREA (adapted from http://www.TiddlyWiki.com/#TiddlyBookmarklets) %/
*<<tiddler RescueStoreAreaCommand with: "&sum; - Rescue current storeArea contents">>/%

========================== LOAD REMOTE PLUGINS... %/

//Load remote plugins: {{fine{(load on demand)}}}///%

========================== TiddlyTools (Eric Shulman)...%/
*[[TiddlyTools|http://www.TiddlyTools.com/]]{{block{/%

========================== LOAD IMPORT TIDDLERS PLUGIN
%/<<tiddler LoadRemotePlugin with:
	[[ImportTiddlersPlugin]]
	[[Load ImportTiddlersPlugin from svn.TiddlyWiki.org repository]]
	[[http://svn.tiddlywiki.org/Trunk/contributors/EricShulman/plugins/ImportTiddlersPlugin.js]]
	[[window.story.displayTiddler(null,'ImportTiddlers')]]
	[[version.extensions.importTiddlers!=undefined]]
>>/%

========================== LOAD TIDDLER TWEAKER PLUGIN
%/<<tiddler LoadRemotePlugin with:
	[[TiddlerTweakerPlugin]]
	[[Load TiddlerTweakerPlugin from svn.TiddlyWiki.org repository]]
	[[http://svn.tiddlywiki.org/Trunk/contributors/EricShulman/plugins/TiddlerTweakerPlugin.js]]
	[[window.story.displayTiddler(null,'TiddlerTweaker')]]
	[[version.extensions.tiddlerTweaker!=undefined]]
>>/%

========================== LOAD REARRANGE TIDDLERS PLUGIN
%/<<tiddler LoadRemotePlugin with:
	[[RearrangeTiddlersPlugin]]
	[[Load RearrangeTiddlersPlugin from www.TiddlyTools.com]]
	[[http://www.TiddlyTools.com/plugins/RearrangeTiddlersPlugin.js]]
	[[window.story.forEachTiddler(function(t,e){window.story.refreshTiddler(t,null,true)}); window.refreshDisplay()]]
	[[Story.prototype.rearrangeTiddlersHijack_refreshTiddler!=undefined]]
>>/%

%/}}}/%

========================== Abego Software (Udo Borkowski)...%/
*[[Abego Software|http://tiddlywiki.abego-software.de/]]{{block{/%

========================== LOAD YOURSEARCH PLUGIN
%/<<tiddler LoadRemotePlugin with:
	[[YourSearchPlugin]]
	[[Load YourSearchPlugin from tiddlywiki.abego-software.de]]
	[[http://tiddlywiki.abego-software.de/archive/YourSearchPlugin/Plugin-YourSearch-src.2.1.1.js]]
	[[window.refreshPageTemplate()]]
	[[version.extensions.YourSearchPlugin!=undefined]]
>>/%
%/}}}/%

========================== Firefox Privileges (Xavier Vergés) %/
*[[FirefoxPrivileges.TiddlySpot.com|http://firefoxprivileges.tiddlyspot.com/]]{{block{/%

========================== LOAD AND DISPLAY FIREFOX PRIVILEGE MANAGER
%/<<tiddler LoadRemotePlugin with:
	[[Firefox Privilege Manager]]
	[[Load Firefox Privilege Manager from svn.TiddlyWiki.org repository]]
	[[http://svn.tiddlywiki.org/Trunk/contributors/XavierVerges/plugins/FirefoxPrivilegesPlugin.js]]
	[[config.macros.firefoxPrivileges.onload()]]
	[[config.macros.firefoxPrivileges!=undefined]]
	[[backstage.switchTab("firefoxPrivileges")]]
>>/%
%/}}}/%

========================== Jash (Billy Reisinger) %/
*[[BillyReisinger.com:|http://www.billyreisinger.com/jash/]]{{block{/%

========================== LOAD AND DISPLAY JAVASCRIPT SHELL
%/<<tiddler LoadRemotePlugin with:
	[[Jash (JAvascript SHell)]]
	[[Load Jash (JAvascript SHell) from www.billyreisinger.com/jash]]
	[[http://www.billyreisinger.com/jash/source/latest/Jash.js]]
	[[window.jash.close()]]
	[[window.jash!=undefined]]
>>/%
%/}}}

}}}/%  END NOWRAP %/
/%
|''URL:''|http://jackparke.googlepages.com/jtw.html|
|''Description:''|Plugins, Macros and Hacks|
|''Author:''|JackParker|
%/
/*{{{*/
/**
* $Id: Jash.css,v 1.3 2007/11/16 03:06:33 billyreisinger Exp $
*
* Jash - JavaScript Shell
* Copyright: 2007, Billy Reisinger
* Documentation: http://www.billyreisinger.com/jash/
* License: GNU General Public License - http://www.gnu.org/licenses/gpl.html
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
**/
#JashParent {
	width: 581px;
	height: 450px;
	border: 1px solid gray;
	-moz-border-radius: 10px; /* ELS */
	color: black;
	z-index: 10000;
	overflow: hidden;
	background: #ccc;
	opacity: 0.90;
	filter: alpha(opacity=90);
	position: absolute;
	left: 25%;
	color: black;
	font-family: monospace;
	margin: 0;
}
#JashParent div {
	margin: 0;
}
#JashParent a, #JashParent a:visited, #JashParent a:active, #JashParent a:hover {
	text-decoration: none;
	color: black;
}
.transparentMode {
	opacity: 0.20 !important;
	filter: alpha(opacity=20) !important;
}
#JashDragBar {
	BACKGROUND: gray;
	CURSOR: move;
	COLOR: white;
	font-family: arial,helvetica,sans-serif; /* ELS - changed from monospace to arial,helvetica,sans-serif */
	font-weight: bold;
	text-indent: 4px;
	font-size: 14pt; /* ELS - changed from 14px to 14pt */
	HEIGHT: 25px;
	TEXT-ALIGN: left;
	overflow: hidden;
	border: 1px outset white;
	-moz-border-radius-topleft: 10px; /* ELS */
	-moz-border-radius-topright: 10px; /* ELS */
}
.JashXButton {
    border: 1px solid white;
    -moz-border-radius: 5px; /* ELS */
    color: white !important;
    position: absolute;
    background: #bbb;
    width: 20px; 
    text-align: center;
    display: block;
    right: 3px; _right: 1px;
    top: 4px; _top: 1px;
    font-family: arial,helvetica,sans-serif; /* ELS - changed to arial,helvetica,sans-serif */
    font-size: 8pt; /* ELS - changed from 18px to 8pt */
    cursor: pointer;
}
a.JashXButton:hover {
	background: #ddd; 
}
#JashTextareaWrap {
	width: 100%;
	_height: 420px;
}
html>body #JashTextareaWrap {
	height: 100%;
}
#JashOutput {
	border: 2px inset white;
	FONT-SIZE: 10px;
	font-family: "Lucida Console", monaco, monospace;
	BACKGROUND: black;
	width: 99%;
	COLOR: lightgreen;
	PADDING: 2px;
	height: 60%;
	height: expression(parseInt(this.parentNode.parentNode.offsetHeight * (3/5)) + 'px');
	
}
#JashInput {
	padding: 2px;
	WIDTH: 99%;
	border: 2px inset white;
	-moz-border-radius-bottomleft: 10px; /* ELS */
	-moz-border-radius-bottomright: 10px; /* ELS */
	HEIGHT: 25%;
	font-family: monospace;
	font-size: 11px;
	height: expression(parseInt(this.parentNode.parentNode.offsetHeight * (3/13)) + 'px');
}
#JashParent .cssEntry {
	background: lightgreen;
	font-size: 11px;
	font-family: monospace;
}
#JashBottomBar {
	BACKGROUND: #ccc;
	POSITION: relative;
	HEIGHT: 20px;
	overflow: hidden;
	margin-top: 2px;
}
#JashBottomBar a {
	HEIGHT: 14px;
	font-size: 9px;
	font-weight: normal;
	font-family: arial;
	float: left;
	padding: 4px;
	background: #eee;
	cursor: pointer;
	border: 1px outset white;
	margin-right: 1px;
}
#JashBottomBar a:hover {
	padding-top: 3px;
	padding-bottom: 5px;
	background-color: white;
}
#JashBottomBar a:active, #JashBottomBar a:focus {
	padding-top: 5px;
	padding-bottom: 3px;
	background-color: #ddd;
}
#JashResizeButton {
	BORDER: 1px solid gray;
	-moz-border-radius-bottomright: 10px; /* ELS */
	BACKGROUND: #eee;
	WIDTH: 17px;
	height: 17px;
	line-height: 0;
	CURSOR: move;
	position: absolute;
	bottom: -1px;
	right: -1px;
	z-index: 2000;
}
/*}}}*/
//{{{
// Jash - JavaScript Shell
// Copyright: 2007, Billy Reisinger
// Documentation: http://www.billyreisinger.com/jash/
// License: GNU General Public License - http://www.gnu.org/licenses/gpl.html

// MODIFIED BY ELS (www.TiddlyTools.com) on 12/11/2007 for embedded use within TiddlyWiki documents
// * disabled setting of stylesheet from remote URL - use internal CSS definitions instead (see [[jash.css]] tiddler)
// * disabled automatic display on startup (but initialize jash panel so ESC key will work)

window.Jash=function(){this.jashRoot="http://www.billyreisinger.com/jash/source/latest/";this.domGetElFunctions={id:new Array("document.getElementById","$"),className:new Array("getElementsByClassName","$C")};var line="-------------------------------------------------";var _null="nooutput";this.revision="$Revision: 1.14 $".replace(/(\$|[A-Za-z]|\s|:)/g,'');this.version="$Name: REL_1_35_7 $".replace(/\$|Name:|\s|REL_/g,'').replace(/_/g,'.');this.versionDate="$Date: 2007/11/16 03:24:54 $";this.main=function(){this.browser=this.returnBrowserType();this.lineNumber=0;this.mainBlock;this.output=document.getElementById("JashOutput");this.input;this.outputHistory=new Array();this.cssEvalFlag=false;this.innerHtmlInspection=false;this.accessKeyText=this.getAccessKeyText();this.defaultText="Jash, v"+this.version+"\nEnter \"jash.help()\" for a list of commands.\n";this.cls=this.clear;this.tabIndexIndex=0;this.currentNode={};this.tips=["Did you know?\nThe DOM Inspector will automatically put\n an element with an ID in the input field for you.","Did you know?\nYou can tie this script into your own to jash scripts. Use 'jash.methodName' anywhere\n in your scripts, and pull\n up this window before executing to see\n the results.","Did you know?\nUse jash.stopWatch.start() and jash.stopWatch.stop() to\n time execution speeds! Handy for optimization.","Did you know?\nPress TAB to complete a function, method, or property name.\n If more than one match is found, a list of possible\n matches will appear.","Did you know?\nYou can use jash.show() to show a list of the names\nand types of an object's members.\nOn the other hand, jash.dump will show names and\n_values_ of an object's members.","Whoa ---- you can now tab-complete HTML element ids after typing document.getElementsById(' (or the '$' shorthand if using Prototype).  This also works with class names (i.e. document.getElementsByClassName)"]
this.defaultText+=line+"\n"+this.tips[(parseInt((Math.random()*10)%this.tips.length))]+"\n"+line+"\n";

/* 
ELS: disable loading of remote stylesheet!  (use styles from [[jash.css]] tiddler intead)
if(this.returnBrowserType()!="sa"){this.stylesheet=document.body.appendChild(document.createElement('link'));}else{this.stylesheet=document.getElementsByTagName("head")[0].appendChild(document.createElement("link"));}
this.stylesheet.type='text/css';this.stylesheet.rel='stylesheet';this.stylesheet.href=this.jashRoot+'Jash.css';
*/

this.create();Jash.TabComplete.prototype=this;this.tabComplete=new Jash.TabComplete();Jash.Evaluator.prototype=this;this.evaluation=new Jash.Evaluator();this.history=new Jash.History();var _self=this;window.setTimeout(function(){_self.input.focus();},500);if(typeof event!="undefined")delete event;}
this.returnBrowserType=function(){if(window.navigator.userAgent.toLowerCase().indexOf("opera")!=-1){return"op";}
if(window.navigator.userAgent.toLowerCase().indexOf("msie")!=-1){return"ie";}
if(window.navigator.userAgent.toLowerCase().indexOf("firefox")!=-1){return"ff";}
if(window.navigator.userAgent.toLowerCase().indexOf("safari")!=-1){return"sa";}}
this.returnOsType=function(){var ua=window.navigator.userAgent.toLowerCase();if(ua.indexOf("macintosh")!=-1){return"mac";}else if(ua.indexOf("windows")!=-1){return"win";}else if(ua.indexOf("linux i686")!=-1){return"linux";}}
this.getAccessKeyText=function(){var txt;var agt=this.returnOsType();switch(this.browser){case"ie":txt="Alt";break;case"ff":if(agt=="mac"){txt="Ctrl";}else if(agt=="linux"){txt="Alt";}else{txt="Alt-Shift";}
break;case"op":txt="Shift-Esc";break;case"sa":if(agt=="mac"){txt="Ctrl";}else{txt="Alt";}
break;default:txt="Alt";break;}
return txt;}
this.print=function(text,clear,suppressLineNumbers,autoscroll){clear=(typeof clear!="undefined")?clear:false;autoscroll=(typeof autoscroll!="undefined")?autoscroll:true;if(this.output==null||document.getElementById("JashParent")==null){this.create();this.output=document.getElementById("JashOutput");this.mainBlock=document.getElementById("JashParent");}
if(clear){this.clear();}
if(text!=""){if(typeof suppressLineNumbers!="undefined"&&!suppressLineNumbers){this.output.value+=this.lineNumber+". ";}
this.output.value+=text+"\n";if(autoscroll){this.output.scrollTop=this.output.scrollHeight;}
this.lineNumber++;}
return _null;}
this.show=function(obj){this.print(line,false,true);var out="";this.lineNumber=0;for(var p in obj){if(typeof obj[p]=="function"){var t=obj[p].toString();t=t.replace(/[\x0A\x0D]/g,"").replace(/\s+/g,"").replace(/\{.+\}/g,"{ ... }");t=t.replace(p,"");t=p+": "+t;}else{t=p+": "+typeof obj[p];}
out+=++this.lineNumber+". "+t+"\n";}
this.print(out,false,true);this.print(line,false,true);this.output.scrollTop=this.output.scrollHeight;return _null;}
this.dump=function(obj){if(typeof obj=="string"){this.print(obj);}else{this.print(line,false,true);var out=new Array();if(typeof obj.push=="undefined"){for(var th in obj){out.push(++this.lineNumber+". "+th+" = "+obj[th]);}}else{for(var i=0;i<obj.length;i++){out.push(++this.lineNumber+". "+obj[i]);}}
this.print(out.join("\n"),false,true);this.print(line,false,true);this.output.scrollTop=this.output.scrollHeight;}
return _null;}
this.clear=function(){this.outputHistory.push(this.output.value);this.output.value="";this.input.focus();return _null;}
this.showOutputHistory=function(){this.outputHistory.push(this.output.value);this.dump(this.outputHistory);}
this.assignInputKeyEvent=function(keyCode){if(keyCode==13){this.evaluation.evaluate(this.input.value);this.input.value="";return false;}else if(keyCode==38){if(this.browser!="op"){this.input.value=this.history.getPreviousInput();}
return false;}else if(keyCode==40){if(this.browser!="op"){this.input.value=this.history.getNextInput();}
return false;}else if(keyCode==9){this.tabComplete.tabComplete();return false;}}
this.getXBrowserYOffset=function(){var y;if(self.pageYOffset){y=self.pageYOffset;}else if(document.documentElement&&document.documentElement.scrollTop){y=document.documentElement.scrollTop;}else if(document.body){y=document.body.scrollTop;}
return y;}
this.getMouseXY=function(e){var tempX=0
var tempY=0
if(window.event){if(document.documentElement&&document.documentElement.scrollTop){tempX=window.event.clientX+document.documentElement.scrollLeft;tempY=window.event.clientY+document.documentElement.scrollTop;}else{tempX=window.event.clientX+document.body.scrollLeft;tempY=window.event.clientY+document.body.scrollTop;}}else{tempX=e.pageX;tempY=e.pageY;}
return{x:tempX,y:tempY};}
this.getDimensions=function(el){var dims={}
if(document.all){dims.x=el.offsetWidth;dims.y=el.offsetHeight;}else{dims.x=parseInt(document.defaultView.getComputedStyle(el,"").getPropertyValue("width"));dims.y=parseInt(document.defaultView.getComputedStyle(el,"").getPropertyValue("height"));}
return dims;}
this.addEvent=function(obj,eventName,func){if(obj.addEventListener)
return obj.addEventListener(eventName,func,true);else if(obj.attachEvent){obj.attachEvent("on"+eventName,func);return true;}
return false;}
this.findElementPosition=function(obj){var curleft=0;var curtop=0;if(obj.offsetParent){curleft=obj.offsetLeft
curtop=obj.offsetTop
while(obj=obj.offsetParent){curleft+=obj.offsetLeft
curtop+=obj.offsetTop}}
return[curleft,curtop];}
this.create=function(){if(document.getElementsByTagName("frameset").length>0){alert("Jash currently does not support pages with frames.");return;}
var self=this;var debugParent=document.createElement("div");var windowScrollY=0;if(document.documentElement&&document.documentElement.scrollTop){windowScrollY=document.documentElement.scrollTop;}else if(document.body){windowScrollY=document.body.scrollTop}else{windowScrollY=window.scrollY;}
debugParent.style.top=windowScrollY+50+"px";debugParent.id="JashParent";

/*
ELS: 12/12/2007 - REMOVED ESC HANDLER SO OTHER PAGE ELEMENTS GET THEM!... SEE BELOW FOR ALTERNATIVE SHIFT-ESC HANDLER
this.addEvent(document,"keydown",function(e){e=(typeof window.event!="undefined")?window.event:e;if(e.keyCode=="27"){if(typeof e.shiftKey=="undefined"||!e.shiftKey && (this.mainBlock.style.display!="none")){self.close();}}});
*/

var textareaWrap=document.createElement("div");textareaWrap.id="JashTextareaWrap";var debugOutput=document.createElement("textarea");debugOutput.id="JashOutput";debugOutput.wrap="off";debugOutput.readOnly="true";debugOutput.value=this.defaultText;var inp=document.createElement("textarea");inp.id="JashInput";var last="";inp.onkeydown=function(e){e=(typeof window.event!="undefined")?window.event:e;return self.assignInputKeyEvent(e.keyCode);}
inp.onkeypress=function(e){e=(typeof window.event!="undefined")?window.event:e;var k=e.keyCode;if(!self.evaluation.cssEvalFlag){if(k==9||k==13||k==38||k==40){if(k!=40&&this.browser!="ie"){return false;}}}else if(k==9){return false;}}
var dragBut=document.createElement("div");dragBut.innerHTML="Jash";dragBut.id="JashDragBar";dragBut.onmousedown=function(e){e=(typeof window.event!="undefined")?window.event:e;var xplus=(typeof e.layerX=="undefined")?e.offsetX:e.layerX;var yplus=(typeof e.layerY=="undefined")?e.offsetY:e.layerY;document.onmousemove=function(e){var coords=self.getMouseXY(e);document.getElementById("JashParent").style.top=coords.y-yplus+"px";document.getElementById("JashParent").style.left=coords.x-xplus+"px";}
return false;}
document.onmouseup=function(){document.onmousemove=null;};dragBut.onclick=function(){return false;}
var xBut=document.createElement("a");xBut.className="JashXButton";xBut.innerHTML="X";xBut.href="#";xBut.onclick=function(){self.close();return false;}
var clearBut=document.createElement("a");clearBut.innerHTML="Clear ("+this.accessKeyText+"-C)";clearBut.accessKey="C";clearBut.className="JashButton";clearBut.onclick=function(){self.clear();return false;}
this.setCrossBrowserAccessKeyFunctionForAnchor(clearBut);var evalBut=document.createElement("a");evalBut.value="Evaluate ("+this.accessKeyText+"-Z)";evalBut.innerHTML="Evaluate ("+this.accessKeyText+"-Z)";evalBut.accessKey="Z";evalBut.className="JashButton";evalBut.title="Evaluate current input ("+this.accessKeyText+"-Z)";evalBut.onclick=function(){self.evaluation.evaluate(inp.value);if(!self.evaluation.cssEvalFlag){inp.value="";}
inp.focus();return false;}
this.setCrossBrowserAccessKeyFunctionForAnchor(evalBut);var helpBut=document.createElement("a");helpBut.innerHTML="Help";helpBut.className="JashButton";helpBut.title="Help: show list of commands (or type jash.help(); )";helpBut.onclick=function(){self.help();}
var domBut=document.createElement("a");domBut.innerHTML="Mouseover DOM ("+this.accessKeyText+"-X)";domBut.title="Mouseover DOM: toggle to turn on/off inspection of document nodes ("+this.accessKeyText+"-X)";domBut.className="JashButton";domBut.accessKey="X";domBut.tabIndex="4";this.domActive=false;domBut.onclick=function(){if(!self.domActive){document.body.onmouseover=function(e){if(typeof e=="undefined"){e=window.event;}
self.showNodes(e);}
self.setButtonVisualActiveState(domBut,"on");self.domActive=true;}else{document.body.onmouseover=function(){}
self.domActive=false;self.setButtonVisualActiveState(domBut,"off");}
return _null;}
this.setCrossBrowserAccessKeyFunctionForAnchor(domBut);var innerHtmlInspectBut=document.createElement("a");innerHtmlInspectBut.innerHTML="innerHTML Dump ("+this.accessKeyText+"-A)";innerHtmlInspectBut.title="innerHTML Inspect: toggle to turn on/off innerHTML inspection of document nodes ("+this.accessKeyText+"-A)";innerHtmlInspectBut.className="JashButton";innerHtmlInspectBut.accessKey="A";innerHtmlInspectBut.tabIndex="5";this.innerHtmlInspection=false;innerHtmlInspectBut.onclick=function(){self.innerHtmlInspection=!self.innerHtmlInspection;self.setButtonVisualActiveState(innerHtmlInspectBut,self.innerHtmlInspection?"on":"off");return _null;}
this.setCrossBrowserAccessKeyFunctionForAnchor(innerHtmlInspectBut);var cssBut=document.createElement("a");cssBut.innerHTML="CSS Input ("+this.accessKeyText+"-S)";cssBut.title="CSS Input: turn on CSS input to enter arbitrary CSS ("+this.accessKeyText+"-S)";cssBut.className="JashButton";cssBut.accessKey="S";cssBut.onclick=function(){if(!self.evaluation.cssEvalFlag){self.setButtonVisualActiveState(cssBut,"on");self.evaluation.cssEvalFlag=true;inp.className="cssEntry";if(document.getElementById("JashStyleInput")!=null){self.evaluation.styleInputTag.disabled=false;}
inp.value="";}else{self.setButtonVisualActiveState(cssBut,"off");inp.className="";self.evaluation.cssEvalFlag=false;if(document.getElementById("JashStyleInput")!=null){self.evaluation.styleInputTag.disabled=true;}
inp.value="";}
inp.focus();return _null;}
this.setCrossBrowserAccessKeyFunctionForAnchor(cssBut);var resizeBut=document.createElement("div");resizeBut.id="JashResizeButton";this.minDims={x:100,y:100};resizeBut.onmousedown=function(e){e=(typeof window.event!="undefined")?window.event:e;var originalDims=self.getDimensions(textareaWrap);var originMouseDims=self.getMouseXY(e);document.onmousemove=function(e){var newMouseDims=self.getMouseXY(e);var newWidth=originalDims.x+(newMouseDims.x-originMouseDims.x);if(newWidth<self.minDims.x){newWidth=self.minDims.x;}
textareaWrap.style.width=newWidth+"px";debugParent.style.width=newWidth+"px";var newHeight=originalDims.y+(newMouseDims.y-originMouseDims.y);if(newHeight<self.minDims.y){newHeight=self.minDims.y;}
textareaWrap.style.height=newHeight+"px";debugParent.style.height=newHeight+"px";}
document.onmouseup=function(){document.onmousemove="";}}
var bottomBar=document.createElement("div");bottomBar.id="JashBottomBar";debugParent.appendChild(dragBut);debugParent.appendChild(xBut);bottomBar.appendChild(evalBut);bottomBar.appendChild(cssBut);bottomBar.appendChild(domBut);bottomBar.appendChild(innerHtmlInspectBut);bottomBar.appendChild(clearBut);bottomBar.appendChild(helpBut);debugParent.appendChild(bottomBar);debugParent.appendChild(resizeBut);document.body.appendChild(debugParent);textareaWrap.appendChild(debugOutput);textareaWrap.appendChild(inp);debugParent.appendChild(textareaWrap);this.bottomBar=document.getElementById("JashBottomBar");this.dragBar=document.getElementById("JashDragBar")
this.output=document.getElementById("JashOutput");this.input=document.getElementById("JashInput");this.mainBlock=debugParent;this.addEvent(window,'scroll',function(){debugParent.style.top=50+self.getXBrowserYOffset()+'px';});}
this.setButtonVisualActiveState=function(button,state){if(state=="on"){button.style.backgroundColor="lightgreen";}else{button.style.backgroundColor="";}}
this.help=function(){var out=new Array();out.push(line);out.push("Jash v"+this.version+" "+this.versionDate.replace(/\$/g,''),true);out.push("http://www.billyreisinger.com/jash/documentation.html");out.push(line);out.push("METHODS");out.push(line);out.push("this.cls() - clear console and terminal");out.push("jash.print(str,clear) - output str to console ~~ str = string ~~ clear = true|false: clear console before output");out.push("this.close() - close this console");out.push("this.dump(obj) - output object and members to console");out.push("this.show(obj) - print out the names and types (only) of all members of obj");out.push("this.stopWatch.start() - start timer");out.push("this.stopWatch.stop() - end timer and return result in ms");out.push("this.kill(HTML Element) - remove an element from the page.");out.push("this.getDimensions(HTML Element) - get width, height dimensions of an html element. Returns an object [x,y]");out.push(line);out.push("KEYSTROKES");out.push(line);out.push("press up arrow in input field to retrieve last input");out.push("press ESC to show/hide console");out.push("press "+this.accessKeyText+"-Q to turn on/off Transparent mode, so you can see through the Jash.");out.push("press ENTER in input field to enter a command");out.push("press TAB to auto-complete input");out.push("press "+this.accessKeyText+"-Z to evaluate input");out.push("press "+this.accessKeyText+"-X to activate/deactivate DOM inspector");out.push("press "+this.accessKeyText+"-A to activate/deactivate innerHTML dump (only works w/ DOM inspector)");out.push("press "+this.accessKeyText+"-C to clear output and input");out.push("press "+this.accessKeyText+"-S to turn on/off CSS input mode. In CSS input mode, you can enter arbitrary CSS selectors and rules, as you would normally do in a CSS stylesheet.");this.print(out.join("\n"));return _null;}
this.close=function(){if(this.mainBlock.style.display=="none"){this.mainBlock.style.display="block";this.input.focus();}else{this.mainBlock.style.display="none";}}
this.setCrossBrowserAccessKeyFunctionForAnchor=function(el){var self=this;el.tabIndex=++this.tabIndexIndex;if(this.browser=="ie"){el.onfocus=function(){if(window.event.altKey){el.onclick();}
self.input.focus();}}}
this.stopWatch={t_start:0,t_end:0,t_total:0,start:function(){t_start=new Date().getTime();return t_start;},stop:function(){t_end=new Date().getTime();t_total=t_end-t_start;return(t_total);}}
this.showNodes=function(e){if(typeof e=="undefined")e=window.event;var el=typeof e.target=="undefined"?e.srcElement:e.target;this.currentNode=el;var childMost=this.identifyNode(el,false);var out="";var childmostTxt="childmost..... "+childMost.txt+"\n";while(el=el.parentNode){if(el.nodeName.toLowerCase()=="html"){out="parentmost.... <html>\n"+out;break;}
out=this.identifyNode(el).txt+"\n"+out;}
out="**** PRESS "+this.accessKeyText+"-X TO PAUSE / UNPAUSE ****\n"+out;out+=childmostTxt;this.print(out,true,true,false);if(this.innerHtmlInspection){this.print("INNER HTML");if(this.currentNode.innerHTML.indexOf("<")!=-1){this.print(Jash.Indenter.indent(this.currentNode.innerHTML),false,true,false);}else{this.print(this.currentNode.innerHTML,false,true,false);}}
if(!this.evaluation.cssEvalFlag){if(childMost.id!=""){if(typeof $!="undefined"){this.input.value='$("'+childMost.id+'")';}else{this.input.value='document.getElementById("'+childMost.id+'")';}}else{this.input.value="this.currentNode";}}}
this.identifyNode=function(el,showDots){showDots=typeof showDots=="boolean"?showDots:true;var out={txt:"",id:""};if(showDots)out.txt+=".............. ";out.txt+="<"+el.nodeName.toLowerCase();for(var i=0;i<el.attributes.length;i++){if((this.browser=="ie"&&el.attributes[i].specified===true)||this.browser!="ie"){out.txt+=" "+el.attributes[i].name;out.txt+="=\""+el.attributes[i].value+"\"";}}
out.txt+=">";return out;}
this.kill=function(){this.currentNode.parentNode.removeChild(this.currentNode);}}
Jash.Evaluator=function(){this.cssEvalFlag=false;var _null="nooutput";this.evaluate=function(input){if(input=="")return false;this.history.add(input);if(this.cssEvalFlag){this.evalCss(input);this.print(input);}else{var output=this.evalJs(input);if(typeof output!="undefined"){this.print(">> "+input);this.print(output);}}}
this.evalJs=function(input){try{var result;if(this.browser=="ie"){result=eval(input);}else{result=window.eval(input);}
if(result!=null&&result.toString()!=_null){return(result.toString());}else{return"null"}}catch(e){return(e.message);}}
this.evalCss=function(input){try{this.insertStyleRule(input);}catch(e){}
return input;}
this.insertStyleRule=function(rule){var lastStyleSheetIndex=document.styleSheets.length-1;if(document.getElementById("JashStyleInput")==null){this.styleInputTag=document.createElement("style");this.styleInputTag.id="JashStyleInput";this.styleInputTag.type="text/css";document.body.appendChild(this.styleInputTag);}
if(this.browser=="ff"||this.browser=="op"){this.styleInputTag.innerHTML+=rule+"\n";}else if(this.browser=="ie"||this.browser=="sa"){if(this.browser=="ie"){var i=0;}else if(this.browser="sa"){var i=document.styleSheets.length-1;}
var rulesArray=rule.split("}");for(var t=0;t<rulesArray.length;t++){var ruleSplit=rulesArray[t].split("{");var selectors=ruleSplit[0].split(",");for(var k=0;k<selectors.length;k++){document.styleSheets[i].addRule(selectors[k],ruleSplit[1]);}}}
return"";}
return this;}
Jash.History=function(){this.entries=new Array('');this.position=0;}
Jash.History.prototype={add:function(input){this.entries.push(input);this.position=this.entries.length-1;},getPreviousInput:function(){if(this.position<0){return'';}
var entry=typeof this.entries[this.position]!="undefined"?this.entries[this.position]:'';if(this.position>0){this.position--;}
return entry;},getNextInput:function(){if(this.position+1<this.entries.length){return this.entries[++this.position];}else{return'';}}}
Jash.Indenter={indentChar:"\t",nodesCommonlyUnclosed:new Array("link ","img ","meta ","!DOCTYPE ","input ","param","hr","br"),stringRepeat:function(stringToRepeat,times){var string=new Array();for(var i=0;i<times;i++){string.push(stringToRepeat);}
return string.join('');},closeUnclosedNode:function(str){for(var k=0;k<this.nodesCommonlyUnclosed.length;k++){var reg=new RegExp("^"+this.nodesCommonlyUnclosed[k].toLowerCase());if(str.toLowerCase().match(reg)){return str.replace(">","/>");}}
return str;},indentAndAdd:function(level,string,arr){var indents=this.stringRepeat(this.indentChar,level);arr.push(indents+string);return arr;},indent:function(source){var source=source;var arr=new Array();source=source.replace(/[\n\r\t]/g,'');source=source.replace(/>\s+/g,">");source=source.replace(/\s+</g,"<");var splitsrc=source.split("<");for(i=0;i<splitsrc.length;i++){splitsrc[i]=this.closeUnclosedNode(splitsrc[i]);}
source=splitsrc.join("<");var level=0;var sourceLength=source.length;var position=0;while(position<sourceLength){if(source.charAt(position)=='<'){var startedAt=position;var tagLevel=1;if(source.charAt(position+1)=='/'){tagLevel=-1;}
if(source.charAt(position+1)=='!'){tagLevel=0;}
while(source.charAt(position)!='>'){position++;}
if(source.charAt(position-1)=='/'){tagLevel=0;}
var tagLength=position+1-startedAt;if(tagLevel===-1){level--;}
arr=this.indentAndAdd(level,source.substr(startedAt,tagLength),arr);if(tagLevel===1){level++;}}
if((position+1)<sourceLength){if(source.charAt(position+1)!=='<'){startedAt=position+1;while(source.charAt(position)!=='<'&&position<sourceLength){position++;}
if(source.charAt(position)==='<'){tagLength=position-startedAt;arr=this.indentAndAdd(level,source.substr(startedAt,tagLength),arr);}}else{position++;}}else{break;}}
return arr.join("\n");}}
Jash.Profiler=function(func,onFinish){this.func=func;this.time=0;this.defaultOnFinish=function(){};this.results=new Array();this.onFinish=typeof onFinish!="function"?this.defaultOnFinish:onFinish;var self=this;this.reverseWhile=function(reps){this.stopWatch.start();while(reps>0){this.func();reps--;}
return this.stopWatch.stop();}
this.forLoop=function(reps){this.stopWatch.start();for(i=0;i<reps;i++){this.func();}
return this.stopWatch.stop();}
this.loop=function(kind,reps){if(!this.results[kind]){this.results[kind]=new Array();}
var repsMemberName="r_"+reps;if(!this.results[kind][repsMemberName]){this.results[kind][repsMemberName]=new Array();}
var time=this[kind](reps);this.results[kind][repsMemberName].push(time);}
this.runOnce=function(){if(!this.results.runOnce){this.results.runOnce=new Array();}
this.stopWatch.start();func();this.results.runOnce.push(this.stopWatch.stop());}
this.stopWatch={t_start:0,t_end:0,t_total:0,start:function(){t_start=new Date().getTime();return t_start;},stop:function(){t_end=new Date().getTime();t_total=t_end-t_start;self.time=t_total;return t_total;}}
this.average=function(arr){var sum=0;for(i=0;i<arr.length;i++){sum+=arr[i];}
return sum/arr.length}
this.multiPass=function(passes,type,reps){if(typeof type=="undefined"){type="runOnce";}else if(typeof this[type]=="undefined"){jash.print("Error: the loop type '"+type+"' does not exist");return false;}
var self=this;if(type=="runOnce"){if(passes<1){self.reportProfile(Math.round(this.average(this.results.runOnce)),type,reps);}else{window.setTimeout(function(){self.runOnce();self.multiPass(--passes,type);},50);}}else{if(passes<1){var repsMemberName="r_"+reps;self.reportProfile(Math.round(this.average(this.results[type][repsMemberName])),type,reps);}else{window.setTimeout(function(){self.loop(type,reps);self.multiPass(--passes,type,reps);},50);}}}
this.reportProfile=function(avgMs,type,reps){var line="-------PROFILER----------------------------------------------";var str=line+"\n"+this.func+"\n"+line+"\n";str+="Type of profile: "+type+"\n";if(typeof reps!="undefined"){str+="Loop iterations: "+reps+"\n";}
str+="Average execution time: "+avgMs+"ms"+"\n";if(type=="runOnce"){howManyTimes=this.results.runOnce.length;}else{repsMemberName="r_"+reps;howManyTimes=this.results[type][repsMemberName].length;}
str+="Average calculated from "+howManyTimes+" pass(es)\n";str+=line+"\n";jash.print(str);}}
Jash.TabComplete=function(){this.tabComplete=function(e){e=(typeof window.event!="undefined")?window.event:e;var inputText=this.input.value;var match=null;if(match=this.searchInputForDomGetElFunctions(inputText)){this.tabCompleteIdOrClassInJavascript(match.match[0],match.type);this.focusCaretAtEndOfInput();return false;}else if(this.evaluation.cssEvalFlag){this.tabCompleteIdOrClassInCss(inputText);this.focusCaretAtEndOfInput();return false;}else{this.tabCompleteJavascript(e,inputText);this.focusCaretAtEndOfInput();}}
this.focusCaretAtEndOfInput=function(){this.input.selectionEnd=this.input.selectionStart=this.input.value.length;}
this.tabCompleteJavascript=function(e,inputText){var words=inputText.split(/\s+/);var lastWord=words[(words.length-1)];var numOpeningParens=lastWord.split("(").length-1;var numClosingParens=lastWord.split(")").length-1;var scope;var sentinel=0;var diff=numOpeningParens-numClosingParens;if(diff>0){numClosingParens=lastWord.split("(")[numOpeningParens].split(")").length-1;var numRealDanglers=numOpeningParens-numClosingParens;scope=lastWord.split("(").slice(numRealDanglers).join("(");}else if(diff<0){this.print("error: too many closing parentheses");return false;}else{scope=lastWord;}
scope=scope.split(".");var fragment=scope.pop();scope=scope.join(".");if(scope=="")scope="window";var members=this.getMembers(scope);var results=this.findTextMatchesInArray(members,fragment);if(results==false){}else if(typeof results!="string"){this.dump(results);var bestMatch=this.findBestStringMatch(fragment,results);if(fragment!=''){fragReg=new RegExp(fragment+"$");this.input.value=this.input.value.replace(fragReg,bestMatch);}else{this.input.value+=bestMatch;}}else{var reggie=new RegExp(fragment+"$");this.input.value=this.input.value.replace(reggie,results);}
return false;}
this.doAllStringsInArrayHaveSameCharacterAtIndex=function(index,arr){var matched=0;if(!arr[0].charAt(index))return false;var character=arr[0].charAt(index);for(var i=1;i<arr.length;i++){if(!arr[i].charAt(index)||arr[i].charAt(index)!=character){return false;}}
return true;}
this.findBestStringMatch=function(str,arr){var fragLength=str.length;var matches=this.doAllStringsInArrayHaveSameCharacterAtIndex(fragLength,arr);while(matches){fragLength++;matches=this.doAllStringsInArrayHaveSameCharacterAtIndex(fragLength,arr);}
return arr[0].substr(0,fragLength);}
this.tabCompleteIdOrClassInJavascript=function(inputText,type){var query=inputText.split("(");query=query[query.length-1].replace(/\W/g,'');var matches=new Array();var els=document.getElementsByTagName("*");if(type=="id"){for(var i=0;i<els.length;i++){if(els[i].id&&els[i].id.indexOf(query)==0){matches.push(els[i].id);}}}else if(type=="class"){for(var i=0;i<els.length;i++){if(els[i].className&&els[i].className!=''){var classes=els[i].className.split(/\s/);for(var ii=0;ii<classes.length;ii++){if(classes[ii].indexOf(query)==0||query==''){if(matches.join("***").indexOf(classes[ii])==-1){matches.push(classes[ii]);}}}}}}
if(matches.length==1){this.input.value+=matches[0].split(query)[1];}else if(matches.length==0){this.print("no match");}else{this.dump(matches.sort());var bestMatch=this.findBestStringMatch(query,matches);if(query!=''){var replacement=inputText.split("(");replacement[replacement.length-1]=replacement[replacement.length-1].replace(query,bestMatch);this.input.value=this.input.value.replace(inputText,replacement.join("("));}else{this.input.value+=bestMatch;}}}
this.tabCompleteIdOrClassInCss=function(inputText){var selectors=inputText.replace(/(\.|#)/g,' $1').split(/\s+/);var lastSelector=selectors[selectors.length-1];var els=document.getElementsByTagName("*");var matches=new Array();if(lastSelector.match(/^\./)){for(var i=0;i<els.length;i++){if(els[i].className&&els[i].className!=''){var classes=els[i].className.split(/\s/);for(var ii=0;ii<classes.length;ii++){if(classes[ii].indexOf(lastSelector.substr(1))==0||lastSelector=="."){if(matches.join("***").indexOf(classes[ii])==-1){matches.push("."+classes[ii]);}}}}}}else if(lastSelector.match(/^#/)){for(var i=0;i<els.length;i++){if(els[i].id&&els[i].id.indexOf(lastSelector.substr(1))==0){matches.push("#"+els[i].id);}}}
if(matches.length==1){this.input.value+=matches[0].split(lastSelector)[1];}else if(matches.length==0){this.print("no match");}else{this.dump(matches.sort());var bestMatch=this.findBestStringMatch(lastSelector,matches);if(lastSelector!=''){this.input.value=this.input.value.replace(lastSelector,bestMatch);}else{this.input.value+=bestMatch;}}}
this.searchInputForDomGetElFunctions=function(inputText){for(var i=0;i<this.domGetElFunctions.id.length;i++){var selfct=new RegExp(this.domGetElFunctions.id[i].replace("\$","\\\$")+"\\\(['\"]\\w*$");if(inputText.match(selfct)){return{match:inputText.match(selfct),type:"id"};}}
for(var i=0;i<this.domGetElFunctions.className.length;i++){var selfct=new RegExp(this.domGetElFunctions.className[i].replace("\$","\\\$")+"\\\(['\"]\\w*$");if(inputText.match(selfct)){return{match:inputText.match(selfct),type:"class"};}}}
this.findTextMatchesInArray=function(arrayToTest,findMe){var resultsArray=new Array();var tester=new RegExp("^"+findMe);for(var i=0;i<arrayToTest.length;i++){if(tester.test(arrayToTest[i])){resultsArray.push(arrayToTest[i]);}}
if(resultsArray.length>1){resultsArray.sort();return resultsArray;}else if(resultsArray.length==1){return resultsArray[0];}else{return false;}}
this.getMembers=function(context){var members=new Array();for(memberName in eval(context)){members.push(memberName);}
return members;}
return this;}

// ELS 12/12/2007: init is deferred until first time panel is shown
window.toggleJash=function() // show/hide panel...
	{ if("jash" in window)window.jash.close();else{window.jash=new Jash();window.jash.main();} }
window.isJashVisible=function() // so scripts can find out the current display state
	{ return window.jash?window.jash.mainBlock.style.display!="none":false; }
addEvent(document,"keydown",function(ev){ // SHIFT-ESC shows/hides panel, ESC hides panel
	var e=(typeof window.event!="undefined")?window.event:ev;
	if(e.keyCode=="27"&&(e.shiftKey||window.isJashVisible())) window.toggleJash(); });
//}}}
<html><hide linebreaks><a href="javascript:;" class="button"
	title='JASH: Javascript Shell - view/modify internal run time variables and functions!'
	onclick="if (window.toggleJash) toggleJash(); return false;"
	onmouseover="this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
		+encodeURIComponent(encodeURIComponent(this.onclick))
		+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';">
	$1
</a></html>
/***
|Name|JumpMacro|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#JumpMacro|
|Version|1.0|
|Requires|~TW2.x|
!Description:
Macro version of the core jump command, that also provides an optional 'jump to top' button.

!Demo:
click the 'j' button in the hoverMenu on the right.

!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.

!Usage
{{{<<jump>>}}}<<jump>>
{{{<<jump customlabel customtooltip top>>}}} <<jump customlabel customtooltip top>>
Note: passing the third parameter as top, enables the 'top' button in the dropdown.

!History:
27-07-06, ver1.0

!Code
***/

//{{{
config.macros.jump= {};
config.macros.jump.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
        var label = (params[0] && params[0]!=".")? params[0]: 'jump';
        var tooltip = (params[1] && params[1]!=".")? params[1]: 'jump to an open tiddler';
        var top = (params[2] && params[2]=='top') ? true: false;        

        var btn =createTiddlyButton(place,label,tooltip,this.onclick);
        if (top==true)
              btn.setAttribute("top","true")
}

config.macros.jump.onclick = function(e)
{
        if (!e) var e = window.event;
        var theTarget = resolveTarget(e);
        var top = theTarget.getAttribute("top");
	var popup = Popup.create(this);
	if(popup)
		{
                 if(top=="true")
                                {createTiddlyButton(createTiddlyElement(popup,"li"),'Top ↑','Top of TW',config.macros.jump.top);
                                 createTiddlyElement(popup,"hr");}
		
		story.forEachTiddler(function(title,element) {
			createTiddlyLink(createTiddlyElement(popup,"li"),title,true);
			});
                }
	Popup.show(popup,false);
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
	return false;
}

config.macros.jump.top = function()
{
       window.scrollTo(0,0);
}
//}}}
/***
|Name|JumpToTopMacro|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#JumpToTopMacro|
|Version|1.0|
|Requires|~TW2.x|
!Description:
Provides a toolbar command and a macro, that create a button for quickly jumping to the top of your TW.
Handy to place in the tiddler toolbar (edit the ViewTemplate)

Note: You can add an extra toolbar to the bottom of tiddlers as well with buttons of your choice, to allow easy access to the buttons/commands in it.

!Demo:
{{{<<top>>}}}<<top>>

!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.

!History:
*23-07-06: ver 1.0

!Code
***/
//{{{
config.macros.top={};
config.macros.top.handler=function(place,macroName)
{
               createTiddlyButton(place,"^","jump to top",this.onclick);
}
config.macros.top.onclick=function()
{
               window.scrollTo(0,0);
};

config.commands.top =
{
               text:" ^ ",
               tooltip:"jump to top"
};

config.commands.top.handler = function(event,src,title)
{
               window.scrollTo(0,0);
}
//}}}
<div class='header'  macro='gradient vert #FFF #FFF '>
     <div class='gradient'>                
	<div class='titleLine' >
<span class='searchBar' macro='search'></span>
		<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
		<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
	</div>
<div id='topMenu' refresh='content' tiddler='MainMenu'></div>
    </div>
</div>
<div id='bodywrapper'>
<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 id='displayFooter'></div>
</div>
/***
Inspired by k2

!General
***/
/*{{{*/
body {
 background: #EDEDED;
}

 #contentWrapper{
 background: #fff;
 border:1px solid #DDD;
 margin: 0 auto;
 width: 780px;
 padding:0;
}
/*}}}*/


/***
!Links
***/
/*{{{*/
a,
a.tiddlyLink,
a.button,
a.externalLink,
#sidebarOptions .sliderPanel a{
 color: #1D65BC;
 text-decoration: none;
 background: transparent;
 border: 0;
}

a:hover,
a.tiddlyLink:hover,
a.button:hover,
a.externalLink:hover,
#sidebarOptions .sliderPanel a:hover
{
 border: 0;
 color: #1D65BC;
 text-decoration: underline;
background:transparent;
}
.button:active {background:#1d65bc; border:0;}
.viewer .button:active, .viewer .marked, .viewer .highlight {
color: #fff !important;
background: #3371a3;
border: 0;
}
/*}}}*/

/***
!Header
***/
/*{{{*/
.gradient {margin-top:20px; background:#3371A3;}

.titleLine{padding: 80px 40px 32px 40px;}

.titleLine a:hover{color:#fff; border-bottom:1px dotted #eee; text-decoration:none;}

.titleLine a{color:#fff; border-bottom:1px dotted #ccc;}

.siteTitle {
	font-size: 2.2em;
        font-weight: bold;
        color:#fff;
}

.siteSubtitle {
	font-size: 1.0em;
        display: block;
        margin: .3em auto 1em;
color:#fff;
}
/*}}}*/

/***
!TopMenu
***/
/*{{{*/
#topMenu br {display:none;  }
#topMenu { background: #3371A3; font-size:1em; }
#topMenu { padding:5px 32px; }
#topMenu .button, #topMenu .tiddlyLink {
 margin-left:0.1em; margin-right:0.1em;
 padding:0.5em;
 color:white; font-weight:normal;
}
#topMenu a.button:hover, #topMenu a.tiddlyLink:hover { background:#fff; color:#333; text-decoration:none;}

 .searchBar {float:right; font-size:0.9em;}
.searchBar .button {display:block; border:none; color:#ccc;}
.searchBar .button:hover{border:none; color:#eee;}

.searchBar input{
	border: 1px inset #1d65bc; background:#dbdee3;
}

.searchBar input:focus {
	border: 1px inset #3371a3; background:#fff;
}
/*}}}*/

/***
!Display
***/
/***
!!!Display General
***/
/*{{{*/


#displayArea { margin: 0em 15.7em 0em 1em; }

#displayFooter {
 clear: both;
}
#displayFooter {
 clear: both;
}

#tiddlerDisplay{padding-top:1em;}
/*}}}*/
/***
!!!Tiddler
***/
/*{{{*/
.tiddler {margin-bottom:1em; padding-bottom:1em;}

.tiddler {padding-left:2em;}

.title {color:#333; font-size:1.8em; border-bottom:1px solid #333; padding-bottom:0.3px;}

.subtitle { font-size:90%; color:#bbb; padding-left:0.25em; margin-top:0.1em; }

.shadow .title {
	color: #aaa;
}

h1,h2,h3,h4,h5 { color: #333; background: transparent; padding-bottom:2px; border-bottom: 1px dotted #666; }

* html .viewer pre {
	margin-left: 0em;
}

.viewer hr {
	border: 0;
	border-top: solid 1px #333;
 margin: 0 8em;
	color: #333;
}

.viewer a.button {color:#000; border:1px solid #1D65BC; font-weight:bold;}

.viewer a.button:hover{color:#fff; background:#3371a3; text-decoration:none;}

.tagClear {clear:none;}

.toolbar .button {color:#bbb; border:none;}
.toolbar .button:hover, .toolbar .highlight, .toolbar .marked, .toolbar a.button:active {background:transparent; color:#111; border:none; text-decoration:underline;}


.tiddler {border-bottom:3px solid #EEF1F3; padding-bottom:2em; padding-top:0em;}
.title {border-bottom:none; margin-right:8em;}

h1,h2,h3,h4,h5 { color: #333; background: transparent; padding-bottom:2px; border-bottom: none; }

.viewer pre, .viewer code {
border: 1px solid #B2B6BE;
background: #EBEEF1;} 



.tagging, .tagged {
	border: 1px solid #dbdee3;
	background-color: #ebeef1;
}

.selected .tagging, .selected .tagged {
	background-color: #dbdee3;
	border: 1px solid #B2B6BE;
}

 .tagging .listTitle, .tagged .listTitle {
	color: #bbb;
}

.selected .tagging .listTitle, .selected .tagged .listTitle {
	color: #014; 
}

.tagging .button:hover, .tagged .button:hover {
		border: none; background:transparent; text-decoration:underline; color:#014;
}

.tagged .highlight, .tagged .marked, .tagged a.button:active {text-decoration:underline; background:transparent; color:#014;}

.tagging .button, .tagged .button {
		color:#bbb;
}

.selected .tagging .button, .selected .tagged .button {
		color:#014;
}

.viewer blockquote {
	border-left:7px solid #ebeef1;
}

.viewer table {
	border: 1px solid #3371a3;
}

.viewer th, thead td {
	background: #3371a3;
	border: 1px solid #3371a3;
	color: #fff;
}

.viewer td, .viewer tr {
	border: 1px solid #3371a3;
}
/*}}}*/
/***
!!!Editor
***/
/*{{{*/

* html .editor textarea, * html .editor input {
	width: 98%;
}
.editor input, .editor textarea {
	border: 1px solid #1d65bc; background:#ebeef1;
}

.editor {padding-top:0.3em;}

.editor textarea:focus, .editor input:focus {
	border: 1px inset #3371a3; background:#fff;
}
/*}}}*/







/***
!Sidebar
***/
/*{{{*/
#sidebar{
position:relative;
float:right;
margin-bottom:1em;
display:inline;
width: 16em;
}


#sidebar .tabSelected, #sidebar .tabSected:hover {
 color: #000;
 background: #dbdee3;
 border-top: solid 1px #B2B6BE;
 border-left: solid 1px #B2B6BE;
 border-right: solid 1px #B2B6BE;
 border-bottom:solid 1px #dbdee3 !important;
padding-bottom:1px;
text-decoration:none;
}

#sidebarOptions, #sidebarTabs  {border-left: 1px solid #B2B6BE;}
#sidebarTabs {border-bottom: 1px solid #B2B6BE;}



#sidebar .tabUnselected, #sidebar .tabUnselected:hover {
color: #F0F3F5;
background: #B2B6BE ;
border: solid 1px #B2B6BE ;
padding-bottom:1px;
}

#sidebarTabs .tabContents {border:none; background:#DBDEE3; }

#sidebarTabs .tabContents {border-top:1px solid #B2B6BE;}

#sidebarTabs .tabContents .tabContents {border-left:1px solid #b2b6be;}

#sidebarOptions .sliderPanel {
	background: #EBEEF1; border:none;
}

#sidebarOptions input {
	border: 1px solid #1d65bc;
}

#sidebarOptions input:hover, #sidebarOptions input:active,  #sidebarOptions input:focus {
	border: 1px inset #3371a3;
}

#sidebar {background: #EBEEF1 ; right:0;}

#sidebar .button:active, #sidebar .marked, #sidebar .highlight {color:#014; background:transparent;text-decoration:none}
/*}}}*/

/***
!!Popups
***/
/*{{{*/
.popup {
	background: #3371a3;
	border: 1px solid #333;
}

.popup hr {
	color: #333;
	background: #333;
	border-bottom: 1px;
}

.popup li.disabled {
	color: #333;
}

.popup li a, .popup li a:visited {
	color: #eee;
	border: none;
}

.popup li a:hover {
	background: #3371a3;
	color: #fff;
	border: none;
        text-decoration:underline;
}
/*}}}*/




/***
!!Message Area
***/
/*{{{*/

#messageArea {
	border: 2px dashed #3371a3;
	background: #dbdee3;
	color: #fff;
        font-size:90%;
}

#messageArea .button {
	color: #1d65bc;
	background: #ebeef1;
        text-decoration:none;
        font-weight:bold;
        border:none; 
}

#messageArea a.button {color:#1d65bc;}

#messageArea .button:hover {text-decoration:underline;}
/*}}}*/
/***
!!Tabs
***/
/*{{{*/
.viewer .tabSelected, .viewer .tabSelected:hover{
	color: #014;
	background: #eee;
	border-left: 1px solid #B2B6BE;
	border-top: 1px solid #B2B6BE;
	border-right: 1px solid #B2B6BE;
}

.viewer .tabUnselected, .viewer .tabUnselected:hover {
	color: #fff;
	background: #B2B6BE;
}

. viewer .tabContents {
	color: #014;
	background: #ebeef1;
	border: 1px solid #B2B6BE;
}
/*}}}*/
.blog h2, .blog h3, .blog h4{
  margin:0;
  padding:0;
border-bottom:none;
}
.blog {margin-left:1.5em;}  


.blog .excerpt {
  margin:0;
margin-top:0.3em;
  padding: 0;
  margin-left:1em;
  padding-left:1em;
  font-size:90%;
  border-left:1px solid #ddd;
}

#tiddlerWhatsNew h1, #tiddlerWhatsNew h2 {border-bottom:none;}
div[tags~="RecentUpdates"], div[tags~="lewcidExtension"] {margin-bottom: 2em;}


#topMenu .fontResizer {float:right;}

#topMenu .fontResizer .button{border:1px solid #3371A3;}
#topMenu .fontResizer .button:hover {border:1px solid #fff; color:#3371A3;}
#sidebarTabs .txtMainTab .tiddlyLinkExisting {
 font-weight: normal;
 font-style: normal;
}

#sidebarTabs .txtMoreTab .tiddlyLinkExisting {
 font-weight: bold;
 font-style: normal;
}
tiddlers:
*K2BlogStyleSheet
*K2BlogPageTemplate

<<applyTheme K2Blog Preview>>
<div class='header' macro='gradient vert #FFF #FFF '>
 <div class='gradient'> 
 <div class='titleLine' >
<span class='searchBar' macro='search'></span>
 <span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
 <span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
 </div>
<div id='topMenu' refresh='content' tiddler='MainMenu'></div>
 </div>
</div>
<div id='bodywrapper'>
<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 id='displayFooter'></div>
</div>
/***
!General
***/
/*{{{*/
body {
 background: #EDEDED;
}

 #contentWrapper{
 background: #fff;
 border:1px solid #DDD;
 margin: 0 1em;
 padding:0;

height:1%;
}
/*}}}*/


/***
!Links
***/
/*{{{*/
a,
a.tiddlyLink,
a.button,
a.externalLink,
#sidebarOptions .sliderPanel a{
 color: #1D65BC;
 text-decoration: none;
 background: transparent;
 border: 0;
}

a:hover,
a.tiddlyLink:hover,
a.button:hover,
a.externalLink:hover,
#sidebarOptions .sliderPanel a:hover
{
 border: 0;
 color: #1D65BC;
 text-decoration: underline;
background:transparent;
}
/*}}}*/

/***
!Header
***/
/*{{{*/
.gradient {margin-top:1em; background:#3371A3;}

.titleLine{padding: 30px 40px 15px 30px;}

.titleLine a:hover{color:#fff; border-bottom:1px dotted #eee; text-decoration:none;}

.titleLine a{color:#fff; border-bottom:1px dotted #ccc;}

.siteTitle {
 font-size: 2.2em;
 font-weight: bold;
 color:#fff;
}

.siteSubtitle {
 font-size: 1.0em;
 display: block;
 margin: .3em auto 1em;
color:#fff;
}
/*}}}*/

/***
!TopMenu
***/
/*{{{*/
#topMenu br {display:none; }
#topMenu { background: #3371A3; font-size:1em; }
#topMenu { padding:5px 32px; }
#topMenu .button, #topMenu .tiddlyLink {
 margin-left:0.1em; margin-right:0.1em;
 padding:0.5em;
 color:white; font-weight:bold;
}
#topMenu a.button:hover, #topMenu a.tiddlyLink:hover { background:#fff; color:#333; text-decoration:none;}

 
/*}}}*/

/***
!Display
***/
/***
!!!Display General
***/
/*{{{*/


#displayArea { margin: 0em 15.7em 0em 0em; }

#displayFooter {
 clear: both;
}
/*}}}*/
/***
!!!Tiddler
***/
/*{{{*/
.tiddler {margin-bottom:1em; padding-bottom:1em;}

.tiddler {padding-left:1.5em;}

.title {color:#333; font-size:1.8em; border-bottom:1px solid #333; padding-bottom:0.3px;}

.subtitle { font-size:90%; color:#bbb; padding-left:0.25em; margin-top:0.1em; }

.shadow .title {
 color: #aaa;
}

h1,h2,h3,h4,h5 { color: #333; background: transparent; padding-bottom:2px; border-bottom: 1px dotted #666; }

* html .viewer pre {
 margin-left: 0em; 
}



.viewer hr {
 border: 0;
 border-top: solid 1px #333;
 margin: 0 8em;
 color: #333;
}

.viewer a.button {color:#000; border:1px solid #1D65BC; font-weight:bold;}

.viewer a.button:hover{color:#fff; background:#3371a3; text-decoration:none;}

.tagClear {clear:none;}
/*}}}*/
/***
!!!Editor
***/
/*{{{*/

* html .editor textarea, * html .editor input {
 width: 98%;
}
/*}}}*/







/***
!Sidebar
***/
/*{{{*/
#sidebar{
position:relative;
float:right;
margin-bottom:1em;
display:inline;
width: 16em;
}
/*}}}*/


.toolbar .button {color:#bbb; border:none;}
.toolbar .button:hover, .toolbar .highlight, .toolbar .marked, .toolbar a.button:active {background:transparent; color:#111; border:none; text-decoration:underline;}


.tiddler {border-bottom:3px solid #EEF1F3; padding-bottom:2em; padding-top:0em;}
.title {border-bottom:none; margin-right:8em;}

h1,h2,h3,h4,h5 { color: #333; background: transparent; padding-bottom:2px; border-bottom: none; }

#sidebar {background: #EBEEF1 ; right:0;}



#displayFooter {
 clear: both;
}

#tiddlerDisplay{padding-top:1em;}



#sidebar .tabSelected, #sidebar .tabSected:hover {
 color: #000;
 background: #dbdee3;
 border-top: solid 1px #B2B6BE;
 border-left: solid 1px #B2B6BE;
 border-right: solid 1px #B2B6BE;
 border-bottom:solid 1px #dbdee3 !important;
padding-bottom:1px;
text-decoration:none;
}

#sidebarOptions, #sidebarTabs {border-left: 1px solid #B2B6BE;}
#sidebarTabs {border-bottom: 1px solid #B2B6BE;}



#sidebar .tabUnselected, #sidebar .tabUnselected:hover {
color: #F0F3F5;
background: #B2B6BE ;
border: solid 1px #B2B6BE ;
padding-bottom:1px;
}

#sidebarTabs .tabContents {border:none; background:#DBDEE3; }

#sidebarTabs .tabContents {border-top:1px solid #B2B6BE;}

#sidebarTabs .tabContents .tabContents {border-left:1px solid #b2b6be;}









.viewer pre, .viewer code {
border: 1px solid #B2B6BE;
background: #EBEEF1;} 

#sidebarOptions .sliderPanel {
 background: #EBEEF1; border:none;
}

#sidebarOptions input {
 border: 1px solid #1d65bc;
}

#sidebarOptions input:hover, #sidebarOptions input:active, #sidebarOptions input:focus {
 border: 1px inset #3371a3;
}

.tagging, .tagged {
 border: 1px solid #dbdee3;
 background-color: #ebeef1;
}

.selected .tagging, .selected .tagged {
 background-color: #dbdee3;
 border: 1px solid #B2B6BE;
}

 .tagging .listTitle, .tagged .listTitle {
 color: #bbb;
}

.selected .tagging .listTitle, .selected .tagged .listTitle {
 color: #014; 
}

.tagging .button:hover, .tagged .button:hover {
 border: none; background:transparent; text-decoration:underline; color:#014;
}

.tagged .highlight, .tagged .marked, .tagged a.button:active {text-decoration:underline; background:transparent; color:#014;}

.tagging .button, .tagged .button {
 color:#bbb;
}

.selected .tagging .button, .selected .tagged .button {
 color:#014;
}

.viewer blockquote {
 border-left:7px solid #ebeef1;
}

.viewer table {
 border: 1px solid #3371a3;
}

.viewer th, thead td {
 background: #3371a3;
 border: 1px solid #3371a3;
 color: #fff;
}

.viewer td, .viewer tr {
 border: 1px solid #3371a3;
}

.editor input, .editor textarea {
 border: 1px solid #1d65bc; background:#ebeef1;
}

.editor {padding-top:0.3em;}

.editor textarea:focus, .editor input:focus {
 border: 1px inset #3371a3; background:#fff;
}










.popup {
 background: #3371a3;
 border: 1px solid #333;
}

.popup hr {
 color: #333;
 background: #333;
 border-bottom: 1px;
}

.popup li.disabled {
 color: #333;
}

.popup li a, .popup li a:visited {
 color: #eee;
 border: none;
}

.popup li a:hover {
 background: #3371a3;
 color: #fff;
 border: none;
 text-decoration:underline;
}

.viewer .button:active, .viewer .marked, .viewer .highlight {
color: #fff !important;
background: #3371a3;
border: 0;
}

.button:active {background:#1d65bc; border:0;}

#sidebar .button:active, #sidebar .marked, #sidebar .highlight {color:#014; background:transparent;text-decoration:none}

#messageArea {
 border: 2px dashed #3371a3;
 background: #dbdee3;
 color: #fff;
 font-size:90%;
}

#messageArea .button {
 color: #1d65bc;
 background: #ebeef1;
 text-decoration:none;
 font-weight:bold;
 border:none; 
}

#messageArea a.button {color:#1d65bc;}

#messageArea .button:hover {text-decoration:underline;}

.viewer .tabSelected, .viewer .tabSelected:hover{
 color: #014;
 background: #eee;
 border-left: 1px solid #B2B6BE;
 border-top: 1px solid #B2B6BE;
 border-right: 1px solid #B2B6BE;
}

.viewer .tabUnselected, .viewer .tabUnselected:hover {
 color: #fff;
 background: #B2B6BE;
}

. viewer .tabContents {
 color: #014;
 background: #ebeef1;
 border: 1px solid #B2B6BE;
}

.searchBar {float:right; font-size:0.9em;}
.searchBar .button {display:block; border:none; color:#ccc;}
.searchBar .button:hover{border:none; color:#eee;}

.searchBar input{
 border: 1px inset #1d65bc; background:#dbdee3;
}

.searchBar input:focus {
 border: 1px inset #3371a3; background:#fff;
}

.blog h2, .blog h3, .blog h4{
  margin:0;
  padding:0;
border-bottom:none;
}
.blog {margin-left:1.5em;}  


.blog .excerpt {
  margin:0;
margin-top:0.3em;
  padding: 0;
  margin-left:1em;
  padding-left:1em;
  font-size:90%;
  border-left:1px solid #ddd;
}

#tiddlerWhatsNew h1, #tiddlerWhatsNew h2 {border-bottom:none;}
div[tags~="RecentUpdates"], div[tags~="lewcidExtension"] {margin-bottom: 2em;}


#topMenu .fontResizer {float:right;}

#topMenu .fontResizer .button{border:1px solid #3371A3;}
#topMenu .fontResizer .button:hover {border:1px solid #fff; color:#3371A3;}
#sidebarTabs .txtMainTab .tiddlyLinkExisting {
 font-weight: normal;
 font-style: normal;
}

#sidebarTabs .txtMoreTab .tiddlyLinkExisting {
 font-weight: bold;
 font-style: normal;
}
tiddlers:
*K2WSStyleSheet
*K2WSPageTemplate

<<applyTheme K2WS Preview>>
/***
|Name|Let's Get Tanked!|
|Source|http://www.TiddlyTools.com/#Let's Get Tanked!|
|Version||
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|CSS|
|Requires||
|Overrides||
|Description|theme: dark blue fishtank photo background|
|StyleSheet|Let's Get Tanked!|
|PageTemplateReadOnly|PageTemplateReadOnly|
|EditTemplateReadOnly|EditTemplateReadOnly|
***/

[[StyleSheetAdjustments]]
[[BrightText]]
/* ==== Let's Get Tanked! ==== */
/*{{{*/
body
	{ background-image: url('[[Let's Get Tanked! Background]]'); background-attachment: fixed; background-color:#113; }
.menubox
	{ background: #003; border:1px solid; -moz-border-radius:1em; padding:1em }
.viewer
	{ background: #003; border:1px solid; -moz-border-radius:1em; padding:1em; opacity:0.8; filter:'alpha(opacity:80)'; }
#tiddlerWelcome .tabContents
	{ opacity:0.9; filter:'alpha(opacity:90)'; }
.header
	{ background-image: none; background-color:transparent; color:#ccf; border:0; }
.floatingPanel, .attachPanel, #importPanel, #exportPanel,
	{ background: #eef; }
.floatingPanel a, .attachPanel a, #importPanel a, #exportPanel a, #sidebarTabs .tabContents a,
.floatingPanel .button, .attachPanel .button, #importPanel .button, #exportPanel .button, #sidebarTabs .tabContents .button,
.floatingPanel .tiddlyLinkExisting, .attachPanel .tiddlyLinkExisting, #importPanel .tiddlyLinkExisting, #exportPanel .tiddlyLinkExisting, #sidebarTabs .tabContents .tiddlyLinkExisting
	{ color:#009; }
.siteMenu .floatingPanel, #messageArea 
	{ background: #eef; }
.tiddlyCard { background:#ffd; }
.viewer h1,.viewer h2,.viewer h3,.viewer h4,.viewer h5 { background: #666; color:#fff; }
.viewer .tabContents, #sidebarTabs .tabContents
	{ background-color:#002; }
.tabContents a, .tabContents .button, .tabContents .tiddlyLinkExisting
	{ color:#99f; }
/*}}}*/
| source file|{{{...images\fish.jpg}}}|
| attached on|20 May 2006 by ELSDesignStudios|
| embedded data|//none//|
| local link|//none//|
| remote link|/%REMOTE_LINK%/[[images/fish.jpg|images/fish.jpg]]|
image
<<<
usage: {{{[img[tooltip|Let's Get Tanked! Background]] or [img[tooltip|Let's Get Tanked! Background][link]]}}}
[img[tooltip|Let's Get Tanked! Background]]
<<<
<!--{{{-->
<div class='header'>
     <div class='gradient' macro='gradient vert #FF8614 #DA4A0D '>
	<div class='titleLine' >
		<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
		<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
	</div>
<div id='topMenu' refresh='content' tiddler='MainMenu'></div>
    </div>
</div>
<div id='bodywrapper'>
<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 id='contentFooter'>TiddlyWiki</div>
</div>

<!--}}}-->
[[SideBarWG]]

/***
!Top Menu Styles
***/
/*{{{*/
#topMenu br {display:none; }
#topMenu { background: #000 ; color:#fff;padding: 1em 1em;}
/*}}}*/

/***
!General
***/
/*{{{*/
body {
 background: #444;
 margin: 0 auto;
}

 #contentWrapper{
 background: #fff;
 border: 0;
 margin: 0 auto;
 width: 792px;
 padding:0;
}
/*}}}*/

/***
!Header rules
***/
/*{{{*/
.titleLine{
 margin: 80px auto 0em ;
margin-left:1.7em;
margin-bottom: 40px;
 padding: 0;
 text-align: left;
 color: #fff;
}

.siteTitle {
	font-size: 2em;
        font-weight: bold;
}

.siteSubtitle {
	font-size: 1.1em;
        display: block;
        margin: .5em auto 1em;
}

.gradient {margin: 0 auto;}



.header {
 background: #fff; 
 margin: 0 auto;
 padding:0 12px;
 width: 768px;
}
/*}}}*/

/***
!Display Area
***/
/*{{{*/
#bodywrapper {margin:0 12px; padding:0;background:#fff; height:1%}

#displayArea{
 margin: 0em 16em 0em 1em;
 text-align: left;
}

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

h1,h2,h3,h4,h5 { color: #000; background: transparent; padding-bottom:2px; border-bottom: 1px dotted #666; }
.title {color:black; font-size:1.8em; border-bottom:1px solid #333; padding-bottom:0.3px;}
.subtitle { font-size:90%; color:#ccc; padding-left:0.25em; margin-top:0.1em; }

.shadow .title {
	color: #aaa;
}

.tagClear{
	clear: none; 
}

* html .viewer pre {
	margin-left: 0em;
}

* html .editor textarea, * html .editor input {
	width: 98%;
}

.tiddler {margin-bottom:1em; padding-bottom:0em;}


.toolbar .button {color:#bbb; border:none;}
.toolbar .button:hover, .toolbar .highlight, .toolbar .marked, .toolbar a.button:active {background:transparent; color:#111; border:none; text-decoration:underline;}

#sidebar .highlight, #sidebar .marked {background:transparent;}

.tagging, .tagged {
	border: 1px solid #eee;
	background-color: #F7F7F7;
}

.selected .tagging, .selected .tagged {
	background-color: #eee;
	border: 1px solid #bbb;
}

 .tagging .listTitle, .tagged .listTitle {
	color: #bbb;
}

.selected .tagging .listTitle, .selected .tagged .listTitle {
	color: #222; 
}


.tagging .button:hover, .tagged .button:hover {
		border: none; background:transparent; text-decoration:underline; color:#000;
}

.tagging .button, .tagged .button {
		color:#aaa;
}

.selected .tagging .button, .selected .tagged .button {
		color:#000;
}

.viewer blockquote {
	border-left: 3px solid #000;
}

.viewer pre, .viewer code {
	border: 1px dashed #ccc;
	background: #eee;}

.viewer hr {
	border: 0;
	border-top: solid 1px #333;
 margin: 0 8em;
	color: #333;
}

.highlight, .marked {background:transparent; color:#111; border:none; text-decoration:underline;}

.viewer .highlight, .viewer .marked {text-decoration:none;}

#sidebarTabs .highlight, #sidebarTabs .marked {color:#000; text-decoration:none;}

.tabSelected {
 color: #000;
 background: #fff;
 border-top: solid 1px #ccc;
 border-left: solid 1px #ccc;
 border-right: solid 1px #ccc;
 border-bottom: none;
}

.viewer .tabSelected:hover{color:#000;}

.viewer .tabSelected {font-weight:bold;}

.tabUnselected {
 color: #999;
 background: #eee;
 border-top: solid 1px #ccc;
 border-left: solid 1px #ccc;
 border-right: solid 1px #ccc;
 border-bottom: solid 1px #ccc;
 padding-bottom:1px;
}

.tabContents {
 background: #fff;
  color: #000;
}
/*}}}*/
/***
!!!Tables
***/
/*{{{*/
.viewer table {
	border: 1px solid #000;
}

.viewer th, thead td {
	background: #000;
	border: 1px solid #000;
	color: #fff;
}

.viewer td, .viewer tr {
	border: 1px solid #111;
}
/*}}}*/


/***
!!!Editor area
***/
/*{{{*/
.editor input, .editor textarea {
	border: 1px solid #ccc;
}

.editor {padding-top:0.3em;}

.editor textarea:focus, .editor input:focus {
	border: 1px solid #333;
}
/*}}}*/

/***
!Sidebar
***/
/*{{{*/
#sidebar{
position:relative;
float:right;
margin-bottom:1em;
display:inline;
width: 16em;
}

#sidebarOptions .sliderPanel {
	background: #eee; border:1px solid #ccc;
}

/*}}}*/

/***
!Body Footer rules
***/
/*{{{*/
#contentFooter {
 text-align: left;
 clear: both;
 color:#fff;
 background: #000;
 padding: 1em 2em;
font-weight:bold;
}

/*}}}*/
/***
!Link Styles
***/
/*{{{*/
a{
	color: #000;
}

a:hover{
        color: #FF6600;
        background:#fff;
}


.button {
	color: #000;
	border: 1px solid #fff;
}

.button:hover {
	color: #fff;
	background: #ff8614;
	border-color: #000;
}

.button:active {
	color: #fff;
	background: #ff8614;
	border: 1px solid #000;
}

.tiddlyLink {border-bottom: 1px dotted #000;}
.tiddlyLink:hover {border-bottom: 1px dotted #FF6600;} 

.titleLine a {border-bottom: 1px dotted #FF9900;}

.titleLine a:hover {border-bottom: 1px dotted #fff;}

.siteTitle a, .siteSubtitle a{
 color: #fff;
}

.viewer .button {border: 1px solid #ff8614; font-weight:bold;}
.viewer .button:hover, .viewer .marked, .viewer .highlight{background:#ff8614; color:#fff; font-weight:bold; border: 1px solid #000;}

#topMenu .button, #topMenu .tiddlyLink {
 margin-left:0.5em; margin-right:0.5em;
 padding-left:3px; padding-right:3px;
 color:white;
}
#topMenu .button:hover, #topMenu .tiddlyLink:hover { background:#000; color:#FF8814}

#topMenu a{border:none;}
/*}}}*/

/***
!Message Area /%=================================================%/
***/
/*{{{*/
#messageArea {
	border: 4px dotted #ff8614;
	background: #000;
	color: #fff;
        font-size:90%;
}

#messageArea .button {
	padding: 0.2em;
	color: #000;
	background: #fff;
        text-decoration:none;
        font-weight:bold;
        border:1px solid #000; 
}

#messageArea a {color:#fff;}

#messageArea a:hover {color:#ff8614; background:transparent;}

#messageArea .button:hover {background: #FF8614; color:#fff; border:1px solid #fff; }

/*}}}*/

/***
!Popup /%=================================================%/
***/
/*{{{*/
.popup {
	background: #ff8814;
	border: 1px solid #333;
}

.popup hr {
	color: #333;
	background: #333;
	border-bottom: 1px;
}

.popup li.disabled {
	color: #333;
}

.popup li a, .popup li a:visited {
	color: #eee;
	border: none;
}

.popup li a:hover {
	background: #ff8614;
	color: #fff;
	border: none;
        text-decoration:underline;
}
/*}}}*/

.blog h2, .blog h3, .blog h4{
  margin:0;
  padding:0;
border-bottom:none;
}
.blog {margin-left:1.5em;}  


.blog .excerpt {
  margin:0;
margin-top:0.3em;
  padding: 0;
  margin-left:1em;
  padding-left:1em;
  font-size:90%;
  border-left:1px solid #ddd;
}

#tiddlerWhatsNew h1, #tiddlerWhatsNew h2 {border-bottom:none;}
div[tags~="RecentUpdates"], div[tags~="lewcidExtension"] {margin-bottom: 2em;}

#hoverMenu  .button, #hoverMenu  .tiddlyLink {border:none; font-weight:bold; background:#f37211; color:#fff; padding:0 5px; float:right; margin-bottom:4px;}
#hoverMenu .button:hover, #hoverMenu .tiddlyLink:hover {font-weight:bold; border:none; color:#f37211; background:#000; padding:0 5px; float:right; margin-bottom:4px;}

#topMenu .fontResizer {float:right;}

#topMenu .fontResizer .button{border:1px solid #000;}
#topMenu .fontResizer .button:hover {border:1px solid #f37211; color:#fff;}
#sidebarTabs .txtMainTab .tiddlyLinkExisting {
 font-weight: normal;
 font-style: normal;
}

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

.blog h2, .blog h3, .blog h4{
  margin:0;
  padding:0;
border-bottom:none;
}
.blog {margin-left:1.5em;}  


.blog .excerpt {
  margin:0;
margin-top:0.3em;
  padding: 0;
  margin-left:1em;
  padding-left:1em;
  font-size:90%;
  border-left:1px solid #ddd;
}

#tiddlerWhatsNew h1, #tiddlerWhatsNew h2 {border-bottom:none;}
div[tags~="RecentUpdates"], div[tags~="lewcidExtension"] {margin-bottom: 2em;}

#hoverMenu {background:transparent;}
#hoverMenu  .button, #hoverMenu  .tiddlyLink {border:none; font-weight:bold; background:#f37211; color:#fff; padding:0 5px; float:right; margin-bottom:4px;}
#hoverMenu .button:hover, #hoverMenu .tiddlyLink:hover {font-weight:bold; border:none; color:#f37211; background:#000; padding:0 5px; float:right; margin-bottom:4px;}

#topMenu .fontResizer {float:right;}

#topMenu .fontResizer .button{border:1px solid #000;}
#topMenu .fontResizer .button:hover {border:1px solid #f37211; color:#fff;}
#sidebarTabs .txtMainTab .tiddlyLinkExisting {
 font-weight: normal;
 font-style: normal;
}

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

tiddlers:
*LewcidOrangeBlogStyleSheet
*LewcidOrangeBlogPageTemplate

<<applyTheme LewcidOrangeBlog Preview>>
tiddlers:
*StyleSheet
*PageTemplate

<<applyTheme '' Preview>>
/%
|''URL:''|http://tw.lewcid.org/|
|''Description:''|a repository of my extensions for TW|
|''Author:''|SaqImtiaz|
%/
/***
|Name|ListboxPlugin|
|Source|http://www.TiddlyTools.com/#ListboxPlugin|
|Documentation|http://www.TiddlyTools.com/#ListboxPluginInfo|
|Version|1.0.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|set tiddler fields by selecting enumerated values from a listbox or droplist|
The {{{<<select>>}}} macro allows you to set tiddler field values by selecting pre-configured enumerated values from a listbox/droplist control.  
!!!!!Documentation
>see [[ListboxPluginInfo]]
!!!!!Revisions
<<<
2008.04.28 [1.0.1] added "=tagvalue" syntax for generating lists of tiddlers tagged with a given value
|please see [[ListboxPluginInfo]] for additional revision details|
2007.05.12 [0.5.0] started
<<<
!!!!!Code
***/
//{{{
version.extensions.select= {major: 1, minor: 0, revision: 1, date: new Date(2008,4,28)};

config.macros.select = {
	tooltip: "select a value for %0@%1",
	blankTooltip: "set %0@%1=[null] (delete field value)",
	valueTooltip: "set %0@%1=%2",
	otherLabel: "other",
	otherTooltip: "set %0@%1=[???] (enter custom value)",
	otherPrompt: "enter a value for '%0'",
	editLabel: "edit list...",
	editTooltip: "edit '%0' list definition (%1)",
	changeMsg: "setting %0@%1=%2",
	verbose: false,
	hereKeyword: "here",
	defaultTarget: "SiteFields",
	handler:
	function(place,macroName,params,wikifier,paramString,tiddler) {

		// get containing tiddler (or use default "SiteFields" catch-all tiddler)
		var here=story.findContainingTiddler(place);
		var targetID=here?here.getAttribute("tiddler"):this.defaultTarget;
		// get field name
		var field=params.shift();
		var pos=field.indexOf("@"); // if non-default target ("field@tiddler" syntax)
		if(pos!=-1) { // split field into field and tiddlername.
			if (field.substr(pos+1)!=this.hereKeyword) // "here" == use default target
				targetID=field.substr(pos+1); // switch to different target tiddler
			field=field.substr(0,pos);
		}

		// if no field name, do nothing
		if(!field || !field.length) return;

		var p=params.shift();
		var rows="0"; if (p.substr(0,5)=="rows:") { rows=p.substr(5); p=params.shift(); } // optional list height in lines
		var width="auto"; if (p.substr(0,6)=="width:") { width=p.substr(6); p=params.shift(); } // optional CSS width
		var autosave=(p.toLowerCase()=="autosave"); if (autosave) p=params.shift(); // optional autosave
		var allowBlank=(p.toLowerCase()=="allowblank"); if (allowBlank) p=params.shift(); // add optional empty item
		var allowOther=(p.toLowerCase()=="allowother"); if (allowOther) p=params.shift(); // add optional "other: ____" item

		if (tiddler && !story.isDirty(tiddler.title)) autosave=true; // if tiddler is in VIEW mode, force autosave

		var list=[];
		if (p.substr(0,1)=="+"||p.substr(0,1)=="*") { // get list from HR-separated tiddler (* means wikify source first)
			var listsrc=p.substr(1);
			var listtxt=store.getTiddlerText(listsrc);
			var wikifyData=p.substr(0,1)=="*"; if (wikifyData) listtxt=this.getWikifiedData(listtxt);
			var separator="\n";
			if (listtxt && listtxt.indexOf("\n----\n")!=-1) separator="\n----\n";
			if (listtxt && listtxt.length) var list=listtxt.split(separator);
			var allowEdit=(params[0] && params[0].toLowerCase()=="allowedit"); // add optional "edit list..." item
			if (allowEdit) p=params.shift();
		}
		else if (p.substr(0,1)=="=") { // get list from tagged tiddlers
			var tids=store.getTaggedTiddlers(p.substr(1));
			for (var t=0; t<tids.length; t++) list.push(tids[t].title);
		}
		else { // get list from macro params: "value value value ..." or "label=value label=value label=value ..."
			while (p) {
				var parts=p.split("=");
				var label=parts[0]; var v=parts[1]?parts[1]:parts[0];
				list.push(label+"="+v);
				p=params.shift();
			}
		}
		// register notification handler for ALL tiddler changes (to sync lists)
		store.addNotification(null,this.refresh);
		// render the control
		this.render(createTiddlyElement(place,"span"), null, targetID, field, list, listsrc, wikifyData, rows, width, autosave, allowBlank, allowOther, allowEdit);
	},
	getWikifiedData: // wikify tiddler content, then extract text WITH newlines and HRs included
	function(txt) {
		var e=createTiddlyElement(document.body,"div"); wikify(txt,e);
		var breaks=e.getElementsByTagName("br");
		for (var b=0; b<breaks.length; b++) breaks[b].parentNode.insertBefore(document.createTextNode("\n"),breaks[b]);
		var lines=e.getElementsByTagName("hr");
		for (var l=0; l<lines.length; l++) lines[l].parentNode.insertBefore(document.createTextNode("----\n"),lines[l]);
		var items=e.getElementsByTagName("li");
		for (var i=0; i<items.length; i++) items[i].parentNode.insertBefore(document.createTextNode("\n"),items[i]);
		var txt=getPlainText(e); removeNode(e); return txt;
	},
	refresh:
	function (title) {
		var lists=document.getElementsByTagName("select");
		for (i=0; i<lists.length; i++) {
			if (lists[i].getAttribute("listsrc")==title) {
				var here=lists[i];
				var place=here.parentNode;
				var targetID=here.getAttribute("tiddler");
				var field=here.getAttribute("edit");
				var listsrc=here.getAttribute("listsrc");
				var rows=here.getAttribute("rows");
				var width=here.getAttribute("width");
				var autosave=here.getAttribute("autosave")=="true";
				var allowBlank=here.getAttribute("allowBlank")=="true";
				var allowOther=here.getAttribute("allowOther")=="true";
				var allowEdit=here.getAttribute("allowEdit")=="true";
				var wikifyData=here.getAttribute("wikifyData")=="true";
				// get the list
				var listtxt=store.getTiddlerText(listsrc,""); if (wikifyData) listtxt=config.macros.select.getWikifiedData(listtxt);
				var separator="\n"; if (listtxt && listtxt.indexOf("\n----\n")!=-1) separator="\n----\n";
				var list=[]; if (listtxt && listtxt.length) var list=listtxt.split(separator);
				// re-render control
				config.macros.select.render(place, here, targetID, field, list, listsrc, wikifyData, rows, width, autosave, allowBlank, allowOther, allowEdit);
			}
		}
	},
	render:
	function (place, here, targetID, field, list, listsrc, wikifyData, rows, width, autosave, allowBlank, allowOther, allowEdit) {
		// use selected value from existing listbox (except for "edit list..." item)
		if (here && here.selectedIndex!=-1 && here.options[here.selectedIndex].text!=config.macros.select.editLabel)
			{ var val=here.value; if (val && !val.length) val=undefined; }
		// if listbox doesn't yet exist, or 'edit list' item was selected, use value from existing field, if available...
		if (!val) var val=store.getValue(targetID,field);
		var count=0; var options="";
		// add default 'undefined' item
		if (val==undefined || allowBlank) {
			var title=this.blankTooltip.format([field,targetID]);
			options+='<option value="" title="'+title+'"></option>';
			count++;
		}
		// add enumerated items
		var isOther=(val!=undefined);
		for (opt=0; opt<list.length; opt++) {
			var lines=list[opt].split("\n"); var parts=lines[0].split("=");
			var label=parts[0];
			var v=parts[1]?parts[1]:parts[0];
			var title=lines[1]?lines[1]:this.valueTooltip.format([field,targetID,v]);
			options+='<option value="'+v+'" '+(val==v?'selected':'')+' title="'+title+'">'+label+'</option>';
			if (val==v) isOther=false; // found matching value in list
			count++;
		}
		// add other... item
		if (isOther||allowOther) {
			var label="other"+(isOther?(": "+val):"...");
			var v=isOther?val:"";
			var title=this.otherTooltip.format([field,targetID]);
			options+='<option value="'+v+'" '+(isOther?'selected':'')+' title="'+title+'">'+label+'</option>';
			count++;
		}
		// add edit list... item
		if (listsrc && (!store.tiddlerExists(listsrc) || allowEdit)) {
			var title=this.editTooltip.format([field,listsrc]);
			options+='<option value="'+listsrc+'" title="'+title+'">'+this.editLabel+'</option>';
			count++;
		}
		// construct full HTML
		var html='<select ';
		html+=(val!=undefined?'value="'+val+'" ':'')+'" edit="'+field+'" ';
		html+='onclick="return config.macros.select.onClick(this,event)" ';
		html+='onchange="return config.macros.select.onChange(this,event)" ';
		html+='ondblclick="return false" ';
		html+='autosave="'+autosave+'" allowBlank="'+allowBlank+'" ';
		html+='allowOther="'+allowOther+'" allowEdit="'+allowEdit+'" ';
		html+='rows="'+rows+'" size="'+(rows!=0?rows:count)+'" ';
		html+='tiddler="'+targetID+'" '+'" listsrc="'+listsrc+'" wikifyData="'+wikifyData+'" ';
		html+='title="'+this.tooltip.format([field,targetID])+'" style="width:'+width+'">'+options+'</select>';
		// pass to browser for rendering
		place.innerHTML=html;
	},
	onClick:
	function(here,event) {
		var label=config.macros.select.otherLabel;
		if (here.getAttribute("allowother")=="true" && here.options[here.selectedIndex].text.substr(0,label.length)==label)
			here.onchange.apply(here,arguments);
	},
	onChange:
	function(here,event) {
		if (here.options[here.selectedIndex].text==config.macros.select.editLabel) {
			story.displayTiddler(story.findContainingTiddler(here),here.value,DEFAULT_EDIT_TEMPLATE);
			return false;
		}
		var label=config.macros.select.otherLabel;
		if (here.getAttribute("allowother")=="true" && here.options[here.selectedIndex].text.substr(0,label.length)==label) {
			var newval=prompt(config.macros.select.otherPrompt.format([here.getAttribute("edit")]),here.value);
			if (!newval) {// user cancelled
				var v=store.getValue(here.getAttribute("tiddler"),here.getAttribute("edit"));
				{ here.value=v; if (v==undefined) here.selectedIndex=0; return false; }
			};
			here.options[here.selectedIndex].value=newval;
			here.options[here.selectedIndex].text=config.macros.select.otherLabel+": "+newval;
			here.value=newval;
		}
		if (here.getAttribute("autosave")=="true") config.macros.select.setFieldValue(here);
		return false;
	},
	setFieldValue: function(here) {
		var tid=here.getAttribute("tiddler"); if (!tid || !tid.length) return; // no target tiddler specified, do nothing
		var field=here.getAttribute("edit");
		// if tiddler doesn't exist, create it...
		if (!store.tiddlerExists(tid)) store.saveTiddler(tid,tid,"",config.options.txtUserName,new Date(),[]);
		// set the field value in the target tiddler
		store.setValue(tid,field,here.value.length?here.value:null); // if value is blank, delete field
		// touch target tiddler so that modified and modifier are updated
		var t=store.getTiddler(tid);
		store.saveTiddler(tid,tid,t.body,config.options.txtUserName,new Date(),t.tags,t.fields);
		if (config.macros.select.verbose) // tell user what happened
			{ clearMessage(); displayMessage(config.macros.select.changeMsg.format([field,tid,here.value])); }
	}
}
//}}}
|Name|ListboxPlugin|
|Source|http://www.TiddlyTools.com/#ListboxPlugin|
|Documentation|http://www.TiddlyTools.com/#ListboxPluginInfo|
|Version|1.0.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for ListboxPlugin|
The {{{<<select>>}}} macro allows you to set tiddler field values by selecting pre-configured enumerated values from a listbox/droplist control.  
!!!!!Usage
<<<
The macro may be used within the ViewTemplate or EditTemplate to add a listbox/droplist to every tiddler, or embedded directly in specific tiddler content to create interfaces for custom-built TW "applications" that use tiddler fields to store application-specific values.

Syntax for use in ViewTemplate/EditTemplate:
{{{
<div class="editor" macro="select fieldname@tiddlername rows:nn width:xxx autoSave allowBlank allowOther
	value value value ..."></div>
<div class="editor" macro="select fieldname@tiddlername rows:nn width:xxx autoSave allowBlank allowOther
	label=value label=value label=value ..."></div>
<div class="editor" macro="select fieldname@tiddlername rows:nn width:xxx autoSave allowBlank allowOther
	=TiddlerName allowEdit"></div>
<div class="editor" macro="select fieldname@tiddlername rows:nn width:xxx autoSave allowBlank allowOther
	+TiddlerName allowEdit"></div>
}}}

Syntax for direct embedding in tiddler content:
{{{
<<select fieldname@tiddlername rows:nn width:xxx allowBlank allowOther
	value value value ...>>
<<select fieldname@tiddlername rows:nn width:xxx allowBlank allowOther
	label=value label=value label=value ...>>
<<select fieldname@tiddlername rows:nn width:xxx allowBlank allowOther
	=TiddlerName allowEdit>>
<<select fieldname@tiddlername rows:nn width:xxx allowBlank allowOther
	+TiddlerName allowEdit>>
}}}

//where://
''fieldname@tiddlername''
>specifies the tiddler field associated with the list display.  The "@tiddlername" portion is optional and, when omitted, the current tiddler is assumed (note: you may also use the special keyword, "@here", to designate the current tiddler)
''rows:nn''
>specifies the number of lines to display in the list.  If rows=1, a 'droplist' is displayed. If rows>1 a fixed-height listbox is used.  By default (or if rows=0 is used), the listbox is displayed with enough lines to show all items without scrolling (i.e., "fit to contents - vertically")
''width:xxx''
>specifies the width of the list, using a CSS dimension value (px, em, in, cm, or %).  The default is auto (i.e., "fit to contents - horizontally").
''autoSave''
>when used in EditTemplate, this keyword forces selection changes to be applied immediately rather than waiting for the "done" command to be invoked.  Note: because the standard ViewTemplate toolbar does not have a "done" command to signal the end of the editing activity, ''autoSave'' is always enabled when working with a selection list that is being displayed in 'view mode'.
''allowBlank''
>when the value of a tiddler field is "undefined", a 'blank' item is added at the beginning of the list to represent the undefined field value.  When a field value is subsequently selected, the blank item is removed from the list.   Use the ''allowBlank'' keyword to always include the blank item in the list.  Selecting the blank item sets the field value back to "undefined" (i.e., deletes the field).
''allowOther''
>when the value of a tiddler field does not match any of the values in the list, a special 'other' item is added at the end of the list so that the unrecognized field value can be shown.  If another field value is subsequently selected, the 'other' item is removed from the list.  Use the ''allowOther'' keyword to always include the 'other item in the list.  When this item is selected, you will be prompted to enter a custom value to assign to the field.
''value value value ...'' //or// ''label=value label=value label=value ...'' //(inline list definition)//
//or// ''=tagvalue'' //(tag-based list definition)//
//or// ''+~TiddlerName'' //or// ''*~TiddlerName'' //(tiddler-based list definition)//
>specifies list item values or label/value pairs.  You can use the ''=tagvalue'' syntax to generate a list whose items are the names of tiddlers tagged with that value (e.g., "=systemConfig" to list all plugins, or "=friends" to list all tiddlers tagged as "friends").  You can also use the ''+~TiddlerName'' or ''*~TiddlerName'' syntax to define the values or label/value pairs using a tiddler containing an "HR-separated" list, where each list item is one or two lines of text, separated from the next item by a horizontal rule: """----""".  The first line of each item contains the value or label=value that will appear in the list.  The second, optional line allows you to specify a custom tooltip for that list item.  If you use "*" preceding the ~TiddlerName, the contents of the tiddler will be processed by the TiddlyWiki parser before being processed as a list definition.  This allows you to use macros to dynamically generate list definitions based on the current document contents (such as available tag names).  The default tooltip for a list item is: "{{{set fieldname@tiddlername=itemvalue}}}".  Note: if all list entries are single-line (i.e., you are not defining ANY custom tooltips), you can omit the horizontal rule between entries... each line of text will be treated as a separate list entry.
''allowEdit'' //(for use with +~TiddlerName param only)//
>adds optional "edit list..." item to the end of the list, to enable quick editing of a tiddler-based list definition.  Note: if the ''+~TiddlerName'' parameter refers to a tiddler that does not yet exist, the "edit list..." item is automatically added to the list, even if ''allowEdit'' was not specified.  This allows you to place an 'empty' tiddler-based list into your content (e.g., """<<select fieldname =NewTiddlerName>>"""), and then create and define the tiddler-based list later on.
<<<
!!!!!Examples
<<<
''inline list definition:''
{{{<<select thing rows:1 eenie meenie miney moe>>}}}
<<select thing rows:1 eenie meenie miney moe>>
{{{<<select size rows:1 xsmall=30 small=32 medium=34 large=36 xlarge=38>>}}}
<<select size rows:1 xsmall=30 small=32 medium=34 large=36 xlarge=38>>
{{{<<select size allowOther xsmall=30 small=32 medium=34 large=36 xlarge=38>>}}}
<<select size allowOther xsmall=30 small=32 medium=34 large=36 xlarge=38>>

''tiddler-based list definition:''
{{{<<select color rows:1 +ListboxSample>>}}}
<<select color rows:1 +ListboxSample>>
{{{<<select color allowBlank allowOther +ListboxSample allowEdit>>}}}
<<select color allowBlank allowOther +ListboxSample allowEdit>>
{{{<<select demo@ListboxDemoTarget +ListboxNewSample>>}}}
<<select demo@ListboxDemoTarget +ListboxNewSample>>

''tag-based list definition:''
{{{<<select plugins rows:1 =systemConfig>>}}}
<<select plugins rows:1 allowBlank =systemConfig>>
{{{<<select faq rows:1 allowBlank =faq>>}}}
<<select faq rows:1 =faq>>
<<<
!!!!!Revisions
<<<
2008.04.28 [1.0.1] added "=tagvalue" syntax for generating lists of tiddlers tagged with a given value
2007.08.31 [0.8.2] corrected handling for "@tiddlername" syntax for non-default 'target' tiddler.
2007.08.06 [0.8.1] added support for "@here" keyword syntax and cleaned up handling for identifying 'target' tiddler.  Also added 'onclick' handler for "other:" item, so that prompt dialog is presented even if "other" was already selected (and hence, no "onchange" event)
2007.07.29 [0.8.0] added getWikifiedData() and support for "*" prefix on TiddlerName.  Causes tiddler content to be wikified before processing it as a listbox definition.  Allows you to use macros or inline scripts to *generate* dynamic list definitions from current document content.  Based on a request from EdgarWhipple.
2007.07.26 [0.7.3] in onChange(), corrected call to config.macros.select.setFieldValue() instead of config.macros.setFieldValue().  Thanks to EdgarWhipple for the bug report!
2007.07.24 [0.7.2] in setFieldValue(), 'touch' target tiddler AFTER setting value to avoid early refresh event that steps on listbox attributes, causing a fatal error (in IE only).  Thanks go to Ken Girard for the bug report!  Also, in render(), fixed problem where selecting "edit list..." would set the value of the field to the name of the tiddler containing the list.  Also removed unneeded deferred (setTimeout) handling for invoking setFieldValue()
2007.06.28 [0.7.1] in render(), retrieve current val from tiddler editor control (when editing) or use stored field (when viewing).
2007.05.29 [0.7.0] split render() logic from handler(), added notification-based refresh() for lists that use +TiddlerName definition so changes in underlying tiddler definition are automatically sync'ed up in any currently displayed lists
2007.05.15 [0.6.1] code/documentation cleanup
2007.05.14 [0.6.0] lots more options
2007.05.12 [0.5.0] started
<<<
Red=#FF0000
----
Orange=#FF9900
----
Yellow=#FFFF00
----
Green=#00FF00
----
Blue=#0000FF
----
Indigo=#000099
----
Violet=#9900FF
----
Black=#000000
----
White=#FFFFFF
/%
|Name|LoadRemotePlugin|
|Source|http://www.TiddlyTools.com/#LoadRemotePlugin|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|Load a plugin from a remote URL|

Usage:
<<tiddler LoadRemotePlugin with: "label" "tip" "URL" "onloadfunction" "preloadedtest" "onrunfunction>>

see [[InstantBookmarklets]] for examples

%/<script label="$1" title="$2">
	if ('$5'!='$'+'5' && ($5)) {
		clearMessage();
		if ('$6'!='$'+'6') {$6;} else {$4;}
		displayMessage('$1 is already installed.');
		return false;
	}
	var s=document.createElement('script');
	s.src='$3';
	s.onerror=function() {
		clearMessage();
		displayMessage('Could not load $1 from');
		displayMessage(this.src,this.src);
	};
	s.onload=function() {
		clearMessage();
		{$4;}
		displayMessage('$1 has been loaded from');
		displayMessage(this.src,this.src);
	};
	s.onreadystatechange=function() { /* for IE */
		if(this.readyState=='complete'){
			clearMessage();
			{$4;}
			displayMessage('$1 has been loaded from');
			displayMessage(this.src,this.src);
		}
	};
	document.getElementsByTagName('head')[0].appendChild(s);
	return false;
</script>
/***
|''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);
}
//}}}
/***
|Name|LoadTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#LoadTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#LoadTiddlersPluginInfo|
|Version|3.6.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|macro for automated updates or one-click installations of tiddlers from remote sources|
!!!!!Documentation
>see [[LoadTiddlersPluginInfo]]
!!!!!Configuration
<<<
__password-protected server settings //(optional, if needed)//:__
>username: <<option txtRemoteUsername>> password: <<option txtRemotePassword>>
>{{{usage: <<option txtRemoteUsername>> <<option txtRemotePassword>>}}}
>''note: these settings are also used by [[ExternalTiddlersPlugin]] and [[ImportTiddlersPlugin]]''
<<<
!!!!!Revisions
<<<
2008.01.07 [3.6.0] added 'init' option to automatically invoke plugin tiddlers as soon as they are loaded (without needing save/reload)
|please see [[LoadTiddlersPluginInfo]] for additional revision details|
2005.07.20 [1.0.0] Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.loadTiddlers = {major: 3, minor: 6, revision: 0, date: new Date(2008,1,7)};

config.macros.loadTiddlers = {
	label: "",
	prompt: "add/update tiddlers from '%0'",
	lockedTag: "noReload",	// if existing tiddler has this tag value, don't overwrite it, even if inbound tiddler is newer
	askMsg: "Please enter a local path/filename or a remote URL",
	openMsg: "Opening %0",
	openErrMsg: "Could not open %0 - error=%1",
	readMsg: "Read %0 bytes from %1",
	foundMsg: "Found %0 tiddlers in %1",
	nochangeMsg: "'%0' is up-to-date... skipped.",
	lockedMsg: "'%0' is tagged '%1'... skipped.",
	skippedMsg: "skipped (cancelled by user)",
	loadedMsg: "Loaded %0 of %1 tiddlers from %2",
	reportTitle: "ImportedTiddlers",
	warning: "Warning!!  Processing '%0' as a systemConfig (plugin) tiddler may produce unexpected results! Are you sure you want to proceed?",
	handler: function(place,macroName,params) {
		var label=(params[0] && params[0].substr(0,6)=='label:')?params.shift().substr(6):this.label;
		var prompt=(params[0] && params[0].substr(0,7)=='prompt:')?params.shift().substr(7):this.prompt;
		var filter="updates";
		if (params[0] && (params[0]=='all' || params[0]=='new' || params[0]=='changes' || params[0]=='updates'
			|| params[0].substr(0,8)=='tiddler:' || params[0].substr(0,4)=='tag:'))
			filter=params.shift();
		var src=params.shift(); if (!src || !src.length) return; // filename is required
		var quiet=(params[0]=="quiet"); if (quiet) params.shift();
		var ask=(params[0]=="confirm"); if (ask) params.shift();
		var force=(params[0]=="force"); if (force) params.shift();
		var init=(params[0]=="init"); if (init) params.shift();
		var noreport=(params[0]=="noreport"); if (noreport) params.shift();
		this.newTags=[]; if (params[0]) this.newTags=params; // any remaining params are used as "autotags"
		if (label.trim().length) {
			// link triggers load tiddlers from another file/URL and then applies filtering rules to add/replace tiddlers in the store
			createTiddlyButton(place,label.format([src.replace(/%20/g," ")]),prompt.format([src.replace(/%20/g," ")]), function() {
				if (src=="ask") src=prompt(this.askMsg);
				config.macros.loadTiddlers.loadFile(src,config.macros.loadTiddlers.doImport,{quiet:quiet,ask:ask,filter:filter,force:force,init:init,noreport:noreport});
			})
		}
		else {
			// load tiddlers from another file/URL and then apply filtering rules to add/replace tiddlers in the store
			if (src=="ask") src=prompt(this.askMsg);
			config.macros.loadTiddlers.loadFile(src,config.macros.loadTiddlers.doImport,{quiet:quiet,ask:ask,filter:filter,force:force,init:init,noreport:noreport});
		}
	},
	fileExists: function(theFile) {
		var found=false;
		// DEBUG: alert('testing fileExists('+theFile+')...');
		if(window.Components) {
			try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
			catch(e) { return false; } // security access denied
			var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
			try { file.initWithPath(theFile); }
			catch(e) { return false; } // invalid directory
			found = file.exists();
		}
		else { // use ActiveX FSO object for MSIE 
			var fso = new ActiveXObject("Scripting.FileSystemObject");
			found = fso.FileExists(theFile)
		}
		// DEBUG: alert(theFile+" "+(found?"exists":"not found"));
		return found;
	},
	loadFile: function(src,callback,params) {
		var quiet=params.quiet;
		if (src==undefined || !src.length) return null; // filename is required
		if (!quiet) clearMessage();
		if (!quiet) displayMessage(this.openMsg.format([src.replace(/%20/g," ")]));
		if (src.substr(0,5)!="http:" && src.substr(0,5)!="file:") { // if src is relative (i.e., not a URL)
			if (!this.fileExists(src)) { // if file cannot be found, might be relative path.. try fixup
				var pathPrefix=document.location.href;  // get current document path and trim off filename
				var slashpos=pathPrefix.lastIndexOf("/"); if (slashpos==-1) slashpos=pathPrefix.lastIndexOf("\\"); 
				if (slashpos!=-1 && slashpos!=pathPrefix.length-1) pathPrefix=pathPrefix.substr(0,slashpos+1);
				src=pathPrefix+src;
				if (pathPrefix.substr(0,5)!="http:") src=getLocalPath(src);
			}
		}
		if (src.substr(0,4)!="http" && src.substr(0,4)!="file") { // if not a URL, read from local filesystem
			var txt=loadFile(src);
			if ((txt==null)||(txt==false)) // file didn't load
				{ if (!quiet) displayMessage(this.openErrMsg.format([src.replace(/%20/g," "),"(unknown)"])); }
			else {
				if (!quiet) displayMessage(this.readMsg.format([txt.length,src.replace(/%20/g," ")]));
				if (callback) callback(true,params,convertUTF8ToUnicode(txt),src,null);
			}
		} else {
			var name=config.options.txtRemoteUsername; var pass=config.options.txtRemotePassword;
			var x=doHttp("GET",src,null,null,name,pass,callback,params,null)
		}
	},
	readTiddlersFromHTML: function(html) {
		// for TW2.2+
		if (TiddlyWiki.prototype.importTiddlyWiki!=undefined) {
			var remoteStore=new TiddlyWiki();
			remoteStore.importTiddlyWiki(html);
			return remoteStore.getTiddlers("title");	
		}
	},
	doImport: function(status,params,html,src,xhr) {
		var quiet=params.quiet;
		var ask=params.ask;
		var filter=params.filter;
		var force=params.force;
		var init=params.init;
		var noreport=params.noreport;
		var tiddlers = config.macros.loadTiddlers.readTiddlersFromHTML(html);
		var count=tiddlers?tiddlers.length:0;
		var querypos=src.lastIndexOf("?"); if (querypos!=-1) src=src.substr(0,querypos);
		if (!quiet) displayMessage(config.macros.loadTiddlers.foundMsg.format([count,src.replace(/%20/g," ")]));
		store.suspendNotifications();
		var count=0;
		if (tiddlers) for (var t=0;t<tiddlers.length;t++) {
			var inbound = tiddlers[t];
			var theExisting = store.getTiddler(inbound.title);
			if (inbound.title==config.macros.loadTiddlers.reportTitle)
				continue; // skip "ImportedTiddlers" history from the other document...
			if (theExisting && theExisting.tags.contains(config.macros.loadTiddlers.lockedTag)) {
				if (!quiet) displayMessage(config.macros.loadTiddlers.lockedMsg.format([theExisting.title,config.macros.loadTiddlers.lockedTag]));
				continue; // skip existing tiddler if tagged with 'noReload'
			}
			// apply the all/new/changes/updates filter (if any)
			if (filter && filter!="all") {
				if ((filter=="new") && theExisting) // skip existing tiddlers
					continue;
				if ((filter=="changes") && !theExisting) // skip new tiddlers
					continue;
				if ((filter.substr(0,4)=="tag:") && inbound.tags.indexOf(filter.substr(4))==-1) // must match specific tag value
					continue;
				if ((filter.substr(0,8)=="tiddler:") && inbound.title!=filter.substr(8)) // must match specific tiddler name
					continue;
				if (!force && store.tiddlerExists(inbound.title) && ((theExisting.modified.getTime()-inbound.modified.getTime())>=0))
					{ if (!quiet) displayMessage(config.macros.loadTiddlers.nochangeMsg.format([inbound.title])); continue; }
			}
			// get confirmation if required
			if (ask && !confirm((theExisting?"Update":"Add")+" tiddler '"+inbound.title+"'\nfrom "+src.replace(/%20/g," ")))
				{ tiddlers[t].status=config.macros.loadTiddlers.skippedMsg; continue; }
			// DO IT!
			var tags=Array.concat(inbound.tags,config.macros.loadTiddlers.newTags);
	                store.saveTiddler(inbound.title, inbound.title, inbound.text, inbound.modifier, inbound.modified, tags, inbound.fields, true, inbound.created);
	                store.fetchTiddler(inbound.title).created = inbound.created; // force creation date to imported value - needed for TW2.1.3 or earlier
			tiddlers[t].status=theExisting?"updated":"added"
			if (init && tags.contains("systemConfig") && !tags.contains("systemConfigDisable")) {
				var ok=true;
				if (ask||!quiet) ok=confirm(config.macros.loadTiddlers.warning.format([inbound.title]))
				if (ok) { // run the plugin
					try { window.eval(inbound); tiddlers[t].status+=" (plugin initialized)"; }
					catch(ex) { displayMessage(config.messages.pluginError.format([exceptionText(ex)])); }
				}
			}
			count++;
		}
		store.resumeNotifications();
		if (count) {
			// refresh display
			store.setDirty(true); store.notifyAll();
			// generate a report
			if (!noreport) config.macros.loadTiddlers.report(src,tiddlers,count,quiet);
		}
		// always show final message when tiddlers were actually loaded
		if (!quiet||count) displayMessage(config.macros.loadTiddlers.loadedMsg.format([count,tiddlers.length,src.replace(/%20/g," ")]));
	},
	report: function(src,tiddlers,count,quiet) {
		// format the new report content
		var newText = "On "+(new Date()).toLocaleString()+", ";
		newText += config.options.txtUserName+" loaded "+count+" tiddlers ";
		newText += "from\n[["+src+"|"+src+"]]:\n";
		newText += "<<<\n";
		for (var t=0; t<tiddlers.length; t++)
			if (tiddlers[t].status)
				newText += "#[["+tiddlers[t].title+"]] - "+tiddlers[t].status+"\n";
		newText += "<<<\n";
		// get current report (if any)
		var title=config.macros.loadTiddlers.reportTitle;
		var currText="";
		var theReport = store.getTiddler(title);
		if (theReport) currText=((theReport.text!="")?'\n----\n':"")+theReport.text;
		// update the ImportedTiddlers content and show the tiddler
		store.saveTiddler(title, title, newText+currText, config.options.txtUserName, new Date(), theReport?theReport.tags:null, theReport?theReport.fields:null);
		if (!quiet) { story.displayTiddler(null,title,1,null,null,false); story.refreshTiddler(title,1,true); }
	}
}
//}}}
/***
|Name|LoadTiddlersPluginInfo|
|Source|http://www.TiddlyTools.com/#LoadTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#LoadTiddlersPluginInfo|
|Version|3.6.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for LoadTiddlersPlugin|
!!!!!Usage
<<<
Syntax:
{{{<<loadTiddlers label:text prompt:text filter source quiet confirm force init noreport tag tag tag...>>}}}

Example:
{{{<<loadTiddlers "label:load tiddlers from %0" example.html confirm temporary>>}}}
<<loadTiddlers "label:load tiddlers from %0" example.html confirm temporary>>

Where:
''"""label:text"""'' and ''"""prompt:text"""''
>defines link text and tooltip (prompt) that can be clicked to trigger the load tiddler processing.  If a label is NOT provided, then no link is created and the loadTiddlers function is performed whenever the containing tiddler is rendered.
''filter'' (optional) determines which tiddlers will be automatically selected for importing.  Use one of the following keywords:
>''"all"'' retrieves ALL tiddlers from the import source document, even if they have not been changed.
>''"new"'' retrieves only tiddlers that are found in the import source document, but do not yet exist in the destination document
>''"changes"'' retrieves only tiddlers that exist in both documents for which the import source tiddler is newer than the existing tiddler
>''"updates"'' retrieves both ''new'' and ''changed'' tiddlers (this is the default action when none is specified)
>''""""tiddler:TiddlerName""""'' retrieves only the specific tiddler named in the parameter.
>''""""tag:text""""'' retrieves only the tiddlers tagged with the indicated text.
>> Note: ''if an existing tiddler is tagged with 'noReload', then it will not be overwritten'', even if the inbound tiddler has been selected by the filtering process.  This allows you to make local changes to imported tiddlers while ensuring that those changes won't be lost due to automatic tiddler updates retrieved from the import source document.
''source'' (required) is the location of the imported document.  It can be either a local document path/filename in whatever format your system requires, or a remote web location (starting with "http://" or "https://")
>use the keyword ''ask'' to prompt for a source location whenever the macro is invoked
''"quiet"'' (optional)
>supresses all status message during the import processing (e.g., "opening local file...", "found NN tiddlers..." etc).  Note that if ANY tiddlers are actualy imported, a final information message will still be displayed (along with the ImportedTiddlers report), even when 'quiet' is specified.  This ensures that changes to your document cannot occur without any visible indication at all.
''"confirm"'' (optional)
>adds interactive confirmation.  A browser message box (OK/Cancel) is displayed for each tiddler that will be imported, so that you can manually bypass any tiddlers that you do not want to import.
''"init"'' (optional)
>invoke tiddlers tagged with <<tag systemConfig>> as plugins as soon as they are imported, without requiring a save-and-reload action first.  For safety, a browser message box (OK/Cancel) is displayed for each imported plugin, so that you can manually bypass any plugins that you do not want to invoke.  Note, however, that those tiddlers are still //imported// into your document and therefore will still take effect the next time you save-and-reload the document.
''"force"'' (optional)
>import all matching tiddlers, even if unchanged
''"noreport"'' (optional)
>suppress generation of [[ImportedTiddlers]] report
''"tag tag tag..."'' (optional)
>any remaining parameters are used as tag values to be added to each imported tiddler (i.e., "tag-on-import")
<<<
!!!!!Configuration
<<<
__password-protected server settings //(optional, if needed)//:__
>username: <<option txtRemoteUsername>> password: <<option txtRemotePassword>>
>{{{usage: <<option txtRemoteUsername>> <<option txtRemotePassword>>}}}
>''note: these settings are also used by [[ExternalTiddlersPlugin]] and [[ImportTiddlersPlugin]]''
<<<
!!!!!Revisions
<<<
2008.01.07 [3.6.0] added 'init' option to automatically invoke plugin tiddlers as soon as they are loaded (without needing save/reload)
2008.01.03 [3.5.0] in loadFile(), use lower-level doHttp() instead of loadRemoteFile() in order to support username/password access to remote server
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.06.27 [3.4.8] added missing 'fields' params to saveTiddler() call. Fixes problem where importing tiddlers would lose the custom fields.
2007.06.25 [3.4.7] add calls to store.suspendNotifications() and store.resumeNotifications() to eliminate redisplay overhead DURING import activities.
2007.05.27 [3.4.6] in handler(),  loadRemoteFile() and doImport(), added 'noreport' flag to suppress generation of ImportedTiddlers
2007.05.27 [3.4.5] in handler(),  initialize 'newTags' to [] (empty array) instead of null... fixes fatal error when loading tiddler without autotagging.
2007.04.22 [3.4.4] in readTiddlersFromHTML(), for TW2.2 and above, use importTiddlyWiki() (new core functionality) to get tiddlers from remote file content.  Also, copied updated TW21Loader.prototype.internalizeTiddler() definition from TW2.2b5 so plugin can read tiddlers from TW2.2+ even when running under TW2.1.x
2007.04.05 [3.4.3] in doImport(), changed this.readTiddlersFromHTML(html) to config.macros.loadTiddlers.readTiddlersFromHTML(html).  Fixes error caused when ImportTiddlersPlugin has NOT been installed along side this plugin.
2007.03.26 [3.4.2] renamed import() to doImport() to fix IE load-time error ("identifier expected").  This may also cause a problem with FF1.5.0.x.... Apparently, "import" is a reserved word in some browsers...
2007.03.22 [3.4.1] code cleanup: moved all functions inside object def'n, re-wrote report function
2007.03.21 [3.4.0] split ImportTiddlersPlugin and LoadTiddlersPlugin functionality into separate plugins
|please see [[ImportTiddlersPluginInfo]] for additional revision details|
2005.07.20 [1.0.0] Initial Release
<<<
/***
|Name|LoadTiddlersPluginPatch|
|Source|http://www.TiddlyTools.com/#LoadTiddlersPluginPatch|
|Version|3.5.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|LoadTiddlersPlugin|
|Overrides||
|Description|backward-compatible function patches for use with LoadTiddlersPlugin and TW2.1.x or earlier|

!!!!!Usage
<<<
The current version LoadTiddlersPlugin is compatible with the TW2.2.x core functions.
This "patch" plugin provides additional functions needed to enable the current version of LoadTiddlersPlugin to operate correctly under TW2.1.x or earlier.

{{medium{You do not need to install this plugin if you are using TW2.2.0 or above}}}
(though it won't hurt anything if you do... it will just take up more space).
<<<
!!!!!Revisions
<<<
''2008.01.03 [3.5.0]'' added support for passing txtRemoteUsername and txtRemotePassword for accessing password-protected remote servers
''2007.06.27 [3.4.8]'' compatibility functions split from LoadTiddlersPlugin
|please see [[LoadTiddlersPlugin]] for additional revision details|
''2005.07.20 [1.0.0]'' Initial Release
<<<
!!!!!Code
***/
//{{{
// these functions are only defined when installed in TW2.1.x and earlier... 
if (version.major+version.minor/10 <= 2.1) {

// Version
version.extensions.LoadTiddlersPatch21x = {major: 3, minor: 5, revision: 0, date: new Date(2008,1,3)};

config.macros.loadTiddlers.loadFile = function(src,callback,params) {
	var quiet=params.quiet;
	if (src==undefined || !src.length) return null; // filename is required
	if (!quiet) clearMessage();
	if (!quiet) displayMessage(this.openMsg.format([src]));
	if (src.substr(0,5)!="http:" && src.substr(0,5)!="file:") { // if src is relative (i.e., not a URL)
		if (!this.fileExists(src)) { // if file cannot be found, might be relative path.. try fixup
			var pathPrefix=document.location.href;  // get current document path and trim off filename
			var slashpos=pathPrefix.lastIndexOf("/"); if (slashpos==-1) slashpos=pathPrefix.lastIndexOf("\\"); 
			if (slashpos!=-1 && slashpos!=pathPrefix.length-1) pathPrefix=pathPrefix.substr(0,slashpos+1);
			src=pathPrefix+src;
			if (pathPrefix.substr(0,5)!="http:") src=getLocalPath(src);
		}
	}
	if (src.substr(0,4)!="http" && src.substr(0,4)!="file") { // if not a URL, read from local filesystem
		var txt=loadFile(src);
		if ((txt==null)||(txt==false)) // file didn't load
			{ if (!quiet) displayMessage(this.openErrMsg.format([src,"(unknown)"])); }
		else {
			if (!quiet) displayMessage(this.readMsg.format([txt.length,src]));
			if (callback) callback(true,params,convertUTF8ToUnicode(txt),src,null);
		}
	}
	else {
		var x; // get an request object
		try {x = new XMLHttpRequest()} // moz
		catch(e) {
			try {x = new ActiveXObject("Msxml2.XMLHTTP")} // IE 6
			catch (e) {
				try {x = new ActiveXObject("Microsoft.XMLHTTP")} // IE 5
				catch (e) { return }
			}
		}
		// setup callback function to handle server response(s)
		x.onreadystatechange = function() {
			if (x.readyState == 4) {
				if (x.status==0 || x.status == 200) {
					if (!quiet) displayMessage(config.macros.loadTiddlers.readMsg.format([x.responseText.length,src]));
					if (callback) callback(true,params,x.responseText,src,x);
				}
				else {
					if (!quiet) displayMessage(config.macros.loadTiddlers.openErrMsg.format([src,x.status]));
				}
			}
		}
		// get privileges to read another document's DOM via http:// or file:// (moz-only)
		if (typeof(netscape)!="undefined") {
			try { netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); }
			catch (e) { if (!quiet) displayMessage(e.description?e.description:e.toString()); }
		}
		// send the HTTP request
		try {
			var url=src+(src.indexOf('?')<0?'?':'&')+'nocache='+Math.random();
			x.open("GET",src,true,config.options.txtRemoteUsername,config.options.txtRemotePassword);
			if (x.overrideMimeType) x.overrideMimeType('text/html');
			x.send(null);
		}
		catch (e) {
			if (!quiet) {
				displayMessage(this.openErrMsg.format([src,"(unknown)"]));
				displayMessage(e.description?e.description:e.toString());
			}
		}
	}
}

config.macros.loadTiddlers.readTiddlersFromHTML=function(html) {
	// for TW2.1 and earlier
	// extract store area from html 
	var start=html.indexOf('<div id="storeArea">');
	var end=html.indexOf("<!--POST-BODY-START--"+">",start);
	if (end==-1) var end=html.indexOf("</body"+">",start); // backward-compatibility for older documents
	var sa="<html><body>"+html.substring(start,end)+"</body></html>";

	// load html into iframe document
	var f=document.getElementById("loaderFrame"); if (f) document.body.removeChild(f);
	f=document.createElement("iframe"); f.id="loaderFrame";
	f.style.width="0px"; f.style.height="0px"; f.style.border="0px";
	document.body.appendChild(f);
	var d=f.document;
	if (f.contentDocument) d=f.contentDocument; // For NS6
	else if (f.contentWindow) d=f.contentWindow.document; // For IE5.5 and IE6
	d.open(); d.writeln(sa); d.close();

	// read tiddler DIVs from storeArea DOM element	
	var sa = d.getElementById("storeArea");
	if (!sa) return null;
	sa.normalize();
	var nodes = sa.childNodes;
	if (!nodes || !nodes.length) return null;
	var tiddlers = [];
	for(var t = 0; t < nodes.length; t++) {
		var title = null;
		if(nodes[t].getAttribute)
			title = nodes[t].getAttribute("tiddler");
		if(!title && nodes[t].id && (nodes[t].id.substr(0,5) == "store"))
			title = nodes[t].id.substr(5);
		if(title && title != "")
			tiddlers.push((new Tiddler()).loadFromDiv(nodes[t],title));
	}
	return tiddlers;
}

// // COPIED FROM TW2.2beta5
// // enables reading tiddler definitions using TW2.2 storeArea format, even when plugin is running under TW2.1.x
// // storeArea format changes include:
// // <pre> nodes
// // attribute(tiddler) renamed to attribute(title)
// // attribute(modified) is omitted if created==modified
TW21Loader.prototype.internalizeTiddler = function(store,tiddler,title,node)
{
	var e = node.firstChild;
	var text = null;
	if(node.getAttribute("tiddler")) {
		text = getNodeText(e).unescapeLineBreaks();
	} else {
		while(e.nodeName!="PRE" && e.nodeName!="pre") {
			e = e.nextSibling;
		}
		text = e.innerHTML.replace(/\r/mg,"").htmlDecode();
	}
	var modifier = node.getAttribute("modifier");
	var c = node.getAttribute("created");
	var m = node.getAttribute("modified");
	var created = c ? Date.convertFromYYYYMMDDHHMM(c) : version.date;
	var modified = m ? Date.convertFromYYYYMMDDHHMM(m) : created;
	var tags = node.getAttribute("tags");
	var fields = {};
	var attrs = node.attributes;
	for(var i = attrs.length-1; i >= 0; i--) {
		var name = attrs[i].name;
		if (attrs[i].specified && !TiddlyWiki.isStandardField(name)) {
			fields[name] = attrs[i].value.unescapeLineBreaks();
		}
	}
	tiddler.assign(title,text,modifier,modified,tags,created,fields);
	return tiddler;
};

} // END OF TW2.1.x backward-compatibility functions
//}}}
/%
|''URL:''|http://www.martinswiki.com/ |
|''Description:''|Martin Buddens's Plugins |
|''Author:''|MartinBudden |
%/
/%
|''URL:''|http://mptw.tiddlyspot.com/|
|''Description:''|a tiddlywiki distribution and plugins document|
|''Author:''|SimonBaird|
%/
/***

|Name|NavigationMacro|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#NavigationMacro|
|Version|0.3 |
|Requires|~TW2.08+|
!Description:
*Creates Next and Prev buttons on tiddlers, to cycle through tiddlers in order.
**you can create next and previous buttons to navigate through your journals, or the tiddlers of a tutorial.
*You can exclude certain tiddlers, or navigate through tiddlers with a specific tag only.
*The tiddlers can be sorted by modified or created.
*Custom ordering will be available after the release of TW 2.1
*Needs to be added to the ViewTemplate
*Buttons are updated dynamically and are hidden if there is no next or previous tiddler.

!Usage
{{{<<navigation>>}}}
or for more options:
{{{<<navigation sort exclude tag labelPrevious labelNext >>}}}
where sort is ''created'' (default) or ''modified''
exlcude is the tag to exclude.
tag is the tag to navigate through.
labelPrevious is the label for the previous button.
labelNext is the label for the next button. 

I recommend adding it to the ViewTemplate in the viewer div:
{{{<div class='viewer'>
<span macro='view text wikified'></span>
<span macro='navigation "" "" plugin'></span></div>}}}



!Example:
The next and previous buttons at the bottom of this tiddler will cycle through all of my extensions for TW.
!History
* 25-06-06 : version 0.3, first release

!Code
***/
//{{{
window.refreshNavLink = function (e) {
             var title = e.getAttribute("here");
             var sort = e.getAttribute("sort");
             var exclude =  e.getAttribute("exclude");
             if (e.getAttribute("tag")!=undefined) var tag = e.getAttribute("tag");
             var navtype = e.getAttribute("navtype");
              if (tag) {var tiddlers = store.getTaggedTiddlers(tag,sort);}
              else {var tiddlers = store.getTiddlers(sort,exclude);}
              for (var g=0; g<tiddlers.length; g++)
                  {if (title==tiddlers[g].title)
                       {if(navtype=="next" && !tiddlers[g+1])                             
                             e.className += " navNonExisting"
                        else if (navtype=="prev" && !tiddlers[g-1])
                             e.className += " navNonExisting"
                        else e.className = "button";}
                  }
}


config.refreshers.navLink = function(e,changeList){         
             refreshNavLink(e);
} 



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

          var sort = (params[0] && params[0]!=".")? params[0]: "created";
          var exclude =(params[1] && params[1]!=".")? params[1]: undefined;
          if (params[2])
                {var tag= params[2];
                 if(tiddler.tags.contains(tag)==false)
                 return false;
                }
          var labelPrev = params[3] ? params[3] : "Previous";
          var labelNext = params[4] ? params[4] : "Next";

          var next = function(e){
              if (!e) var e=window.event;
              var theTarget = resolveTarget(e);
              var navtype = theTarget.getAttribute("navtype");
              if (tag) {var tiddlers = store.getTaggedTiddlers(tag,sort);}
              else {var tiddlers = store.getTiddlers(sort,exclude);}
              for (var g=0; g<tiddlers.length; g++)
                  {if (tiddler.title==tiddlers[g].title)
                        {if (navtype == "next")
                            story.displayTiddler(theTarget,tiddlers[g+1].title)
                        else if (navtype == "prev")
                            story.displayTiddler(theTarget,tiddlers[g-1].title)}
                  }
              }

     var createNavBtn = function(text,theId,mode){
         var nextBtn = createTiddlyButton(place,text,text,next,null,theId);
         nextBtn.setAttribute("refresh","navLink");
         nextBtn.setAttribute("here",tiddler.title);
         nextBtn.setAttribute("sort",sort);
         nextBtn.setAttribute("exclude",exclude);
         nextBtn.setAttribute("navtype",mode);
         if (tag) nextBtn.setAttribute("tag",tag);
         refreshNavLink(nextBtn);
         }
    createNavBtn(labelNext+" â–º","NavNext","next");
    createNavBtn("â—„ "+labelPrev,"NavPrevious","prev");

}

setStylesheet(
"#NavNext {float:right;}\n"+
"#NavPrevious {float:left;}\n"+
".navNonExisting {display:none;}\n"+
 "",
"NavMacroStyles");
//}}}
/***
|Name|NestedSlidersPlugin|
|Source|http://www.TiddlyTools.com/#NestedSlidersPlugin|
|Documentation|http://www.TiddlyTools.com/#NestedSlidersPluginInfo|
|Version|2.4.3|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|show content in nest-able sliding/floating panels, without creating separate tiddlers for each panel's content|
This plugin adds new wiki syntax for embedding 'slider' panels directly into tiddler content.  
!!!!!Documentation
>see [[NestedSlidersPluginInfo]]
!!!!!Configuration
<<<
Enable animation for slider panels
<<option chkFloatingSlidersAnimate>> allow sliders to animate when opening/closing
>(note: This setting is in //addition// to the general option for enabling/disabling animation effects:
><<option chkAnimate>> enable animations (entire document)
>For slider animation to occur, you must also allow animation in general.

Debugging messages for 'lazy sliders' deferred rendering:
<<option chkDebugLazySliderDefer>> show debugging alert when deferring slider rendering
<<option chkDebugLazySliderRender>> show debugging alert when deferred slider is actually rendered
<<<
!!!!!Revisions
<<<
2008.05.07 - 2.4.3 updated Morpher hijack to adjust floatingPanel styles after animation without affecting other animated elements (i.e. popups).  Also, updated adjustSliderPos() to account for scrollwidth and use core findWindowWidth().
|please see [[NestedSlidersPluginInfo]] for additional revision details|
2005.11.03 - 1.0.0 initial public release.  Thanks to RodneyGomes, GeoffSlocock, and PaulPetterson for suggestions and experiments.
<<<
!!!!!Code
***/
//{{{
version.extensions.nestedSliders = {major: 2, minor: 4, revision: 3, date: new Date(2008,5,7)};
//}}}

//{{{
// options for deferred rendering of sliders that are not initially displayed
if (config.options.chkDebugLazySliderDefer==undefined) config.options.chkDebugLazySliderDefer=false;
if (config.options.chkDebugLazySliderRender==undefined) config.options.chkDebugLazySliderRender=false;

if (config.options.chkFloatingSlidersAnimate==undefined) config.options.chkFloatingSlidersAnimate=true;

// default styles for 'floating' class
setStylesheet(".floatingPanel { position:absolute; z-index:10; padding:0.5em; margin:0em; \
	background-color:#eee; color:#000; border:1px solid #000; text-align:left; }","floatingPanelStylesheet");
//}}}

//{{{
config.formatters.push( {
	name: "nestedSliders",
	match: "\\n?\\+{3}",
	terminator: "\\s*\\={3}\\n?",
	lookahead: "\\n?\\+{3}(\\+)?(\\([^\\)]*\\))?(\\!*)?(\\^(?:[^\\^\\*\\@\\[\\>]*\\^)?)?(\\*)?(\\@)?(?:\\{\\{([\\w]+[\\s\\w]*)\\{)?(\\[[^\\]]*\\])?(\\[[^\\]]*\\])?(?:\\}{3})?(\\#[^:]*\\:)?(\\>)?(\\.\\.\\.)?\\s*",
	handler: function(w)
		{
			lookaheadRegExp = new RegExp(this.lookahead,"mg");
			lookaheadRegExp.lastIndex = w.matchStart;
			var lookaheadMatch = lookaheadRegExp.exec(w.source)
			if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
			{
				var defopen=lookaheadMatch[1];
				var cookiename=lookaheadMatch[2];
				var header=lookaheadMatch[3];
				var panelwidth=lookaheadMatch[4];
				var transient=lookaheadMatch[5];
				var hover=lookaheadMatch[6];
				var buttonClass=lookaheadMatch[7];
				var label=lookaheadMatch[8];
				var openlabel=lookaheadMatch[9];
				var panelID=lookaheadMatch[10];
				var blockquote=lookaheadMatch[11];
				var deferred=lookaheadMatch[12];

				// location for rendering button and panel
				var place=w.output;

				// default to closed, no cookie, no accesskey, no alternate text/tip
				var show="none"; var cookie=""; var key="";
				var closedtext=">"; var closedtip="";
				var openedtext="<"; var openedtip="";

				// extra "+", default to open
				if (defopen) show="block";

				// cookie, use saved open/closed state
				if (cookiename) {
					cookie=cookiename.trim().slice(1,-1);
					cookie="chkSlider"+cookie;
					if (config.options[cookie]==undefined)
						{ config.options[cookie] = (show=="block") }
					show=config.options[cookie]?"block":"none";
				}

				// parse label/tooltip/accesskey: [label=X|tooltip]
				if (label) {
					var parts=label.trim().slice(1,-1).split("|");
					closedtext=parts.shift();
					if (closedtext.substr(closedtext.length-2,1)=="=")	
						{ key=closedtext.substr(closedtext.length-1,1); closedtext=closedtext.slice(0,-2); }
					openedtext=closedtext;
					if (parts.length) closedtip=openedtip=parts.join("|");
					else { closedtip="show "+closedtext; openedtip="hide "+closedtext; }
				}

				// parse alternate label/tooltip: [label|tooltip]
				if (openlabel) {
					var parts=openlabel.trim().slice(1,-1).split("|");
					openedtext=parts.shift();
					if (parts.length) openedtip=parts.join("|");
					else openedtip="hide "+openedtext;
				}

				var title=show=='block'?openedtext:closedtext;
				var tooltip=show=='block'?openedtip:closedtip;

				// create the button
				if (header) { // use "Hn" header format instead of button/link
					var lvl=(header.length>5)?5:header.length;
					var btn = createTiddlyElement(createTiddlyElement(place,"h"+lvl,null,null,null),"a",null,buttonClass,title);
					btn.onclick=onClickNestedSlider;
					btn.setAttribute("href","javascript:;");
					btn.setAttribute("title",tooltip);
				}
				else
					var btn = createTiddlyButton(place,title,tooltip,onClickNestedSlider,buttonClass);
				btn.innerHTML=title; // enables use of HTML entities in label

				// set extra button attributes
				btn.setAttribute("closedtext",closedtext);
				btn.setAttribute("closedtip",closedtip);
				btn.setAttribute("openedtext",openedtext);
				btn.setAttribute("openedtip",openedtip);
				btn.sliderCookie = cookie; // save the cookiename (if any) in the button object
				btn.defOpen=defopen!=null; // save default open/closed state (boolean)
				btn.keyparam=key; // save the access key letter ("" if none)
				if (key.length) {
					btn.setAttribute("accessKey",key); // init access key
					btn.onfocus=function(){this.setAttribute("accessKey",this.keyparam);}; // **reclaim** access key on focus
				}
				btn.setAttribute("hover",hover?"true":"false");
				btn.onmouseover=function(event) {
					// optional 'open on hover' handling
					if (this.getAttribute("hover")=="true" && this.sliderPanel.style.display=='none') {
						document.onclick(event); // close transients
						onClickNestedSlider(event); // open this slider
					}
					// mouseover on button aligns floater position with button
					if (window.adjustSliderPos) window.adjustSliderPos(this.parentNode,this,this.sliderPanel);
				}

				// create slider panel
				var panelClass=panelwidth?"floatingPanel":"sliderPanel";
				if (panelID) panelID=panelID.slice(1,-1); // trim off delimiters
				var panel=createTiddlyElement(place,"div",panelID,panelClass,null);
				panel.button = btn; // so the slider panel know which button it belongs to
				btn.sliderPanel=panel; // so the button knows which slider panel it belongs to
				panel.defaultPanelWidth=(panelwidth && panelwidth.length>2)?panelwidth.slice(1,-1):"";
				panel.setAttribute("transient",transient=="*"?"true":"false");
				panel.style.display = show;
				panel.style.width=panel.defaultPanelWidth;
				panel.onmouseover=function(event) // mouseover on panel aligns floater position with button
					{ if (window.adjustSliderPos) window.adjustSliderPos(this.parentNode,this.button,this); }

				// render slider (or defer until shown) 
				w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
				if ((show=="block")||!deferred) {
					// render now if panel is supposed to be shown or NOT deferred rendering
					w.subWikify(blockquote?createTiddlyElement(panel,"blockquote"):panel,this.terminator);
					// align floater position with button
					if (window.adjustSliderPos) window.adjustSliderPos(place,btn,panel);
				}
				else {
					var src = w.source.substr(w.nextMatch);
					var endpos=findMatchingDelimiter(src,"+++","===");
					panel.setAttribute("raw",src.substr(0,endpos));
					panel.setAttribute("blockquote",blockquote?"true":"false");
					panel.setAttribute("rendered","false");
					w.nextMatch += endpos+3;
					if (w.source.substr(w.nextMatch,1)=="\n") w.nextMatch++;
					if (config.options.chkDebugLazySliderDefer) alert("deferred '"+title+"':\n\n"+panel.getAttribute("raw"));
				}
			}
		}
	}
)

// TBD: ignore 'quoted' delimiters (e.g., "{{{+++foo===}}}" isn't really a slider)
function findMatchingDelimiter(src,starttext,endtext) {
	var startpos = 0;
	var endpos = src.indexOf(endtext);
	// check for nested delimiters
	while (src.substring(startpos,endpos-1).indexOf(starttext)!=-1) {
		// count number of nested 'starts'
		var startcount=0;
		var temp = src.substring(startpos,endpos-1);
		var pos=temp.indexOf(starttext);
		while (pos!=-1)  { startcount++; pos=temp.indexOf(starttext,pos+starttext.length); }
		// set up to check for additional 'starts' after adjusting endpos
		startpos=endpos+endtext.length;
		// find endpos for corresponding number of matching 'ends'
		while (startcount && endpos!=-1) {
			endpos = src.indexOf(endtext,endpos+endtext.length);
			startcount--;
		}
	}
	return (endpos==-1)?src.length:endpos;
}
//}}}

//{{{
window.onClickNestedSlider=function(e)
{
	if (!e) var e = window.event;
	var theTarget = resolveTarget(e);
	while (theTarget && theTarget.sliderPanel==undefined) theTarget=theTarget.parentNode;
	if (!theTarget) return false;
	var theSlider = theTarget.sliderPanel;
	var isOpen = theSlider.style.display!="none";

	// toggle label
	theTarget.innerHTML=isOpen?theTarget.getAttribute("closedText"):theTarget.getAttribute("openedText");
	// toggle tooltip
	theTarget.setAttribute("title",isOpen?theTarget.getAttribute("closedTip"):theTarget.getAttribute("openedTip"));

	// deferred rendering (if needed)
	if (theSlider.getAttribute("rendered")=="false") {
		if (config.options.chkDebugLazySliderRender)
			alert("rendering slider '"+theTarget.innerHTML+"':\n\n"+theSlider.getAttribute("raw"));
		var place=theSlider;
		if (theSlider.getAttribute("blockquote")=="true")
			place=createTiddlyElement(place,"blockquote");
		wikify(theSlider.getAttribute("raw"),place);
		theSlider.setAttribute("rendered","true");
	}
	// show/hide the slider
	if(config.options.chkAnimate && (!hasClass(theSlider,'floatingPanel') || config.options.chkFloatingSlidersAnimate))
		anim.startAnimating(new Slider(theSlider,!isOpen,e.shiftKey || e.altKey,"none"));
	else
		theSlider.style.display = isOpen ? "none" : "block";
	// reset to default width (might have been changed via plugin code)
	theSlider.style.width=theSlider.defaultPanelWidth;
	// align floater panel position with target button
	if (!isOpen && window.adjustSliderPos) window.adjustSliderPos(theSlider.parentNode,theTarget,theSlider);
	// if showing panel, set focus to first 'focus-able' element in panel
	if (theSlider.style.display!="none") {
		var ctrls=theSlider.getElementsByTagName("*");
		for (var c=0; c<ctrls.length; c++) {
			var t=ctrls[c].tagName.toLowerCase();
			if ((t=="input" && ctrls[c].type!="hidden") || t=="textarea" || t=="select")
				{ ctrls[c].focus(); break; }
		}
	}
	var cookie=theTarget.sliderCookie;
	if (cookie && cookie.length) {
		config.options[cookie]=!isOpen;
		if (config.options[cookie]!=theTarget.defOpen)
			saveOptionCookie(cookie);
		else { // remove cookie if slider is in default display state
			var ex=new Date(); ex.setTime(ex.getTime()-1000);
			document.cookie = cookie+"=novalue; path=/; expires="+ex.toGMTString();
		}
	}

	// prevent SHIFT-CLICK from being processed by browser (opens blank window... yuck!)
	// prevent clicks *within* a slider button from being processed by browser
	// but allow plain click to bubble up to page background (to close transients, if any)
	if (e.shiftKey || theTarget!=resolveTarget(e))
		{ e.cancelBubble=true; if (e.stopPropagation) e.stopPropagation(); }
	Popup.remove(); // close open popup (if any)
	return false;
}
//}}}

//{{{
// click in document background closes transient panels 
document.nestedSliders_savedOnClick=document.onclick;
document.onclick=function(ev) { if (!ev) var ev=window.event; var target=resolveTarget(ev);

	if (document.nestedSliders_savedOnClick)
		var retval=document.nestedSliders_savedOnClick.apply(this,arguments);
	// if click was inside a popup... leave transient panels alone
	var p=target; while (p) if (hasClass(p,"popup")) break; else p=p.parentNode;
	if (p) return retval;
	// if click was inside transient panel (or something contained by a transient panel), leave it alone
	var p=target; while (p) {
		if ((hasClass(p,"floatingPanel")||hasClass(p,"sliderPanel"))&&p.getAttribute("transient")=="true") break;
		p=p.parentNode;
	}
	if (p) return retval;
	// otherwise, find and close all transient panels...
	var all=document.all?document.all:document.getElementsByTagName("DIV");
	for (var i=0; i<all.length; i++) {
		 // if it is not a transient panel, or the click was on the button that opened this panel, don't close it.
		if (all[i].getAttribute("transient")!="true" || all[i].button==target) continue;
		// otherwise, if the panel is currently visible, close it by clicking it's button
		if (all[i].style.display!="none") window.onClickNestedSlider({target:all[i].button}) 
	}
	return retval;
};
//}}}

//{{{
// adjust floating panel position based on button position
if (window.adjustSliderPos==undefined) window.adjustSliderPos=function(place,btn,panel) {
	if (hasClass(panel,"floatingPanel")) {
		var rightEdge=document.body.offsetWidth-1;
		var panelWidth=panel.offsetWidth;
		var left=0;
		var top=btn.offsetHeight; 
		if (place.style.position=="relative" && findPosX(btn)+panelWidth>rightEdge) {
			left-=findPosX(btn)+panelWidth-rightEdge; // shift panel relative to button
			if (findPosX(btn)+left<0) left=-findPosX(btn); // stay within left edge
		}
		if (place.style.position!="relative") {
			var left=findPosX(btn);
			var top=findPosY(btn)+btn.offsetHeight;
			var p=place; while (p && !hasClass(p,'floatingPanel')) p=p.parentNode;
			if (p) { left-=findPosX(p); top-=findPosY(p); }
			if (left+panelWidth>rightEdge) left=rightEdge-panelWidth;
			if (left<0) left=0;
		}
		panel.style.left=left+"px"; panel.style.top=top+"px";
	}
}
//}}}

//{{{
// TW2.1 and earlier:
// hijack Slider animation handler 'stop' handler so overflow is visible after animation has completed
Slider.prototype.coreStop = Slider.prototype.stop;
Slider.prototype.stop = function()
	{ this.coreStop.apply(this,arguments); this.element.style.overflow = "visible"; }

// TW2.2+
// hijack stop handler so floatingPanel can be adjusted after animation
if (version.major+.1*version.minor+.01*version.revision>=2.2) {
	Morpher.prototype.coreStop = Morpher.prototype.stop;
	Morpher.prototype.stop = function() {
		this.coreStop.apply(this,arguments);
		var e=this.element;
		if (hasClass(e,"floatingPanel")) {  // adjust floating panel overflow and position after animation
			e.style.overflow = "visible";
			if (window.adjustSliderPos) window.adjustSliderPos(e.parentNode,e.button,e);
		}
	};
}
//}}}
/***
|Name|NestedSlidersPluginInfo|
|Source|http://www.TiddlyTools.com/#NestedSlidersPlugin|
|Documentation|http://www.TiddlyTools.com/#NestedSlidersPluginInfo|
|Version|2.4.3|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for NestedSlidersPlugin|
This plugin adds new wiki syntax for embedding 'slider' panels directly into tiddler content.
!!!!!Usage
<<<
Use {{{+++}}} and {{{===}}} to delimit the slider content.  You can also 'nest' these sliders as deep as you like (see complex nesting example below), so that expandable 'tree-like' hierarchical displays can be created.  This is most useful when converting existing in-line text content to create in-line annotations, footnotes, context-sensitive help, or other subordinate information displays.

Additional optional syntax elements let you specify
*default to open
*cookiename
*heading level
*floater (with optional CSS width value)
*transient display (clicking elsewhere closes panel)
*open on hover (without needing to click)
*custom class/label/tooltip/accesskey
*alternate label/tooltip (displayed when panel is open)
*panelID (for later use with {{{<<DOM>>}}} macro.  See [[DOMTweaksPlugin]])
*automatic blockquote style on panel
*deferred rendering of panel content
The complete syntax, using all options, is:
//{{{
++++(cookiename)!!!!!^width^*@{{class{[label=key|tooltip][altlabel|alttooltip]}}}#panelID:>...
content goes here
===
//}}}
where:
* ''"""+++""" (or """++++""") and """==="""''<br>marks the start and end of the slider definition, respectively.  When the extra {{{+}}} is used, the slider will be open when initially displayed.
* ''"""(cookiename)"""''<br>saves the slider opened/closed state, and restores this state whenever the slider is re-rendered.
* ''"""! through !!!!!"""''<br>displays the slider label using a formatted headline (Hn) style instead of a button/link style
* ''"""^width^ (or just ^)"""''<br>makes the slider 'float' on top of other content rather than shifting that content downward.  'width' must be a valid CSS value (e.g., "30em", "180px", "50%", etc.).  If omitted, the default width is "auto" (i.e., fit to content)
* ''"""*"""''<br>denotes "transient display": when a click occurs elsewhere in the document, the slider/floating panel will be automatically closed.  This is useful for creating 'pulldown menus' that automatically go away after they are used.  //Note: using SHIFT-click on a slider label will open/close that slider without triggering the automatic closing of any transient slider panels that are currently displayed, permitting ''temporary'' display of several transient panels at once.//
* ''"""@"""''<br>denotes "open on hover": the slider/floating panel will be automatically opened as soon as the mouse moves over the slider label, without requiring a click.
* ''"""{{class{[label=key|tooltip][altlabel|alttooltip]}}}"""''<br>uses label/tooltip/accesskey.  """{{class{...}}}""", """=key""", """|tooltip""" and """[altlabel|alttooltip]""" are optional.  'class' is any valid CSS class name, used to style the slider label text.  'key' must be a ''single letter only''.  altlabel/alttooltip specify alternative label/tooltip for use when slider/floating panel is displayed.  //Note: you can use HTML syntax within the label text to include HTML entities (e.g., {{{&raquo;}}} (&raquo;) or {{{&#x25ba;}}} (&#x25ba;), or even embedded images (e.g., {{{<img src="images/eric3.gif">}}}).//
* ''"""#panelID:"""''<br>defines a unique DOM element ID that is assigned to the panel element used to display the slider content.  This ID can then be used later to reposition the panel using the {{{<<DOM move id>>}}} macro (see [[DOMTweaksPlugin]]), or to access/modify the panel element through use of {{{document.getElementById(...)}}}) javascript code in a plugin or inline script.
* ''""">"""''<br>automatically adds blockquote formatting to slider content
* ''"""..."""''<br>defers rendering of closed sliders until the first time they are opened.  //Note: deferred rendering may produce unexpected results in some cases.  Use with care.//

//Note: to make slider definitions easier to read and recognize when editing a tiddler, newlines immediately following the {{{+++}}} 'start slider' or preceding the {{{===}}} 'end slider' sequence are automatically supressed so that excess whitespace is eliminated from the output.//
<<<
!!!!!Examples
<<<
simple in-line slider: 
{{{
+++
   content
===
}}}
+++
   content
===
----
use a custom label and tooltip: 
{{{
+++[label|tooltip]
   content
===
}}}
+++[label|tooltip]
   content
===
----
content automatically blockquoted: 
{{{
+++>
   content
===
}}}
+++>
   content
===
----
all options (except cookie) //(default open, heading, sized floater, transient, open on hover, class, label/tooltip/key, blockquoted, deferred)//
{{{
++++!!!^30em^*@{{big{[label=Z|click or press Alt-Z to open]}}}>...
   content
===
}}}
++++!!!^30em^*@{{big{[label=Z|click or press Alt-Z to open]}}}>...
   content
===
----
complex nesting example:
{{{
+++[get info...=I|click for information or press Alt-I]
	put some general information here,
	plus a floating panel with more specific info:
	+++^10em^[view details...|click for details]
		put some detail here, which could in turn contain a transient panel,
		perhaps with a +++^25em^*[glossary definition]explaining technical terms===
	===
===
}}}
+++[get info...=I|click for information or press Alt-I]
	put some general information here,
	plus a floating panel with more specific info:
	+++^10em^[view details...|click for details]
		put some detail here, which could in turn contain a transient panel,
		perhaps with a +++^25em^*[glossary definition]explaining technical terms===
	===
===
----
embedded image as slider button
{{{
+++[<img src=images/eric3.gif>|click me!]>
	{{big{OUCH!}}}
===
}}}
+++[<img src=images/eric3.gif>|click me!]>
	{{big{OUCH!}}}
===
<<<
!!!!!Revisions
<<<
2008.05.07 - 2.4.3 updated Morpher hijack to adjust floatingPanel styles after animation without affecting other animated elements (i.e. popups).  Also, updated adjustSliderPos() to account for scrollwidth and use core findWindowWidth().
2008.04.02 - 2.4.2 in onClickNestedSlider, handle clicks on elements contained //within// slider buttons (e.g., when using HTML to display an image as a slider button).
2008.04.01 - 2.4.1 open on hover also triggers document.onclick to close other transient sliders
2008.04.01 - 2.4.0 re-introduced 'open on hover' feature using "@" symbol
2008.03.26 - 2.3.5 in document.onclick(), if click is in popup, don't dismiss transient panel (if any)
2008.01.08 - [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.28 - 2.3.4 added hijack for Animator.prototype.startAnimating().  Previously, the plugin code simply set the overflow to "visible" after animation.  This code tweak corrects handling of elements that were styled with overflow=hidden/auto/scroll before animation by saving the overflow style and then restoring it after animation has completed.
2007.12.17 - 2.3.3 use hasClass() instead of direct comparison to test for "floatingPanel" class.  Allows floating panels to have additional classes assigned to them (i.e., by AnimationEffectsPlugin).
2007.11.14 - 2.3.2 in onClickNestedSlider(), prevent SHIFT-click events from opening a new, empty browser window by setting "cancelBubble=true" and calling "stopPropagation()".  Note: SHIFT-click is still processed as a normal click (i.e., it toggles the slider panel display).  Also, using SHIFT-click will prevent 'transient' sliders from being automatically closed when another slider is opened, allowing you to *temporarily* display several transient sliders at once.
2007.07.26 - 2.3.1 in document.onclick(), propagate return value from hijacked core click handler to consume OR bubble up click as needed.  Fixes "IE click disease", whereby nearly every mouse click causes a page transition.
2007.07.20 - 2.3.0 added syntax for setting panel ID (#panelID:).  This allows individual slider panels to be repositioned within tiddler content simply by giving them a unique ID and then moving them to the desired location using the {{{<<DOM move id>>}}} macro.
2007.07.19 - 2.2.0 added syntax for alttext and alttip (button label and tooltip to be displayed when panel is open)
2007.07.14 - 2.1.2 corrected use of 'transient' attribute in IE to prevent (non-recursive) infinite loop
2007.07.12 - 2.1.0 replaced use of "*" for 'open/close on rollover' (which didn't work too well).  "*" now indicates 'transient' panels that are automatically closed if a click occurs somewhere else in the document.  This permits use of nested sliders to create nested "pulldown menus" that automatically disappear after interaction with them has been completed.  Also, in onClickNestedSlider(), use "theTarget.sliderCookie", instead of "this.sliderCookie" to correct cookie state tracking when automatically dismissing transient panels.
2007.06.10 - 2.0.5 add check to ensure that window.adjustSliderPanel() is defined before calling it (prevents error on shutdown when mouse event handlers are still defined)
2007.05.31 - 2.0.4 add handling to invoke adjustSliderPanel() for onmouseover events on slider button and panel.  This allows the panel position to be re-synced when the button position shifts due to changes in unrelated content above it on the page.  (thanks to Harsha for bug report)
2007.03.30 - 2.0.3 added chkFloatingSlidersAnimate (default to FALSE), so that slider animation can be disabled independent of the overall document animation setting (avoids strange rendering and focus problems in floating panels)
2007.03.01 - 2.0.2 for TW2.2+, hijack Morpher.prototype.stop so that "overflow:hidden" can be reset to "overflow:visible" after animation ends
2007.03.01 - 2.0.1 in hijack for Slider.prototype.stop, use apply() to pass params to core function
2006.07.28 - 2.0.0 added custom class syntax around label/tip/key syntax: {{{{{classname{[label=key|tip]}}}}}}
2006.07.25 - 1.9.3 when parsing slider, save default open/closed state in button element, then in onClickNestedSlider(), if slider state matches saved default, instead of saving cookie, delete it.  Significantly reduces the 'cookie overhead' when default slider states are used.
2006.06.29 - 1.9.2 in onClickNestedSlider(), when setting focus to first control, skip over type="hidden"
2006.06.22 - 1.9.1 added panel.defaultPanelWidth to save requested panel width, even after resizing has changed the style value
2006.05.11 - 1.9.0 added optional '^width^' syntax for floating sliders and '=key' syntax for setting an access key on a slider label
2006.05.09 - 1.8.0 in onClickNestedSlider(), when showing panel, set focus to first child input/textarea/select element
2006.04.24 - 1.7.8 in adjustSliderPos(), if floating panel is contained inside another floating panel, subtract offset of containing panel to find correct position
2006.02.16 - 1.7.7 corrected deferred rendering to account for use-case where show/hide state is tracked in a cookie
2006.02.15 - 1.7.6 in adjustSliderPos(), ensure that floating panel is positioned completely within the browser window (i.e., does not go beyond the right edge of the browser window)
2006.02.04 - 1.7.5 add 'var' to unintended global variable declarations to avoid FireFox 1.5.0.1 crash bug when assigning to globals
2006.01.18 - 1.7.4 only define adjustSliderPos() function if it has not already been provided by another plugin.  This lets other plugins 'hijack' the function even when they are loaded first.
2006.01.16 - 1.7.3 added adjustSliderPos(place,btn,panel,panelClass) function to permit specialized logic for placement of floating panels.  While it provides improved placement for many uses of floating panels, it exhibits a relative offset positioning error when used within *nested* floating panels.  Short-term workaround is to only adjust the position for 'top-level' floaters.
2006.01.16 - 1.7.2 added button property to slider panel elements so that slider panel can tell which button it belongs to.  Also, re-activated and corrected animation handling so that nested sliders aren't clipped by hijacking Slider.prototype.stop so that "overflow:hidden" can be reset to "overflow:visible" after animation ends
2006.01.14 - 1.7.1 added optional "^" syntax for floating panels.  Defines new CSS class, ".floatingPanel", as an alternative for standard in-line ".sliderPanel" styles.
2006.01.14 - 1.7.0 added optional "*" syntax for rollover handling to show/hide slider without requiring a click (Based on a suggestion by tw4efl)
2006.01.03 - 1.6.2 When using optional "!" heading style, instead of creating a clickable "Hn" element, create an "A" element inside the "Hn" element.  (allows click-through in SlideShowPlugin, which captures nearly all click events, except for hyperlinks)
2005.12.15 - 1.6.1 added optional "..." syntax to invoke deferred ('lazy') rendering for initially hidden sliders
removed checkbox option for 'global' application of lazy sliders
2005.11.25 - 1.6.0 added optional handling for 'lazy sliders' (deferred rendering for initially hidden sliders)
2005.11.21 - 1.5.1 revised regular expressions: if present, a single newline //preceding// and/or //following// a slider definition will be suppressed so start/end syntax can be place on separate lines in the tiddler 'source' for improved readability.  Similarly, any whitespace (newlines, tabs, spaces, etc.) trailing the 'start slider' syntax or preceding the 'end slider' syntax is also suppressed.
2005.11.20 - 1.5.0 added (cookiename) syntax for optional tracking and restoring of slider open/close state
2005.11.11 - 1.4.0 added !!!!! syntax to render slider label as a header (Hn) style instead of a button/link style
2005.11.07 - 1.3.0 removed alternative syntax {{{(((}}} and {{{)))}}} (so they can be used by other formatting extensions) and simplified/improved regular expressions to trim multiple excess newlines
2005.11.05 - 1.2.1 changed name to NestedSlidersPlugin
2005.11.04 - 1.2.0 added alternative character-mode syntax {{{(((}}} and {{{)))}}}
tweaked "eat newlines" logic for line-mode {{{+++}}} and {{{===}}} syntax
2005.11.03 - 1.1.1 fixed toggling of default tooltips ("more..." and "less...") when a non-default button label is used.  code cleanup, added documentation
2005.11.03 - 1.1.0 changed delimiter syntax from {{{(((}}} and {{{)))}}} to {{{+++}}} and {{{===}}}.  changed name to EasySlidersPlugin
2005.11.03 - 1.0.0 initial public release
<<<
/%
|Name|NextTiddler|
|Source|http://www.TiddlyTools.com/#NextTiddler|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|insert a link that, when clicked, closes the current tiddler and opens another one in its place|

usage: <<tiddler NextTiddler with: NewTiddlerTitle linktext>>


%/<script label="$2">
	var tiddler=story.findContainingTiddler(place);
	story.displayTiddler(tiddler,"$1");
	story.closeTiddler(tiddler.getAttribute("tiddler")); // close self
	return false;
</script>
/%
|Name|OpenTaggedTiddlers|
|Source|http://www.TiddlyTools.com/#OpenTaggedTiddlers|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|open multiple tagged tiddlers with a single click|

Usage: <<tiddler OpenTaggedTiddlers with: "label" "tagToMatch" "sortBy" "reverse" "close">>

"sortBy" is an optional tiddler fieldname, and defaults to "title" (use "modified" or "created" for dates)
"reverse" is an optional KEYWORD, and reverses the order of display of the matched tiddler (i.e., descending vs. ascending)
"close" is an optional KEYWORD, that closes all open tiddlers before opening the tagged tiddlers

%/<script label="$1">
	var list=[];
	var sortBy="$3"; if ((sortBy=="$"+"3")||(sortBy=="")) sortBy="title";
	var tids=store.getTaggedTiddlers("$2",sortBy);
	if ("$4"=="reverse") tids=tids.reverse();
	for (var t=0;t<tids.length;t++) list.push(tids[t].title);
	if ("$5"=="close") story.closeAllTiddlers();
	story.displayTiddlers(story.findContainingTiddler(place),list);
	return false;
</script>
/%
|Name|OpenTiddlers|
|Source|http://www.TiddlyTools.com/#OpenTiddlers|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|open multiple tiddlers with a single click|

Usage: <<tiddler OpenTiddlers with: "label with space" "tiddler tiddler [[tiddler with spaces]] tiddler..." template>>
(template is optional and defaults to ViewTemplate)

%/<script label="$1">
	var tidlist="$2";
	if ("$3"!="$"+"3") var template="$3";
	story.displayTiddlers(story.findContainingTiddler(place),tidlist.readBracketedList(),template);
	return false;
</script>
/***
|Name|OpenTiddlersMacro|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#OpenTiddlersMacro|
|Version|0.2 |
|Requires|~TW2.08+|
!Description:
*Allows creation of tiddlyLinks that open multiple tiddlers.
*Also useful for creating links to shadowTiddlers, which if normally created are not in bold.

!Usage
{{{<<openTiddlers text:"TextForLink" tiddlers:"Tiddler1 Tiddler2 [[Tiddler with spaces]] Tiddler4">>}}}

!Example:
{{{<<openTiddlers text:"This link opens multiple tiddlers" tiddlers:"Project Saq">>}}}
<<openTiddlers text:"This link opens multiple tiddlers" tiddlers:"Project Saq">>

!History
*30-04-06, version 0.2, modifed and rename following feedback from Eric.
*29-04-06, version 0.1, working.

!To Do:
*option to close other tiddlers
*option to open in edit template

!Code
***/
//{{{
window.onClickMultiLink= function(e){
                         story.displayTiddlers(this,this.getAttribute("tiddlerstring").readBracketedList());
                         return(false);
}

config.macros.openTiddlers={};
config.macros.openTiddlers.handler = function(place,macroName,params,wikifier,paramString,tiddler){
                           var nAV = paramString.parseParams('test', null, true);
                           var text = nAV[0].text[0];
                           var tiddlerstring = nAV[0].tiddlers[0];
                           var btn= createTiddlyButton(place,text,null,onClickMultiLink,"tiddlyLinkExisting");
                           btn.setAttribute("tiddlerstring",tiddlerstring);
}
//}}}
/***
|Name|OpenTopPlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#OpenTopPlugin|
|Version|0.1|
|Requires|~TW2.x|
!!!Description:
Open new tiddlers at the top of the screen.

!!!Code
***/
//{{{
Story.prototype.coreLewcidDisplayTiddler=Story.prototype.displayTiddler ;
Story.prototype.displayTiddler =
function(srcElement,title,template,unused1,unused2,animate,slowly)
{
       var srcElement=null;
       if (document.getElementById(this.idPrefix + title))
          {story.closeTiddler(title);}
       this.coreLewcidDisplayTiddler(srcElement,title,template,unused1,unused2,animate,slowly);
       window.scrollTo(0,0);
}
//}}}
/%
|''URL:''|http://bradleymeck.tiddlyspot.com/|
|''Description:''|Resources that are Ripe for the Picking|
|''Author:''|BradleyMeck|
%/
/***
|''Name:''|~PopupMacro|
|''Version:''|1.0.0 (2006-05-09)|
|''Source:''|http://tw.lewcid.org/#PopupMacro|
|''Author:''|Saq Imtiaz|
|''Description:''|Create popups with custom content|
|''Documentation:''|[[PopupMacro Documentation|PopupMacroDocs]]|
|''~Requires:''|TW Version 2.0.8 or better|
***/
// /%
{{{
config.macros.popup = {};
config.macros.popup.arrow = (document.all?"â–¼":"â–¾");
config.macros.popup.handler = function(place,macroName,params,wikifier,paramString,theTiddler) {

        if (!params[0] || !params[1]) 
             {createTiddlyError(place,'missing macro parameters','missing label or content parameter');
              return false;};
   
        var label = params[0];
        var source = (params[1]).replace(/\$\)\)/g,">>"); 
        var nestedId = params[2]? params[2]: 'nestedpopup';        

	var onclick = function(event) {
	        if(!event){var event = window.event;}
                var theTarget = resolveTarget(event);
                var nested = (!isNested(theTarget));
               
                if ((Popup.stack.length > 1)&&(nested==true)) {Popup.removeFrom(1);}
                else if(Popup.stack.length > 0 && nested==false) {Popup.removeFrom(0);};
                
                var theId = (nested==false)? "popup" : nestedId; 
	        var popup = createTiddlyElement(document.body,"ol",theId,"popup",null);
	        Popup.stack.push({root: button, popup: popup});

                wikify(source,popup);
		Popup.show(popup,true);
	        event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
		return false;
	}
	var button = createTiddlyButton(place, label+this.arrow,label, onclick, null);
};

window.isNested = function(e) {
        while (e != null) {
                var contentWrapper = document.getElementById("contentWrapper");
                if (contentWrapper == e) return true;
                e = e.parentNode;
                }
        return false;
};

setStylesheet(
".popup, .popup a, .popup a:visited {color: #fff;}\n"+
".popup  a:hover {background: #014; color: #fff; border: none;}\n"+
".popup li , .popup ul, .popup ol {list-style:none !important; margin-left:0.3em !important; margin-right:0.3em; font-size:100%; padding-top:0.5px !important; padding:0px !important;}\n"+
"#nestedpopup {background:#2E5ADF; border: 1px solid #0331BF; margin-left:1em; }\n"+
"",
"CustomPopupStyles");

config.shadowTiddlers.PopupMacroDocs="The documentation is available [[here.|http://tw.lewcid.org/#PopupMacroDocs]]";
}}}
//%/
''If you want this documentation available offline, you will need to copy this tiddler to your TW.''
!Description:
Using the popup macro you can create popups with any wiki text. The wiki text can be written in the macro call, can be generated using a different macro, or included from a tiddler.

!Usage:
*the button label is the first parameter
*the text to put in the popup is the second parameter
**embed macro output like forEachTiddler or tiddlerList
***start macro calls with {{{<<}}} like normal, but end with {{{$))}}}
**define popup content inline, or embed from a tidder using the core tiddler macro {{{<<tiddler$))}}}
*you can nest popups up to one level
**nested popups have an id of 'nestedpopup' for easier styling.
**specify unique id's for nested popups by passing the id as a third parameter.

----
!Example's

''Put a forEachTiddler macro generated list in a popup:''
{{{<<popup forEachTiddlerDemo [[<<forEachTiddler where 'tiddler.tags.contains("systemConfig")']]$))}}}
<<popup forEachTiddlerDemo [[<<forEachTiddler
where
'tiddler.tags.contains("systemConfig")'$))]]>>

''Use the core {{{<<tiddler>>}}} macro to put the contents of a tiddler into a popup:''
MainMenu popup:
{{{<<popup MainMenu [[<<tiddler MainMenu$))]]>>}}}
<<popup MainMenu [[<<tiddler MainMenu$))]]>>

''Or create a custom menu in a tiddler using various macro's and normal tiddlylinks.''
{{{<<popup CustomMenu '<<tiddler CustomMenu$))'>>}}}
<<popup CustomMenu '<<tiddler CustomMenu$))'>>
this menu was created with a combination of forEachTiddler and normal tiddlyLinks!
Note that the 'Plugins' button opens a second nested popup.
Source tiddler: CustomMenu

''Or define your custom menu inline.''
{{{<<popup 'Inline Custom Menu' [[Custom Menu
*MainMenu
----
<<forEachTiddler
 where
 'tiddler.tags.contains("systemConfig")']]$))]] 
>>}}}
<<popup 'Inline Custom Menu' [[Custom Menu
*MainMenu
----
<<forEachTiddler where 'tiddler.tags.contains("systemConfig")'$))]] 
>>

''Note: you can pass a third parameter and it will be set as the id of any nested popups''
By default, nested popups have an id of 'nestedpopup' to facilitate styling.

----
!Current Issues:
*better support for custom classes for popups and nestedpopups
----
!Code
PopupMacro

/%
|''URL:''|http://ptw.sourceforge.net/ptwe.html|
|''Description:''|BramChen's Extensions for TiddlyWiki|
|''Author:''|BramChen|
%/
Provides a secondary toolbar for use when editing a tiddler.  This toolbar allows you to quickly insert TiddlyWiki tiddler links, images, macros, etc. or common formatting sequences directly into tiddler content, as well as providing find/replace, sort, and 'split' functions that operate on the tiddler source content displayed in the editor.

+++{{medium{[installation instructions...]}}}>...
After importing these tiddlers, add the following line to your EditTemplate:
{{{
<div macro='tiddler QuickEditToolbar'></div>
}}}
and add the following line to your StyleSheet:
{{{
[[StyleSheetShortcuts]]
}}}
Note that, after adding the QuickEditToolbar to your EditTemplate, it is //not automatically displayed when editing a tiddler//.  To enable display of the toolbar, you can add the following configuration option control to your SideBarOptions (or any other suitable location):
{{{
<<option chkShowQuickEdit>> show QuickEdit toolbar
}}}
When this option is checked and you subsequently edit a tiddler, the QuickEditToolbar will then be displayed.  Alternatively, you can 'hard-code' this setting, so that the QuickEditToolbar will //always// be displayed, by creating a tiddler (e.g., ConfigTweaks), tagged with <<tag systemConfig>>, containing:
{{{
config.options.chkShowQuickEdit=true;
}}}
Optionally, to add a tiddler command item that toggles the display of the QuickEditToolbar while editing a tiddler, add the following line to your EditTemplate:
{{{
<span class='toolbar' macro='toolbar toggleQuickEdit'></span>
}}}
You can also add individual ~QuickEdit toolbar buttons (e.g. [[QuickEdit_replace]], [[QuickEdit_link]], etc) directly to the tiddler editor menu, by adding one or more lines to your EditTemplate, like this:
{{{
<span class='toolbar' macro='tiddler QuickEdit_replace'></span>
}}}
===
/***
|Name|QuickEditPlugin|
|Source|http://www.TiddlyTools.com/#QuickEditPlugin|
|Documentation|http://www.TiddlyTools.com/#QuickEditPlugin|
|Version|2.4.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Support for QuickEdit_* buttons: styles, utility functions, and 'toggleQuickEdit' command|
!!!!!Revisions
<<<
2008.05.17 [2.4.0] copied code from StickyPopupPlugin to remove dependency
2008.05.12 [2.3.0] added "toggleQuickEdit" command handler (replaces inline script command)
2008.01.11 [2.2.0] converted from inline script
2007.03.29 [1.0.0] initial release (as inline script)
<<<
!!!!!Code
***/
//{{{
version.extensions.QuickEdit= {major: 2, minor: 4, revision: 0, date: new Date(2008,5,17)};

// SET STYLESHEET (for toolbar button style)
setStylesheet(".quickEdit a { border:2px outset ButtonFace; -moz-appearance:button; padding:0px 3px; \
	background-color:ButtonFace; color:ButtonText !important;  line-height:200%; font-weight:normal; }", "quickEditStyles");

// UTILITY FUNCTIONS
config.quickEdit = {
	getField: function(where) {
		var here=story.findContainingTiddler(where); if (!here) return null;
		var e=story.getTiddlerField(here.getAttribute("tiddler"),"text");
		if (e&&e.getAttribute("edit")=="text") return e;
		return null;
	},
	setSelection: function(where,newtext) {
		var e=this.getField(where); if (!e) return false;
		e.focus(); replaceSelection(e,newtext);
		return false;
	},
	wrapSelection: function(where,before,after) {
		var e=this.getField(where); if (!e) return false;
		e.focus(); replaceSelection(e,before+config.quickEdit.getSelection(e)+after);
		return false;
	},
	getSelection: function(e) {
		var seltext="";
		if (e&&e.setSelectionRange)
			seltext=e.value.substr(e.selectionStart,e.selectionEnd-e.selectionStart);
		else if (document.selection) {
			var range = document.selection.createRange();
			if (range.parentElement()==e) seltext=range.text
		}
		return seltext;
	},
	promptForFilename: function(msg,path,file) {
		if(window.Components) { // moz
			try {
				netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
				var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
				var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
				picker.init(window, msg, nsIFilePicker.modeOpen);
				var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
				thispath.initWithPath(path);
				picker.displayDirectory=thispath;
				picker.defaultExtension='jpg';
				picker.defaultString=file;
				picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterImages);
				if (picker.show()!=nsIFilePicker.returnCancel)
					var result="file:///"+picker.file.persistentDescriptor.replace(/\\/g,'/');
			}
			catch(e) { alert('error during local file access: '+e.toString()) }
		}
		else { // IE
			try { // XP only
				var s = new ActiveXObject('UserAccounts.CommonDialog');
				s.Filter='All files|*.*|JPG files|*.jpg|GIF files|*.gif|PNG files|*.png|';
				s.FilterIndex=1; // default to JPG files;
				s.InitialDir=path;
				s.FileName=file;
				if (s.showOpen()) var result=s.FileName;
			}
			catch(e) { var result=prompt(msg,path+file); } // fallback for non-XP IE
		}
		return result;
	}
}
//}}}

//{{{
if (config.options.chkShowQuickEdit===undefined) config.options.chkShowQuickEdit=false;
config.commands.toggleQuickEdit = {
	hideReadOnly: true,
	getText: function() { return config.options.chkShowQuickEdit?'\u221Aquickedit':'quickedit'; },
	tooltip: 'show QuickEdit toolbar buttons',
	handler: function(event,src,title) {
		config.options.chkShowQuickEdit=!config.options.chkShowQuickEdit;
		config.macros.option.propagateOption("chkShowQuickEdit","checked", config.options.chkShowQuickEdit,"input");
		// save cookie when toolbar shown, remove cookie when toolbar hidden
		if (config.options.chkShowQuickEdit) saveOptionCookie("chkShowQuickEdit");
		else {
			var ex=new Date(); ex.setTime(ex.getTime()-1000);
			document.cookie = "chkShowQuickEdit=novalue; path=/; expires="+ex.toGMTString();
		}
		// set link and title based on option state
		src.innerHTML=config.commands.toggleQuickEdit.getText();
		// refresh all actively displayed tiddler editor(s)
		story.forEachTiddler(function(t,e){if (story.isDirty(t)) refreshElements(e);});
		return false;
	}
};
//}}}

// // COPIED FROM [[StickyPopupPlugin]] TO ELIMINATE PLUGIN DEPENDENCY
//{{{
if (config.options.chkStickyPopups==undefined) config.options.chkStickyPopups=false;
Popup.stickyPopup_onDocumentClick = function(ev)
{
	// if click is in a sticky popup, ignore it so popup will remain visible
	var e = ev ? ev : window.event; var target = resolveTarget(e);
	var p=target; while (p) {
		if (hasClass(p,"popup") && (hasClass(p,"sticky")||config.options.chkStickyPopups)) break;
		else p=p.parentNode;
	}
	if (!p) // not in sticky popup (or sticky popups disabled)... use normal click handling
		Popup.onDocumentClick(ev);
	return true;
};
try{removeEvent(document,"click",Popup.onDocumentClick);}catch(e){};
try{addEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
//}}}
/%
|Name|QuickEditToolbar|
|Source|http://www.TiddlyTools.com/#QuickEditToolbar|
|Version|2.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.2|
|Type|script|
|Requires|QuickEditPlugin, InlineJavascriptPlugin|
|Optional|QuickEdit_replace, QuickEdit_split, QuickEdit_link, QuickEdit_macro, QuickEdit_image, QuickEdit_tiddler, QuickEdit_file, QuickEdit_format, QuickEdit_sort|
|Overrides||
|Description|quickly insert TiddlyWiki tiddler links or common formatting sequences directly into tiddler content|

Usage (in EditTemplate): <div macro='tiddler QuickEditToolbar'></div>

%/<<tiddler HideTiddlerTags>>/%

TOOLBAR DEFINITIONS BEGIN HERE...
= = = = = = = = = = = = = = = = =
%/{{hidden fine center quickEdit{
<script>
	// note: always show toolbar when directly viewing the tiddler containing the actual toolbar definition!
	var here=story.findContainingTiddler(place); if (here) var tid=here.getAttribute("tiddler");
	place.style.display=(config.options.chkShowQuickEdit||tid=="QuickEditToolbar")?"block":"none";
</script>/%
%/<<tiddler QuickEdit_replace>>/%
%/<<tiddler QuickEdit_split>>/%
%/<<tiddler QuickEdit_sort>>/%
%/ &nbsp;/% (SPACER)
%/<<tiddler QuickEdit_link>>/%
%/<<tiddler QuickEdit_macro>>/%
%/<<tiddler QuickEdit_image>>/%
%/<<tiddler QuickEdit_tiddler>>/%
%/<<tiddler QuickEdit_file>>/%
%/ &nbsp;/% (SPACER)
%/<<tiddler QuickEdit_format>>/%
%/<<tiddler QuickEdit_align>>/%
%/<<tiddler QuickEdit_color>>/%
%/<<tiddler QuickEdit_font>>/%
%/<<tiddler QuickEdit_css>>/%
%/}}}
/%
|Name|QuickEdit_align|
|Source|http://www.TiddlyTools.com/#QuickEdit_align|
|Version|2.2.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.2|
|Type|script|
|Requires|QuickEditPlugin|
|Overrides||
|Description|definition for toolbar button for text alignment|

Usage:
QuickEditToolbar: <<tiddler QuickEdit_align>>
OR
EditTemplate: <span class='toolbar' macro='tiddler QuickEdit_align'></span>

**** ALIGNMENT ****
%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink"
title="align text"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select text alignment...','');
	s.onchange=function(){
		config.quickEdit.wrapSelection(this.button,'{{'+this.value+'{','}}}');
		Popup.remove(); return false;
	};
	s.options[s.length]=new Option('left','left');
	s.options[s.length-1].title='{{left{...}}}';
	s.options[s.length]=new Option('center','center');
	s.options[s.length-1].title='{{center{...}}}';
	s.options[s.length]=new Option('right','right');
	s.options[s.length-1].title='{{right{...}}}';
	s.options[s.length]=new Option('justify','justify');
	s.options[s.length-1].title='{{justify{...}}}';
	s.options[s.length]=new Option('float left','float left');
	s.options[s.length-1].title='{{floatleft{...}}}';
	s.options[s.length]=new Option('float right','float right');
	s.options[s.length-1].title='{{floatright{...}}}';
	Popup.show(p,false);
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>align</a></html>
/%
|Name|QuickEdit_color|
|Source|http://www.TiddlyTools.com/#QuickEdit_color|
|Version|2.2.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.2|
|Type|script|
|Requires|QuickEditPlugin|
|Overrides||
|Description|definition of toolbar button for "color" command|

Usage:
QuickEditToolbar: <<tiddler QuickEdit_color>>
OR
EditTemplate: <span class='toolbar' macro='tiddler QuickEdit_color'></span>

**** COLOR ****
%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink"
title="text/background color - @@color:#RGB;background-color:#RGB;...@@"
onclick="var p=Popup.create(this,null,'popup sticky smallform'); if (!p) return false;
 	p.style.padding='2px';
	function hex(d) { return '0123456789ABCDEF'.substr(d,1); }
	var fg=createTiddlyElement(p,'select'); fg.button=this;
	fg.style.width='12em';
	fg.options[0]=new Option('text color...','');
	fg.options[1]=new Option('\xa0 or enter a value','_ask');
	fg.options[2]=new Option('\xa0 or use default color','');
	for (var r=0;r<16;r+=3) for (var g=0;g<16;g+=3) for (var b=0;b<16;b+=3) {
		var label=hex(r)+hex(g)+hex(b);
		fg.options[fg.length]=new Option(label,'#'+label);
		fg.options[fg.length-1].style.color='#'+label;
	}
	fg.onchange=function(){ var val=this.value;
		if (val=='_ask') { val=prompt('Enter a CSS color value');
		if (!val||!val.length) return false; }
		this.options[0].value=val; this.options[0].text=val.length?'text: '+val:'text color...';
		var bg=this.nextSibling;
		for (var i=3;i<bg.options.length;i++) bg.options[i].style.color=val;
		var preview=this.nextSibling.nextSibling.nextSibling;
		var t=config.quickEdit.getSelection(config.quickEdit.getField(this.button));
		t=t.replace(/^@@(color\:.+;)?(background-color\:.+;)?/,'').replace(/@@$/,'');
		if (!t.length) t='~AaBbCcDdEeFfGgHhIiJj 1234567890';
		var fg=this.value; if (fg.length) fg='color:'+fg+';';
		var bg=this.nextSibling.value; if (bg.length) bg='background-color:'+bg+';';
		if (fg.length||bg.length) t='@@'+fg+bg+t+'@@';
		removeChildren(preview); wikify(t,preview);
		this.selectedIndex=0; return false;
	};
	var bg=createTiddlyElement(p,'select'); bg.button=this;
	bg.style.width='12em';
	bg.options[0]=new Option('background color...','');
	bg.options[1]=new Option('\xa0 or enter a value','_ask');
	bg.options[2]=new Option('\xa0 or use default color','');
	for (var r=0;r<16;r+=3) for (var g=0;g<16;g+=3) for (var b=0;b<16;b+=3) {
		var label=hex(15-r)+hex(15-g)+hex(15-b);
		bg.options[bg.length]=new Option(label,'#'+label);
		bg.options[bg.length-1].style.backgroundColor='#'+label;
	}
	bg.onchange=function(){ var val=this.value;
		if (val=='_ask') { val=prompt('Enter a CSS color value');
		if (!val||!val.length) return false; }
		this.options[0].value=val;
		this.options[0].text=val.length?'background: '+val:'background color...';
		var fg=this.previousSibling;
		for (var i=3;i<fg.options.length;i++) fg.options[i].style.backgroundColor=val;
		var preview=this.nextSibling.nextSibling;
		var t=config.quickEdit.getSelection(config.quickEdit.getField(this.button));
		t=t.replace(/^@@(color\:.+;)?(background-color\:.+;)?/,'').replace(/@@$/,'');
		if (!t.length) t='~AaBbCcDdEeFfGgHhIiJj 1234567890';
		var fg=this.previousSibling.value; if (fg.length) fg='color:'+fg+';';
		var bg=this.value; if (bg.length) bg='background-color:'+bg+';';
		if (fg.length||bg.length) t='@@'+fg+bg+t+'@@';
		removeChildren(preview); wikify(t,preview);
		this.selectedIndex=0; return false;
	};
	var b=createTiddlyElement(p,'input',null,null,null,{type:'button'}); b.button=this;
	b.value='ok'; b.style.width='4em';
	b.onclick=function() {
		var fg=this.previousSibling.previousSibling.value; if (fg.length) fg='color:'+fg+';';
		var bg=this.previousSibling.value; if (bg.length) bg='background-color:'+bg+';';
		var t=config.quickEdit.getSelection(config.quickEdit.getField(this.button));
		t=t.replace(/^@@(color\:.+;)?(background-color\:.+;)?/,'').replace(/@@$/,'');
		if (fg.length||bg.length) config.quickEdit.setSelection(this.button,'@@'+fg+bg+t+'@@');
		Popup.remove(); return false;
	};
	var preview=createTiddlyElement(p,'div',null,'viewer'); var s=preview.style;
	s.border='1px solid'; s.margin='2px'; s.width='24em'; s.padding='3px'; s.MozBorderRadius='3px';
	s.overflow='hidden'; s.textAlign='center'; s.whiteSpace='normal';
	var t=config.quickEdit.getSelection(config.quickEdit.getField(this));
	wikify(t.length?t:'~AaBbCcDdEeFfGgHhIiJj 1234567890',preview);
	Popup.show(p,false);
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>color</a></html>
/%
|Name|QuickEdit_css|
|Source|http://www.TiddlyTools.com/#QuickEdit_css|
|Version|2.2.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.2|
|Type|script|
|Requires|QuickEditPlugin|
|Overrides||
|Description|definition for toolbar button for inline css and css class wrappers|

Usage:
QuickEditToolbar: <<tiddler QuickEdit_css>>
OR
EditTemplate: <span class='toolbar' macro='tiddler QuickEdit_css'></span>

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink"
	title="inline CSS styles - @@attr:value;attr:value;...@@"
	onclick="var css=prompt('Enter CSS attribute/value pairs (attr:val;attr:val;...;)','');
		if (!css) return false; /* cancelled by user */
		return config.quickEdit.wrapSelection(this,'@@'+css+';','@@');"
>style</a></html>/%

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink"
	title="CSS class wrapper - {{classname classname etc{...}}}"
	onclick="var c=prompt('Enter a CSS classname','');
		if (!c) return false; /* cancelled by user */
		return config.quickEdit.wrapSelection(this,'{{'+c+'{','}}}');"
>class</a></html>
/%
|Name|QuickEdit_file|
|Source|http://www.TiddlyTools.com/#QuickEdit_file|
|Version|2.2.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.2|
|Type|script|
|Requires|QuickEditPlugin|
|Overrides||
|Description|definition for toolbar buttons that insert content from external files|

Usage:
QuickEditToolbar: <<tiddler QuickEdit_file>>
OR
EditTemplate: <span class='toolbar' macro='tiddler QuickEdit_file'></span>

**** INSERT FILE ****
%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink"
	title="insert content from an external text file"
	onclick="var fn=config.quickEdit.promptForFilename('Enter/select a text file',getLocalPath(document.location.href),'');
	if (!fn) return false; /* cancelled by user */
	var text=loadFile(getLocalPath(fn)); if (!text) { alert('Error: unable to read contents from \0027'+fn+'\0027'); return; }
	return config.quickEdit.setSelection(place,text);"
>file</a></html>
/%
|Name|QuickEdit_font|
|Source|http://www.TiddlyTools.com/#QuickEdit_font|
|Version|2.2.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.2|
|Type|script|
|Requires|QuickEditPlugin|
|Overrides||
|Description|definition for toolbar button that set font-family CSS attribute|

Usage:
QuickEditToolbar: <<tiddler QuickEdit_font>>
OR
EditTemplate: <span class='toolbar' macro='tiddler QuickEdit_macro'></span>

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink"
title="set font-family CSS attribute - @@font-family:facename;...@@"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select a font family...','');
	s.onchange=function(){
		if (this.value=='_edit')
			story.displayTiddler(story.findContainingTiddler(this.button),'QuickEdit_fontList',DEFAULT_EDIT_TEMPLATE);			
		else
			config.quickEdit.wrapSelection(this.button,'@@font-family:\x22'+this.value+'\x22;','@@');
		Popup.remove(); return false;
	};
	var fonts=store.getTiddlerText('QuickEdit_fontList','').split('\n');
	for (var i=0; i<fonts.length; i++) {
		if (!fonts[i].length) continue;
		s.options[s.length]=new Option(fonts[i],fonts[i]);
		s.options[s.length-1].style.fontFamily=fonts[i];
	}
	s.options[s.length]=new Option('[Edit font list...]','_edit');
	s.options[s.length-1].title='enter fonts, one per line...';
	Popup.show(p,false);
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>font</a></html>
Arial,helvetica,sans-serif
Times New Roman,times,serif
Courier,monospaced
/%
|Name|QuickEdit_format|
|Source|http://www.TiddlyTools.com/#QuickEdit_format|
|Version|2.2.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.2|
|Type|script|
|Requires|QuickEditPlugin|
|Overrides||
|Description|definition for toolbar button for text formatting|

Usage:
QuickEditToolbar: <<tiddler QuickEdit_format>>
OR
EditTemplate: <span class='toolbar' macro='tiddler QuickEdit_format'></span>

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" title="''bold''" accesskey="B" 
onclick="config.quickEdit.wrapSelection(this,'\x27\x27','\x27\x27'); return false;"
>&nbsp;B&nbsp;</a></html>/%

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" title="//italics//" accesskey="I" 
onclick="config.quickEdit.wrapSelection(this,'//','//'); return false;"
>&nbsp;I&nbsp;</a></html>/%

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" title="__underline__" accesskey="U" 
onclick="config.quickEdit.wrapSelection(this,'__','__'); return false;"
>&nbsp;U&nbsp;</a></html>/%

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" title="--strikethrough--" accesskey="S" 
onclick="config.quickEdit.wrapSelection(this,'--','--'); return false;"
>&nbsp;S&nbsp;</a></html>/%

%/ &nbsp;/%  SPACER

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink"
title="format text"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select text format...','');
	s.onchange=function(){
		var parts=this.value.split(',');
		config.quickEdit.wrapSelection(this.button,parts[0],parts[1]);
		Popup.remove(); return false;
	};
	s.options[s.length]=new Option('superscript','^^,^^');
	s.options[s.length-1].title='^^superscript^^';
	s.options[s.length]=new Option('subscript','~~,~~');
	s.options[s.length-1].title='~~subcript~~';
	s.options[s.length]=new Option('blockquote','\n\<\<\<\n,\n\<\<\<\n');
	s.options[s.length-1].title='indented blockquote - \<\<\<';
	s.options[s.length]=new Option('monospaced','{{{,}}}');
	s.options[s.length-1].title='inline monospaced text - {{{...}}}';
	s.options[s.length]=new Option('pre','\n{{{\n,\n}}}\n');
	s.options[s.length-1].title='multi-line monospaced text box - {{{...}}}';
	s.options[s.length]=new Option('heading 1','\n!,\n');
	s.options[s.length-1].title='H1 heading - !';
	s.options[s.length]=new Option('heading 2','\n!!,\n');
	s.options[s.length-1].title='H2 heading - !';
	s.options[s.length]=new Option('heading 3','\n!!!,\n');
	s.options[s.length-1].title='H3 heading - !';
	s.options[s.length]=new Option('heading 4','\n!!!!,\n');
	s.options[s.length-1].title='H4 heading - !';
	s.options[s.length]=new Option('heading 5','\n!!!!!,\n');
	s.options[s.length-1].title='H5 heading - !';
	s.options[s.length]=new Option('comment','/%,%/');
	s.options[s.length-1].title='comment (hidden content) - /%...%/';
	s.options[s.length]=new Option('HTML','<html>,<\x2fhtml>');
	s.options[s.length-1].title='HTML syntax - <html>...<\x2fhtml>';
	Popup.show(p,false);
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>format</a></html>
/%
|Name|QuickEdit_image|
|Source|http://www.TiddlyTools.com/#QuickEdit_image|
|Version|2.2.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.2|
|Type|script|
|Requires|QuickEditPlugin|
|Overrides||
|Description|definition for toolbar buttons that insert embedded image references|

Usage:
QuickEditToolbar: <<tiddler QuickEdit_image>>
OR
EditTemplate: <span class='toolbar' macro='tiddler QuickEdit_image'></span>

**** INSERT IMAGE ****
%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink"
	title="embed an image (jpg/gif/png) - [img[tooltip|URL]] or [img[tooltip|path/to/file.ext]]"
	onclick="var fn=config.quickEdit.promptForFilename('Enter/select an image file',getLocalPath(document.location.href),'');
	if (!fn) return false;  /* cancelled by user */
	var tip=prompt('Enter a tooltip for this image',''); if (!tip) tip=''; else tip+='|';
	return config.quickEdit.setSelection(this,'[img['+tip+fn+']]');"
>image</a></html>
/%
|Name|QuickEdit_link|
|Source|http://www.TiddlyTools.com/#QuickEdit_link|
|Version|2.2.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.2|
|Type|script|
|Requires|QuickEditPlugin|
|Overrides||
|Description|toolbar button that inserts a ~PrettyTiddlyLink to a tiddler or external file|

Usage:
QuickEditToolbar: <<tiddler QuickEdit_link>>
OR
EditTemplate: <span class='toolbar' macro='tiddler QuickEdit_link'></span>

**** INSERT LINK ****
%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink"
title="add a 'PrettyLink' to another tiddler - [[link text|TiddlerName]]"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select a tiddler or file...','');
	s.onchange=function(){
		var title=this.value; var txt=title;
		if (title=='_file') {
			title=config.quickEdit.promptForFilename('Select a file',
				getLocalPath(document.location.href),'');
			if (!title) { this.selectedIndex=0; this.focus(); return false; }
			var txt=title.substr(title.lastIndexOf('/')+1);
		}
		var txt=prompt('Enter the text to display for this link',txt);
		if (!txt) { this.selectedIndex=0; this.focus(); return false; }
		config.quickEdit.setSelection(this.button,'[['+txt+'|'+title+']]');
		Popup.remove(); return false;
	};
	s.options[s.length]=new Option('[browse for file...]','_file');
	var tids=store.getTiddlers('title');
	for (var t=0; t<tids.length; t++) {
		s.options[s.length]=new Option(tids[t].title,tids[t].title);
		s.options[s.length-1].title=tids[t].getSubtitle();
	}
	var s=createTiddlyElement(p,'select');
	s.options[0]=new Option('match tag...','');
	s.onchange=function(){
		var tag=this.value;
		var tids=tag.length?store.getTaggedTiddlers(tag,'title'):store.getTiddlers('title');
		var list=this.previousSibling;
		while (list.length) list.options[0]=null;
		var prompt='select a tiddler or file...';
		if (tag.length) prompt='select a tagged tiddler ['+tids.length+' matches]...';
		list.options[0]=new Option(prompt,'');
		if (!tag.length) list.options[list.length]=new Option('[browse for file...]','_file');
		for (var t=0; t<tids.length; t++) {
			list.options[list.length]=new Option(tids[t].title,tids[t].title);
			list.options[list.length-1].title=tids[t].getSubtitle();
		}
	};
	var tags=store.getTags();
	for (var t=0; t<tags.length; t++) s.options[s.length]=new Option(tags[t][0],tags[t][0]);
	Popup.show(p,false);
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>link</a></html>
/%
|Name|QuickEdit_macro|
|Source|http://www.TiddlyTools.com/#QuickEdit_macro|
|Version|2.2.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.2|
|Type|script|
|Requires|QuickEditPlugin|
|Overrides||
|Description|definition for toolbar button that inserts macros with guide text|

Usage:
QuickEditToolbar: <<tiddler QuickEdit_macro>>
OR
EditTemplate: <span class='toolbar' macro='tiddler QuickEdit_macro'></span>

**** INSERT MACRO ****
The "macro" command can include optional "guideText" for any given macro, as an aide to entering macro parameters, by embedding placeholders or recommended default values into the macro syntax that is inserted into your tiddler content.  For built-in TW core macros, this guideText is defined below.  You can add guideText to your own plugin-defined macros by using the following javascript syntax: config.macros.macroName.guideText="guide text goes here";
%/<<tiddler {{
	/* SET MACRO GUIDE TEXT (for built-in core macros) (11/17 - TBD - incomplete list) */
	config.macros.edit.guideText="fieldname #rows";
	config.macros.view.guideText="fieldname (link,wikified,date) format";
	config.macros.slider.guideText="cookie TiddlerName label tooltip";
	config.macros.option.guideText="(txtCookieName,chkCookieName)";
	config.macros.tiddler.guideText="TiddlerName with: params...";
	""; /* must return blank to suppress output */ }}>>/%
%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink"
title="add a macro - \<\<macroName ...\>\>"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select a macro...','');
	s.onchange=function(){
		config.quickEdit.setSelection(this.button,'\<\<'+this.value+'\>\>');
		Popup.remove(); return false;
	};
	var macros=[]; for (var m in config.macros) if (config.macros[m].handler) macros.push(m); macros.sort();
	for (var i=0; i<macros.length; i++) { var m=macros[i];
		var help=config.macros[m].guideText; if (!help) help=''; else help=' '+help;
		s.options[s.length]=new Option(m,m+help);
		s.options[s.length-1].title='\<\<'+m+help+'\>\>';
	}
	Popup.show(p,false);
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>macro</a></html>
/%
|Name|QuickEdit_replace|
|Source|http://www.TiddlyTools.com/#QuickEdit_replace|
|Version|2.2.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.2|
|Type|script|
|Requires|QuickEditPlugin|
|Overrides||
|Description|definition for find/replace toolbar button|

Usage:
QuickEditToolbar: <<tiddler QuickEdit_replace>>
OR
EditTemplate: <span class='toolbar' macro='tiddler QuickEdit_replace'></span>

**** FIND/REPLACE/NEXT/ALL ****
%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink"
title="find/replace selected text with replacement text"
onclick="var here=story.findContainingTiddler(this); if (!here) return false;
	var e=config.quickEdit.getField(here);
	var s=config.quickEdit.getSelection(e); 
	var p=Popup.create(this,null,'popup sticky smallform'); if (!p) return false;
	var t=createTiddlyElement(p,'input'); t.onfocus=function(){this.select()};
	t.value=s.length?s:'enter target text';
	var r=createTiddlyElement(p,'input'); r.onfocus=function(){this.select()};
	r.value='enter replacement text';
	var tid=here.getAttribute('tiddler');
	var b=createTiddlyElement(p,'button',null,null,'?',{tid:tid});
	b.style.width='2em';
	b.title='FIND/FIND NEXT target text';
	b.onclick=function(ev) { /* FIND */
		var e=story.getTiddlerField(this.getAttribute('tid'),'text');
		if (!e||e.getAttribute('edit')!='text') return;
		var t=this.previousSibling.previousSibling;
		e.focus();
		if (e.setSelectionRange) { /* MOZ */
			var newstart=e.value.indexOf(t.value,e.selectionStart+1);
			if (newstart==-1) newstart=e.value.indexOf(t.value); /* wrap around */
			if (newstart==-1) { alert('\u0022'+t.value+'\u0022 not found'); t.focus(); return; }
			e.setSelectionRange(newstart,newstart+t.value.length);
			var linecount=e.value.split('\n').length;
			var thisline=e.value.substr(0,e.selectionStart).split('\n').length;
			e.scrollTop=Math.floor((thisline-1-e.rows/2)*e.scrollHeight/linecount);
		} else if (document.selection) { /* IE */
			var range=document.selection.createRange();
			if(range.parentElement()==e) {
				range.collapse(false);
				var found=false; try{found=range.findText(t.value,e.value.length,4)}catch(e){}
				if (found) range.select();
				else { alert('\u0022'+t.value+'\u0022 not found'); t.focus(); }
			}
		}
	};
	b=createTiddlyElement(p,'button',null,null,'=',{tid:tid});
	b.style.width='2em';
	b.title='REPLACE selected text';
	b.onclick=function(ev) { /* REPLACE */
		var e=story.getTiddlerField(this.getAttribute('tid'),'text');
		if (!e||e.getAttribute('edit')!='text') return;
		var t=this.previousSibling.previousSibling.previousSibling;
		var r=this.previousSibling.previousSibling;
		if (   (e.selectionStart!==undefined && e.selectionEnd==e.selectionStart)
		    || (document.selection && document.selection.createRange().text==''))
			this.previousSibling.click(); /* no selection... do FIND first */
		if (   (e.selectionStart!==undefined && e.selectionEnd==e.selectionStart)
		    || (document.selection && document.selection.createRange().text==''))
			{ t.focus(); return; } /* still no selection... goto target input */
		e.focus(); replaceSelection(e,r.value);
	};
	b=createTiddlyElement(p,'button',null,null,'+',{tid:tid});
	b.style.width='2em';
	b.title='REPLACE selected text AND FIND NEXT target text';
	b.onclick=function(ev) { /* REPLACE and FIND NEXT */
		this.previousSibling.click();
		this.previousSibling.previousSibling.click();
	};
	b=createTiddlyElement(p,'button',null,null,'!',{tid:tid});
	b.style.width='2em';
	b.title='REPLACE ALL occurrences of target text';
	b.onclick=function(ev) { /* REPLACE ALL */
		var e=story.getTiddlerField(this.getAttribute('tid'),'text');
		if (!e||e.getAttribute('edit')!='text') return;
		var t=this.previousSibling.previousSibling.previousSibling.previousSibling.previousSibling;
		var r=this.previousSibling.previousSibling.previousSibling.previousSibling;
		if (!t.value.length) { alert('Please enter the target text'); t.focus(); return; }
		var m='This will replace all occurences of:\n\n';
		m+='\''+t.value+'\'\n\nwith:\n\n\''+r.value+'\'\n\nAre you sure?';
		if (!confirm(m)) { r.focus(); r.select(); return; }
		e.value=e.value.replace(new RegExp(t.value.escapeRegExp(),'gm'),r.value);
		e.focus(); e.select(); Popup.remove();
	};
	Popup.show(p,false);
	if (!s.length) {t.focus();t.select()} else {r.focus();r.select()}
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>replace</a></html>
/%
|Name|QuickEdit_sort|
|Source|http://www.TiddlyTools.com/#QuickEdit_sort|
|Version|2.2.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.2|
|Type|script|
|Requires|QuickEditPlugin|
|Overrides||
|Description|definition for toolbar "sort" button|

Usage:
QuickEditToolbar: <<tiddler QuickEdit_sort>>
OR
EditTemplate: <span class='toolbar' macro='tiddler QuickEdit_sort'></span>

**** SORT LINES ****
%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink"
title="sort lines of text"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select sort order...','');
	s.onchange=function(){
		var e=config.quickEdit.getField(this.button); if (!e) return false;
		var lines=config.quickEdit.getSelection(e).split('\n').sort();
		if (this.value=='D') lines=lines.reverse();
		replaceSelection(e,lines.join('\n'));
		e.focus();
		Popup.remove(); return false;
	};
	s.options[s.length]=new Option('ascending','A');
	s.options[s.length-1].title='ascending';
	s.options[s.length]=new Option('descending','D');
	s.options[s.length-1].title='descending';
	Popup.show(p,false);
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>sort</a></html>
/%
|Name|QuickEdit_split|
|Source|http://www.TiddlyTools.com/#QuickEdit_split|
|Version|2.2.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.2|
|Type|script|
|Requires|QuickEditPlugin|
|Overrides||
|Description|toolbar button: split selected content into separate tiddler|

Based on ideas originally developed by YannPerrin
(http://yann.perrin.googlepages.com/twkd.html#easySlicer)

Usage
QuickEditToolbar: <<tiddler QuickEdit_split>>
OR
EditTemplate:
<div class='toolbar'>
	<span macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'></span>
	<span macro='tiddler QuickEdit_split'></span>
</div>

**** SPLIT TIDDLER ****
%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink"
title="move selection to new tiddler and insert link, embedded tiddler, or slider"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	p.style.whiteSpace='nowrap';
	var i=createTiddlyElement(p,'input');
	i.defaultValue='Enter a new tiddler title';
	i.onfocus=function(){this.select()};
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select type...','');
	s.options[0].title='select split type';
	s.options[1]=new Option('link','link');
	s.options[1].title='replace with [[TiddlerName]]';
	s.options[2]=new Option('embed','embed');
	s.options[2].title='replace with \<\<tiddler TiddlerName\>\>';
	s.options[3]=new Option('slider','slider');
	s.options[3].title='replace with \<\<slider \u0022\u0022 [[TiddlerName]] [[label]] [[tooltip]]\>\>';
	s.onchange=function(){
		if (s.previousSibling.value==s.previousSibling.defaultValue)
			{ alert('A tiddler title is required'); s.selectedIndex=0; s.previousSibling.focus(); return false; }
		var tid=s.previousSibling.value;
		if (store.tiddlerExists(tid) && !confirm(config.messages.overwriteWarning.format([tid])))
			{ s.previousSibling.focus(); return false; }
		switch(s.value) {
			case 'link':
				var newtxt='[['+tid+']]';
				break;
			case 'embed':
				var newtxt='\<\<tiddler [['+tid+']]\>\>';
				break;
			case 'slider':
				var label=prompt('Enter a slider label',tid);
				if (!label) { Popup.remove(); return false; }
				var tip=prompt('Enter a slider tooltip',label);
				if (!tip) { Popup.remove(); return false; }
				var newtxt='\<\<slider \u0022\u0022 [['+tid+']] [['+label+']] [['+tip+']]\>\>';
				break;
		}
		var txt=config.quickEdit.getSelection(config.quickEdit.getField(this.button));
		store.saveTiddler(tid,tid,txt,config.options.txtUserName,new Date(),[],{});
		story.displayTiddler(story.findContainingTiddler(this.button),tid);
		config.quickEdit.setSelection(this.button,newtxt);
		Popup.remove(); return false;
	};
	Popup.show(p,false);
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>split</a></html>
/%
|Name|QuickEdit_tiddler|
|Source|http://www.TiddlyTools.com/#QuickEdit_tiddler|
|Version|2.2.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.2|
|Type|script|
|Requires|QuickEditPlugin|
|Overrides||
|Description|definition for toolbar button that inserts content from another tiddler|

Usage:
QuickEditToolbar: <<tiddler QuickEdit_tiddler>>
OR
EditTemplate: <span class='toolbar' macro='tiddler QuickEdit_tiddler'></span>

**** INSERT TIDDLER ****
%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink"
title="copy content from another tiddler"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select a tiddler...','');
	s.onchange=function(){
		var txt=store.getTiddlerText(this.value);
		if (!txt) { displayMessage(this.value+' not found'); this.selectedIndex=0; this.focus(); return false; }
		config.quickEdit.setSelection(this.button,txt);
		Popup.remove(); return false;
	};
	var tids=store.getTiddlers('title');
	for (var t=0; t<tids.length; t++) {
		s.options[s.length]=new Option(tids[t].title,tids[t].title);
		s.options[s.length-1].title=tids[t].getSubtitle();
	}
	var s=createTiddlyElement(p,'select');
	s.options[0]=new Option('match tag...','');
	s.onchange=function(){
		var tag=this.value;
		var tids=tag.length?store.getTaggedTiddlers(tag,'title'):store.getTiddlers('title');
		var list=this.previousSibling;
		while (list.length) list.options[0]=null;
		var prompt='select a '+(tag.length?'tagged ':'')+'tiddler'+(tag.length?(' ['+tids.length+' matches]'):'')+'...';
		list.options[0]=new Option(prompt,'');
		for (var t=0; t<tids.length; t++) {
			list.options[list.length]=new Option(tids[t].title,tids[t].title);
			list.options[list.length-1].title=tids[t].getSubtitle();
		}
	};
	var tags=store.getTags();
	for (var t=0; t<tags.length; t++) s.options[s.length]=new Option(tags[t][0],tags[t][0]);
	Popup.show(p,false);
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>tiddler</a></html>
/***
|Name|RearrangeTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#RearrangeTiddlersPlugin|
|Version|0.0.0|
|Author|Joe Raii|
|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.refreshTiddler|
|Description|drag tiddlers by title to re-order story column display|

adapted from: http://www.cs.utexas.edu/~joeraii/dragn/#Draggable
changes by ELS:
* hijack refreshTiddler() instead of overridding createTiddler()
* find title element by className instead of elementID
* set cursor style via code instead of stylesheet
* set tooltip help text
* set tiddler "position:relative" when starting drag event, restore saved value when drag ends
* update 2006.08.07: use getElementsByTagName("*") to find title element, even when it is 'buried' deep in tiddler DOM elements (due to custom template usage)
* update 2007.03.01: use apply() to invoke hijacked core function
* update 2008.01.13: only hijack core function once.  (allows for dynamic loading of plugin via bookmarklet)

***/
//{{{

if (Story.prototype.rearrangeTiddlersHijack_refreshTiddler===undefined) {
Story.prototype.rearrangeTiddlersHijack_refreshTiddler = Story.prototype.refreshTiddler;
Story.prototype.refreshTiddler = function(title,template)
{
	this.rearrangeTiddlersHijack_refreshTiddler.apply(this,arguments);
	var theTiddler = document.getElementById(this.idPrefix + title); if (!theTiddler) return;
	var theHandle;
	var children=theTiddler.getElementsByTagName("*");
	for (var i=0; i<children.length; i++) if (hasClass(children[i],"title")) { theHandle=children[i]; break; }
	if (!theHandle) return theTiddler;

	Drag.init(theHandle, theTiddler, 0, 0, null, null);
	theHandle.style.cursor="move";
	theHandle.title="drag title to re-arrange tiddlers"
	theTiddler.onDrag = function(x,y,myElem) {
		if (this.style.position!="relative")
			{ this.savedstyle=this.style.position; this.style.position="relative"; }
		y = myElem.offsetTop;
		var next = myElem.nextSibling;
		var prev = myElem.previousSibling;
		if (next && y + myElem.offsetHeight > next.offsetTop + next.offsetHeight/2) { 
			myElem.parentNode.removeChild(myElem);
			next.parentNode.insertBefore(myElem, next.nextSibling);//elems[pos+1]);
			myElem.style["top"] = -next.offsetHeight/2+"px";
		}
		if (prev && y < prev.offsetTop + prev.offsetHeight/2) { 
			myElem.parentNode.removeChild(myElem);
			prev.parentNode.insertBefore(myElem, prev);
			myElem.style["top"] = prev.offsetHeight/2+"px";
		}
	};
	theTiddler.onDragEnd = function(x,y,myElem) {
		myElem.style["top"] = "0px";
		if (this.savedstyle!=undefined)
			this.style.position=this.savedstyle;
	}
	return theTiddler;
}
}

/**************************************************
 * dom-drag.js
 * 09.25.2001
 * www.youngpup.net
 **************************************************
 * 10.28.2001 - fixed minor bug where events
 * sometimes fired off the handle, not the root.
 **************************************************/

var Drag = {
	obj:null,

	init:
	function(o, oRoot, minX, maxX, minY, maxY) {
		o.onmousedown = Drag.start;
		o.root = oRoot && oRoot != null ? oRoot : o ;
		if (isNaN(parseInt(o.root.style.left))) o.root.style.left="0px";
		if (isNaN(parseInt(o.root.style.top))) o.root.style.top="0px";
		o.minX = typeof minX != 'undefined' ? minX : null;
		o.minY = typeof minY != 'undefined' ? minY : null;
		o.maxX = typeof maxX != 'undefined' ? maxX : null;
		o.maxY = typeof maxY != 'undefined' ? maxY : null;
		o.root.onDragStart = new Function();
		o.root.onDragEnd = new Function();
		o.root.onDrag = new Function();
	},

	start:
	function(e) {
		var o = Drag.obj = this;
		e = Drag.fixE(e);
		var y = parseInt(o.root.style.top);
		var x = parseInt(o.root.style.left);
		o.root.onDragStart(x, y, Drag.obj.root);
		o.lastMouseX = e.clientX;
		o.lastMouseY = e.clientY;
		if (o.minX != null) o.minMouseX = e.clientX - x + o.minX;
		if (o.maxX != null) o.maxMouseX = o.minMouseX + o.maxX - o.minX;
		if (o.minY != null) o.minMouseY = e.clientY - y + o.minY;
		if (o.maxY != null) o.maxMouseY = o.minMouseY + o.maxY - o.minY;
		document.onmousemove = Drag.drag;
		document.onmouseup = Drag.end;
		Drag.obj.root.style["z-index"] = "10";
		return false;
	},

	drag:
	function(e) {
		e = Drag.fixE(e);
		var o = Drag.obj;
		var ey = e.clientY;
		var ex = e.clientX;
		var y = parseInt(o.root.style.top);
		var x = parseInt(o.root.style.left);
		var nx, ny;
		if (o.minX != null) ex = Math.max(ex, o.minMouseX);
		if (o.maxX != null) ex = Math.min(ex, o.maxMouseX);
		if (o.minY != null) ey = Math.max(ey, o.minMouseY);
		if (o.maxY != null) ey = Math.min(ey, o.maxMouseY);
		nx = x + (ex - o.lastMouseX);
		ny = y + (ey - o.lastMouseY);
		Drag.obj.root.style["left"] = nx + "px";
		Drag.obj.root.style["top"] = ny + "px";
		Drag.obj.lastMouseX = ex;
		Drag.obj.lastMouseY = ey;
		Drag.obj.root.onDrag(nx, ny, Drag.obj.root);
		return false;
	},

	end:
	function() {
		document.onmousemove = null;
		document.onmouseup = null;
		Drag.obj.root.style["z-index"] = "0";
		Drag.obj.root.onDragEnd(parseInt(Drag.obj.root.style["left"]), parseInt(Drag.obj.root.style["top"]), Drag.obj.root);
		Drag.obj = null;
	},

	fixE:
	function(e) {
		if (typeof e == 'undefined') e = window.event;
		if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
		if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
		return e;
	}
};
//}}}
/***
|Name|RecentChangesPlugin|
|Source|http://www.TiddlyTools.com/#RecentChangesPlugin|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|display droplist of recently changed tiddlers with goto, edit, and preview buttons|
!!!!!Usage
<<<
The {{{<<recentChanges>>}}} macro displays a droplist of all tiddlers that have been changed within the last N days (default=10 days).  
<<<
!!!!!Examples
<<<
{{{<<recentChanges>>}}}
<<recentChanges>>
or
{{{<<recentChanges #ofdays previewheight previewclass>>}}}
where:
* #ofdays specifies the time limit for list changed tiddlers.  Use 0 (zero) to list all tiddlers in the document
* previewheight is a CSS height measurement and sets the FIXED height of the tiddler preview area (default is 15em)
* previewclass is any CSS classname, and can be used to apply custom styles to the preview area (default is to use the standard 'viewer' class)
<<recentChanges 14 10em groupbox>>
<<<
!!!!!Revisions
<<<
2008.05.01 [2.0.1] fixup for titles with double-quotes
2007.07.26 [2.0.0] re-written as plugin
2006.10.02 [1.0.0] initial release (as inline script ShowRecentChanges)
<<<
!!!!!Code
***/
//{{{
version.extensions.recentChanges= {major: 2, minor: 0, revision: 1, date: new Date(2008,5,1)};

config.shadowTiddlers.RecentChanges="<<recentChanges>>";

config.macros.recentChanges = {
	layout: '<form><!--\
		--><select size=1 name="list" style="width:69.5%" \
			onchange=" \
				this.form.goto.disabled=this.form.edit.disabled=this.form.preview.disabled=!this.value.length; \
				var target=this.parentNode.parentNode.nextSibling; removeChildren(target); \
				if (!this.value.length) \
					{ target.style.display=\'none\'; this.form.preview.value=\'preview\'; } \
				else if (target.style.display==\'block\') { \
					wikify(\'<\'+\'<tiddler [[\'+this.value+\']]>\'+\'>\',target); \
					target.style.display=\'block\'; \
					this.form.preview.value=\'done\'; \
				} \
			"><!--\
		-->%options%<!--\
		--></select><!--\
		--><input type="button" name="goto" value="goto" disabled title="view selected tiddler" style="width:10%" \
			onclick="var target=this.parentNode.parentNode.nextSibling; removeChildren(target); \
				target.style.display=\'none\'; this.form.preview.value=\'preview\'; \
				story.displayTiddler(story.findContainingTiddler(this),this.form.list.value); \
			"><!--\
		--><input type="button" name="edit" value="edit" disabled title="edit selected tiddler" style="width:10%" \
			onclick="var target=this.parentNode.parentNode.nextSibling; removeChildren(target); \
				target.style.display=\'none\'; this.form.preview.value=\'preview\'; \
				story.displayTiddler(story.findContainingTiddler(this),this.form.list.value,DEFAULT_EDIT_TEMPLATE); \
			"><!--\
		--><input type="button" name="preview" value="preview" disabled title="show/hide tiddler preview" style="width:10%" \
			onclick="var target=this.parentNode.parentNode.nextSibling; \
				if (this.value==\'preview\') { \
					removeChildren(target); \
					wikify(\'<\'+\'<tiddler [[\'+this.form.list.value+\']]>\'+\'>\',target); \
					target.style.display=this.form.list.value.length?\'block\':\'none\'; this.value=\'done\'; \
				} else { \
					removeChildren(target); \
					target.style.display=\'none\'; this.value=\'preview\'; \
				} \
			"><!--\
		--></form>',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var days=10; if (!isNaN(params[0])) days=parseInt(params[0]); // time limit in days (use 0 for all tiddlers)
		var height='15em'; if (params[1]) height=params[1]; // preview area fixed height
		var previewclass='viewer'; if (params[2]) previewclass=params[2]; // preview area CSS class
		var tiddlers=store.getTiddlers('modified','excludeLists').reverse();
		var count=tiddlers.length;
		if (days) {
			var timelimit=(new Date()).getTime()-86400000*days;
			for (var count=0; count<tiddlers.length && tiddlers[count].modified>timelimit; count++);
		}
		var opts="";
		opts+='<option value="">';
		opts+=count+' tiddlers have changed since ';
		opts+=new Date(timelimit).formatString("DDD, MMM DDth YYYY 0hh:0mm");
		opts+=' ('+days+' days ago)';
		opts+='</option>';
		for (var i=0; i<count; i++) { var t=tiddlers[i];
			opts+='<option value="'+t.title.replace(/"/g,"&#x22;")+'">';
			opts+=t.modified.formatString('YYYY.0MM.0DD 0hh:0mm')+' - '+t.title;
			opts+='</option>';
		}
		createTiddlyElement(place,"div").innerHTML=this.layout.replace(/%options%/,opts);
		var preview=createTiddlyElement(place,"div",null,previewclass);
		preview.style.display='none';
		preview.style.whiteSpace='normal';
		preview.style.overflow='auto';
		preview.style.height=height;
	}
}
//}}}
/%
|''URL:''|http://solo.dc3.com/tw/|
|''Description:''|Bob Denny's extensions to TiddlyWiki|
|''Author:''|BobDenny|
%/
/%
|Name|RefreshPageDisplay|
|Source|http://www.TiddlyTools.com/#RefreshPageDisplay|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|Refresh all tiddlers and page elements without restarting|
%/<script label="$1" title="Redisplay current page content WITHOUT RESTARTING!">
	story.forEachTiddler(function(t,e){story.refreshTiddler(t,null,true)});
	refreshDisplay();
 	return false;
</script><script>
	if ("$1"=="$"+"1") place.lastChild.innerHTML="refresh page display";
</script>
/%
|Name|RefreshTiddler|
|Source|http://www.TiddlyTools.com/#RefreshTiddler|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|link that forces a refresh of the current tiddler|

usage: <<tiddler RefreshTiddler with: "label" "tooltip">>

where label and tooltip are optional and default to "refresh" and "redisplay tiddler content", respectively.

%/<script label="refresh" title="redisplay tiddler content">
	var here=story.findContainingTiddler(place); if (!here) return false;
	story.refreshTiddler(here.getAttribute("tiddler"),null,true);
	return false;
</script><script>
	if ("$1"!="$"+"1") place.lastChild.innerHTML="$1";
	if ("$2"!="$"+"2") place.lastChild.title="$2";
</script>
/***
|Name|RelatedTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#RelatedTiddlersPlugin|
|Version|1.1.7|
|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|InlineJavascriptPlugin, NestedSlidersPlugin, StyleSheetShortcuts|
|Overrides||
|Options|##Configuration|
|Description|starting from a selected tiddler, display a list and/or tree of linked or transcluded tiddlers|
Given a starting tiddler (default is the current tiddler), this plugin recursively follows the internal links[] data that is associated with each tiddler and constructs a list of all tiddlers that are related to the starting tiddler by being referenced in a TiddlyLink (e.g., {{{[[TiddlerName]]}}}) or used as macro parameter (e.g., {{{<<tiddler TiddlerName>>}}}) within the tiddler content.

Using the terminology of Graph Theory, the plugin's recursive algorithm finds what is called a 'minimal spanning tree' from any specific starting 'root node'.  The results can be displayed as a simple flat list of related tiddler titles, or as an indented tree diagram that shows the specific connections between the related tiddlers, and can be helpful for identifying clusters of interdependent tiddlers or simply generating an on-the-fly site map for quick discovery and navigation through complex or unfamiliar document content. 
!!!!!Usage
<<<
//{{{
<<relatedTiddlers TiddlerName hideform "exclude list">>
//}}}
where:
*TiddlerName (optional)<br>sets the initial "root" to the specified tiddler (and hides the 'select a tiddler' form controls).  You can use keyword 'here' to specify the current tiddler.
*'hideform' (optional) or 'showform' (default)<br>keyword value to suppress display of 'select tiddler' droplist and buttons.
*"exclude list" (optional)<br>space-separated list of tiddlers whose links should not be followed.  use quotes or double-square brackets to ensure list is processed as a single parameter
The plugin also defines two functions that can be called externally (from other plugins or scripts) to generate and retrieve either a list of links or a formatted "tree view":
>{{{var list=config.macros.relatedTiddlers.getList(start,exclude,callback);}}}
>{{{var tree=config.macros.relatedTiddlers.getTree(start,exclude,callback);}}}
These functions accept parameters to specify the starting tiddler, and a list of tiddlers to exclude, as well as an optional callback function that takes any specified tiddler as input and returns a custom-defined array of links related to that tiddler:
>{{{var list=callback(tiddler);}}}
Use of the callback function enables you to generate an alternative list/tree, based on application-specific data (such tiddler references contained in tags or custom fields), rather than using the default "links" list.
<<<
!!!!!Configuration
<<<
<<option chkRelatedTiddlersShowList>> show list display
<<option chkRelatedTiddlersShowTree>> show tree display
<<option chkRelatedTiddlersZoom>> enable autosizing of tree display //(aka, "zoom" or "shrink-and-grow")//
don't follow links contained in these tiddlers: <<option txtRelatedTiddlersExclude>>
<<<
!!!!!Examples
<<<
{{smallform{<<relatedTiddlers>>}}}

Using getList()/getTree() public API from other scripts/plugins:
><script show>
	var start="About";
	var exclude=config.options.txtRelatedTiddlersExclude.readBracketedList();
	var callback=null;
	var list=config.macros.relatedTiddlers.getList(start,exclude,callback);
	var tree=config.macros.relatedTiddlers.getTree(start,exclude,callback);
	return "There are "+list.length+" tiddlers related to [["+start+"]]...\n"+tree;
</script>
<<<
!!!!!Revisions
<<<
''2007.11.11 [1.1.7]'' in findRelatedTiddlers(), refactored code to get links from a given tiddler into separate getlinks() function, and added param for optional callback function that can be used to return an alternative set of links.  Also added API functions, getTree() and getList() for external use by other scripts
''2007.07.13 [1.1.6]'' performance optimizations, more code cleanup
''2007.07.10 [1.1.5]'' extensive code cleanup
''2007.07.08 [1.1.0]'' converted from inline script
''2007.06.29 [1.0.0]'' started (as inline script)
<<<
!!!!!Code
***/
//{{{
version.extensions.RelatedTiddlersPlugin={major: 1, minor: 1, revision: 7, date: new Date(2007,11,11)};

// initialize 'autozoom' and 'exclude' tree options (defaults are not to zoom, and to follow all links)
if (config.options.chkRelatedTiddlersZoom===undefined)
	config.options.chkRelatedTiddlersZoom=false;
if (config.options.txtRelatedTiddlersExclude===undefined)
	config.options.txtRelatedTiddlersExclude='GettingStarted DefaultTiddlers SiteNews Download';
if (config.options.chkRelatedTiddlersShowList===undefined)
	config.options.chkRelatedTiddlersShowList=true;
if (config.options.chkRelatedTiddlersShowTree===undefined)
	config.options.chkRelatedTiddlersShowTree=false;

config.macros.relatedTiddlers={
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {

		// create form with unique DOM element ID (using current timestamp)... permits multiple form instances
		var now=new Date().getTime();
		var span=createTiddlyElement(place,"span");
		span.innerHTML=this.form.format(["relatedTiddlers_form"+now]);
		var form=span.getElementsByTagName("form")[0]; // find form that we just created
		var target=createTiddlyElement(span,"div"); // create target block in which generated output will be placed

		// initialize droplist contents (all tiddlers except hidden ones)
		var tids=store.getTiddlers('title','excludeLists');
		for (i=0; i<tids.length; i++) form.list.options[form.list.options.length]=new Option(tids[i].title,tids[i].title,false,false);

		// initialize exclude field (space-separated list)
		if (config.options.txtRelatedTiddlersExclude) form.exclude.value=config.options.txtRelatedTiddlersExclude;

		// set starting tiddler, form display, and/or exclude list from macro params (if present) and then show the results!
		var root="";
		var hide=false;
		var exclude=config.options.txtRelatedTiddlersExclude;
		if (params[0]) root=params[0]; // TiddlerName
		if (params[1]) hide=(params[1].toLowerCase()=="hideform"); // keyword: "hideform" or "showform" (default)
		if (params[2]) exclude=params[2]; // list of tiddlers whose links should not be followed
		if (root=="here") { var tid=story.findContainingTiddler(place); if (tid) root=tid.getAttribute("tiddler"); }
		if (store.tiddlerExists(root)) {
			// NOTE:  don't hide form when running IE, where putting initial focus on hidden form creates an error
			if (!config.browser.isIE) form.style.display=hide?"none":"block"; // show/hide the controls
			form.list.value=root; // set the root
			form.exclude.value=exclude; // set 'exclude' field
			form.get.click(); // DISPLAY INITIAL RESULTS (if tiddler is selected)
		}
	},
	form:
		"<form id='%0' action='javascript:;' style='display:inline;margin:0;padding:0;' onsubmit='return false'><!-- \
		--><span class='fine' style='float:left;vertical-align:bottom;width:39.5%;'><i>find all tiddlers related to:</i></span><!-- \
		--><span class='fine' style='float:left;vertical-align:bottom;'><i>exclude links contained in:</i></span><!-- \
		--><div style='clear:both'><!-- \
		--><select name=list size=1 style='width:39.5%' onchange='this.form.get.click()'><!-- \
		--><option value=''>select a tiddler...</option><!-- \
		--></select><!-- \
		--><input type='text' option='txtRelatedTiddlersExclude' name='exclude' value='' style='width:40%' \
			title='enter the names of tiddlers whose links should NOT be followed' \
			onkeyup='if (event.keyCode==13) { this.blur(); this.form.get.click(); }'  \
			onchange='config.options[this.getAttribute(\"option\")]=this.value;saveOptionCookie(this.getAttribute(\"option\"));'><!-- \
		--><input type=button name=get value='get related' style='width:10%'  \
			onclick='config.macros.relatedTiddlers.show(this.form,this.form.nextSibling);'><!-- \
		--><input type=button name=done value='done' disabled style='width:10%'  \
			onclick='this.form.list.selectedIndex=0; this.form.get.click();'><!-- \
		--></div><!-- \
		--></form>",
	styles:
		".relatedTiddlers blockquote \
			{ border-left:1px dotted #999; margin:0 25px; padding-left:.5em; font-size:%0%; line-height:115%; } \
		.relatedTiddlers .borderleft \
			{ margin:0; padding:0; margin-left:1em; border-left:1px dotted #999; padding-left:.5em; } \
		.relatedTiddlers .fourcolumns \
			{ display:block; -moz-column-count:4; -moz-column-gap:1em; -moz-column-width:25%} \
		.relatedTiddlers a \
			{ font-weight:normal; } \
		.relatedTiddlers .bold, .relatedTiddlers .bold a \
			{ font-weight:bold; } \
		.relatedTiddlers .floatright \
			{ float:right; } \
		.relatedTiddlers .clear \
			{ clear:both; }	",
	toggleform:
		"{{floatright{<html><a href='javascript:;' class='button' title='show/hide tiddler selection droplist and buttons' \
		onclick='var here=story.findContainingTiddler(this); var tid=here?here.getAttribute(\"tiddler\"):\"\"; \
			var f=document.getElementById(\"%0\"); var hide=(f.style.display!=\"none\"); \
			f.style.display=hide?\"none\":\"inline\"; this.innerHTML=hide?\"show form\":\"hide form\"; return false;'>%1</a></html>}}}",
	treecheck:
		"{{floatright{@@display:none;<<option chkRelatedTiddlersShowTree>>@@<html><a href='javascript:;' class='button' onclick='this.parentNode.previousSibling.firstChild.click(); return false;'>tree view</a></html>}}}",
	tree:
		"{{clear{\n----\n}}} \
		{{floatright small{<<option chkRelatedTiddlersZoom>>autosize tree display}}} \
		{{fine{\n''tiddlers linked from or included by'' [[%0]]\n}}}%1",
	listcheck:
		"{{floatright{@@display:none;<<option chkRelatedTiddlersShowList>>@@<html><a href='javascript:;' class='button' onclick='this.parentNode.previousSibling.firstChild.click(); return false;'>list view</a></html>}}}",
	list:
		"{{clear{\n----\n}}} \
		{{fine{\n''tiddlers containing links to'' [[%0]]\n}}} \
		{{small fourcolumns borderleft{\n%1}}} \
		{{fine{\n''tiddlers linked from or included by'' [[%0]]\n}}} \
		{{borderleft{\n \
			{{fine{\n''bold''=//direct links//, plain=//indirect links//, ''...''=//links not followed//}}} \
			{{small fourcolumns{\n%2}}} \
		}}}",
	skipped:
		"<html><span title='links from %0 have NOT been followed'>...</span></html>",
	mouseover: function(ev) {
		this.saveSize=this.style.fontSize;
		this.style.fontSize='100%';
		this.style.borderLeftStyle='solid';
	},
	mouseout: function(ev) {
		this.style.fontSize=this.saveSize;
		this.style.borderLeftStyle='dotted';
	},
	findRelatedTiddlers: function(tid,tids,treeout,level,exclude,callback) { 
		// recursively build list of related tids (links and includes FROM the root tiddler) and generate treeview output
		var t=store.getTiddler(tid);
		if (!t || tids.contains(tid)) return tids; // tiddler already in results (or missing tiddler)... just return current results
		tids.push(t.title); // add tiddler to results
		var skip=exclude && exclude.contains(tid);
		treeout.text+=level+"[["+tid+"]]"+(skip?this.skipped.format([tid]):"")+"\n";
		if (skip) return tids; // branch is pruned... don't follow links
		var links=callback?callback(t):this.getLinks(t);
		for (var i=0; i<links.length; i++) tids=this.findRelatedTiddlers(links[i],tids,treeout,level+">",exclude);
		return tids;
	},
	getLinks: function(tiddler) {
		if (!tiddler.linksUpdated) tiddler.changed();
		return tiddler.links;
	},
	getTree: function(start,exclude,callback) {
		// get related tiddlers and generate blockquote-indented tree output
		var list=[]; var tree={text:""}; var level="";
		list=this.findRelatedTiddlers(start,list,tree,level,exclude,callback);
		return tree.text;
	},
	getList: function(start,exclude,callback) {
		// get related tiddlers and generate blockquote-indented tree output
		var list=[]; var tree={text:""}; var level="";
		list=this.findRelatedTiddlers(start,list,tree,level,exclude,callback);
		return list;
	},
	show: function(form,target) {
		removeChildren(target); form.done.disabled=true; // clear any existing output and disable 'done' button
		var start=form.list.value; if (!start.length) return; // get selected starting tiddler.  If blank value (heading), do nothing

		// get related tiddlers and generate blockquote-indented tree output
		var rels=[]; var treeview={text:""}; var level="";
		var exclude=config.options.txtRelatedTiddlersExclude.readBracketedList();
		var rels=this.findRelatedTiddlers(start,rels,treeview,level,exclude);
		rels.shift(); // remove self from list
		rels.sort(); // sort titles alphabetically

		// generate list output
		var tid=store.getTiddler(start);
		var relsview=""; for (t=0; t<rels.length; t++) {
			relsview+=tid.links.contains(rels[t])?("{{bold{[["+rels[t]+"]]}}}"):("[["+rels[t]+"]]");
			if (exclude && exclude.contains(rels[t])) relsview+=this.skipped.format([rels[t]]);
			relsview+="\n";
		}
	
		// get references TO the root tiddler, add to related tiddlers and generate refsview output
		var refs=[]; var referers=store.getReferringTiddlers(start);
		for(var r=0; r<referers.length; r++)
			if(referers[r].title!=start && !referers[r].tags.contains("excludeLists")) refs.push(referers[r].title);
		var refcount=refs.length; var relcount=rels.length; // remember individual counts
		for (var r=0; r<refs.length; r++) rels.pushUnique(refs[r]); // combine lists without duplicates
		var total=rels.length; // get combined total
		var refsview="[["+refs.sort().join("]]\n[[")+"]]\n";
	
		// set custom blockquote styles for treeview
		setStylesheet(this.styles.format([config.options.chkRelatedTiddlersZoom?80:100]),'relatedTiddlers_styles');

		// assemble and render output
		var summary=(total?(total+" tiddler"+(total==1?" is":"s are")):"There are no tiddlers")+" related to: [["+start+"]]";
		var list=this.list.format([start,refsview.length?refsview:"//none//",relsview.length?relsview:"//none//"]);
		var tree=this.tree.format([start,treeview.text]);
		var toggle=this.toggleform.format([form.id,(form.style.display=='none'?'show form':'hide form')]);
		var sep="{{floatright{ | }}}";
		var showList=total && config.options.chkRelatedTiddlersShowList;
		var showTree=relcount && config.options.chkRelatedTiddlersShowTree;
		var out="{{relatedTiddlers{"+toggle+(relcount?sep+this.treecheck:"")+(total?sep+this.listcheck:"")+summary+(showList?list:"")+(showTree?tree:"")+"}}}";
		wikify(out,target);
		form.done.disabled=false; // enable 'done' button

		// add mouseover/mouseout handling to blockquotes (for autosizing)
		var blocks=target.getElementsByTagName("blockquote");
		for (var b=0; b<blocks.length; b++)
			{ blocks[b].onmouseover=this.mouseover; blocks[b].onmouseout=this.mouseout; }

		// add side-effect to checkboxes so that display is refreshed when a checkbox state is changed
		var checks=target.getElementsByTagName("input");
		for (var c=0; c<checks.length; c++) {
			if (checks[c].type.toLowerCase()!="checkbox") continue;
			checks[c].coreClick=checks[c].onclick; // save standard click handler
			checks[c].formID=form.id; // link checkbox with correponding form
			checks[c].onclick=function() { this.coreClick.apply(this,arguments); document.getElementById(this.formID).get.click(); }
		}
	}
}
//}}}
/%
|Name|ReplaceDoubleClick|
|Source|http://www.TiddlyTools.com/#ReplaceDoubleClick|
|Version|2.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides|tiddler background click and doubleclick handlers|
|Description|disable doubleclick-to-edit-tiddler or replace doubleclick with shift/ctrl/alt+singleclick|

Usage:
	in tiddler content:
		<<tiddler ReplaceDoubleClick>> or
		<<tiddler ReplaceDoubleClick with: key trigger>>
	in ViewTemplate:
		<span macro="tiddler ReplaceDoubleClick"></span> or
		<span macro="tiddler ReplaceDoubleClick with: key trigger"></span>
where: 
	'key' (optional) is one of: none (default), ctrl, shift, or alt
	'trigger' (optional) is one of: click, doubleclick (default)

* if no key parameter (or "none") is specified, then the double-click action is **disabled** for that tiddler.
* if a key (other than none) is specified, the doubleclick action for the tiddler will only be invoked
	when the key+trigger combination is used.
* note: double-clicking will also trigger the single-click handler.  As a result, when 'click' option is specified,
	either click OR double-click (plus the specified key) will trigger the action.

Revisions:
2.0.0 renamed from ShiftClickToEdit and merged with DoubleClickDisable and added support specifying alternative key+click combination

%/<script>
	var here=story.findContainingTiddler(place); if (!here) return;
	if (here.ondblclick) {
		here.setAttribute("editKey","none");
		if ("$1"=="shift" || "$1"=="ctrl" || "$1"=="alt")
			here.setAttribute("editKey","$1"+"Key");
		var trigger=("$2"=="click")?"onclick":"ondblclick";
		here.save_dblclick=here.ondblclick;
		here.ondblclick=null;
		if (here.getAttribute("editKey")!="none")
			here[trigger]=function(e) {
				var ev=e?e:window.event;
				if (ev[this.getAttribute("editKey")])
					this.save_dblclick.apply(this,arguments);
			}
	}
</script>
/%
|Name|ReplaceTiddlerTitle|
|Source|http://www.TiddlyTools.com/#ReplaceTiddlerTitle|
|Version|1.0.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|replace tiddler's title text with other content - may include wiki syntax|

Usage:
	<<tiddler ReplaceTiddlerTitle with: "new title text">>

%/<script>
	// get the tiddler element
	var here=story.findContainingTiddler(place);
	if (!here || here.getAttribute("tiddler")=="ReplaceTiddlerTitle") return; // don't change the title on the script itself!
	var nodes=here.getElementsByTagName("*");
	for (var i=0; i<nodes.length; i++)
		if (hasClass(nodes[i],"title")) { removeChildren(nodes[i]); wikify("$1",nodes[i]); break; }
</script>
/%
|Name|RescueStoreAreaCommand|
|Source|http://www.TiddlyTools.com/#RescueStoreAreaCommand|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script bookmarklet|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|rescue tiddler changes from online document when net goes down during editing|
%/<script label="$1" title="rescue tiddlers from current document storeArea">
	if(typeof version==undefined||version.title!='TiddlyWiki')
		{alert(document.location.href+'\n\nis not a TiddlyWiki document');return false;}
	if (!confirm('Preparing to rescue storeArea contents... press OK to proceed')) return false;
	var sa=store.allTiddlersAsHtml().htmlEncode();
	var win=window.open();
	win.document.open();
	win.document['write']('<html><body><pre>'+sa+'</pre></body></html>');
	win.document.close();
	alert('copy/paste the displayed storeArea content into a local text file');
	win.focus();
</script><script>
	if ("$1"=="$"+"1") place.lastChild.innerHTML="Rescue current storeArea contents";
</script>
/%
|Name|ResetChangeCounters|
|Source|http://www.TiddlyTools.com/#ResetChangeCounters|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires||
|Overrides||
|Description|clear all tiddler change counter values|
%/<script label="&empty; - Reset tiddler change counters..." title="remove change counters from all tiddlers in this document">
	var msg="Are you sure you want to remove the change counters from these tiddlers:\n\n";
	var t=store.getTiddlers("title"); var tids=[];
	for (var i=0;i<t.length;i++) {
		var v=store.getValue(t[i],"changecount");
		if (v) { msg+=t[i].title+" ("+v+")\n"; tids.push(t[i]); }
	}
	msg+="\nPress OK to proceed";
	if (!confirm(msg)) return false;
	for (var i=0;i<tids.length;i++) tids[i].clearChangeCount();
	displayMessage("Change counters have been reset to 0");
	displayMessage("Don't forget to save your document!");
	return false;
</script>
/%
|Name|ResetOptionCookies|
|Source|http://www.TiddlyTools.com/#ResetOptionCookies|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|Reset all TiddlyWiki option cookies (with confirmation)|
%/<script label="&lowast; - Reset all cookie options..." title="Clears all TiddlyWiki options stored in browser cookies (w/confirmation)">
	var opts=new Array(); var p=document.cookie.split('; ');
	for (var i=0;i<p.length;i++){
		var c=p[i]; var v=''; var pos=p[i].indexOf('=');
		if (pos!=-1) { c=p[i].substr(0,pos); v=unescape(p[i].slice(pos+1)); }
		if (config.options[c]!==undefined) opts.push(c);
	} opts.sort();
	var msg='There are '+opts.length+' option cookies:\n\n'+opts.join(', ');
	msg+='\n\nPress OK to proceed, or press CANCEL to keep options unchanged'; if (!confirm(msg)) return false;
	var msg='Press OK reset all options at once, or press CANCEL to confirm each option, one at a time';
	var quiet=confirm(msg);
	for (var i=0;i<opts.length;i++) {
		if (quiet || confirm('Press OK to reset option: '+opts[i])) {
			var ex=new Date(); ex.setTime(ex.getTime()-1000);
			document.cookie=opts[i]+'=deleted; path=/; expires='+ex.toGMTString();
		}
	}
 	return false;
</script>
/%
|Name|RollText|
|Source|http://www.TiddlyTools.com/#RollText|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|AnimationEffectPlugin|
|Overrides||
|Description|display text phrase a word-at-a-time, using AnimationEffectPlugin|

Usage: <<tiddler RollText with: "text" timing speed pause repeat>>

%/<script>
	var out="";
	var txt="$1";
	var what="fontSize";
	var format="%0%";
	var start=0;
	var stop=100;
	var txt="The RollText script uses AnimationEffectsPlugin, available for download and installation from http://www.TiddlyTools.com/";
	if ("$1"!="$"+"1") txt="$1";
	var timing=500; if ("$2"!="$"+"2") timing=$2; // total time in between start of one word and the next (ms)
	var speed=800; if ("$3"!="$"+"3") speed=$3; // speed for word to zoom in/out (ms)
	var pause=1500; if ("$4"!="$"+"4") pause=$4; // delay between zoom in and zoom out
	var repeat=2; if ("$5"!="$"+"5") repeat=$5; // animation cycles
	var parts=txt.split(" ");
	var when=0;
	var item="<<animate [[%0 ]] %1 %2 %3 %4 %5 %6 %7 %8>>";
	for (var p=0; p<parts.length; p++) {
		out+=item.format([parts[p],what,format,start,stop,when,speed,repeat,pause]);
		when+=timing;
	}
	if ("$1"=="$"+"1") out="{{center medium{\n"+out+"}}}";
	return out;
</script>
/***
|Name|SaveAsPlugin|
|Source|http://www.TiddlyTools.com/#SaveAsPlugin|
|Documentation|http://www.TiddlyTools.com/#SaveAsPluginInfo|
|Version|2.1.2|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Save current document to a different path/filename|
This plugin automatically adds a 'save as' command to the TiddlyWiki 'backstage' menu that allows you to quickly create an exact copy of the current TiddlyWiki document.  The plugin also defines a macro that you can use to place a "save as..." command link into your sidebar/mainmenu/any tiddler (or wherever you like).
>//Note: This plugin now supersedes [[NewDocumentPlugin]], which has been retired and is no longer being distributed.  In addition, the HTML+CSS "snapshot" functionality previous provided by that plugin has been moved to a separate plugin.  Please see [[SnapshotPlugin]] for additional information.//
!!!!!Documentation
<<<
see [[SaveAsPluginInfo]]
<<<
!!!!!Revisions
<<<
2008.04.22 [2.1.2] corrected use of getTarget() to check for "user cancelled"
2008.04.22 [2.1.1] documentation fixes
2008.04.22 [2.1.0] added support for tag filtering to completely replace [[NewDocumentPlugin]] (now retired)
2008.04.12 [2.0.1] automatically add "saveAs" to backstage commands
2008.04.12 [2.0.0] initial release based on [[NewDocumentPlugin]]
| Please see [[SaveAsPluginInfo]] for additional revision details |
2006.02.03 [1.0.0] Created.
<<<
!!!!!Code
***/
//{{{
version.extensions.SaveAsPlugin= {major: 2, minor: 1, revision: 2, date: new Date(2008,4,22)};

config.macros.saveAs = {
	label: "save as...",
	labelparam: "label:",
	prompt: "Save current document to a different path/file",
	promptparam: "prompt:",
	filePrompt: "Please select or enter a target path/filename",
	defaultFilename: "new.html",
	askParam: "ask",
	askMsg: "Enter a tag filter (use * for all tiddlers, 'none' for blank document)",
	emptyParam: "none",
	confirmMsg: "Found %0 tiddlers matching\n\n'%1'\n\nPress OK to proceed",
	okmsg: "%0 tiddlers written to %1",
	failmsg: "An error occurred while creating %1",
	filter: "",
	handler: function(place,macroName,params) {
		if (params[0] && params[0].substr(0,this.labelparam.length)==this.labelparam)
			var label=params.shift().substr(this.labelparam.length)
		if (params[0] && params[0].substr(0,this.promptparam.length)==this.promptparam)
			var prompt=params.shift().substr(this.promptparam.length)
		var btn=createTiddlyButton(place,label||this.label,prompt||this.prompt,
			function(){config.macros.saveAs.go(this.getAttribute('filter'))});
		btn.setAttribute("filter",params.join(" "));
	},
	go: function(filter) {
		var cm=config.messages; // abbreviation
		var cms=config.macros.saveAs; // abbreviation
		if (window.location.protocol!="file:") // make sure we are local
			{ displayMessage(cm.notFileUrlError); return; }
		var currPath=getLocalPath(window.location.href);
		var original=loadFile(currPath);
		if (!original) // if current file not loaded
			{ displayMessage(cm.cantSaveError); return; }
		if (!locateStoreArea(original)) // make sure it is a valid TW document
			{ displayMessage(cm.invalidFileError.format([currPath])); return; }
		// get tidders, assemble revised document and write target
		var tids=cms.selectTiddlers(filter);
		if (tids===false) return; // cancelled by user
		if (cms.filter!=cms.emptyParam && cms.filter.length)
			if (!confirm(cms.confirmMsg.format([tids.length,cms.filter]))) return;
		var target=cms.getTarget();
		if (!target) return; // cancelled by user
		var revised=cms.assemble(original,tids);
		var link="file:///"+target.replace(/\\/g,'/');
		var msg=saveFile(target,revised)?cms.okmsg:cms.failmsg
		clearMessage(); displayMessage(msg.format([tids.length,target]),link);
	},
	selectTiddlers: function(filter) {
		var cms=config.macros.saveAs; // abbreviation
		cms.filter=filter||"";
		if (filter==cms.emptyParam) return [];
		if (!filter||!filter.length) return store.getTiddlers("title");
		// get filtered tiddlers
		if (filter==config.macros.saveAs.askParam) {
			filter=prompt(config.macros.saveAs.askMsg,"");
			if (!filter) return false;  // cancelled by user
			cms.filter=filter=="*"?"":filter;
			if (filter=="*") return store.getTiddlers("title");
		}
		return store.filterTiddlers("[tag["+filter+"]]");
	},
	assemble: function(original,tids) {
		var divs=[]; for (var i=0; i<tids.length; i++)
			divs.push(store.getSaver().externalizeTiddler(store,tids[i]));
		var divs=divs.join("\n");
		var posDiv = locateStoreArea(original);
		var revised = original.substr(0,posDiv[0]+startSaveArea.length)+"\n"
			+convertUnicodeToUTF8(divs)+"\n"+original.substr(posDiv[1]);
		var newSiteTitle = convertUnicodeToUTF8(getPageTitle()).htmlEncode();
		revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
		revised = updateLanguageAttribute(revised);
		// reset all MARKUP blocks
		revised = updateMarkupBlock(revised,"PRE-HEAD");
		revised = updateMarkupBlock(revised,"POST-HEAD");
		revised = updateMarkupBlock(revised,"PRE-BODY");
		revised = updateMarkupBlock(revised,"POST-SCRIPT");
		return revised;
	},
	getTarget: function() {
		var cms=config.macros.saveAs; // abbreviation
		// get new target path/filename
		var newPath=getLocalPath(window.location.href);
		var slashpos=newPath.lastIndexOf("/"); if (slashpos==-1) slashpos=newPath.lastIndexOf("\\"); 
		if (slashpos!=-1) newPath=newPath.substr(0,slashpos+1); // trim filename
		var target=cms.askForFilename(cms.filePrompt,newPath,cms.defaultFilename);
		if (!target) return; // cancelled by user
		// if specified file does not include a path, assemble fully qualified path and filename
		var slashpos=target.lastIndexOf("/"); if (slashpos==-1) slashpos=target.lastIndexOf("\\");
		if (slashpos==-1) target=target+cms.defaultFilename;
		return target;
	},
	askForFilename: function(msg,path,file) {
		if(window.Components) { // moz
			try {
				netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
				var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
				var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
				picker.init(window, msg, nsIFilePicker.modeSave);
				var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
				thispath.initWithPath(path);
				picker.displayDirectory=thispath;
				picker.defaultExtension='html';
				picker.defaultString=file;
				picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
				if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.persistentDescriptor;
			}
			catch(e) { alert('error during local file access: '+e.toString()) }
		}
		else { // IE
			try { // XP/Vista only
				var s = new ActiveXObject('UserAccounts.CommonDialog');
				s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
				s.FilterIndex=3; // default to HTML files;
				s.InitialDir=path;
				s.FileName=file;
				if (s.showOpen()) var result=s.FileName;
			}
			catch(e) { var result=prompt(msg,path+file); } // fallback for non-XP IE
		}
		return result;
	}
};
//}}}
//{{{
// automatically add saveAs to backstage
config.tasks.saveAs = {
	text: "saveAs",
	tooltip: config.macros.saveAs.prompt,
	action: function(){ clearMessage(); config.macros.saveAs.go(); }
}
config.backstageTasks.splice(config.backstageTasks.indexOf("save")+1,0,"saveAs");
//}}}
|Name|SaveAsPluginInfo|
|Source|http://www.TiddlyTools.com/#SaveAsPlugin|
|Documentation|http://www.TiddlyTools.com/#SaveAsPluginInfo|
|Version|2.1.2|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|Documentation for SaveAsPlugin|
This plugin automatically adds a 'save as' command to the TiddlyWiki 'backstage' menu that allows you to quickly create an exact copy of the current TiddlyWiki document.  The plugin also defines a macro that you can use to place a "save as..." command link into your sidebar/mainmenu/any tiddler (or wherever you like).
>//Note: This plugin now supersedes [[NewDocumentPlugin]], which has been retired and is no longer being distributed.  In addition, the HTML+CSS "snapshot" functionality previous provided by that plugin has been moved to a separate plugin.  Please see [[SnapshotPlugin]] for additional information.//
!!!!!Usage
<<<
When the command link is clicked, a standard system-specific dialog box will be displayed so you can select/enter the desired target path and filename.  The default is to create a file called "new.html" in the same directory as the current document.
Syntax:
{{{
<<saveAs label:text prompt:text tagfilter>>
}}}
where:
*''label:text'' //(optional)//<br>defines alternative link text (replaces default "save as..." display)
*''prompt:text'' //(optional)//<br>defines alternative tooltip text for 'mouseover' prompting (replaces default hard-coded tooltip text)
*''tagfilter'' //(optional)//<br>You can use the tag filter parameter to select a subset of tiddlers to be written into the new document file.  If you specify a single tag value, then only tiddlers that are tagged with that value are included in the resulting file.  To use a combination of tag values, you can install [[MatchTagsPlugin]], which provides full 'boolean' logic with AND, OR, and NOT operators, as well as nested parentheses, to create complex expressions for filtering and selecting the desired set of tiddlers.
*If you specify the keyword, ''ask'' in place of the tagfilter, you will be prompted to enter a tag or tag expression whenever you click on the 'save as...' command link.
*Alternatively, you can specify the keyword, ''none'' in place of the tagfilter to omit all tiddlers and create a new //empty// document.
*By default, when no tag filter parameter is provided, all tiddlers in the document are written to the new file.
<<<
!!!!!Examples
<<<
save all tiddlers:
>{{{<<saveAs>>}}}<br>try it: <<saveAs>>
save only tiddlers matching a single tag:
>{{{<<saveAs "label:create Import/Export starter" ImportExportPackage>>}}}<br>try it: <<saveAs "label:create Import/Export starter" ImportExportPackage>>
save tiddlers matching a complex combination of tags (requires [[MatchTagsPlugin]]):
>{{{<<saveAs (alpha or settings) and not systemConfig>>}}}<br>try it: <<saveAs (alpha or settings) and not systemConfig>>
prompts for tag or tag expression each time:
>{{{<<saveAs "label:custom save as..." ask>>}}}<br>try it: <<saveAs "label:custom save as..." ask>>
<<<
!!!!!Revisions
<<<
2008.04.22 [2.1.2] corrected use of getTarget() to check for "user cancelled"
2008.04.22 [2.1.1] documentation fixes
2008.04.22 [2.1.0] added support for tag filtering to completely replace [[NewDocumentPlugin]] (now retired)
2008.04.12 [2.0.1] automatically add "saveAs" to backstage commands
2008.04.12 [2.0.0] initial release based on [[NewDocumentPlugin]]

Previous revisions from [[NewDocumentPlugin]]
2008.04.20 [1.8.0] added support for 'noCSS' and 'viewer' params for alternative snapshot output
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.04 [*.*.*] update for ~TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.03.30 [1.7.0] added support for "print" param as alternative for "snap".  When "print" is used, the filename is ignored and ouput is directed to another browser tab/window, where the print dialog is then automatically triggered.
2007.03.30 [1.6.1] added support for "here" keyword for current tiddler elementID and "prompt:text" param for specifying tooltip text
2007.02.12 [1.6.0] in onClickNewDocument(), reset HTML source 'markup'
2006.10.23 [1.5.1] in onClickNewDocument(), get saved parameter value for snapID instead of using default "contentWrapper" (oops!)
2006.10.18 [1.5.0] new optional param for 'snap'... specify alternative DOM element ID (default is still "contentWrapper").  Based on a suggestion from Xavier Verges.
2006.08.03 [1.4.3] in promptForFilename(), for IE (~WinXP only), added handling for ~UserAccounts.~CommonDialog
2006.07.29 [1.4.2] in onClickNewDocument(), okmsg display is now linked to newly created file
2006.07.24 [1.4.1] in promptForFilename(), check for nsIFilePicker.returnCancel to allow nsIFilePicker.returnOK **OR** nsIFilePicker.returnReplace to be processed.
2006.05.23 [1.4.0] due to very poor performance, support for tag *expressions* has been removed, in favor of a simpler "containsAny()" scan for tags.
2006.04.09 [1.3.6] in onClickNewDocument, added call to convertUnicodeToUTF8() to better handle international characters.
2006.03.15 [1.3.5] added nsIFilePicker() handler for selecting filename in moz-based browsers.  IE and other non-moz browsers still use simple prompt() dialog
2006.03.15 [1.3.0] added "label:text" param for custom link text.  added special "all" filter parameter for "save as..." handling (writes all tiddlers to output file)
2006.03.09 [1.2.0] added special "snap" filter parameter to generate and write "snapshot" files containing static HTML+CSS for currently rendered document.
2006.02.24 [1.1.2] Fix incompatiblity with TW 2.0.5 by removing custom definition of getLocalPath() (which is now part of TW core)
2006.02.03 [1.1.1] concatentate 'extra' params so that tag expressions don't have to be quoted.   moved all text to 'formatted' string definitions for easier translation.
2006.02.03 [1.1.0] added support for tag EXPRESSIONS.  plus improved documentation and code cleanup
2006.02.03 [1.0.0] Created.
<<<
/***
|Name|SearchOptionsPlugin|
|Source|http://www.TiddlyTools.com/#SearchOptionsPlugin|
|Documentation|http://www.TiddlyTools.com/#SearchOptionsPluginInfo|
|Version|2.7.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.search, TiddlyWiki.prototype.search, config.macros.search.onKeyPress|
|Options|##Configuration|
|Description|extend core search function with additional user-configurable options|
Extend core search function with additional user-configurable options including selecting which data items to search, enabling/disabling incremental key-by-key searches, and generating a ''list of matching tiddler'' instead of immediately displaying all matches.  This plugin also adds syntax for rendering 'search links' within tiddler content to embed one-click searches using pre-defined 'hard-coded' search terms.
!!!!!Documentation
>see [[SearchOptionsPluginInfo]]
!!!!!Configuration
<<<
Search in:
<<option chkSearchTitles>> titles <<option chkSearchText>> text <<option chkSearchTags>> tags <<option chkSearchFields>> fields <<option chkSearchShadows>> shadows
<<option chkSearchList>> Show list of matches in [[SearchResults]]
<<option chkSearchIncremental>> Incremental (key-by-key) searching
<<option chkSearchTitlesFirst>> Show title matches first
<<option chkSearchByDate>> Sort matching tiddlers by date
<<<
!!!!!Revisions
<<<
2008.05.03 [2.7.1] in searchLink formatter handler(), use separate setAttribute() call instead of passing attribs to createTiddlyButton().  Avoids conflict with errant code in TiddlerNotesPlugin (v2.1 26/10/07)
|please see [[SearchOptionsPluginInfo]] for additional revision details|
2005.10.18 [1.0.0] Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.searchOptions = {major: 2, minor: 7, revision: 1, date: new Date(2008,5,3)};

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;
if (config.macros.search.reportTitle==undefined)
	config.macros.search.reportTitle="SearchResults"; // note: not a cookie!
//}}}

//{{{
// searchLink formatter:
// syntax: [search[text to find]] OR [search[text to display|text to find]]
config.formatters.push( {
	name: "searchLink",
	match: "\\[search\\[",
	lookaheadRegExp: /\[search\[(.*?)(?:\|(.*?))?\]\]/mg,
	prompt: "search for: '%0'",
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var label=lookaheadMatch[1];
			var text=lookaheadMatch[2]||label;
			var prompt=this.prompt.format([text]);
			var btn=createTiddlyButton(w.output,label,prompt,
				function(){story.search(this.getAttribute("searchText"))},"searchLink");
			btn.setAttribute("searchText",text);
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
});
//}}}

//{{{
config.macros.search.searchOptions_onKeyPress = config.macros.search.onKeyPress;
config.macros.search.onKeyPress = function(e)
{
	if(!e) var e = window.event;
	if (config.options.chkSearchIncremental || e.keyCode==13 || e.keyCode==10 || e.keyCode==27)
		config.macros.search.searchOptions_onKeyPress.apply(this,arguments);
}
//}}}

//{{{
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;
}
//}}}

//{{{
// SearchResuls 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=\"discardSearchResults()\" 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 temporary");
	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);
	store.notify(config.macros.search.reportTitle,true);
}
//}}}
/***
|Name|SearchOptionsPluginInfo|
|Source|http://www.TiddlyTools.com/#SearchOptionsPlugin|
|Documentation|http://www.TiddlyTools.com/#SearchOptionsPluginInfo|
|Version|2.7.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|Documentation for SearchOptionsPlugin|
Extend core search function with additional user-configurable options including selecting which data items to search, enabling/disabling incremental key-by-key searches, and generating a ''list of matching tiddler'' instead of immediately displaying all matches.  This plugin also adds syntax for rendering 'search links' within tiddler content to embed one-click searches using pre-defined 'hard-coded' search terms.
!!!!!Syntax
To insert a 'search link' into tiddler content, you can write:
{{{
[search[text to find]]
}}}
or
{{{
[search[text to display|text to find]]
}}}
Clicking on the resulting search link will trigger the search functionality, just as if the specified 'text to find' had been entered into the standard search input field usually displayed in the document sidebar.
!!!!!Configuration
<<<
Search in:
<<option chkSearchTitles>> titles <<option chkSearchText>> text <<option chkSearchTags>> tags <<option chkSearchFields>> fields <<option chkSearchShadows>> shadows
<<option chkSearchList>> Show list of matches in [[SearchResults]]
<<option chkSearchIncremental>> Incremental (key-by-key) searching
<<option chkSearchTitlesFirst>> Show title matches first
<<option chkSearchByDate>> Sort matching tiddlers by date
<<<
!!!!!Revisions
<<<
2008.05.03 [2.7.1] in searchLink formatter handler(), use separate setAttribute() call instead of passing attribs to createTiddlyButton().  Avoids conflict with errant code in TiddlerNotesPlugin (v2.1 26/10/07)
2008.04.29 [2.7.0] added searchLink formatter (syntax: {{{[search[text]]}}} or {{{[search[display|text]]}}})
2008.04.08 [2.6.2] don't automatically add options to AdvancedOptions shadow tiddler
2007.02.17 [2.6.1] added redefinition of config.macros.search.onKeyPress() to restore check to bypass key-by-key searching (i.e., when chkSearchIncremental==false), which had been unintentionally removed with v2.6.0
2007.02.13 [2.6.0] remove redefinition of config.macros.search.handler since core now includes handling for ENTER key.
2007.02.08 [2.5.1] include 'temporary' tag when creating SearchResults (for use with TemporaryTiddlersPlugin)
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.
<<<
!!!!!__2008.01.22 IMPORTANT NOTICE__
As of TiddlyWiki version 2.3.0, this plugin has been replaced by [[SwitchThemePlugin]], which can be imported and installed from http://www.TiddlyTools.com/#SwitchThemePlugin

{{small{You will be automatically redirected to [[SwitchThemePlugin]] in <<tiddler TimedTiddlerTour with: SwitchThemePlugin 10 fold>> seconds}}}
/***

''This plugin was previously called StyleChooser.''

|Name|SelectThemePlugin|
|Created by|SimonBaird and SaqImtiaz|
|Location|http://tw.lewcid.org/#SelectThemePlugin|
|Version|1.2.5|
|Requires|~TW2.x|
!Description
*An alternative style switcher, can be used to switch just stylesheets and/or pagetemplates, or a combination of both (a theme)
*you can add your own stylesheets and pagetemplates, or use a ThemePack, like BigThemePack.

!Usage
* You have to have fetch or create some styleSheets and pageTemplates to use this plugin.
**You can either get a ThemePack like BigThemePack which automatically adds themes to ThemeSelect.
**or create tiddlers with styleSheets and pageTemplates and tag them styleSheets and pageTemplates respectively.
* Put {{{<<themeSelect style 'Select theme'>>}}} in your SideBarOptions.

!Creating Theme Packs
*You can create your own theme pack if you like. Instructions can be found [[here.|CreateThemePack]]

!History
*20-Dec-06, v 1.2.5, fixed horizontal rules for IE (thanks Clint), compatibility fix with HoverMenuPlugin
* 08-Sept-06, v1.2.4, fixed bug with TW2.1
* 15-May-06, v1.2.3, added paramifier so you can put theme on url, eg http://www.somewhere.com/twfile.html#theme:Berry2, thanks Clint (Simon).
* 28-Apr-o6, v1.2.2, fixed bug with opening TW after deleting themepacks. (Saq)
* 26-Apr-06, v1.2.1, more code optimization, dropdowns now updated on the fly. (Saq)
* 25-Apr-06, v1.2.0, added 3rd party ThemePack support, and made various other improvements.(Simon & Saq)
* 24-Apr-06, v1.1.0, added: no styles and default styles options,<<br>>support for ThemePack, support for tag variations(Saq)
* 21-Apr-06, v1.0.0, Reworked dropdowns to include option for pagetemplates (Saq)
* 21-Apr-06, v0.9.0, Rewrote and added Saq's lovely dropdown select (Simon)
* 20-Apr-06, v0.0.1, Basic switcher working (Simon)

!Examples
|!Source|!Output|h
|{{{<<themeSelect style>>}}} for a dropdown with StyleSheets|<<themeSelect style>>|
|{{{<<themeSelect pagetemplate>>}}} for a dropdown with PageTemplates|<<themeSelect pagetemplate>>|
|{{{<<themeSelect style customlabel>>}}} to use a customlabel|<<themeSelect style customlabel>>|
* When applying a stylesheet or template, it also looks for a template or stylesheet respectively based on naming convention, eg MyFunkyStyleSheet and MyFunkyPageTemplate.

!Notes
* See also http://www.tiddlytools.com/#SelectStyleSheetPlugin for a more feature-rich style sheet switcher

! Ideas
* do ViewTemplate also?
* Pretty up the [x] bit

!Code
***/
//{{{
// for compatibility with TW <2.0.9
if (!Array.prototype.contains)
   Array.prototype.contains = function(item)
   {
    return this.find(item) != null;
    };

// for compatibility with TW <2.0.9
if (!Array.prototype.containsAny)
   Array.prototype.containsAny = function(items)
   {
    for(var i=0; i<items.length; i++)
        if (this.contains(items[i]))
            return true;
    return false;
    };
//}}}

//{{{
version.extensions.SelectTheme = { major: 1, minor: 2, revision: 5, date: new Date(2006,12,20),
	source: "http://tw.lewcid.org/#SelectTheme"
};

config.SelectTheme = {
	things: {
		style: {
			tag:        ["StyleSheets","StyleSheet","styleSheet","styleSheets","stylesheet","stylesheets"],
			theDefault: "StyleSheet",
			suffix:     "StyleSheet",
			notify:     refreshStyles,
			cookie:     "txtStyleSheet",
			otherThing: "pagetemplate",
			label:      "Choose StyleSheet: ",
			tooltip:     "Choose a StyleSheet",
			caseNone: { text:"None", title:"NoStyleSheet"},
                        caseDefault: { text:"Default", title:"StyleSheet" }

		},
		pagetemplate: {
			tag:        ["PageTemplates","PageTemplate","pageTemplates","pageTemplate","pagetemplate","pagetemplates"],
			theDefault: "PageTemplate",
			suffix:     "PageTemplate",
			notify:     refreshPageTemplate,
			cookie:     "txtPageTemplate",
			otherThing: "style",
			label: "Choose PageTemplate: ",
			tooltip:    "Choose a PageTemplate",
			caseNone: { text:"None", title:"NoPageTemplate"},
                        caseDefault: { text:"Default", title:"PageTemplate" }
		}

	},

                         specialCases: ["caseNone","caseDefault"]

};

TiddlyWiki.prototype.removeNotification = function(title,fn) {
	for (var i=0;i<this.namedNotifications.length;i++)
		if((this.namedNotifications[i].name == title) && (this.namedNotifications[i].notify == fn))
			this.namedNotifications.splice(i,1); // counting on it only being there once
}


var things = config.SelectTheme.things;
var specialCases=config.SelectTheme.specialCases;

for (var zz in things) {
	// make sure we have a value
	if (!config.options[things[zz].cookie])
		config.options[things[zz].cookie] = things[zz].theDefault;

	// remove core notify
	store.removeNotification(things[zz].theDefault,things[zz].notify);

	// and add our one
	store.addNotification(config.options[things[zz].cookie],things[zz].notify);

}

//checks to see if a tiddler exists in store or as a shadow.
TiddlyWiki.prototype.isTiddler= function (title)
        {return store.tiddlerExists(title) || store.isShadowTiddler(title)}

//hijack core function & make sure template exists
window.applyPageTemplate_themeSelect=window.applyPageTemplate;
window.applyPageTemplate=function(title){
           if(!store.isTiddler(title))
                       {title = things.pagetemplate.theDefault;}
           applyPageTemplate_themeSelect(title);
 }

TiddlyWiki.prototype.makeActiveTheme = function(what,title,alsoCheckOtherThing) {

	var thing = things[what];
        if (!store.isTiddler(title))
		title = thing.theDefault;

	var oldTitle = config.options[thing.cookie];

	if (what == "style") {
		// remove old style element from DOM
		var oldStyleElement = document.getElementById(oldTitle);
		oldStyleElement.parentNode.removeChild(oldStyleElement);
	}

	store.removeNotification(oldTitle,thing.notify);
	store.addNotification(title,thing.notify);
	store.notify(title);

	config.options[thing.cookie] = title;
	saveOptionCookie(thing.cookie);
	if (alsoCheckOtherThing)
		this.makeActiveTheme(thing.otherThing,
				title.replace(new RegExp(thing.suffix+"$"),"") + things[thing.otherThing].suffix,
						false);
};

if (config.hoverMenu)
    {
    old_hovermenu_makeActiveTheme = TiddlyWiki.prototype.makeActiveTheme;
    TiddlyWiki.prototype.makeActiveTheme = function(what,title,alsoCheckOtherThing)
        {
         old_hovermenu_makeActiveTheme.apply(this,arguments);
         if (!alsoCheckOtherThing)
                    config.hoverMenu.handler();
        };
    }

config.shadowTiddlers.NoStyleSheet = "";
config.shadowTiddlers.NoPageTemplate = config.shadowTiddlers.PageTemplate;


function switchTheme(e){
         if (!e) var e = window.event;
         var theTarget = resolveTarget(e);
         var theLink = theTarget;
         var switchTo= theLink.getAttribute("switchTo");
         var mode = theLink.getAttribute("mode");
         if ((config.options[things[mode].cookie])!=switchTo)
               {store.makeActiveTheme(mode,switchTo,true);};
         return(false);
}


config.macros.themeSelect={};
config.macros.themeSelect.dropdownchar = (document.all?"â–¼":"â–¾");
config.macros.themeSelect.handler = function(place,macroName,params,wikifier,paramString,tiddler){
         var arrow = config.macros.themeSelect.dropdownchar;
         var mode = params[0];
         var label = (params[1]?params[1]:things[mode].label) + arrow;
         var cookie = (config.options[things[mode].cookie]);

         var onclick = function(e)
             { if (!e) var e = window.event;
             var popup = Popup.create(this);

             var tagged=[];

	     store.forEachTiddler(function(title,tiddler) {
                  if ((tiddler.tags).containsAny(things[mode].tag)){
					tagged.push(tiddler.title);}
	     });

             //integrate ThemePacks
	     if (config.themes) {
		     // see what themes have been loaded...
		     for (var i=0;i<config.themes.length;i++) {
			    // see if there is one
			    var lookForThis = config.themes[i] + things[mode].suffix;
			    if (store.isShadowTiddler(lookForThis)) {
				   tagged.pushUnique(lookForThis);
			    }
		    }
		     tagged = tagged.sort();
             }

             //this function used later to create buttons
             var createThemeButton = function(switchTo){
                        var theButton = createTiddlyButton(createTiddlyElement(popup,"li"),text,null,switchTheme,useClass);
                        theButton.setAttribute("switchTo",switchTo);
                        theButton.setAttribute("mode",mode);};

            //create Buttons for None(shadow styles) & Default (StyleSheet)
                     // Default button is not created if StyleSheet doesnt exist.
             for(var t=0; t<specialCases.length; t++){
             var special = specialCases[t];
             var text = things[mode][special].text;
             var useClass = "tiddlyLinkExisting";   //redundant, optimize!
             if ((things[mode][special].title==cookie)||(special=="caseNone"&&!store.isTiddler(cookie)))
                      {text+= " [x]";
                      useClass = "currentlySelected";}
             if (!((special=="caseDefault")&&(!store.getTiddler(things[mode][special].title))))
             createThemeButton(things[mode][special].title);     }

             //insert horizontal rule
             //createTiddlyElement(createTiddlyElement(popup,"li"),"hr");
             createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");

             //create buttons for all other stylesheet tiddlers
             for(var t=0; t<tagged.length; t++)
                     { var useClass = "tiddlyLinkExisting";
                       var text = (tagged[t]).replace((things[mode].suffix),"");
                     if (tagged[t]==(cookie) )
                           {text+=" [x]"; useClass="currentlySelected";}
                     if ((tagged[t]!= (things[mode].theDefault))&&tagged[t]!= (things[mode].none))
                        {createThemeButton(tagged[t]);}}
             Popup.show(popup,false);
             e.cancelBubble = true;
             if (e.stopPropagation)
                e.stopPropagation();
             return(false);
             };

        var createdropperButton = function(place){
           var sp = createTiddlyElement(place,"span",null,"ThemeChooserButton");
           var theDropDownBtn = createTiddlyButton(sp,label,things[mode].tooltip,onclick);
        };

        createdropperButton(place);
};


setStylesheet(".popup li a.currentlySelected {background:#ccc;color:black;font-weight:bold;}","currentlySelectedStyle"); // could do better probably...

config.macros.layoutChooser=config.macros.themeSelect;

//shadow tiddler to hold instructions for creating ThemePacks
config.shadowTiddlers.ThemePack='See http://simonbaird.com/mptw/#CreateThemePack'; 

config.macros.applyTheme = {handler: function (place,macroName,params,wikifier,paramString,tiddler) {
	var theme = params[0];
	var label = params[1]?params[1]:'Apply theme "' + theme + '"';
        var tooltip = 'Apply the "'+theme+'" theme to this TiddlyWiki';
	createTiddlyButton(place,label,tooltip,function() {
		store.makeActiveTheme("style",theme+things.style.suffix,true);
	});
}};


// this means you can put #theme:ThemeName in url. suggested by Clint
config.paramifiers.theme = {
	onstart: function(themeName) {
		store.makeActiveTheme("style",themeName+config.SelectTheme.things.style.suffix,true);
	}
};

//}}}

SelectThemePlugin made compatible with HoverMenuPlugin. Horizontal rules fixed for IE. (thanks Clint!)
/***
|Name|SetIconPlugin|
|Source|http://www.TiddlyTools.com/#SetIconPlugin|
|Documentation|http://www.TiddlyTools.com/#SetIconPluginInfo|
|Version|1.8.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.3|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|add an image to a toolbar, macro, or slider link|
!!!!!Documentation
>see [[SetIconPluginInfo]]
!!!!!Configuration
<<<
<<option chkIconsShowImage>> show images on links
<<option chkIconsShowText>> include link text with images
default image style: {{stretch{<<option txtIconsCSS>>}}}
<<<
!!!!!Revisions
<<<
2008.05.11 [1.8.0] added optional 'notext' value for iconpos to force text to be hidden for specific links
| see [[SetIconPluginInfo]] for additional revision details |
2008.05.09 [1.0.0] initial release (as inline script)
<<<
!!!!!Code
***/
//{{{
version.extensions.setIcon= {major: 1, minor: 8, revision: 0, date: new Date(2008,5,11)};

if (config.options.chkIconsShowImage===undefined)
	config.options.chkIconsShowImage=true;
if (config.options.chkIconsShowText===undefined)
	config.options.chkIconsShowText=true;
if (config.options.txtIconsCSS===undefined)
	config.options.txtIconsCSS="vertical-align:middle;width:auto;height:auto";

config.macros.setIcon = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if (!config.options.chkIconsShowImage) return; // text-only - do nothing
		if (!params[0]) return; // no image src specified - do nothing

		// find nearest link element
		var btn=place.lastChild; // look for sibling link
		while (btn && btn.nodeName!="A") btn=btn.previousSibling;
		if (!btn) { // look for child link
			var links=place.getElementsByTagName("A");
			if (links.length) btn=links[links.length-1];
		}
		if (!btn) { // look for parent link
			var btn=place.parentNode.lastChild;
			while (btn && btn.nodeName!="A") btn=btn.previousSibling;
		}
		if (!btn) { // look for cousin link
			var links=place.parentNode.getElementsByTagName("A");
			if (links.length) btn=links[links.length-1];
		}
		if (!btn) return; // can't find a link - do nothing

		// set icon and command text/tip
		var txt=btn.innerHTML;
		var src=params[0];  // default to direct URL
		if (config.macros.attach && config.macros.attach.isAttachment(src))
			src=config.macros.attach.getAttachment(src); // retrieve attachment (if any)
		var css=params[1]; if (!css||!css.length) css=config.options.txtIconsCSS;
		var after=params[2]&&params[2].toUpperCase()=="RIGHT";
		var notext=params[2]&&params[2].toUpperCase()=="NOTEXT";
		btn.innerHTML="<img src='"+src+"' style='"+css+"'>";
		if (config.options.chkIconsShowText && !notext)
			btn.innerHTML=after?txt+btn.innerHTML:btn.innerHTML+txt;
		else
			btn.title=txt.toUpperCase()+": "+btn.title; // add text to tooltip

		// adjust nested slider button text/tip
		if (btn.getAttribute("closedtext")!=null) {
			btn.setAttribute("closedtext",btn.innerHTML);
			btn.setAttribute("openedtext",btn.innerHTML);
			if (!config.options.chkIconsShowText || notext) {
				btn.setAttribute("closedtip",txt.toUpperCase()+": "+btn.getAttribute("closedtip"));
				btn.setAttribute("openedtip",txt.toUpperCase()+": "+btn.getAttribute("openedtip"));
			}
		}
	}
};
//}}}
/***
|Name|SetIconPlugin|
|Source|http://www.TiddlyTools.com/#SetIconPlugin|
|Documentation|http://www.TiddlyTools.com/#SetIconPluginInfo|
|Version|1.8.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.3|
|Type|documentation|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|documentation for SetIconPluginInfo|
!!!!!Syntax
<<<
{{{
<<setIcon image style iconpos>>
}}}
where:
*''image''<br>is a tiddlername for an attached image or a URL for an external image
*''style''<br>(optional) is CSS style attributes applied to the image (default="vertical-align:middle;width:auto;height:auto")
*''iconpos''<br>(optional) indicates the placement of the image relative to the link text.  Use keywords: ''left'', ''right'' or ''notext'' (default=''left'', i.e., the text follows the image).  ''notext'' hides the link text, even if the global option (see Configuration section, below) is set to display the link text along with image.  //Note:  when specifying the non-default //''right''// or //''notext''// value, you can use "" as a placeholder for the ''style'' parameter to apply the standard CSS styles)//
<<<
!!!!!Usage
<<<
First, create a link element using any of:
* ''links:''<br>&nbsp;&nbsp;"""[[TiddlerName]]""" or """[[text|TiddlerName]]""" or """[[text|URL]]"""
* ''macros that generate links:''<br>&nbsp;&nbsp;"""<<toolbar ...>>""", """<<slider ...>>""", """<<saveChanges>>""", etc.
* ''inline sliders:'' (using NestedSlidersPlugin)<br>&nbsp;&nbsp;"""+++[sliderlabel]...==="""
* '''onclick' scripts:'' (using InlineJavascriptPlugin)<br>&nbsp;&nbsp;"""<script label="...">...</script>"""
* ''~HTML-based links:''<br>&nbsp;&nbsp;"""<html><a href="...">...</a></html>"""
* ''transcluded links:'' (where the output of the specified ~TiddlerName contains a link)<br>&nbsp;&nbsp;"""<<tiddler TiddlerName>>""" 
Then, ''embed the """<<setIcon>>""" macro immediately following the generated link''.  The macro looks for the last rendered //sibling// link element that occurs within the same DOM container and adds the specified image to that link.  It is important to note that the macro does not initially look within the //child// DOM elements of the current container.  This is necessary so that 'sliderPanel' content created by the """<<slider>>""" macro can be skipped over, allowing the correct 'sliderButton' link element to be located.

When you use the """<<tiddler>>""" macro to transclude content containing a link, or you directly embed a link using HTML syntax, the resulting link element will //always// be rendered within a //child// DOM element container.  However, the """<<setIcon>>""" macro only looks within //child// DOM elements when no //sibling// link elements are found within the current DOM container.  In order to ensure that the """<<setIcon>>""" macro will not inadvertently find a sibling link element, you will need to isolate the child DOM element container link along with the associated """<<setIcon>>""" macro that follows it by enclosing the both elements within a surrounding SPAN 'class wrapper' element, like this:
{{{
{{span{<<tiddler SomeTranscludedLink>><<setIcon ...>>}}}
{{span{<html><a href="...">...</a></html><<setIcon ...>>}}}
}}}
This same technique should also be applied for any other macros that may generate output that is nested within their own containing DOM elements.  Similarly, in addition to """<<tiddler>>""" and ~HTML-based content, link elements that are defined directly within a ViewTemplate or EditTemplate definition using """<span macro='...'></span>""" are also rendered within their own DOM element containers.  In order to ensure that the associated """<span macro='setIcon ...'></span>""" macro will locate the correct template-defined link element, it should be inserted //within// the span that invokes the link-generating macro, like this:
{{{
<span macro='...'><span macro='setIcon ...'></span></span>
}}}
or, your can surround the paired link+icon sequence in an enclosing span, like this:
{{{
<span><span macro='...'></span><span macro='setIcon ...'></span></span>
}}}
so that the span containing the link element is a //cousin// (i.e., a //child// of the //parent// container) of the span that invokes the setIcon macro.

''In general, whether the link element is rendered in tiddler content or directly from a template, if you are uncertain when an 'isolation span' is needed, you can always choose to surround every link+icon sequence within a enclosing span, regardless of the type of link content being rendered.''
<<<
!!!!!Examples
<<<
''~TiddlyLink:'' [[About]]<<setIcon information.png>>
{{{
[[About]]<<setIcon information.png>>
}}}
''toolbar command:'' <<toolbar jump>><<setIcon page_go.png>>
{{{
in tiddler content:
	<<toolbar jump>><<setIcon page_go.png>>
in template definitions:
	<span class='toolbar' macro='toolbar jump'><span macro='setIcon page_go.png'></span></span>
}}}
''slider macro:''<<slider "" PluginManager Plugins "view installed plugin status">><<setIcon cog.png>>
{{{
in tiddler content:
	<<slider "" PluginManager Plugins "view installed plugin status">><<setIcon cog.png>>
in template definitions:
	<span macro='slider ...'><span macro='setIcon page_go.png'></span></span>
}}}
''nested (inline) slider:'' +++[settings]<<list filter [tag[settings]]>>===<<setIcon wrench.png>>
{{{
+++[settings]
	<<list filter [tag[settings]]>>
===<<setIcon wrench.png>>
}}}
''onclick script:'' <script label="print document">window.print();</script><<setIcon printer.png>>
{{{
<script label="print document">
	window.print();
</script><<setIcon printer.png>>
}}}
''tiddler macro:'' {{span{<<tiddler SiteUrl>><<setIcon exclamation.png>>}}}
{{{
in tiddler content:
	{{span{<<tiddler SiteUrl>><<setIcon exclamation.png>>}}}
in template definitions:
	<span macro='tiddler ...'><span macro='setIcon exclamation.png'></span></span>
}}}
''HTML link:'' {{span{<html><a href="http://www.TiddlyWiki.com">TiddlyWiki.com</a></html><<setIcon server_go.png>>}}}
{{{
in tiddler content:
	{{span{<html><a href="http://www.TiddlyWiki.com">TiddlyWiki.com</a></html><<setIcon server_go.png>>}}}
in template definitions:
	<span><a href="http://www.TiddlyWiki.com">TiddlyWiki.com</a><span macro='setIcon server_go.png'></span></span>
}}}
''macro link:'' {{span{<<saveChanges>><<setIcon disk.png>>}}}
{{{
in tiddler content:
	{{span{<<saveChanges>><<setIcon disk.png>>}}}
in template definitions:
	<span macro='saveChanges'><span macro='setIcon disk.png'></span></span>
}}}
<<<
!!!!!Configuration
<<<
<<option chkIconsShowImage>> show icons on links //(unchecked=text-only)//
^^{{{<<option chkIconsShowImage>>}}}^^
<<option chkIconsShowText>> include link text with images //(unchecked=icons-only, ignored if no icons displayed)//
^^{{{<<option chkIconsShowText>>}}}^^
default image style: {{stretch{<<option txtIconsCSS>>}}}
^^{{{<<option txtIconsCSS>>}}}^^
<<<
!!!!!Revisions
<<<
2008.05.11 [1.8.0] added optional 'notext' value for iconpos to force text to be hidden for specific links
2008.05.11 [1.7.0] support use within template definitions by looking for nearest link using: siblings, children, parents, or cousins.  Also, major documentation re-write with improved examples
2008.05.11 [1.6.0] added optional iconpos param to control icon placement ("left" or "right", default="left")
2008.05.10 [1.5.0] converted to plugin/macro and reduced code size by moving documentation into SetIconPluginInfo
2008.05.10 [1.4.0] handle links contained in {{{<<tiddler>>}}} and {{{<html>...</html}}}
2008.05.10 [1.3.0] added support for setting styles on images
2008.05.09 [1.2.0] handle links created by TiddlyLinks, sliders, and nested sliders syntax
2008.05.09 [1.1.0] added support for external URLs and options for displaying text with images
2008.05.09 [1.0.0] initial release (as inline script)
<<<
/%
|Name|SetPopupsHeight|
|Source|http://www.TiddlyTools.com/#SetPopupsHeight|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|use CSS to set a scrolling, fixed or percentage height for popups (e.g. tags display)|

usage: <<tiddler SetPopupsHeight with: height>>

where 'height' is an *optional* param to override the current value (if any)

%/<script>
	if (config.options.txtPopupsHeight==undefined) config.options.txtPopupsHeight="auto";
	if ('$'+'1'!='$1') config.options.txtPopupsHeight='$1';
	window.setPopupsHeight=function() {
		var opt="txtPopupsHeight";
		var h=config.options[opt]; if (!h.length) h='auto';
		if (!h.replace(/[0-9]*/,"").length) h+="px"; // add "px" suffix if only numeric value
		config.options[opt]=h;
		if (h.indexOf("%")!=-1)
			h=(findWindowHeight()*parseInt(h.replace(/%/,""))/100)+"px"; // % of window
		var heightParam=(config.browser.isIE?"height":"max-height")+":"+h;
		var overflowParam='overflow:'+(h!='auto'?'auto':'hidden')+' !important'; 
		var css='.popup { '+heightParam+'; '+overflowParam+'; }';
		setStylesheet(css,"popupStyles");
		config.macros.option.propagateOption(opt,"value",config.options[opt],"input");
	}
	setTimeout('window.setPopupsHeight()',1); // initialize height
	if (window.addEventListener) window.addEventListener("resize",window.setPopupsHeight,false);
</script>popups height: {{smallform{<<option txtPopupsHeight>><script>
	var t=place.lastChild
	t.style.width="4em";
	t.style.textAlign="center";
	t.title="enter height using CSS dimensions (px, em, in, cm, %) or 'auto'";
	t.onfocus=function(){this.select();};
	t.onblur=function(){this.onchange();}; /* for IE */
	// hijack onchange for this field so CSS can be updated on the fly
	t.coreOnChange=t.onchange;
	t.onchange=function() {
		if (this.coreOnChange) this.coreOnChange();
		window.setPopupsHeight();
	};
</script>}}}
/%
|Name|SetSidebarTabsHeight|
|Source|http://www.TiddlyTools.com/#SetSidebarTabsHeight|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|use CSS to set a scrolling, fixed or percentage height for the sidebar tabs area|

usage: <<tiddler SetSidebarTabsHeight with: height>>

where 'height' is an *optional* param to override the current value (if any)

%/<script>
	if (config.options.txtSidebarTabsHeight==undefined) config.options.txtSidebarTabsHeight="auto";
	if ('$'+'1'!='$1') config.options.txtSidebarTabsHeight='$1';
	window.setSidebarTabsHeight=function() {
		var opt="txtSidebarTabsHeight";
		var h=config.options[opt]; if (!h.length) h='auto';
		if (!h.replace(/[0-9]*/,"").length) h+="px"; // add "px" suffix if only numeric value
		config.options[opt]=h;
		var top=findPosY(document.getElementById("sidebarTabs"));
		if (h.indexOf("%")!=-1)
			h=((findWindowHeight()-top)*parseInt(h.replace(/%/,""))/100)+"px"; // % of window
		var heightParam=(config.browser.isIE?"height":"max-height")+":"+h;
		var overflowParam='overflow:'+(h!='auto'?'auto':'hidden')+' !important'; 
		var css='#sidebarTabs { '+heightParam+'; '+overflowParam+'; }';
		setStylesheet(css,"sidebarTabsStyles");
		config.macros.option.propagateOption(opt,"value",config.options[opt],"input");
	}
	setTimeout('window.setSidebarTabsHeight()',1); // initialize height
	if (window.addEventListener) window.addEventListener("resize",window.setSidebarTabsHeight,false);
</script>tabs height: {{smallform{<<option txtSidebarTabsHeight>><script>
	var t=place.lastChild
	t.style.width="4em";
	t.style.textAlign="center";
	t.title="enter height using CSS dimensions (px, em, in, cm, %) or 'auto'";
	t.onfocus=function(){this.select();};
	t.onblur=function(){this.onchange();}; /* for IE */
	// hijack onchange for this field so CSS can be updated on the fly
	t.coreOnChange=t.onchange;
	t.onchange=function() {
		if (this.coreOnChange) this.coreOnChange();
		window.setSidebarTabsHeight();
	};
</script>}}}
/%
|Name|SetStoryHeight|
|Source|http://www.TiddlyTools.com/#SetStoryHeight|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|use CSS to set a scrolling, fixed or percentage height for the story column|

usage: <<tiddler SetStoryHeight with: height>>

where 'height' is an *optional* param to override the current value (if any)

%/<script>
	if (config.options.txtStoryHeight==undefined) config.options.txtStoryHeight="auto";
	if ('$'+'1'!='$1') config.options.txtStoryHeight='$1';
	window.setStoryHeight=function() {
		// set story height
		var opt="txtStoryHeight";
		var h=config.options[opt]; if (!h.length) h='auto';
		if (!h.replace(/[0-9]*/,"").length) h+="px"; // add "px" to numeric value
		config.options[opt]=h;
		var top=findPosY(document.getElementById("tiddlerDisplay"));
		if (h.indexOf("%")!=-1)
			h=((findWindowHeight()-top)*parseInt(h.replace(/%/,""))/100)+"px";
		var heightParam=(config.browser.isIE?"height":"max-height")+":"+h;
		var overflowParam='overflow:'+(h!='auto'?'auto':'visible')+' !important'; 
		var css='#tiddlerDisplay { '+heightParam+'; '+overflowParam+'; }';
		setStylesheet(css,"storyHeightStyles");
		config.macros.option.propagateOption(opt,"value",config.options[opt],"input");
	}
	setTimeout('window.setStoryHeight()',1); // initialize height
	if (window.addEventListener) window.addEventListener("resize",window.setStoryHeight,false);
</script>story height: {{smallform{<<option txtStoryHeight>><script>
	var t=place.lastChild
	t.style.width="4em";
	t.style.textAlign="center";
	t.title="enter height using CSS dimensions (px, em, in, cm, %) or 'auto'";
	t.onfocus=function(){this.select();};
	t.onblur=function(){this.onchange();}; /* for IE */
	// hijack onchange for this field so CSS can be updated on the fly
	t.coreOnChange=t.onchange;
	t.onchange=function() {
		// call original core onchange handler
		if (this.coreOnChange) this.coreOnChange();
		window.setStoryHeight();
	};
</script>}}}
/%
|Name|SetTiddlerBackground|
|Source|http://www.TiddlyTools.com/#SetTiddlerBackground|
|Version|1.1.2|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|set tiddler background and font color CSS attributes|

usage:
	<<tiddler SetTiddlerBackground with: bgstyle fgstyle matchtag class>>
where:
	'bgstyle' and 'fgstyle' (optional, but specify at least one)
		are CSS background style attributes (most often color values, e.g., #rgb or #rrggbb)
	'matchtag' (optional)
		is a tag value that allows selective control of tiddler background/foreground colors
	'class' (optional)
		is the class of the tiddler element to which the fgstyle/bgstyle will be applied (default is "viewer").
		Use "title" to set the background of the tiddler's 'title' area instead of its 'viewer' area.

The bgstyle and fgstyle assignments are only performed if the tiddler has the matching tag (or if no matchtag value is specfied).  In addition, to set just the background or the foreground color (but not both), you can use a dash ("-") as a placeholder value for whichever value you do NOT want to set.  For example:
	<<tiddler SetTiddlerBackground with: #F00 - urgent>>
sets the background color (but NOT the foreground color) to RED for only those tiddlers tagged with "urgent".  Also, note that in that instead of using #RGB color definitions, you can also use CSS color keywords (i.e., "red", "yellow", "green") or *any* other valid CSS value that can be applied to the 'background' style attribute.  For example, to use a background image for any tiddler tagged with "wallpaper", you can write:
        <<tiddler SetTiddlerBackground with: url(images/bg.jpg) - wallpaper>>

You can use this script several times in a row to define a set of tag-to-color mappings, stored in a *single* convenient tiddler... first, create a tiddler (e.g. [[BackgroundColors]]) containing something like this:
	<<tiddler SetTiddlerBackground with: red - urgent>>
	<<tiddler SetTiddlerBackground with: yellow - active>>
	<<tiddler SetTiddlerBackground with: green - done>>

To apply tag-based color mapping to any specific tiddler, just embed:
	<<tiddler BackgroundColors>>
directly in that tiddler's content and set the appropriate tag to select the desired background color.

To apply tag-based color mapping to ALL tiddlers in your document without having to embed the <<tiddler BackgroundColors>> macro into each 'colorized' tiddler, add:
        <span macro="tiddler BackgroundColors" style="display:none"></span>
in your [[ViewTemplate]].  Then, anytime you want to add another tag-to-color mapping, all you have to do is just edit the [[BackgroundColors]] tiddler and then start tagging the desired tiddlers accordingly.

%/<script>
	if ("$1"!="$"+"1" && "$1"!="-") var bg="$1";
	if ("$2"!="$"+"2" && "$2"!="-") var fg="$2";
	if ("$3"!="$"+"3" && "$3"!="-") var tag="$3";
	if ("$4"!="$"+"4" && "$4"!="-") var c="$4"; else var c="viewer";
	var here=story.findContainingTiddler(place); if (!here) return;
	var tiddler=store.getTiddler(here.getAttribute("tiddler"));
	if (tag && (!tiddler||!tiddler.isTagged(tag))) return;
	if (c=="tiddler") target=here;
	else {
		var children=here.getElementsByTagName("*");
		for (var i=0; i<children.length; i++)
			if (hasClass(children[i],c)) { var target=children[i]; break; }
	}
	if (!target) return;
	if (bg) target.style.background=bg;
	if (fg) target.style.color=fg;
</script>
/%
|Name|SetTiddlerColumns|
|Source|http://www.TiddlyTools.com/#SetTiddlerColumns|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires||
|Overrides||
|Description|use CSS3 "-moz-column-count" to set single or multi-column tiddler layout|

usage: <<tiddler SetTiddlerColumns with: columncount>>

where 'columncount' is an *optional* param to override the current value (if any)

credits: Much thanks to "maki" (www.makiaea.org) for pointing out the -moz-column-* attributes.
Important note: these CSS3 features are not supported in InternetExplorer.

%/<script>
	if (config.options.txtTiddlerColumns==undefined) config.options.txtTiddlerColumns="1";
	if ('$'+'1'!='$1') config.options.txtStoryHeight='$1';
	window.setTiddlerColumns=function() {
		// set tiddler columns
		var opt="txtTiddlerColumns";
		var cols=config.options[opt]; if (!cols.length) cols='1';
		config.options[opt]=cols;
		var td=document.getElementById("tiddlerDisplay");
		td.style.MozColumnCount=config.options[opt];
		config.macros.option.propagateOption(opt,"value",config.options[opt],"input");
	}
	setTimeout('window.setTiddlerColumns()',1); // initialize height
	if (window.addEventListener) window.addEventListener("resize",window.setTiddlerColumns,false);
</script>tiddler columns: {{smallform{<<option txtTiddlerColumns>><script>
	var t=place.lastChild
	t.style.width="4em";
	t.style.textAlign="center";
	t.title="enter height using CSS dimensions (px, em, in, cm, %) or 'auto'";
	t.onfocus=function(){this.select();};
	if (config.browser.isIE) {
		t.disabled=true;
		t.value=1;
		t.title="Sorry, multiple column tiddler display is not supported in Internet Explorer";
		return;
	}
	// hijack onchange for this field so CSS can be updated on the fly
	t.coreOnChange=t.onchange;
	t.onchange=function() {
		// call original core onchange handler
		if (this.coreOnChange) this.coreOnChange();
		window.setTiddlerColumns();
	};
</script>}}}
/%
|Name|SetTiddlerHeight|
|Source|http://www.TiddlyTools.com/#SetTiddlerHeight|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|use CSS to set a fixed or percentage height for each tiddler|

usage: <<tiddler SetTiddlerHeight with: height>>

where 'height' is an *optional* param to override the current value (if any)

revisions:
1.1.0 - added support for percentage height
1.0.1 - for non-IE browsers, use "max-height" CSS3 attribute instead of "height" attribute.

%/<script>
	if (config.options.txtTiddlerHeight==undefined) config.options.txtTiddlerHeight="auto";
	if ('$'+'1'!='$1') config.options.txtTiddlerHeight='$1';
	window.setTiddlerHeight=function() {
		// set tiddler height
		var opt="txtTiddlerHeight";
		var h=config.options[opt]; if (!h.length) h='auto';
		if (!h.replace(/[0-9]*/,"").length) h+="px"; // add "px" to numeric value
		config.options[opt]=h;
		var top=findPosY(document.getElementById("tiddlerDisplay"));
		if (h.indexOf("%")!=-1)
			h=((findWindowHeight()-top)*parseInt(h.replace(/%/,""))/100)+"px";
		var heightParam=(config.browser.isIE?"height":"max-height")+":"+h;
		var css='.viewer { '+heightParam+'; overflow:'+(h!='auto'?'auto':'visible')+'; }';
		setStylesheet(css,"tiddlerHeightStyles");
		config.macros.option.propagateOption(opt,"value",config.options[opt],"input");
	}
	setTimeout('window.setTiddlerHeight()',1); // initialize height
	if (window.addEventListener) window.addEventListener("resize",window.setTiddlerHeight,false);
</script>tiddler height: {{smallform{<<option txtTiddlerHeight>><script>
	var t=place.lastChild
	t.style.width="4em";
	t.style.textAlign="center";
	t.title="enter height using CSS dimensions (px, em, in, cm, %) or 'auto' to fit contents";
	t.onfocus=function(){this.select();};
	t.onblur=function(){this.onchange();}; /* for IE */
	// hijack onchange for this field so CSS can be updated on the fly
	t.coreOnChange=t.onchange;
	t.onchange=function() {
		// call original core onchange handler
		if (this.coreOnChange) this.coreOnChange();
		window.setTiddlerHeight();
	};
</script>}}}
/***
|Name|SetUserNamePlugin|
|Source|http://www.TiddlyTools.com/#SetUserNamePlugin|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|prompt for TiddlyWiki username|
!!!!!Usage
If default username ("YourName") is set, display prompt box to get new username
!!!!!Installation Notes
<<<
If you are using the default (shadow) EditTemplate definition, it will be updated to invoke this macro, so that whenever a user attempts to edit/create a tiddler AND the username is "YourName", they will be automatically prompted to enter a new username.  If you are using a customized EditTemplate, you will need to edit it yourself and add the following line:
{{{
<span macro='setUserName'></span>
}}}
<<<
!!!!!Revisions
<<<
2006.12.01 [1.0.0] initial release - converted from SetUserName inline script
<<<
!!!!!Code
***/
//{{{
version.extensions.setUserName= {major: 1, minor: 0, revision: 0, date: new Date(2006,12,1)};

config.macros.setUserName = {
	handler: function(place,macroName,params) {
		// only prompt when needed
		if (readOnly || config.options.txtUserName!="YourName") return;
		var opt="txtUserName";
		var who=prompt("Please set your username",config.options[opt]);
		if (!who||!who.trim().length) return; // cancelled by user
		config.options[opt]=who;
		saveOptionCookie(opt);
		config.macros.option.propagateOption(opt,"value",config.options[opt],"input");
	}
}

// add trigger to default shadow EditTemplate (custom templates: add this by hand)
config.shadowTiddlers.EditTemplate+="<span macro='setUserName'></span>";
//}}}
/%
|Name|ShowAllByTags|
|Source|http://www.TiddlyTools.com/#ShowAllByTags|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|for each tag, show a numbered list of all tiddlers with that tag|
%/<script>
	var tags = store.getTags();
	if(tags.length == 0) return "no tags in document";
	var out="";
	for(var t=0; t<tags.length; t++) {
		out+="*[["+tags[t][0]+"]] ("+tags[t][1]+")"+"\n";
		var tids=store.getTaggedTiddlers(tags[t][0]);
		for (i=0; i<tids.length; i++) out+="##[["+tids[i].title+"]]\n";
	}
	return out;
</script>
/%

NOTE: To be properly displayed, this tiddler needs HTMLFormattingPlugin installed

%/<html><hide linebreaks><table class="borderless"><tr><td style="text-align:center">
	[[Tiddler Icons|ShowAllIcons]] (from the [[Silk|http://www.famfamfam.com/lab/icons/silk/]] collection): &nbsp;<br>
	{{fine{//(move mouse over icons to view descriptions) &nbsp; //}}}
</td><td>
	<a href="javascript:;" style="background:transparent; display:block; padding-top:.5em"
		onclick="story.displayTiddler(story.findContainingTiddler(this),'ShowAllIcons');return false;">
	<<tiddlerIcons recent>>
	<<tiddlerIcons changed>>
	<<tiddlerIcons unsaved>>
	<<tiddlerIcons Trash>>
	<<tiddlerIcons core>>
	<<tiddlerIcons systemConfig>>
	<<tiddlerIcons tag>>
	<<tiddlerIcons CSS>>
	<<tiddlerIcons html>>
	<<tiddlerIcons template>>
	<<tiddlerIcons script>>
	<<tiddlerIcons attachment>>
	<<tiddlerIcons settings>>
	<<tiddlerIcons pluginInfo>>
	<<tiddlerIcons faq>>
	<<tiddlerIcons task>>
	</a>
</td></tr></table></html>
/%
|Name|ShowAllPermalinks|
|Source|http://www.TiddlyTools.com/#ShowAllPermalinks|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires||
|Overrides||
|Description|generate a list containing permalinks for every tiddler in the document|
%/{{small smallform{<html><form style='display:inline'>
	<textarea name=txt rows=10 style='width:100%' onfocus="this.select()"></textarea>
</form></html><script>
	var out=outtxt=""; 
	var tids=store.getTiddlers("title","excludeLists");
	for (var t=0; t<tids.length; t++) {
		var url=store.getTiddlerText("SiteUrl");
		if (!url) url=document.location.href;
		var permalink=encodeURIComponent(String.encodeTiddlyLink(tids[t].title));
		out+="[["+tids[t].title+"|"+url+"#"+permalink+"]]\n";
		outtxt+=url+"#"+permalink+"\n";
	}
	place.lastChild.firstChild.txt.value=outtxt;
	return "{{threecolumns{"+out+"}}}";
</script>}}}
/%
|Name|BlankScript|
|Source|http://www.TiddlyTools.com/#ShowDocumentInfo|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|show current TiddlyWiki version, document timestamp and tiddler info|
%/<script label="[i] - Show TiddlyWiki document info..." title="Show TiddlyWiki version, filedate and tiddler summary">
	if (window.version) {
		var ver=version.major+'.'+version.minor+'.'+version.revision;
		var tids=window.store.getTiddlers('modified').reverse();
		var plugins=window.store.getTaggedTiddlers('systemConfig','modified').reverse();
		var msg='TiddlyWiki version: '+ver
			+'\nDocument modified: '+document.lastModified
			+'\nLast tiddler changed: '+tids[0].title
			+'\n\nThere are a total of '+tids.length+' tiddlers,'
			+' including '+plugins.length+' plugins:\n\n';
		msg+=plugins.map(function(t){
			return t.modified.formatString('YYYY.0MM.0DD 0hh:0mm:0ss')+' | '+t.title; }).join('\n');
		alert(msg);
	}
 	return false;
</script>
/%
|Name|ShowPopup|
|Source|http://www.TiddlyTools.com/#ShowPopup|
|Version|1.0.2|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|transcluded html|
|Requires||
|Overrides||
|Description|display tiddler content in a TW popup|

usage: <<tiddler ShowPopup with: TiddlerName label tooltip buttonClass width popupClass>>

%/<html><a href="javascript:;" class="$4" title="$3" onclick="var p=Popup.create(this); if (!p) return; var t=store.getTiddler('$1'); if (!t) return; p.className+=' $6'; var d=createTiddlyElement(p,'div'); d.style.whiteSpace='normal'; d.style.width='$5'; d.style.padding='2px'; wikify(t.text,d); Popup.show(p,false); event.cancelBubble = true; if (event.stopPropagation) event.stopPropagation(); return(false);">$2</a></html>
/%
|Name|ShowReferences|
|Source|http://www.TiddlyTools.com/#ShowReferences|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|display references to this tiddler (aka, backlinks) directly in tiddler content|

Usage: <<tiddler ShowReferences>>

%/<script>

	// output display format: uncomment ONE of these lines (or add your own)
	var fmt="[[%0]] ";		// space-separated
	// var fmt="\n[[%0]]";		// one per line
	// var fmt="\n* [[%0]]";	// bullets

	var here=story.findContainingTiddler(place); if (!here) return;
	var title=here.getAttribute("tiddler");
	var references = store.getReferringTiddlers(title);
	var out = '';
	for(var r=0; r<references.length; r++)
		if(references[r].title != title && !references[r].tags.contains("excludeLists"))
			out+=fmt.format([references[r].title]);
	return out;
</script>
/%
|Name|ShowTabsForTags|
|Source|http://www.TiddlyTools.com/#ShowTabsForTags|
|Version|1.0.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires||
|Overrides||
|Description|automatically generate a tabbed display for tiddlers with a specified set of tags|

Usage:
	<<tiddler ShowTabsForTags with: "tag tag ...">>
where:
	"tag tag ..." is a space-separated list of tag values, ALL of which
	must be present on the tiddlers that are to be displayed.

%/{{left wrap{<script>
	var tags="$1".readBracketedList(); // get tags list from param
	if ("$1"=="$"+"1") { // if no tags were specified, then ASK for tags...
		var response=prompt("enter tag(s) to match:","faq");  
		if (!response) return "no tags specified"; // cancelled by user
		var tags=response.readBracketedList(); 
	}
	// get tiddlers with a least one matching tag, in date order (newest first)
	// and, for each tiddler that matches ALL tags, add macro params to output...
	var out="";
	var tids=store.getTaggedTiddlers(tags[0],'modified').reverse();
	for (var t=0; t<tids.length; t++)
		if (tids[t].tags.containsAll(tags)) out+='[[%0 ]] "view %0" [[%0]]'.format([tids[t].title]); 
	// if any tiddlers matched, output the <<tabs>> macro...
	if (out.length) return "<<tabs tabTabsForTags "+out+">>";
	// otherwise, output a message with popups for each specified tag...
	return "There are no tiddlers tagged with <<tag "+tags.join(">> and <<tag ")+">>";
</script>}}}
/%
|Name|ShowTagInfo|
|Source|http://www.TiddlyTools.com/#ShowTagInfo|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|NestedSlidersPlugin, MoveablePanelPlugin, InlineJavascriptPlugin|
|Overrides||
|Description|display extended tag information in a floating panel|

As an alternative to core <<tag tagname>> macro, this script uses a floating panel to display a description/instructions along side the list of tagged tiddlers, using the content of the "tag tiddler" (if any) as the source of the description.

Usage: <<tiddler ShowTagInfo with: tagname>>

Try it:
* Install this script (and required plugins)
* create a tiddler, give it a tag (e.g., "MyTag")
* create another tiddler, called [[MyTag]], and enter some description
* add <<tiddler ShowTagInfo with: MyTag>> to some tiddler content
* click the "MyTag" link in that tiddler 

%/<script>
	if ("$1"=="$"+"1") return; // tag param is required
	var tag="$1";
	var out="";
	out+="@@position:relative;+++^60em^*["+tag+"]...";
	out+="<<moveablePanel>><<tag "+tag+">>";
	out+="\n----\n";
	out+="{{floatright borderleft fine{\n<<tagging "+tag+">>}}}";
	out+="{{justify{"+(store.tiddlerExists(tag)?"<<tiddler "+tag+">>":"//description unavailable//")+"}}}"
	out+="===@@"
	out+=(config.browser.isIE?" ":"\n");
	return out;
</script>
<<showUpdates onlyTag:RecentUpdates maxEntries:8>>
{{{<<showUpdates onlyTag:RecentUpdates maxEntries:8>>}}}

----

<<showUpdates onlyTag:RecentUpdates write:'(index==0? countLine + "\n{{blog{\n":"")+(index<8?"!!![["+tiddler.title+"]]@@color:#999;font-size:70%;" +tiddler.modified.formatString(" - DD/MM/YY")+"@@\n" +"{{excerpt{\n"+tiddler.text.substr(0,100)+"...\n[[read more...|"+tiddler.title+"]]\n}}}\n":"")+(index==count-1?"}}}":"")' >>

{{{
<<showUpdates
onlyTag:RecentUpdates
write:
'(index==0? countLine + "\n{{blog{\n":"")+
(index<8?"!!![["+tiddler.title+"]]@@color:#999;font-size:70%;" +tiddler.modified.formatString(" - DD/MM/YY")+"@@\n" +"{{excerpt{\n"+tiddler.text.substr(0,100)+"...\n[[read more...|"+tiddler.title+"]]\n}}}\n":"")+
(index==count-1?"}}}":"")' 
>>
}}}

this one requires the following css in your StyleSheet:
//{{{
.blog h2, .blog h3, .blog h4{
  margin:0;
  padding:0;
  border-bottom:none;
}
.blog {margin-left:1.5em;}  

.blog .excerpt {
  margin:0;
  margin-top:0.3em;
  padding: 0;
  margin-left:1em;
  padding-left:1em;
  font-size:90%;
  border-left:1px solid #ddd;
}
//}}}
/***
|Name|ShowUpdatesPlugin|
|Created by|SaqImtiaz|
|Version|0.2 |
|Requires|~TW2.x|
!!!Description:
Allows you to list tiddlers that have changed since the users last visit. You can list only all changed tiddlers, or filter them to only show tiddlers that have or do not have a specific tag. By default a simple list of the titles of changed tiddlers is created. However, using an extremely versatile syntax you can provide a custom template for the generated text.

!!!Examples: 
[[ShowUpdatesDocs]]

!!!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.

!!!Syntax:
{{{<<showUpdates>>}}}
additional optional params:
{{{<showUpdates excludeTag:TagToExclude onlyTag:TagToList maxEntries:10 write:CustomWriteParameter >>}}}
excludeTag: ~TagToExclude
onlyTag: ~TagToList
maxEntries: max number of entries displayed when there are no updates. (default is 10, which can be changed in the config.macros.showUpdates.settings part of the code)
write: if a write parameter is not provided, an un-numbered list of the updates is generated. Alternatively, you can specify a custom 'template' for the text generated. The syntax for the write parameter is identical to that of the forEachTiddler macro. Additonal documentation on this syntax will be provided soon.
Some of the variables available in the write parameter are 'index', 'count' and 'lastVisit' where lastVisit is the date of the last visit in the format YYYYMMDDHHMM. Also areUpdates is a boolean that is true if there are new updates since the users last visit.

!!!To Do:
*refactor code to facilitate translations
*a streamlined version without the custom write parameter


!!!Code
***/
//{{{
window.lewcidLastVisit = '';
window.old_lewcid_whatsnew_restart = window.restart;
window.restart = function()
{
        if(config.options.txtLastVisit)
                 lewcidLastVisit= config.options.txtLastVisit;
        config.options.txtLastVisit = (new Date()).convertToYYYYMMDDHHMM();
        saveOptionCookie('txtLastVisit');
        window.old_lewcid_whatsnew_restart();
}

TiddlyWiki.prototype.lewcidGetTiddlers = function(field,excludeTag,includeTag,updatesOnly)
{
              var results = [];
              this.forEachTiddler(function(title,tiddler)
                      {
                      if(excludeTag == undefined || !tiddler.isTagged(excludeTag))
                                    if(includeTag == undefined ||  tiddler.isTagged(includeTag))
                                            if ( updatesOnly == false || tiddler.modified.convertToYYYYMMDDHHMM()>lewcidLastVisit)
                                                  results.push(tiddler);
                      });
              if(field)
                  results.sort(function (a,b) {if(a[field] == b[field]) return(0); else return (a[field] < b[field]) ? -1 : +1; });
              return results;
}

config.macros.showUpdates={};
config.macros.showUpdates.settings =
{
         maxEntries: 10  //max items to show, if there are no updates since last visit
}

config.macros.showUpdates.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
          var args = paramString.parseParams("list",null,true);
          var write = getParam(args, "write", undefined);
          var onlyTag = getParam(args, "onlyTag", undefined);
          var excludeTag = getParam(args, "excludeTag", undefined);
          var sortBy = "modified";
          var maxEntries = getParam(args,"maxEntries",this.settings.maxEntries);

          if (lewcidLastVisit) 
                {var tiddlers = store.lewcidGetTiddlers(sortBy,excludeTag,onlyTag,true);
                 var areUpdates = tiddlers.length>0? true:false;}

          if (!lewcidLastVisit)
               {var countLine = "!!Recent Updates:";
               var tiddlers = store.lewcidGetTiddlers(sortBy,excludeTag,onlyTag,false);
               var areUpdates = false;}
          else if (tiddlers.length == 0)
               {var countLine = "!!@@color:red;No new updates@@ since your last visit. @@color:#999;font-size:70%;" + (Date.convertFromYYYYMMDDHHMM(lewcidLastVisit)).formatString(" (DD/MM/YY)") + "@@\n!!Recent Updates:";
               var tiddlers = store.lewcidGetTiddlers(sortBy,excludeTag,onlyTag,false);}
          else
               {var countLine ="!!@@color:red;"+ tiddlers.length + "@@ new " + (tiddlers.length==1?"update":"updates") + " since your last visit: @@color:#999;font-size:70%;" + (Date.convertFromYYYYMMDDHHMM(lewcidLastVisit)).formatString(" (DD/MM/YY)") + "@@";}

          tiddlers = tiddlers.reverse();
          var lastVisit = lewcidLastVisit? lewcidLastVisit:undefined;
          var count = areUpdates == true? tiddlers.length : maxEntries;
          var sp = createTiddlyElement(place,"span","showUpdates");
          if (write==undefined)
                 {
                  wikify(countLine,sp);
                  var list = createTiddlyElement(sp,"ul");
                  for (var i = 0; i < count; i++)
                          {
                           var tiddler = tiddlers[i];
                           createTiddlyLink(createTiddlyElement(list,"li"), tiddler.title, true);
                          }
                 }
          else
                {
                 var list = '';
                 for (var index = 0; index < count; index++) {
                 var tiddler = tiddlers[index];
                 list += eval(write); }
                 wikify(list, sp);
                }
}
//}}}
/%
|Name|ShowUserName|
|Source|http://www.TiddlyTools.com/#ShowUserName|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|Displays current username, Click for prompt box to change name|
%//%

usage: <<tiddler ShowUserName>>

%/<script label="username">
	var opt="txtUserName";
	var who=prompt("Please set your username",config.options[opt]);
	if (!who||!who.trim().length) return false;
	config.options[opt]=who;
	saveOptionCookie(opt);
	var tid=story.findContainingTiddler(place);
	if (tid) story.refreshTiddler(tid.getAttribute("tiddler"),null,true); // sync containing tiddler
	config.macros.option.propagateOption(opt,"value",config.options[opt],"input");
	return false;
</script><script>
	place.lastChild.title="click to change your username";
	place.lastChild.innerHTML=config.options.txtUserName;
</script>
Fred Grott's Notes
/***
|Name|SliceGridPlugin|
|Source|http://www.TiddlyTools.com/#SliceGridPlugin|
|Documentation|http://www.TiddlyTools.com/#SliceGridPluginInfo|
|Version|1.0.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1.3|
|Type|plugin|
|Requires||
|Overrides||
|Description|Generate a "slice grid" table to get an instant 'birds-eye' overview of your entire document|
Rows are tiddlers, columns are slice names.  If a tiddler has a value defined for a given slice, that grid cell is colored. Move the mouse over a grid cell to view the value for that tiddler slice.  To keep the grid display from getting very wide, the slice names used as column headings are not initially displayed.  ''Click directly above the column to show/hide that heading'', or toggle all column headings at once by clicking the {{{>>>}}} symbol in the upper-left corner of the grid display.
!!!!!Documentation
>see [[SliceGridPluginInfo]]
!!!!!Revisions
<<<
2008.05.01 [1.0.1] in editSlice(), corrected fixup for titles containing double-quotes
2007.09.18 [1.0.0] added 'wikify' param and handling to format wiki-syntax contained in slice values
|please see [[SliceGridPluginInfo]] for additional revision details|
2007.01.30 [0.0.1] started
<<<
!!!!!Code
***/
//{{{
version.extensions.sliceGrid= {major: 1, minor: 0, revision: 1, date: new Date(2008,5,1)};

config.macros.sliceGrid= {
	sizeSliceName: "TiddlerSize", // shadow slice used for retrieving and showing tiddler size as a grid column
	noSlicesMsg: "\n|~SliceGrid: there are no slices to display|\n",
	handler:
	function(place,macroName,params) {
		this.slicesRE=/(?:^\|\s*[\'\/]*~?(\w+)\:?[\'\/]*\s*\|\s*(.*?)\s*\|$)/gm;
		this.wikify=false; // wiki-syntax in slices
		this.edit=false; // 'click-to-edit' feature
		this.verbose=false; // debugging/performance feedback messages
		this.alltiddlers=false; // rows for all tiddlers (even if no slices)
		this.inline=false; // slice value in cell (instead of mouseover)
		this.headers=false; // column headers
		this.cliplength=0; // limit inline display text length (0=no limit)
		this.slices=[]; // slices to show (columns)
		var tablewidth="auto"; // default CSS for table width
		var p=params.shift();
		while (p) {
			if (p.substr(0,6).toUpperCase()=="WIDTH:")
				tablewidth=p.substr(6);
			else if (p.substr(0,5).toUpperCase()=="TAGS:") {
				if (p.substr(5,1)=="@") { // get tags from tiddler
					var tid=store.getTiddler(p.substr(6));
					if (p.substr(6)=="here") {
						var here=story.findContainingTiddler(place);
						if (here) var tid=store.getTiddler(here.getAttribute("tiddler"));
					}
					if (tid) var tags=tid.tags;
				}
				else if (p.substr(5,1)=="+") { // get tags from tiddler contents
					var tid=store.getTiddler(p.substr(6));
					if (p.substr(6)=="here") {
						var here=story.findContainingTiddler(place);
						if (here) var tid=store.getTiddler(here.getAttribute("tiddler"));
					}
					if (tid)
						{ var tags=tid.text.readBracketedList(); }
				}
				else var tags=p.substr(5).readBracketedList();
			}
			else if (p.substr(0,7).toUpperCase()=="SLICES:") {
				if (p.substr(7,1)=="@") { // get slices from tiddler
					var tid=p.substr(8);
					var tiddler=store.getTiddler(tid);
					if (tid=="here") {
						var here=story.findContainingTiddler(place);
						if (here) var tiddler=store.getTiddler(here.getAttribute("tiddler"));
					}
					if (tiddler) {
						var slices=tiddler.getSlices(tiddler.title); for (var s in slices) this.slices.push(s);
					}
				}
				else if (p.substr(7,1)=="+") { // get slices from tiddler contents
					var tid=p.substr(8);
					var tiddler=store.getTiddler(tid);
					if (tid=="here") {
						var here=story.findContainingTiddler(place);
						if (here) var tiddler=store.getTiddler(here.getAttribute("tiddler"));
					}
					if (tiddler)
						{ this.slices=tiddler.text.readBracketedList(); }
				}
				else this.slices=p.substr(7).readBracketedList();
			}
			else switch (p.toUpperCase()) {
				case "EDIT":
					this.edit=true && !readOnly; break; // no editing allowed if readOnly mode
				case "WIKIFY":
					this.wikify=true; break;
				case "VERBOSE":
					this.verbose=true; break;
				case "ALL":
					this.alltiddlers=true; break;
				case "INLINE":
					this.inline=true; this.headers=true; break; // default to show headers with inline grid
				default:
					if (!isNaN(p)) { this.cliplength=p; break; }
					else displayMessage("unrecognized parameter: "+p);
			}
			p=params.shift();
		}
		// get rows and columns
		var rows=[]; var cols=[]; var total=0;
		var tiddlers=store.getTiddlers("title","excludeLists"); // get all tiddlers (except hidden ones)
		if (tags && tags.length) for (t=0;t<tiddlers.length;t++) // filter out tiddlers with no matching tags
			if (!tiddlers[t].tags.containsAny(tags)) { tiddlers.splice(t,1); t--; } // remove non-matching tiddler
		for (i=0; i<tiddlers.length; i++) {
			var slices=this.getSlices(tiddlers[i].title);
			var count=0; for (var s in slices) { cols.pushUnique(s); count++; total++;}
			if (count || this.alltiddlers) rows.push(tiddlers[i].title); // only show rows for tiddlers with slices
		}
		if (!cols.length) { wikify(this.noSlicesMsg,place); return; }
		if (this.verbose) displayMessage("Found %0 slices using %1 slice names in %2 tiddlers".format([total, cols.length,rows.length]));

		// get optional list of slices to show
		if (this.slices.length) var cols=this.slices;

		// generate HTML table
		var out="";
		out+="<html><table cellpadding='0' cellspacing='0' style='border:0;border-collapse:collapse;width:"+tablewidth+"'>";
		// column headings
		out+="<tr style='border:0;'><td style='text-align:right;border:0'>";
		out+="<a href='javascript:;' style='font-size:80%;'";
		out+="	title='show all column headings'";
		out+="	onclick='return config.macros.sliceGrid.toggleAllColumns(this,event,"+(this.headers?"true":"false")+")'>";
		out+=this.headers?"&lt;&lt;&lt;":"&gt;&gt;&gt;";
		out+="</a>";
		out+="</td>";
		for (var i=0;i<cols.length;i++) {
			out+="<td style='text-align:center;cursor:pointer;border:0;padding-left:2px;padding-right:2px;' ";
			out+="	title='show/hide column heading' ";
			out+="	onclick='return config.macros.sliceGrid.toggleColumn(this,event)'>";
			out+="<span style='display:"+(this.headers?"block":"none")+"'>"+cols[i]+"</span>";
			out+="</td>";
		}
		out+="</tr>";
		for (var i=0;i<rows.length;i++) {
			var tiddlersrc=rows[i].replace(/"/g,"&#x22;");
			out +="<tr style='border:0'>";
			// row heading
			out +="<td style='text-align:right;border:0;padding-right:2px;white-space:nowrap;"+(this.inline?'width:1%':'')+";'>";
			out +="<a href='javascript:;' tid=\""+tiddlersrc+"\" onclick='story.displayTiddler(this,this.getAttribute(\"tid\"));return false'>"+tiddlersrc+"</a>";
			out +="</td>";
			var slices=this.getSlices(rows[i]);
			for (var j=0;j<cols.length;j++) {
				var val=slices[cols[j]]; if (!val) val="";
				var bgcolor=val.length?"#999":"transparent";
				var content="&nbsp;";
				if (val.length && this.inline) {
					content=val.htmlEncode();
					if (this.cliplength) content=val.substr(0,this.cliplength)+(val.length>this.cliplength?"...":"");
					bgcolor="transparent";
				}
				out+="<td style='background-color:"+bgcolor+";border:1px solid;"+(!this.inline?'width:1em;':'');
				if (this.inline && cols[j]==this.sizeSliceName) out+="text-align:right !important;"; // right align tiddler size pseudo-slice
				out+="'"; 
				if (this.edit && !(cols[j]==this.sizeSliceName)) { // add edit-in-place, except for tiddler size pseudo-slice
					var onclick="return config.macros.sliceGrid.editSlice(this,event,this.getAttribute(\"tid\"),\""+cols[j]+"\","+(this.inline?"true":"false")+")";
					out+=" tid=\""+tiddlersrc+"\" onclick='"+onclick+"'";
				}
				out+=" title=\""+tiddlersrc+"::"+cols[j]+(!this.inline?("="+val):"")+"\"";
				out+="><span class='slicegrid_content'>"+content+"</span></td>";
			}
			out+="</tr>";
		}
		out+="</table>";
		out+="</html>";
		var span=createTiddlyElement(place,"span")
		span.innerHTML=out;
		if (this.wikify) {
			// find all TD's in table and replace span content with wikified elements
			var tds=span.getElementsByTagName("td");
			for (var t=0; t<tds.length; t++) {
				var content=tds[t].firstChild;
				if (!hasClass(content,"slicegrid_content")) continue;
				var txt=getPlainText(content);
				removeChildren(content);
				wikify(txt,content);
			}
		}
	},
	toggleAllColumns:
	function(here,event,defOpen) {
		if (here.expanded==undefined) here.expanded=defOpen;
		var ex=here.expanded=!here.expanded; 
		here.innerHTML=ex?"&lt;&lt;&lt;":"&gt;&gt;&gt;";
		here.title=ex?'hide all column headings':'show all column headings';
		var cells=here.parentNode.parentNode.getElementsByTagName("td");
		for (i=1; i<cells.length; i++) cells[i].firstChild.style.display=ex?"inline":"none";
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
		return(false);
	},
	toggleColumn:
	function(here,event) {
		here.firstChild.style.display=(here.firstChild.style.display=="none")?"inline":"none";
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
		return(false);
	},
	editSlice:
	function(here,event,tid,slice,inline) {
		// replace prompt box with edit field that is displayed until onBlur
		if (here.editing) return false; // already editing... don't re-init

		var onkeyup='if (event.keyCode==13)'; // SAVE and END
		onkeyup+='	{ config.macros.sliceGrid.setSlice(this.getAttribute(\"tid\"),"'+slice+'",this.value); this.blur(); }';
		onkeyup+='else if (event.keyCode==27)'; // END without saving
		onkeyup+='	{ this.blur(); }';

		var onblur="var tid=this.getAttribute(\"tid\"); var slice=\""+slice+"\"; var currval=config.macros.sliceGrid.getSlice(tid,slice); ";
		onblur+="if (this.value!=currval && confirm(tid+\"::\"+slice+\" has changed... save value?\"))";
		onblur+="	{ config.macros.sliceGrid.setSlice(tid,slice,this.value); currval=this.value; }";
		onblur+="var target=this.parentNode;";
		onblur+="target.editing=false;";
		onblur+="target.style.backgroundColor=target.getAttribute(\"savedColor\");";
		onblur+="target.style.padding=target.getAttribute(\"savedPadding\");";
		onblur+="target.style.width=target.getAttribute(\"savedWidth\");";
		onblur+="if (config.macros.sliceGrid.wikify) { removeChildren(target); wikify(currval,target); }";
		onblur+="else target.innerHTML="+(inline?'currval':'\"&nbsp;\"')+";";

		var style="font-size:1em;font-family:inherit;width:95%;margin:0px;padding:1px 0px 1px 3px;border:0;";
		var title=tid+"::"+slice+" (ENTER=submit, ESC=cancel)";

		here.setAttribute("savedWidth",here.style.width); if (!inline) here.style.width="99%";
		here.setAttribute("savedPadding",here.style.padding); here.style.padding="0px"; 
		here.setAttribute("savedColor",here.style.backgroundColor); here.style.backgroundColor="#fff";
		here.innerHTML="<input type='text' tid=\""+tid.replace(/"/g,"&#x22;")+"\" onkeyup='"+onkeyup+"' onblur='"+onblur+"' style='"+style+"' title='"+title+"'>";
		here.firstChild.value=config.macros.sliceGrid.getSlice(tid,slice); // avoids conflicts with nested quoting in HTML
		here.firstChild.focus();
		here.firstChild.select();
		here.editing=true;

		event.cancelBubble = true; if (event.stopPropagation) event.stopPropagation(); return(false);
	},
	getSlice:
	function(tid,slice) {
		var slices=config.macros.sliceGrid.getSlices(tid);
		return slices[slice]?slices[slice]:"";
	},
	getSlices:
	function(tid) {
		var slices = {};
		var text = store.getTiddlerText(tid,"");
		slices[this.sizeSliceName]=text.length.toString();  // 'shadow slice' for displaying tiddler size
		this.slicesRE.lastIndex = 0;
		do {
			var m = this.slicesRE.exec(text);
			if (m) { if (m[1]) slices[m[1]] = m[2]; else slices[m[3]] = m[4]; }
		} while(m);
		return slices;
	},
	setSlice:
	function(tid,slice,val) {
		var oldval=this.getSlice(tid,slice);
		if (val==oldval) return false; // value is unchanged... do nothing
		// find slice within tiddler text
		var tiddler=store.getTiddler(tid);
		this.slicesRE.lastIndex = 0;
		var lastIndex=0;
		do {
			var m=this.slicesRE.exec(tiddler.text);
			if (m && (m[1]==slice||m[3]==slice)) break;
			if (m) lastIndex=this.slicesRE.lastIndex;
		} while(m);
		if (m) { // if matching slice was found
			if (oldval.length) { // replace old value with new value
				var pos=RegExp.lastMatch.indexOf(oldval);
				var newSlice=RegExp.lastMatch.substr(0,pos)+val+RegExp.lastMatch.substr(pos+oldval.length);
			} else // insert new value into empty slice
				var newSlice=RegExp.lastMatch.substr(0,RegExp.lastMatch.length-1)+val+"|";
			var newText=RegExp.leftContext+newSlice+RegExp.rightContext;
		} else { // create new slice following last slice (or at start of tiddler if no slices)
			var newSlice="|"+slice+"|"+val+"|\n";
			var newText=newSlice+tiddler.text
			if (lastIndex) var newText=tiddler.text.substr(0,lastIndex+1)+newSlice+tiddler.text.substr(lastIndex+1);
		}
		// write tiddler contents
		var user=config.options.txtUserName; var mod=new Date();
		if (config.options.chkForceMinorUpdate)
			{ var user=tiddler.modifier; var mod=tiddler.modified; }
		store.saveTiddler(tid,tid,newText,user,mod,tiddler.tags,tiddler.fields);
		displayMessage(tid+"::"+slice+" has been "+(m?"updated":"created"));
		return(false);
	}
};
//}}}
/***
|Name|SliceGridPluginInfo|
|Source|http://www.TiddlyTools.com/#SliceGridPlugin|
|Documentation|http://www.TiddlyTools.com/#SliceGridPluginInfo|
|Version|1.0.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1.3|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for SliceGridPlugin|
Rows are tiddlers, columns are slice names.  If a tiddler has a value defined for a given slice, that grid cell is colored. Move the mouse over a grid cell to view the value for that tiddler slice.  To keep the grid display from getting very wide, the slice names used as column headings are not initially displayed.  ''Click directly above the column to show/hide that heading'', or toggle all column headings at once by clicking the {{{>>>}}} symbol in the upper-left corner of the grid display.
!!!!!Usage
<<<
{{{<<sliceGrid [[tags:tag tag...]] [[slices:slice slice...]]  inline wikify edit all cliplength verbose>>}}}

all parameters are optional, where:
''tags:'' (list)
> display rows only for those tiddlers with at least ONE of the specified tags (space-separated).  default is to show all tiddlers that have at least one slice defined, regardless of tags
> To use a list of tags defined in a separate tiddler, specify ''{{{tags:+TiddlerName}}}''.  To use the same tags that are being used by a given tiddler, use ''{{{tags:@TiddlerName}}}''
''slices:'' (list)
> display columns for the specified slices.  Default is to display all defined slices
> To use a list of slices defined in a separate tiddler, specify ''{{{slices:+TiddlerName}}}''.  To use the same slices that are being used by a given tiddler, use ''{{{slices:@TiddlerName}}}''.  Note: a special "shadow slice", ''TiddlerSize'', can be used to automatically compute and display the tiddler size in a grid column.  If a tiddler contains a slice named ''TiddlerSize'', then it supercedes the computed value.
''inline'' (keyword)
> display slice value directly in table cell.  Default is to use colored blocks for defined slices, with mouseover 'tooltip' to show value
''wikify'' (keyword)
> parse and format wiki-syntax contained in slice values.  Default is to show slice values "as-is", without converting embedded formatting.
''edit'' (keyword)
> enable click-to-edit to change slice values.  Default is to display only.
''all'' (keyword)
> display a row for each tiddler, even tiddlers that have NO slices defined.   Default is to only show tiddlers that have slices defined. Note: if tags: param is used to select tiddler by tag, then only tiddlers with matching tags are included.
''cliplength'' (number)
> # of characters to show in table cell when using 'inline' keyword.  Text display is truncated with "..."
''verbose'' (keyword)
> adds messages to report on slice grid processing

Note: uses modified version of slices pattern:
{{{slicesRE = /(?:^\|[\'\/]*~?(\w+)\:?[\'\/]*\|\s*(.*?)\s*\|$)/gm;}}}
* eliminates TONS of spurious slices caused by over-eager "description" format pattern matches
* enforces beginning-of-line and end-of-line sequences.  (Allows slice values to contain |, such as in pretty links)
<<<
!!!!!Examples
<<<
{{{<<sliceGrid inline wikify edit [[slices:Version Description]]>>}}}
+++[click to view example...]...<<sliceGrid inline wikify edit [[slices:Version Description]]>>===

{{{<<sliceGrid edit tags:systemConfig>>}}}
+++[click to view example...]...<<sliceGrid edit tags:systemConfig>>===
<<<
!!!!!Revisions
<<<
2008.05.01 [1.0.1] in editSlice(), corrected fixup for titles containing double-quotes
2007.09.18 [1.0.0] added 'wikify' param and handling to format wiki-syntax contained in slice values
2007.08.02 [0.9.8] when generating HTML, replace double-quotes in tiddler titles with {{{&#x22;}}} (entity equivalence) to avoid ambiguity with quotes used as HTML attribute syntax delimiters.
2007.07.22 [0.9.7] removed hard-coded 99% 'width bias' and wordwrap from Description cells, default to autosize (equal size for all columns).  Added width:xxxx param to easily stretch table to fit containing space
2007.06.08 [0.9.6] fixed generation of javascript for rows headings and in edit_slice(), so tiddler titles containing single-quote characters will not create syntax errors in the DOM event handlers
2007.04.24 [0.9.5] added 'shadow slice', "TiddlerSize", so that tiddler size can be retrieved and displayed as a grid column.  Also, fixed click on column headings for show/hide...
2007.04.13 [0.9.4] when getting tiddlers, honor "excludeLists" tag so that 'hidden' tiddlers aren't displayed in the grid
2007.04.08 [0.9.3] corrected setting of cell background color (non-inline grid 'blocks') after edit-in-place adds/clears a slice value
2007.04.07 [0.9.2] support edit in place for non-inline grids (color 'blocks'), and also handle creating new slices in tiddlers where a slice didn't exist previously
2007.04.07 [0.9.1] use locally-defined slicesRE (and getSlice() method) instead of re-defining core slicesRE.  Avoids breaking use of shadow ColorPalette slices.  
2007.04.05 [0.9.0] Added functioning "set slice" handler and "edit-in-place" feature.  Eliminated mouseover popups (use tooltips instead).  Added ''tags:'', ''slices:'' and ''edit'' params.  Lots of code cleanup.
2007.04.04 [0.8.1] in info() and popup() functions, instead of creating popup display, use element tooltip to show mouseover details.   Avoids incorrect positioning of popup if the 'root' element for the popup is in a DIV that has been scrolled.
2007.03.25 [0.8.0] change to BETA status and added support for "tags:tag tag tag tag" filtering param
2007.02.03 [0.0.2] change display of slices from "tiddler[slidename]" to "tiddler:slicename" to match TW slice syntax
2007.01.30 [0.0.1] started (adapted from TagGridPlugin)
<<<
/***
|Name|SnapshotPlugin|
|Source|http://www.TiddlyTools.com/#SnapshotPlugin|
|Documentation|http://www.TiddlyTools.com/#SnapshotPluginInfo|
|Version|1.1.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|save or print HTML+CSS image of rendered document content|
|Status|ALPHA - DO NOT DISTRIBUTE|
This plugin provides a macro as well as tiddler toolbar commands to create a file or browser window containing the //rendered// CSS-and-HTML that is currently being displayed for selected elements of the current document.
!!!!!Documentation
>see [[SnapshotPluginInfo]]
!!!!!Configuration
<<<
<<option chkSnapshotHTMLOnly>> output HTML only (omit CSS)
<<<
!!!!!Revisions
<<<
2008.05.16 [1.1.1] added try..catch around addEvent/removeEvent calls to avoid error in Opera
2008.04.28 [1.1.0] removed 'viewerHTML' from 'ask' droplist and replaced with toggle for "output HTML only".  Removed 'noCSS' parameter and replaced with config.options.chkSnapshotHTMLOnly global option.  Added "select a tiddler..." to 'ask' droplist
2008.04.24 [1.0.1] in saveSnap(), convert output from Unicode to UTF before passing to saveFile().  Fixes "unknown name" error in IE's file.Write() function.  Added viewerHTML to 'ask' droplist.
2008.04.21 [1.0.0] initial release - derived from [[NewDocumentPlugin]] with many improvements, including: "ask for ID" using droplist of available DOM elements, use "<base href=...>" for correctly resolving image references, wrap 'viewer only' output in class="tiddler viewer" for proper application of inherited CSS styles, snapshotSave and snapshotPrint tiddler toolbar command definitions, and more...
<<<
!!!!!Code
***/
//{{{
version.extensions.SnapshotPlugin= {major: 1, minor: 1, revision: 1, date: new Date(2008,5,16)};

if (config.options.chkSnapshotHTMLOnly===undefined) config.options.chkSnapshotHTMLOnly=false;

config.macros.snapshot = {
	snapLabel: "save a snapshot",
	printLabel: "print a snapshot",
	snapPrompt: "save an HTML image of rendered content",
	printPrompt: "print an HTML image of rendered content",
	hereID: "here",
	viewerID: "viewer",
	storyID: "story",
	allID: "all",
	askID: "ask",
	askTiddlerID: "askTiddler",
	askDOMID: "askDOM",
	askMsg: "select an element...",
	hereItem: "tiddler: '%0'",
	viewerItem: "tiddler: '%0' (content only)",
	storyItem: "story column",
	allItem: "entire document",
	tiddlerItem: "select a tiddler...",
	IDItem: "select a DOM element by ID...",
	HTMLItem: "[%0] output HTML only (omit CSS)",
	fileMsg: "select or enter a target path/filename",
	defaultFilename: "snapshot.html",
	okmsg: "snapshot written to %0",
	failmsg: "An error occurred while creating %0",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var printing=params[0]&&params[0]=="print"; if (printing) params.shift();
		params = paramString.parseParams("anon",null,true,false,false);
		var id=getParam(params,"id","here");
		var label=getParam(params,"label",printing?this.printLabel:this.snapLabel);
		var prompt=getParam(params,"prompt",printing?this.printPrompt:this.snapPrompt);
		var btn=createTiddlyButton(place,label,prompt, function(ev){
			this.setAttribute("snapID",this.getAttribute("startID"));
			config.macros.snapshot.go(this,ev)
		});
		btn.setAttribute("startID",id);
		btn.setAttribute("snapID",id);
		btn.setAttribute("printing",printing?"true":"false");
		btn.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
	},
	go: function(here,ev) {
		var cms=config.macros.snapshot; // abbreviation
		var id=here.getAttribute("snapID");
		var printing=here.getAttribute("printing")=="true";
		var HTMLOnly=here.getAttribute("HTMLOnly")=="true";

		if (id==cms.askID||id==cms.askTiddlerID||id==cms.askDOMID) {
			cms.askForID(here,ev);
		} else {
			// get element
			if (id==cms.storyID) id="tiddlerDisplay";
			if (id==cms.allID) id="contentWrapper";
			var snapElem=document.getElementById(id);
			if (id==cms.hereID || id==cms.viewerID)
				var snapElem=story.findContainingTiddler(here);
			if (snapElem && hasClass(snapElem,"tiddler") && (id==cms.viewerID || HTMLOnly)) {
				// find viewer class element within tiddler element
				var nodes=snapElem.getElementsByTagName("*");
				for (var i=0; i<nodes.length; i++)
					if (hasClass(nodes[i],"viewer")) { snapElem=nodes[i]; break; }
			}
			if (!snapElem) // not in a tiddler or no viewer element or unknown ID
				{ e.cancelBubble=true; if(e.stopPropagation)e.stopPropagation(); return(false); }
			// write or print snapshot
			var out=cms.getsnap(snapElem,id,printing,HTMLOnly);
			if (printing) cms.printsnap(out); else cms.savesnap(out);
		}
		return false;
	},
	askForID: function(here,ev) {
		var ev = ev ? ev : window.event; 
		var cms=config.macros.snapshot; // abbreviation
		var id=here.getAttribute("snapID");
		var indent='\xa0\xa0\xa0\xa0';
		var p=Popup.create(here); if (!p) return false; p.className+=' sticky smallform';
		var s=createTiddlyElement(p,'select'); s.button=here;
		if (id==cms.askID) {
			s.options[s.length]=new Option(cms.askMsg,cms.askID);
			var tid=story.findContainingTiddler(here);
			if(tid) { 
				var title=tid.getAttribute("tiddler");
				if (here.getAttribute("HTMLOnly")!="true")
					s.options[s.length]=new Option(indent+cms.hereItem.format([title]),cms.hereID);
				s.options[s.length]=new Option(indent+cms.viewerItem.format([title]),cms.viewerID);
			}
			s.options[s.length]=new Option(indent+cms.tiddlerItem,cms.askTiddlerID);
			s.options[s.length]=new Option(indent+cms.IDItem,cms.askDOMID);
			s.options[s.length]=new Option(indent+cms.storyItem,"tiddlerDisplay");
			s.options[s.length]=new Option(indent+cms.allItem,"contentWrapper");
		}
		if (id==cms.askDOMID) {
			s.options[s.length]=new Option(cms.IDItem,cms.askDOMID);
			var elems=document.getElementsByTagName("*");
			var ids=[];
			for (var i=0;i<elems.length;i++)
				if (elems[i].id.length && elems[i].className!="animationContainer")
					ids.push(elems[i].id);
			ids.sort();
			for (var i=0;i<ids.length;i++) s.options[s.length]=new Option(indent+ids[i],ids[i]);
		}
		if (id==cms.askTiddlerID) {
			s.options[s.length]=new Option(cms.tiddlerItem,cms.askTiddlerID);
			var elems=document.getElementsByTagName("div");
			var ids=[];
			for (var i=0;i<elems.length;i++) { var id=elems[i].id;
				if (id.length && id.substr(0,story.idPrefix.length)==story.idPrefix && id!="tiddlerDisplay")
					ids.push(id);
			}
			ids.sort();
			for (var i=0;i<ids.length;i++) s.options[s.length]=new Option(indent+ids[i].substr(story.idPrefix.length),ids[i]);
		}
		s.options[s.length]=new Option(cms.HTMLItem.format([here.getAttribute("HTMLOnly")=="true"?"\u221a":"_"]),cms.HTMLItem);
		s.onchange=function(ev){
			var ev = ev ? ev : window.event; 
			var cms=config.macros.snapshot; // abbreviation
			var here=this.button;
			if (this.value==cms.HTMLItem) {
				config.options.chkSnapshotHTMLOnly=!config.options.chkSnapshotHTMLOnly;
				here.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
				config.macros.option.propagateOption("chkSnapshotHTMLOnly","checked",
					config.options.chkSnapshotHTMLOnly,"input");
			} else
				here.setAttribute("snapID",this.value);
			config.macros.snapshot.go(here,ev);
			return false;
		};
		Popup.show(p,false);
		ev.cancelBubble=true;
		if(ev.stopPropagation)ev.stopPropagation();
		return false;
	},
	getpath: function() {
		// get current path
		var path=getLocalPath(window.location.href);
		var slashpos=path.lastIndexOf("/");
		if (slashpos==-1) slashpos=path.lastIndexOf("\\"); 
		if (slashpos!=-1) path=path.substr(0,slashpos+1); // trim filename
		return path;
	},
	getsnap: function(snapElem,id,printing,HTMLOnly) {
		var cms=config.macros.snapshot; // abbreviation
		var out="";
		out+="<html><head>\n";
		if (printing)
			out+='<base href="file:///'+cms.getpath().replace(/\\/g,'/')+'"></base>\n';
		if (!HTMLOnly) {
			var styles=document.getElementsByTagName("style");
			for(var i=0; i < styles.length; i++) {
				out+="<style>\n";
				out+="/* stylesheet="+styles[i].getAttribute("id")+" */\n";
				out+=styles[i].innerHTML+"\n\n";
				out+="</style>\n";
			}
		}
		out+="</head><body>\n\n<div"+(id==cms.viewerID?" class='tiddler viewer'>":">");
		out+=snapElem.innerHTML;
		out+="</div>\n\n</body>\n";
		out+="</html>";
		return out;
	},
	printsnap: function(out) {
		var win=window.open("","_blank","");
		win.document.open();
		win.document.writeln(out);
		win.document.close();
		win.focus(); // bring to front
		win.print(); // trigger print dialog
	},
	savesnap: function(out) {
		var cms=config.macros.snapshot; // abbreviation
		// make sure we are local
		if (window.location.protocol!="file:")
			{ alert(config.messages.notFileUrlError); return; }
		var target=cms.askForFilename(cms.fileMsg,cms.getpath(),cms.defaultFilename);
		if (!target) return; // cancelled by user
		// if specified file does not include a path, assemble fully qualified path and filename
		var slashpos=target.lastIndexOf("/");
		if (slashpos==-1) slashpos=target.lastIndexOf("\\");
		if (slashpos==-1) target=target+cms.defaultFilename;
		var link="file:///"+target.replace(/\\/g,'/'); // link for message text
		var ok=saveFile(target,convertUnicodeToUTF8(out));
		var msg=ok?cms.okmsg.format([target]):cms.failmsg.format([target]);
		clearMessage(); displayMessage(msg,link);
	},
	askForFilename: function(msg,path,file) {
		if(window.Components) { // moz
			try {
				netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
				var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
				var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
				picker.init(window, msg, nsIFilePicker.modeSave);
				var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
				thispath.initWithPath(path);
				picker.displayDirectory=thispath;
				picker.defaultExtension='html';
				picker.defaultString=file;
				picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
				if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.persistentDescriptor;
			}
			catch(e) { alert('error during local file access: '+e.toString()) }
		}
		else { // IE
			try { // XP/Vista only
				var s = new ActiveXObject('UserAccounts.CommonDialog');
				s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
				s.FilterIndex=3; // default to HTML files;
				s.InitialDir=path;
				s.FileName=file;
				if (s.showOpen()) var result=s.FileName;
			}
			catch(e) { var result=prompt(msg,path+file); } // fallback for non-XP IE
		}
		return result;
	}
};
//}}}

// // TOOLBAR DEFINITIONS
//{{{
config.commands.snapshotSave = {
	text: "snap",
	tooltip: config.macros.snapshot.snapPrompt,
	handler: function(ev,src,title) {
		src.setAttribute("snapID","ask");
		src.setAttribute("printing","false");
		src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
		config.macros.snapshot.go(src,ev);
		return false;
	}
};
config.commands.snapshotPrint = {
	text: "print",
	tooltip: config.macros.snapshot.printPrompt,
	handler: function(ev,src,title) {
		src.setAttribute("snapID","ask");
		src.setAttribute("printing","true");
		src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
		config.macros.snapshot.go(src,ev);
		return false;
	}
};
//}}}

// // COPIED FROM [[StickyPopupPlugin]] TO ELIMINATE PLUGIN DEPENDENCY
//{{{
if (config.options.chkStickyPopups==undefined) config.options.chkStickyPopups=false;
Popup.stickyPopup_onDocumentClick = function(ev)
{
	// if click is in a sticky popup, ignore it so popup will remain visible
	var e = ev ? ev : window.event; var target = resolveTarget(e);
	var p=target; while (p) {
		if (hasClass(p,"popup") && (hasClass(p,"sticky")||config.options.chkStickyPopups)) break;
		else p=p.parentNode;
	}
	if (!p) // not in sticky popup (or sticky popups disabled)... use normal click handling
		Popup.onDocumentClick(ev);
	return true;
};
try{removeEvent(document,"click",Popup.onDocumentClick);}catch(e){};
try{addEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
//}}}
/***
|Name|SnapshotPluginInfo|
|Source|http://www.TiddlyTools.com/#SnapshotPlugin|
|Documentation|http://www.TiddlyTools.com/#SnapshotPluginInfo|
|Version|1.1.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|Documentation for SnapshotPlugin|
This plugin provides a macro as well as tiddler toolbar commands that creates a file or opens a new browser window containing the //rendered// HTML and CSS style definitions that are being displayed for selected elements of the current document.
!!!!!Usage:
<<<
As a macro embedded in tiddler content:
{{{
<<snapshot print label:text prompt:text id:elementID|here|viewer|story|all|ask>
}}}
where:
*''print'' //(optional)//<br>when present, causes the snapshot output to be directed to a new browser tab/window instead of saving it to a file.  In addition, the print dialog for that tab/window is automatically invoked.
*''label'' //(optional)//<br>is the text to be displayed for the command link generated by the macro
*''prompt'' //(optional)//<br>is the 'tool tip' message displayed when you mouseover the command link
*''id:...'' //(optional)//<br>specifies the document element to be captured, and can be one of:
**''elementID''<br>is a specific DOM element ID, such as "displayArea", "mainMenu", "contentWrapper", etc.
**''here''<br>the containing tiddler in which the macro (or toolbar command) occurs, including the tiddler title and subtitle (date/time/author) information.
**''viewer''<br>same as ''here'', but omits the tiddler title, subtitle and toolbar elements (i.e., it includes //only// the content of the tiddler)
**''story''<br>selects all currently displayed tiddlers (i.e., the 'story column')
**''all''<br>selects the entire document contents, including page header, main menu and sidebar displays
**''ask''<br>when the snapshot command link is clicked, a droplist is displayed so you can choose from several pre-defined elements: "current tiddler", "story column", or "entire document", or "DOM element ID..."  When DOM element ID is chosen, the droplist is refreshed to show the individual ID's for all currently rendered DOM elements (at least, the ones that have ID's).  For any given DOM element ID, only the portions of the document that are contained //within// the specified DOM element will be transcribed to the resulting snapshot or print output.  
//''NOTE: when no parameters are specified, the macro creates a snapshot file using the containing tiddler as the default element.'' (e.g., equivalent to {{{<<snapshot id:here>>}}}//

The snapshot/print functions can also be embedded as tiddler toolbar commands in [[ViewTemplate]]:
{{{
<span class='toolbar' macro='toolbar snapshotSave'></span>
<span class='toolbar' macro='toolbar snapshotPrint'></span>
}}}
* when invoked via toolbar commands, the "id:ask" option is automatically applied, and a droplist of elements to choose from is displayed.

Please note that, although the snapshot/print that is created using the HTML+CSS of the displayed content, ''there is NO javascript code'' written into the snapshot.  As a result, the snapshot only ''reproduces the //appearance// of the displayed content, allowing you to //view// or //print// the result'', but does not permit you to interact with it in other ways.

For example, even simple processing (such as mouseover highlighting) will not function from the snapshot.  You can't click a TiddlyLink to open other tiddlers, because A) there is no code that handles the click and B) there is no underlying 'storeArea' (and core code) to retrieve and render anything!  You also can't use ANY command links, since these also require javascript code (and the core) to operate. 
<<<
!!!!!Examples:
<<<
{{{<<snapshot>>}}}: <<snapshot>>
{{{<<snapshot id:mainMenu>>}}}: <<snapshot id:mainMenu>>
{{{<<snapshot print id:story>>}}}: <<snapshot print id:story>>
{{{<<snapshot print id:ask>>}}}: <<snapshot print id:ask>>
{{{<<snapshot print noCSS id:viewer>>}}}: <<snapshot print noCSS id:viewer>>
<<<
!!!!!Configuration
<<<
<<option chkSnapshotHTMLOnly>> output HTML only (omit CSS)
<<<
!!!!!Revisions
<<<
2008.05.16 [1.1.1] added try..catch around addEvent/removeEvent calls to avoid error in Opera
2008.04.28 [1.1.0] removed 'viewerHTML' from 'ask' droplist and replaced with toggle for "output HTML only".  Removed 'noCSS' parameter and replaced with config.options.chkSnapshotHTMLOnly global option.  Added "select a tiddler..." to 'ask' droplist
2008.04.24 [1.0.1] in saveSnap(), convert output from Unicode to UTF before passing to saveFile().  Fixes "unknown name" error in IE's file.Write() function.
2008.04.21 [1.0.0] initial release - derived from [[NewDocumentPlugin]] with many improvements, including: "ask for ID" using droplist of available DOM elements, use "<base href=...>" for correctly resolving image references, wrap 'viewer only' output in class="tiddler viewer" for proper application of inherited CSS styles, snapshotSave and snapshotPrint tiddler toolbar command definitions, and more...
<<<
/***

''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.
/***
|Name|StickyPopupPlugin|
|Source|http://www.TiddlyTools.com/#StickyPopupPlugin|
|Version|1.0.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Popup.onDocumentClick|
|Options|##Configuration|
|Description|allow mouse interactions inside popups without automatically closing them|
Usually, when a TW popup is displayed, it is automatically closed whenever a click occurs //anywhere// in the document, either //inside// or //outside// the popup itself.  This plugin makes popups persistent (a.k.a, "sticky"), allowing you to perform multiple mouse interactions on content //inside// the popup (e.g., entering form fields, opening links, selecting text, etc.), remaining visible until you click //outside// the popup or perform an action that opens another popup (only one popup can be displayed at any given time).
!!!!!Configuration
<<<
You can cause popups to behave in a persistent ("sticky") manner simply by selecting the option checkbox below.  The selected popup display behavior will be applied to ALL popups in the document automatically.
><<option chkStickyPopups>> make all popups "sticky"
>{{{usage: <<option chkStickyPopups>>}}}
<<<
!!!!!Usage
<<<
If you are developing your own plugins or inline scripts that create popups programmatically using the core function:
{{{
Popup.create(this)
}}}
you can provide additional parameters that specify the desired CSS classname(s) to assign to the popup DOM element.  The default class when none is specified is simply "popup".  To create a //sticky// popup, simply enter a custom class combination like this:
{{{
Popup.create(this,null,"sticky popup")
}}}
<<<
!!!!!Revisions
<<<
2008.05.16 [1.0.1] added try..catch around addEvent/removeEvent calls to avoid error in Opera
2007.11.25 [1.0.0] initial release - moved from [[CoreTweaks]]
<<<
!!!!!Code
***/
//{{{
version.extensions.StickyPopups= {major: 1, minor: 0, revision: 1, date: new Date(2008,5,16)};

if (config.options.chkStickyPopups==undefined) config.options.chkStickyPopups=false;

Popup.stickyPopup_onDocumentClick = function(ev)
{
	// if click is in a sticky popup, ignore it so popup will remain visible
	var e = ev ? ev : window.event; var target = resolveTarget(e);
	var p=target; while (p) {
		if (hasClass(p,"popup") && (hasClass(p,"sticky")||config.options.chkStickyPopups)) break;
		else p=p.parentNode;
	}
	if (!p) // not in sticky popup (or sticky popups disabled)... use normal click handling
		Popup.onDocumentClick(ev);
	return true;
};
try{removeEvent(document,"click",Popup.onDocumentClick);}catch(e){};
try{addEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
//}}}
/***
|Name|StorySaverPlugin|
|Source|http://www.TiddlyTools.com/#StorySaverPlugin|
|Documentation|http://www.TiddlyTools.com/#StorySaverPluginInfo|
|Version|1.4.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|MarkupPostBody|
|Overrides|confirmExit(), getParameters()|
|Description|save/restore current tiddler view between browser sessions|
This plugin automatically saves a list of the currently viewed tiddlers (the "story") in a local cookie, {{{txtSavedStory}}} and then opens those tiddlers when the document is subsequently reloaded... the tiddlers you were viewing in the last browser session are automatically redisplayed in the next session, allowing you to quickly resume working with the document from the same place you left off!!

In addition to automatic cookie-based story tracking, the plugin also provides {{{<<saveStory>>}}} and {{{<<openStory>>}}} macros that allow you to quickly save the current story definition to a tiddler, and then re-display saved stories using simple, one-click command links or droplists.
!!!!!Documentation
>see [[StorySaverPluginInfo]]
!!!!!Revisions
<<<
2008.03.10 [*.*.*] plugin size reduction: documentation moved to [[StorySaverPluginInfo]]
|please see [[StorySaverPluginInfo]] for additional revision details|
2007.10.05 [1.0.0] initial release.   Moved [[SetDefaultTiddlers]] inline script and rewrote as a {{{<<saveStory>>}}} macro.
<<<
!!!!!Code
***/
//{{{
version.extensions.StorySaver= {major: 1, minor: 4, revision: 1, date: new Date(2008,1,1)};
//}}}
// // ''save or clear story cookie on exit:''
//{{{
if (config.options.chkSaveStory==undefined) config.options.chkSaveStory=false; 
if (window.coreTweaks_confirmExit==undefined) {
	window.coreTweaks_confirmExit=window.confirmExit;
	window.confirmExit=function() {
		if (config.options.chkSaveStory) { // save cookie
			var links=[]; story.forEachTiddler(function(title,element){links.push(String.encodeTiddlyLink(title));});
			document.cookie="txtSavedStory=[["+links.join("]] [[")+"]]; expires=Fri, 1 Jan 2038 12:00:00 UTC; path=/";
		}
		else {
			var ex=new Date(); ex.setTime(ex.getTime()-1000);
			document.cookie="txtSavedStory=; path=/; expires="+ex.toGMTString(); // remove cookie
		}
		return window.coreTweaks_confirmExit.apply(this,arguments);
	}
}
//}}}
/***
''apply saved story on startup:'' //important note: the following code is actually located in [[MarkupPostBody]].  This is because it needs to supercede the core's getParameters() function, which is called BEFORE plugins are loaded, preventing the normal plugin-based hijack method from working, while code loaded into [[MarkupPostBody]] will be processed as soon as the document is read, even before the TW main() function is invoked.//
<<tiddler MarkupPostBody>>
***/
// // MACRO definitions
//{{{
config.macros.saveStory = {
	label: "set default tiddlers",
	defaultTiddler: "DefaultTiddlers",
	prompt: "store a list of currently displayed tiddlers in another tiddler",
	askMsg: "Enter the name of a tiddler in which to save the current story:",
	tag: "story",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var tid=params[0]?params[0]:"DefaultTiddlers";
		var label=params[1]?params[1]:this.label;
		var tip=params[2]?params[2]:this.prompt;
		var btn=createTiddlyButton(place,label,tip,this.setTiddler,"button");
		btn.setAttribute("tid",tid);
	},
	setTiddler: function() {
		// get list of current open tiddlers
		var tids=[];
		story.forEachTiddler(function(title,element){tids.push("[["+title+"]]")}); // always put titles in brackets
		// get target tiddler
		var tid=this.getAttribute("tid");
		if (!tid || tid=="ask") {
			tid=prompt(config.macros.saveStory.askMsg,config.macros.saveStory.defaultTiddler);
			if (!tid || !tid.length) return; // cancelled by user
		}
		if(store.tiddlerExists(tid) && !confirm(config.messages.overwriteWarning.format([tid]))) return;
		tids=tids.join("\n"); // separate tiddler links by newlines for easier reading
		var t=store.getTiddler(tid); var tags=t?t.tags:[]; tags.push(config.macros.saveStory.tag);
		store.saveTiddler(tid,tid,tids,config.options.txtUserName,new Date(),tags,t?t.fields:null);
		story.displayTiddler(null,tid); story.refreshTiddler(tid,null,true);
		displayMessage(tid+" has been "+(t?"updated":"created"));
	}
}
//}}}

//{{{
if (config.options.chkStoryFold==undefined) config.options.chkStoryFold=true;
if (config.options.chkStoryClose==undefined) config.options.chkStoryClose=true;
config.macros.openStory = {
	label: "open story: %0",
	prompt: "open the set of tiddlers listed in: '%0'",
	popuplabel: "stories",
	popupprompt: "view a set of tiddlers",
	tag: "story",
	selectprompt: "select a story...",
	optionsprompt: "viewing options...",
	foldcmd: "[%0] fold story",
	foldprompt: "fold story tiddlers when opening a story",
	closecmd: "[%0] close others",
	closeprompt: "close other tiddlers when opening a story",
	addcmd: "add a story...",
	addprompt: "create a new story",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if (params[0].toLowerCase()=="list") return this.createList(place,params);
		else if (params[0].toLowerCase()=="popup") return this.createPopup(place,params);
		else this.createButton(place,params);
	},
	showStory: function(tid) {
		var tids=[];
		var tagged=store.getTaggedTiddlers(tid,"title");
		if (tagged.length) // if tiddler IS a tag, use tagged tiddlers as story
			for (var t=0; t<tagged.length; t++) tids.push(tagged[t].title);
		else { // get tiddler list from content
			var t=store.getTiddler(tid);
			if (t) { if (!t.linksUpdated) t.changed(); tids=t.links; }
		}
		// see [[CollapseTiddlersPlugin]] for more info, re: folding tiddlers
		var template=null;
		if (config.options.chkStoryFold) template="CollapsedTemplate";
		if (!store.tiddlerExists("CollapsedTemplate")) template=null;
		if (config.options.chkStoryClose) story.closeAllTiddlers();
		story.displayTiddlers(null,tids,template);
	},
	createButton: function(place,params) {
		var tid=params[0]?params[0]:"";
		var label=params[1]?params[1]:this.label; label=label.format([tid]);
		var tip=params[2]?params[2]:this.prompt; tip=tip.format([tid]);
		var fn=function(){config.macros.openStory.showStory(this.getAttribute("tid"))};
		var btn=createTiddlyButton(place,label,tip,fn,"button");
		btn.setAttribute("tid",tid);
	},
	createPopup: function(place,params) {
		var label=params[1]?params[1]:this.popuplabel;
		var tip=params[2]?params[2]:this.popupprompt;
		var btn=createTiddlyButton(place,label,tip,this.showPopup,"button");
	},
	showPopup: function(ev) { var e=ev||window.event;
		var indent="\xa0\xa0";
		var p=Popup.create(this); if (!p) return false;
		createTiddlyText(createTiddlyElement(p,"li"),config.macros.openStory.selectprompt);
		var stories=store.getTaggedTiddlers("story","title");
		for (var s=0; s<stories.length; s++) {
			var label=indent+stories[s].title;
			var tip=config.macros.openStory.prompt.format([stories[s].title]);
			var fn=function(){config.macros.openStory.showStory(this.getAttribute("tid"))};
			var btn=createTiddlyButton(createTiddlyElement(p,"li"),label,tip,fn,"button");
			btn.setAttribute("tid",stories[s].title);
		}
		createTiddlyText(createTiddlyElement(p,"li"),config.macros.openStory.optionsprompt);
		if (store.tiddlerExists("CollapsedTemplate")) {
			var label=indent+config.macros.openStory.foldcmd.format([config.options.chkStoryFold?"x":"\xa0\xa0"]);
			var tip=config.macros.openStory.foldprompt;
			var fn=function(){config.options.chkStoryFold=!config.options.chkStoryFold;saveOptionCookie('chkStoryFold')};
			var btn=createTiddlyButton(createTiddlyElement(p,"li"),label,tip,fn,"button");
		}
		var label=indent+config.macros.openStory.closecmd.format([config.options.chkStoryClose?"x":"\xa0\xa0"]);
		var tip=indent+config.macros.openStory.closeprompt;
		var fn=function(){config.options.chkStoryClose=!config.options.chkStoryClose;saveOptionCookie('chkStoryClose')};
		var btn=createTiddlyButton(createTiddlyElement(p,"li"),label,tip,fn,"button");
		if (!readOnly) {
			var label=config.macros.openStory.addcmd;
			var tip=config.macros.openStory.addprompt;
			var fn=config.macros.saveStory.setTiddler;
			createTiddlyElement(createTiddlyElement(p,"li"),"hr");
			var btn=createTiddlyButton(createTiddlyElement(p,"li"),label,tip,fn,"button");
		}
		Popup.show(p,false);
		e.cancelBubble=true;if(e.stopPropagation)e.stopPropagation();
		return false;
	},
	createList: function(place,params) {
		var s=createTiddlyElement(place,"select",null,"storyListbox");
		s.size=1;
		s.onchange=function() {
			if (this.value=="_fold") {
				config.options.chkStoryFold=!config.options.chkStoryFold; saveOptionCookie('chkStoryFold');
				config.macros.openStory.refreshList();
			} else if (this.value=="_close") {
				config.options.chkStoryClose=!config.options.chkStoryClose; saveOptionCookie('chkStoryClose');
				config.macros.openStory.refreshList();
			} else if (this.value=="_add")
				config.macros.saveStory.setTiddler.apply(this,arguments);
			else config.macros.openStory.showStory(this.value);
		}
		setStylesheet(".storyListbox { width:100%; }", "StorySaverStyles");
		store.addNotification(null,this.refreshList); this.refreshList();
		return;
	},
	refreshList: function() {
		var indent="\xa0\xa0\xa0\xa0";
		var lists=document.getElementsByTagName("select");
		for (var i=0; i<lists.length; i++) { if (lists[i].className!="storyListbox") continue;
			var here=lists[i];
			while (here.length) here.options[0]=null; // remove current list items
			here.options[here.length]=new Option(config.macros.openStory.selectprompt,"",true,true);
			var stories=store.getTaggedTiddlers("story","title");
			for (var s=0; s<stories.length; s++)
				here.options[here.length]=new Option(indent+stories[s].title,stories[s].title,false,false);
			if (!readOnly)
				here.options[here.length]=new Option(config.macros.openStory.addcmd,"_add",false,false);
			here.options[here.length]=new Option(config.macros.openStory.optionsprompt,"",false,false);
			if (store.tiddlerExists("CollapsedTemplate")) {
				var msg=config.macros.openStory.foldcmd.format([config.options.chkStoryFold?"x":"\xa0\xa0"]);
				here.options[here.length]=new Option(indent+msg,"_fold",false,false);
			}
			var msg=config.macros.openStory.closecmd.format([config.options.chkStoryClose?"x":"\xa0\xa0"]);
			here.options[here.length]=new Option(indent+msg,"_close",false,false);
		}
	}
}
//}}}
/***
|Name|StorySaverPlugin|
|Source|http://www.TiddlyTools.com/#StorySaverPlugin|
|Documentation|http://www.TiddlyTools.com/#StorySaverPluginInfo|
|Version|1.4.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires|MarkupPostBody|
|Overrides|confirmExit(), getParameters()|
|Description|documentation for StorySaverPlugin|
This plugin automatically saves a list of the currently viewed tiddlers (the "story") in a local cookie, {{{txtSavedStory}}} and then opens those tiddlers when the document is subsequently reloaded... the tiddlers you were viewing in the last browser session are automatically redisplayed in the next session, allowing you to quickly resume working with the document from the same place you left off!!

In addition to automatic cookie-based story tracking, the plugin also provides {{{<<saveStory>>}}} and {{{<<openStory>>}}} macros that allow you to quickly save the current story definition to a tiddler, and then re-display saved stories using simple, one-click command links or droplists.
!!!!!Usage
<<<
If a document URL does not contain a 'paramifier' (i.e., a "#..." suffix), then the saved story cookie (if any) will be used ''//as if//'' it had been entered as a 'permaview' (e.g., a "#tiddler tiddler tiddler..." suffix on the URL), bypassing the [[DefaultTiddlers]] definition.  This behavior is automatically applied whenever the plugin is installed in your document.  You can enable/disable the automatic cookie-based StorySaver feature by using the checkbox below:
>''<<option chkSaveStory>> enable StorySaverPlugin''
>//usage:// {{{<<option chkSaveStory>>}}}
You can also temporarily //bypass// the redisplay of a saved story ''without disabling the StorySaver cookie'' by including a trailing "#" at the end of the document URL.  This will cause your document to be loaded into the browser without displaying //any// initial tiddlers at all.  Alternatively, you can enter {{{#story:storyname}}} on the end of the URL (e.g., {{{#story:DefaultTiddlers}}}) to display any specific saved story, regardless of the value of the cookie-based saved story.

__''saveStory macro:''__
The {{{<<saveStory>>}}} macro lets you write the list of currently viewed tiddlers to a specified tiddler name (e.g., "DefaultTiddlers", "MyFavorites", etc.).  Tiddlers containing saved stories are automatically tagged with <<tag story>>, so that they can be recognized by the {{{<<storyViewer>>}}} macro (see [[StoryViewerPlugin]]).  The syntax for the {{{<<saveStory>>}}} macro is:
{{{
<<saveStory storyname label tooltip>>  or   <<saveStory ask label tooltip>>
}}}
where:
* ''storyname''<br>is the target tiddler in which to save the current story.  If you use the keyword, ''ask'', in place of the tiddlername, you will be prompted to enter a tiddler title when saving the story (default: DefaultTiddlers).
* ''label''<br>is the command link text (default: "set default tiddlers").
* ''tooltip''<br>is the command mouseover guide-text (default: "store a list of currently displayed tiddlers in another tiddler").

__''openStory macro:''__
To redisplay a saved story, the {{{<<openStory>>}}} macro can be used to embed either a droplist of all saved stories, or a link for a specified story.  Selecting from the droplist or clicking the link opens the corresponding set of tiddlers.  
{{{
<<openStory list>> OR <<openStory popup label tooltip>> OR <<openStory storyname label tooltip>>
}}}
where:
* ''list''<br>shows a droplist of all saved stories, plus additional commands/viewing options.  Selecting a story opens the corresponding tiddlers.
* ''popup''<br>shows a popup display containing a list of all saved stories, plus additional commands/viewing options.  Selecting a story opens the corresponding tiddlers.  ''label'' and ''tooltip'' are optional and provide alternative display text and 'mouseover' help text, respectively.
* ''storyname''<br>is a tiddler containing a saved story.  //Note: ''You can also use a tag value as a storyname.''  Instead of reading the tiddler list from the contents of the storyname tiddler, the story view will be composed of all tiddlers tagged with the specified tag value.//
* ''label''<br>is the command link text (default: "open story: %0", where %0 is replaced by the storyname).
* ''tooltip''<br>is the command mouseover guide-text (default: "open the set of tiddlers listed in: '%0'"),

__''PermaView command link enhancement:''__
In order to further aide in saving/restoring the list of tiddlers currently being viewed, the core {{{<<permaview>>}}} command has been enhanced, so its link value always includes the current story view tiddler list as a paramifier in the URL.  This let you quickly use the browser's right-click menu directly on the permalink command text to "bookmark this link...".  Depending upon your system, you may also be able to drag the 'permaview' link directly from the page and drop it onto your desktop to create an instant permaview-bearing URL shortcut icon.
<<<
!!!!!Examples
<<<
*{{{<<saveStory TestStory "save a test story">>}}}<br>{{smallform{<<saveStory TestStory "save a test story">>}}}
*{{{<<openStory TestStory>>}}}<br><<openStory TestStory>>
*{{{<<openStory list>>}}}<br>{{smallform{<<openStory list>>}}}
*{{{<<openStory popup label tooltip>>}}}<br>{{smallform{<<openStory popup>>}}}
<<<
!!!!!Revisions
<<<
2008.03.10 [*.*.*] plugin size reduction: documentation moved to [[StorySaverPluginInfo]]
2008.01.01 [1.4.1] sort list of stories alphabetically
2008.01.01 [1.4.0] added option to display a popup instead of a droplist control.  (Provides more compact presentation)
2007.12.31 [1.3.1] instead of readBracketedList(), use internal tiddler.links[] to retrieve story list from tiddler content. Allows more flexible formatting of story tiddler content: anything content that is not a tiddler link is automatically filtered out of the list.
2007.10.23 [1.3.0] split {{{<<storyViewer>>}}} macro definition into stand-alone [[StoryViewerPlugin]] to allow separate installation of story saving vs. story viewing features.
2007.10.21 [1.2.0] added {{{<<openStory>>}}} and {{{<<storyViewer>>}}} macros.
2007.10.20 [1.1.0] in setTiddler(), automatically add "story" tag to saved story tiddlers
2007.10.18 [1.0.1] added default initialization for chkSaveStory option value.  Also, in setTiddler(), call displayTiddler() after saving story to ensure that altered tiddler is shown to the user.
2007.10.05 [1.0.0] initial release.   Moved [[SetDefaultTiddlers]] inline script and rewrote as a {{{<<saveStory>>}}} macro.  Moved permaview "mouseover HREF" enhancement from [[CoreTweaks]].
<<<
/***
|Name|StoryViewerPlugin|
|Source|http://www.TiddlyTools.com/#StoryViewerPlugin|
|Documentation|http://www.TiddlyTools.com/#StoryViewerPluginInfo|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|view tiddlers in a saved story, one at a time, using a droplist or "first/previous/next/last" links|
A "saved story" is a tiddler that contains a whitespace-separated list of tiddler titles.  The {{{<<storyViewer>>}}} macro allows you to quickly ''display //and// navigate between the tiddlers in a saved story'', one at a time, using a droplist containing tiddler titles or individual "first/previous/next/last" text links.
!!!!!Documentation
> see [[StoryViewerPluginInfo]]
!!!!!Revisions
<<<
2008.03.10 [*.*.*] plugin size reduction: documentation moved to [[StoryViewerPluginInfo]]
|please see [[StoryViewerPluginInfo]] for additional revision details|
2007.10.23 [1.0.0] Initial release, split {{{<<storyViewer>>}}} macro definition from [[StorySaverPlugin]] to allow separate installation of story saving vs. story viewing features.
<<<
!!!!!Code
***/
//{{{
version.extensions.StoryViewer= {major: 1, minor: 1, revision: 0, date: new Date(2007,12,31)};
//}}}
//{{{
config.macros.storyViewer = {
	tag: "story",
	storynotfoundmsg: "'%0' is an empty or unrecognized story",
	firstcmd: "first",
	firstbutton: "<<",
	firstmsg: "display first tiddler in story '%0'",
	nextcmd: "next",
	nextbutton: ">",
	nextmsg: "display next tiddler in story '%0'",
	previouscmd: "previous",
	previousbutton: "<",
	previousmsg: "display previous tiddler in story '%0'",
	lastcmd: "last",
	lastbutton: ">>",
	lastmsg: "display last tiddler in story '%0'",
	refreshmsg: "redisplay '%0'",
	refreshmsg: "",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {

		// get name of current tiddler (if any)
		var here=story.findContainingTiddler(place);
		if (here) var tid=here.getAttribute("tiddler");

		var storyname="";
		var p=params.shift();
		if (!p || p=='first'||p=='previous'||p=='here'||p=='next'||p=='last'||p=='list'||p=='links') {
			// find story from current tiddler name
			if (!tid) return; // not in a tiddler... do nothing!
			var stories=store.getTaggedTiddlers(this.tag);
			if (!stories) return;
			for (var s=0; s<stories.length; s++) {
				if (!stories[s].linksUpdated) stories[s].changed();
				var tids=stories[s].links;
				if (tids.contains(tid)) { storyname=stories[s].title; break; }
			}
			if (!storyname.length) return; // current tiddler is not part of a saved story
		}
		else { storyname=p; p=params.shift(); } // user-specified story name

		// get story from tiddler
		var tids=[];
		var tagged=store.getTaggedTiddlers(storyname,"excludeLists");
		if (tagged.length) // if storyname is a tag, get tagged tiddlers rather than links
			for (var t=0; t<tagged.length; t++) tids.push(tagged[t].title);
		else {
			var t=store.getTiddler(storyname);
			if (t && !t.linksUpdated) t.changed();
			var tids=t?t.links:[];
		}
		var i=0;
		switch (p) {
			case 'first':
				i=0;
				break;
			case 'previous':
				if (!tid) return; // not in a tiddler
				i=tids.indexOf(tid);
				if (i==-1) { i=0; break; } // not in story, link to start of story
				i--; if (i<0) i=0;
				break;
			case 'here': // display a refresh link for current tiddler (even if not in a story)
				if (!tid) return; // not in a tiddler
				var label=tid; if (params[0]) label=params.shift();
				createTiddlyButton(place,label,this.refreshmsg.format([tid]),
					function(){ story.refreshTiddler(story.findContainingTiddler(place).getAttribute("tiddler"), null,true); });
				return; 
			case 'next':
				if (!tid) return; // not in a tiddler
				i=tids.indexOf(tid);
				if (i==-1) { i=0; break; } // not in story, link to start of story
				i++; if (i>tids.length-1) i=tids.length-1;
				break;
			case 'last':
				i=tids.length-1;
				break;
			case 'links':
				var out="{{center{{{floatleft{";
				out+="<<storyViewer [["+storyname+"]] first first>> &nbsp; ";
				out+="<<storyViewer [["+storyname+"]] previous previous>> &nbsp; ";
				out+="}}}{{floatright{";
				out+=" &nbsp; <<storyViewer [["+storyname+"]] next next>>";
				out+=" &nbsp; <<storyViewer [["+storyname+"]] last last>>";
				out+="}}}";
				out+=" &nbsp;(story: [["+storyname+"]])&nbsp; ";
				out+="}}}";
				wikify(out,place);
				return;
			case 'list':
			default:
				var nobuttons=false;
				if (params[0]) nobuttons=(params[0].toLowerCase()=="nobuttons");
				if (nobuttons) params.shift();
				var allbuttons=false;
				if (params[0]) allbuttons=(params[0].toLowerCase()=="allbuttons");
				if (allbuttons) params.shift();
				var onlybuttons=false;
				if (params[0]) onlybuttons=(params[0].toLowerCase()=="onlybuttons");
				if (onlybuttons) params.shift();
				var h="";
				h+='<form style="display:inline">';
				if ((!nobuttons||onlybuttons) && allbuttons) {
					h+='<input type="button" value="'+this.firstbutton+'" ';
					h+='	style="padding:0" title="'+this.firstmsg.format([storyname])+'"';
					h+=' onclick="this.form.list.selectedIndex=1; this.form.list.onchange();">';
				}
				if (!nobuttons||onlybuttons) {
					h+='<input type="button" value="'+this.previousbutton+'" ';
					h+='	style="padding:0 0.3em" title="'+this.previousmsg.format([storyname])+'"';
					h+=' onclick="var i=this.form.list.selectedIndex-1; ';
					h+='	if (i<1) i=1; this.form.list.selectedIndex=i; this.form.list.onchange();">';
				}
				h+='<select size="1" name="list"';
				if (onlybuttons) h+=' style="display:none;"';
				h+=' onchange="if (this.value) story.displayTiddler(this,this.value);">';
				h+='<option value="">'+storyname+'...</option>';
				for (i=0; i<tids.length; i++) {
					h+='<option '+
						(tids[i]==tid?'selected ':'')+
						'value="'+tids[i]+'">\xa0\xa0'+tids[i]+'</option>';
				}
				h+='</select>';
				if (!nobuttons||onlybuttons) {
					h+='<input type="button" value="'+this.nextbutton+'" ';
					h+='	style="padding:0 0.3em" title="'+this.nextmsg.format([storyname])+'"';
					h+=' onclick="var i=this.form.list.selectedIndex+1; ';
					h+='	if (i>this.form.list.options.length-1) i=this.form.list.options.length-1; ';
					h+='	this.form.list.selectedIndex=i; this.form.list.onchange();">';
				}
				if ((!nobuttons||onlybuttons) && allbuttons) {
					h+='<input type="button" value="'+this.lastbutton+'" ';
					h+='	style="padding:0" title="'+this.lastmsg.format([storyname])+'"';
					h+=' onclick="this.form.list.selectedIndex=this.form.list.options.length-1; this.form.list.onchange();">';
				}
				h+='</form>';
				createTiddlyElement(place,"span").innerHTML=h;
				return;
		}
		// override default labelling with specified text (if any)
		var label=tids[i]; if (params[0]) label=params.shift();
		if (tid==tids[i]) { // self-referential links turn into 'refresh links'
			var btn=createTiddlyButton(place,null,this.refreshmsg.format([tid]),
				function() { story.refreshTiddler(story.findContainingTiddler(place).getAttribute("tiddler"),null,true); });
			wikify(label,btn); 
		}
		else // create link
			wikify(label,createTiddlyLink(place,tids[i],false));
	}
}
//}}}
/***
|Name|StoryViewerPlugin|
|Source|http://www.TiddlyTools.com/#StoryViewerPlugin|
|Documentation|http://www.TiddlyTools.com/#StoryViewerPluginInfo|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for StoryViewerPlugin|
A "saved story" is a tiddler that contains a whitespace-separated list of tiddler titles.  The {{{<<storyViewer>>}}} macro allows you to quickly ''display //and// navigate between the tiddlers in a saved story'', one at a time, using a droplist containing tiddler titles or individual "first/previous/next/last" text links.
!!!!!Usage
<<<
You can define a saved story by hand-creating a tiddler containing a whitespace-separated list of tiddler titles, e.g., [[DefaultTiddlers]], [[DocumentInfo]], etc.) and tagging that tiddler with <<tag story>>, so that it will be recognized by the {{{<<storyViewer>>}}} macro.  ''You can also use the {{{<<saveStory>>}}} macro (see [[StorySaverPlugin]]), which automatically creates saved stories based on the tiddlers that are currently being viewed.''

The syntax for the {{{<<storyViewer>>}}} macro is:
{{{
<<storyViewer storyname action buttonoption>>
}}}
where:
* ''storyname''<br>is a tiddler containing a saved story.  If you omit the storyname parameter, the plugin will attempt to identify a suitable story by locating the current tiddler title within a saved story tiddler.  The story view controls are not displayed unless the current tiddler title is explicitly found in at least one saved story.  //Note: ''You can also use any tag value as a storyname.''  Instead of reading the tiddler list from the contents of the storyname tiddler, the story view will be composed of all tiddlers tagged with the specified tag value.//
*  ''action'' is one of the following keywords:
** ''list''<br>displays a droplist of tiddlers for the specified story, along with previous/next pushbuttons on either side of the list.  When using the ''list'' action, you may also specify an //optional// parameter to indicate which buttons will appear when using the droplist display:
*** ''allbuttons''<br>displays buttons for first/last as well as previous/next.
*** ''nobuttons''<br>displays the droplist without any buttons
*** ''onlybuttons''<br>hides the droplist and shows just the buttons
** ''first'', ''previous'', ''here'', ''next'', or ''last''<br>displays an individual link to the indicated tiddler within the story. The next/previous links are automatically calculated relative to the current tiddler, while ''here'' displays the current tiddler name as a link that refreshes (re-renders) the tiddler when clicked.
** ''links''<br>displays the complete set of links (first, previous, next and last) with just one convenient macro invocation, allowing you to quickly and easily embed story navigation links into any tiddler content.

You can also embed the {{{<<storyViewer>>}}} macro directly in the ViewTemplate:
{{{
<span class='floatright smallform' macro='storyViewer list allbuttons'></span>
}}}
If you omit the storyname parameter in the template-based macro, it will automatically display the story navigation interface for those tiddlers that are contained in a saved story, while omitting those controls/links for tiddler that are NOT included in a saved story.
<<<
!!!!!Examples
<<<
*{{{<<storyViewer DocumentInfo>>}}}<br>{{smallform{<<storyViewer DocumentInfo>>}}}
*{{{<<storyViewer systemConfig list allbuttons>>}}} //(uses a tag as a storyname)//<br>{{smallform{<<storyViewer systemConfig list allbuttons>>}}}
*{{{<<storyViewer systemConfig links>>}}} //(uses a tag as a storyname)//<br><<storyViewer systemConfig links>>
<<<
!!!!!Revisions
<<<
2008.03.10 [*.*.*] plugin size reduction: documentation moved to [[StoryViewerPluginInfo]]
2007.12.31 [1.1.0] instead of readBracketedList(), use internal tiddler.links[] to retrieve story list from tiddler content.  Allows more flexible formatting of story tiddler content.
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.23 [1.0.0] Initial release, split {{{<<storyViewer>>}}} macro definition from [[StorySaverPlugin]] to allow separate installation of story saving vs. story viewing features.
<<<
/***
|Name|SwitchThemePlugin|
|Source|http://www.TiddlyTools.com/#SwitchThemePlugin|
|Documentation|http://www.TiddlyTools.com/#SwitchThemePluginInfo|
|Version|5.3.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.3|
|Type|plugin|
|Requires||
|Overrides||
|Description|Select alternative TiddlyWiki template/stylesheet 'themes' from a droplist|
!!!!!Documentation
>see [[SwitchThemePluginInfo]]
!!!!!Configuration
<<<
Current theme:<<switchTheme width:auto>>
<<option chkRandomTheme>> select a random theme at startup
//Note: to prevent a given theme from being chosen at random, tag it with <<tag noRandom>>//
<<<
!!!!!Installation Note
>As of 4/13/2008, a "core patch" function that provides backward-compatibility with TW2.3.x has been split into a separate [[SwitchThemePluginPatch]] tiddler to reduce installation overhead for //this// plugin.  ''You should only install [[SwitchThemePluginPatch]] when using this plugin in documents based on a core version prior to TW2.4.0''
!!!!!Revisions
<<<
2008.04.23 [5.3.0] added option for chkRandomTheme (select random theme at startup)
2008.04.13 [5.2.0] moved TW2.3.x fixup for core's switchTheme() function to [[SwitchThemePluginPatch]] and simplified random theme handling.  Also, changed "Web*" prefix to "*ReadOnly" suffix for compatibility with TW240 core convention.
| Please see [[SwitchThemePluginInfo]] for previous revision details |
2008.01.22 [5.0.0] Completely re-written and renamed from [[SelectStylesheetPlugin]] (now retired)
>//history for retired [[SelectStylesheetPlugin]] omitted//
2005.07.20 [1.0.0] Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.switchTheme = {major: 5, minor: 3, revision: 0, date: new Date(2008,4,23)};

config.macros.switchTheme = {
	handler: function(place,macroName,params) {
		setStylesheet(".switchTheme {width:100%;font-size:8pt;margin:0em}","switchThemePlugin");
		if (params[0] && (params[0].substr(0,6)=="width:"))	var width=(params.shift()).substr(6);
		if (params[0] && (params[0].substr(0,6)=="label:"))	var label=(params.shift()).substr(6);
		if (params[0] && (params[0].substr(0,7)=="prompt:"))	var prompt=(params.shift()).substr(7);
		if (params[0] && params[0].trim().length) // create a link that sets a specific theme
			createTiddlyButton(place,label?label:params[0],prompt?prompt:params[0],
				function(){ config.macros.switchTheme.set(params[0]); return false;});
		else { // create a select list of available themes
			var theList=createTiddlyElement(place,"select",null,"switchTheme",null);
			theList.size=1;
			if (width) theList.style.width=width;
			theList.onchange=function() { config.macros.switchTheme.set(this.value); return true; };
			this.refresh(theList);
		}
	},
	refresh: function(list) {
		var indent = String.fromCharCode(160)+String.fromCharCode(160);
		while(list.length > 0){list.options[0]=null;} // clear list
		list.options[list.length] = new Option("select a theme:","",true,true);
		list.options[list.length] = new Option(indent+"[default]","StyleSheet");
		list.options[list.length] = new Option(indent+"[random]","*");
		var themes=store.getTaggedTiddlers("systemTheme");
		for (var i=0; i<themes.length; i++) if (themes[i].title!="StyleSheet")
			list.options[list.length]=new Option(indent+themes[i].title,themes[i].title);
		// show current selection
		for (var t=0; t<list.options.length; t++)
			if (list.options[t].value==config.options.txtTheme)
				{ list.selectedIndex=t; break; }
	},
	set: function(theme) {
		if (!theme||!theme.trim().length) return;
		if (theme=="*") { // select a random theme (excluding themes tagged with "noRandom")
			var themes=store.getTaggedTiddlers("systemTheme"); if (!themes.length) return false;
			var which=Math.floor(Math.random()*themes.length);
			while (themes[which].title==config.options.txtTheme||themes[which].isTagged("noRandom"))
				which=Math.floor(Math.random()*themes.length);
			theme=themes[which].title;
		}
		// apply and remember selected theme
		story.switchTheme(theme);
		config.options.txtTheme=theme;
		saveOptionCookie("txtTheme");
		// sync theme droplists
		var elems=document.getElementsByTagName("select");
		var lists=[]; for (var i=0; i<elems.length; i++)
			if (hasClass(elems[i],"switchTheme")) lists.push(elems[i]);
		for (var k=0; k<lists.length; k++)
			for (var t=0; t<lists[k].options.length; t++)
				if (lists[k].options[t].value==config.options.txtTheme)
					{ lists[k].selectedIndex=t; break; }
		return;
	}
}
//}}}

// // select a random theme at startup (if enabled)
//{{{
if (config.options.chkRandomTheme===undefined)
	config.options.chkRandomTheme=false;
if (config.options.chkRandomTheme)
	config.macros.switchTheme.set("*");
//}}}
/***
|Name|SwitchThemePluginInfo|
|Source|http://www.TiddlyTools.com/#SwitchThemePlugin|
|Documentation|http://www.TiddlyTools.com/#SwitchThemePluginInfo|
|Version|5.3.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.3|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for SwitchThemePlugin|
This plugin replaces the features previously provided by SelectStylesheetPlugin (which has been retired from distribution because it is no longer compatible with the current release of the TiddlyWiki core).

Please note: ''//This plugin requires TiddlyWiki version 2.3.0 or later//''
!!!!!Usage
<<<
{{medium{__Defining a theme:__}}}
First, create a new tiddler (or import an existing tiddler) containing the desired CSS definitions and tag that tiddler with<<tag systemTheme>>.  At the top of that tiddler, embed a //slice table// that defines at least one slice, "~StyleSheet", whose value is the name of the tiddler itself, e.g., in a tiddler called [[MyTheme]], you would write:
{{{
/***
|StyleSheet|MyTheme|
***/
}}}
>Take note of the use of {{{/***}}} and {{{***/}}} surrounding the slice table syntax.   This is a ~TiddlyWiki-enhanced comment syntax that, when used in a stylesheet, permits the browser to ignore any wiki-syntax that has been embedded within the tiddler while still processing the ~CSS-syntax it contains.
In addition to the "~StyleSheet" slice entry, a theme tiddler can also contain one or more slices that associate customized versions of [[PageTemplate]], [[ViewTemplate]], and/or [[EditTemplate]], for use with that theme:
{{{
/***
|PageTemplate|MyPageTemplate|
|ViewTemplate|MyViewTemplate|
|EditTemplate|MyEditTemplate|
***/
}}}
where the slice //name// is the standard template name, and the slice //value// is the title of the alternative custom template that will be used when that theme is selected.

You can also associate a secondary set of ''"read only" templates that will be automatically applied whenever a document is being viewed online'' (i.e., via http: protocol)
{{{
|PageTemplateReadOnly|MyWebPageTemplate|
|ViewTemplateReadOnly|MyWebViewTemplate|
|EditTemplateReadOnly|MyWebEditTemplate|
}}}
These definitions can be used to seemlessly present a reduced-feature "reader" interface when your document is being viewed on-line by others, while still offering you access to the full-featured "author" interface when you are updating your content locally.

{{medium{__Selecting a theme from a droplist:__}}}
To display a droplist of available themes, use this syntax:
{{{
<<switchTheme width:nnn>>
}}}
where ''width:nnn[cm|px|em|%]'' is optional, and overrides the built-in CSS width declaration (=100%).  Use standard CSS width units (cm=centimeters, px=pixels, em=M-space, %=proportional to containing area).  You can also use a ".switchTheme" custom CSS class definition to override the built-in CSS declarations.}}}

All tiddlers tagged with<<tag systemTheme>> will be included in the droplist of available themes for you to select.  The currently selected theme is remembered between browser sessions using a TiddlyWiki option cookie ("txtTheme").  Each time you reload your document, the selected theme is automatically re-applied, based on the stored cookie value.  If there is no cookie or the selected theme no longer exists in the document (e.g., it was deleted/renamed after being selected), the [default] CSS tiddler, [[StyleSheet]], will be used as a fallback theme.  If [random] is seleced, the plugin automatically selects a random theme.  You can exclude a theme from being randomly selected by tagging it with <<tag noRandom>>.

Example:
{{{<<switchTheme width:30%>>}}}
<<switchTheme width:30%>>

{{medium{__Selecting a theme from a command link:__}}}
The {{{<<switchTheme>>}}} macro can also be used to embed a command link that, when clicked, will apply a specific, pre-selected theme, using the following syntax:
{{{
<<switchTheme "label:link text" "prompt:tooltip text" TiddlerName>>
}}}
where:
* {{block{
''label:text'' and ''prompt:text'' (optional)
define the link text the 'tooltip' text that appears near the mouse pointer when placed over the link, respectively.}}}
* {{block{
''~TiddlerName''
specifies the name of the theme tiddler to be applied (e.g., {{{<<switchTheme [[Woodshop]]>>}}}}}}
Examples:
{{{
<<switchTheme Plain>>
<<switchTheme Blackout>> 
<<switchTheme Woodshop>>
<<switchTheme Textures>>
<<switchTheme [[Edge of Night]]>>
<<switchTheme label:[default] StyleSheet>>
<<switchTheme label:randomize *>>
}}}
<<switchTheme Plain>> <<switchTheme Blackout>> <<switchTheme Woodshop>> <<switchTheme Textures>> <<switchTheme [[Edge of Night]]>> <<switchTheme label:[default] StyleSheet>> <<switchTheme label:randomize *>>

NOTE:
>You can also create a command link that specifies "*" for the theme name.  This will select a theme //at random// from the current list of available themes.  Once selected, the theme is re-applied each time the document is loaded, unless a different theme selection is subsequently made.  To prevent a given theme from being chosen at random, tag it with <<tag noRandom>>.
<<<
!!!!!Configuration
<<<
<<option chkRandomTheme>> select a random theme at startup
//Note: to prevent a given theme from being chosen at random, tag it with <<tag noRandom>>//
<<<
!!!!!Revisions
<<<
2008.04.23 [5.3.0] added option for chkRandomTheme (select random theme at startup)
2008.04.13 [5.2.0] moved TW2.3.x fixup for core's switchTheme() function to [[SwitchThemePluginPatch]] and simplified random theme handling.  Also, changed "Web*" prefix to "*ReadOnly" suffix for compatibility with TW240 core convention.
2008.02.01 [5.1.3] in response to a change for core ticket #435 (see http://trac.tiddlywiki.org/changeset/3450) -- in switchTheme, use config.refresherData.* values (if defined), instead of config.refreshers.*  This change allows the plugin to work with both the current release (~TW230) AND the upcoming ~TW240 release.
2008.02.01 [5.1.2] in switchTheme, replace hard-coded "~StyleSheet" with config.refreshers.stylesheet (used as name of loaded styles)
2008.01.30 [5.1.1] changed tag-detection to use "systemTheme" instead of "theme" for compatibility with core theme switching mechanism.
2008.01.26 [5.1.0] added support for txtTheme="*" (applies random theme at startup) and {{{<<randomTheme>>}}} macro (selects/applies a random theme when a command link is clicked)
2008.01.25 [5.0.1] in refresh() and set(), removed use of ">" to indicate current theme 
2008.01.22 [5.0.0] Completely re-written and renamed from [[SelectStylesheetPlugin]] (now retired)
>//previous history for [[SelectStylesheetPlugin]] omitted//
2005.07.20 [1.0.0] Initial Release
<<<
/***
|Name|SwitchThemePluginPatch|
|Source|http://www.TiddlyTools.com/#SwitchThemePluginPatch|
|Documentation|http://www.TiddlyTools.com/#SwitchThemePluginPatch|
|Version|5.2.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.3|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.switchTheme|
|Description|Patch core switchTheme() function for backward-compatibility with TW2.3.0 and earlier|
!!!!!Usage
<<<
This "patch" plugin provides backward-compatibility needed to enable [[SwitchThemePlugin]] to operate correctly under TW2.3.x or earlier.
{{medium{You should not install this plugin if you are using TW2.4.0 or above}}}
<<<
!!!!!Revisions
<<<
2008.05.09 [5.2.1] Simplified patch code for use with TW230 ONLY - NOT NEEDED FOR TW240 or above
2008.04.13 [5.2.0] moved from SwitchThemePlugin and updated for TW240b1.  Patch code will be simplified further once TW240 final release is available.
<<<
!!!!!Code
***/
//{{{
// OVERRIDE OF CORE story.switchTheme()
// for use with TW230, which uses config.refreshers, while TW240 uses config.refresherData
// also provides fallback for existing Web* slice naming convention
if (!config.refresherData) { // DETECT TW2.3
Story.prototype.switchTheme = function(theme)
{
	if(safeMode) 
		return;
		
	isAvailable = function(title) { 
		var s = title ? title.indexOf(config.textPrimitives.sectionSeparator) : -1; 
		if(s!=-1) 
			title = title.substr(0,s); 
		return store.tiddlerExists(title) || store.isShadowTiddler(title); 
 	};

	getSlice = function(theme,slice) {
		if(readOnly)
			var r = store.getTiddlerSlice(theme,slice+"ReadOnly")
		            || store.getTiddlerSlice(theme,"Web"+slice); // fallback naming convention
		var r = r || store.getTiddlerSlice(theme,slice);
		if(r && r.indexOf(config.textPrimitives.sectionSeparator)==0)
			r = theme + r;
		return isAvailable(r) ? r : slice;
	};

	replaceNotification = function(i,name,theme,slice) {
		var newName = getSlice(theme,slice);
		if(name!=newName && store.namedNotifications[i].name==name) {
			store.namedNotifications[i].name = newName;
			return newName;
		}
		return name;
	};

	var pt = config.refreshers.pageTemplate;
	var vi = DEFAULT_VIEW_TEMPLATE;
	var vt = config.tiddlerTemplates[vi];
	var ei = DEFAULT_EDIT_TEMPLATE;
	var et = config.tiddlerTemplates[ei];

	for(var i=0; i<config.notifyTiddlers.length; i++) {
		var name = config.notifyTiddlers[i].name;
		switch(name) {
		case "PageTemplate":
			config.refreshers.pageTemplate = replaceNotification(i,config.refreshers.pageTemplate,theme,name);
			break;
		case "StyleSheet":
			removeStyleSheet(config.refreshers.styleSheet);
			config.refreshers.styleSheet = replaceNotification(i,config.refreshers.styleSheet,theme,name);
			break;
		case "ColorPalette":
			config.refreshers.colorPalette = replaceNotification(i,config.refreshers.colorPalette,theme,name);
			break;
		default:
			break;
		}
	}
	config.tiddlerTemplates[vi] = getSlice(theme,"ViewTemplate");
	config.tiddlerTemplates[ei] = getSlice(theme,"EditTemplate");
	if(!startingUp) {
		var switchedTemplates=config.refreshers.pageTemplate!=pt || config.tiddlerTemplates[vi]!=vt || config.tiddlerTemplates[ei]!=et;
		if(switchedTemplates) {
			refreshAll();
			story.refreshAllTiddlers(true);
		} else {
			setStylesheet(store.getRecursiveTiddlerText(config.refreshers.styleSheet,"",10),config.refreshers.styleSheet);
		}
		config.options.txtTheme = theme;
		saveOptionCookie("txtTheme");
	}
};
} // end if (!config.refresherData) 
//}}}
/***
|''Name:''|TableSortingPlugin|
|''Description:''|Dynamically sort tables by clicking on column headers|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#TableSortingPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.02|
|''Date:''|25-01-2008|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.3|
!!Usage:
* Make sure your table has a header row
** {{{|Name|Phone Number|Address|h}}}<br> Note the /h/ that denote a header row 
* Give the table a class of 'sortable'
** {{{
|sortable|k
|Name|Phone Number|Address|h
}}}<br>Note the /k/ that denotes a class name being assigned to the table.
* To disallow sorting by a column, place {{{<<nosort>>}}} in it's header
* To automatically sort a table by a column, place {{{<<autosort>>}}} in the header for that column
** Or to sort automatically but in reverse order, use {{{<<autosort reverse>>}}}

!!Example:
|sortable|k
|Name |Salary |Extension |Performance |File Size |Start date |h
|ZBloggs, Fred |$12000.00 |1353 |+1.2 |74.2Kb |Aug 19, 2003 21:34:00 |
|ABloggs, Fred |$12000.00 |1353 |1.2 |3350b |09/18/2003 |
|CBloggs, Fred |$12000 |1353 |1.200 |55.2Kb |August 18, 2003 |
|DBloggs, Fred |$12000.00 |1353 |1.2 |2100b |07/18/2003 |
|Bloggs, Fred |$12000.00 |1353 |01.20 |6.156Mb |08/17/2003 05:43 |
|Turvey, Kevin |$191200.00 |2342 |-33 |1b |02/05/1979 |
|Mbogo, Arnold |$32010.12 |2755 |-21.673 |1.2Gb |09/08/1998 |
|Shakespeare, Bill |£122000.00|3211 |6 |33.22Gb |12/11/1961 |
|Shakespeare, Hamlet |£9000 |9005 |-8 |3Gb |01/01/2002 |
|Fitz, Marvin |€3300.30 |5554 |+5 |4Kb |05/22/1995 |

***/
// /%
//!BEGIN-PLUGIN-CODE
config.tableSorting = {
	
	darrow: "\u2193",
	
	uarrow: "\u2191",
	
	getText : function (o) {
		var p = o.cells[SORT_INDEX];
		return p.innerText || p.textContent || '';
	},
	
	sortTable : function (o,rev) {
		SORT_INDEX = o.getAttribute("index");
		var c = config.tableSorting;
		var T = findRelated(o.parentNode,"TABLE");
		if(T.tBodies[0].rows.length<=1) 
			return;
		var itm = "";
		var i = 0;
		while (itm == "" && i < T.tBodies[0].rows.length) {
			itm = c.getText(T.tBodies[0].rows[i]).trim();
			i++;
		}
		if (itm == "") 
			return; 	
		var r = [];
		var S = o.getElementsByTagName("span")[0];		
		c.fn = c.sortAlpha; 
		if(!isNaN(Date.parse(itm)))
			c.fn = c.sortDate; 
		else if(itm.match(/^[$|£|€|\+|\-]{0,1}\d*\.{0,1}\d+$/)) 
			c.fn = c.sortNumber; 
		else if(itm.match(/^\d*\.{0,1}\d+[K|M|G]{0,1}b$/)) 
			c.fn = c.sortFile; 
		for(i=0; i<T.tBodies[0].rows.length; i++) {
			 r[i]=T.tBodies[0].rows[i]; 
		} 
		r.sort(c.reSort);
		if(S.firstChild.nodeValue==c.darrow || rev) {
			r.reverse();
			S.firstChild.nodeValue=c.uarrow;
		} 
		else 
			S.firstChild.nodeValue=c.darrow;
		var thead = T.getElementsByTagName('thead')[0]; 
		var headers = thead.rows[thead.rows.length-1].cells;
		for(var k=0; k<headers.length; k++) {
			if(!hasClass(headers[k],"nosort"))
				addClass(headers[k].getElementsByTagName("span")[0],"hidden");
		}
		removeClass(S,"hidden");
		for(i=0; i<r.length; i++) { 
			T.tBodies[0].appendChild(r[i]);
			c.stripe(r[i],i);
			for(var j=0; j<r[i].cells.length;j++){
				removeClass(r[i].cells[j],"sortedCol");
			}
			addClass(r[i].cells[SORT_INDEX],"sortedCol");
		}
	},
	
	stripe : function (e,i){
		var cl = ["oddRow","evenRow"];
		i&1? cl.reverse() : cl;
		removeClass(e,cl[1]);
		addClass(e,cl[0]);
	},
	
	sortNumber : function(v) {
		var x = parseFloat(this.getText(v).replace(/[^0-9.-]/g,''));
		return isNaN(x)? 0: x;
	},
	
	sortDate : function(v) {
		return Date.parse(this.getText(v));
	},

	sortAlpha : function(v) {
		return this.getText(v).toLowerCase();
	},
	
	sortFile : function(v) { 		
		var j, q = config.messages.sizeTemplates, s = this.getText(v);
		for (var i=0; i<q.length; i++) {
			if ((j = s.toLowerCase().indexOf(q[i].template.replace("%0\u00a0","").toLowerCase())) != -1)
				return q[i].unit * s.substr(0,j);
		}
		return parseFloat(s);
	},
	
	reSort : function(a,b){
		var c = config.tableSorting;
		var aa = c.fn(a);
		var bb = c.fn(b);
		return ((aa==bb)? 0 : ((aa<bb)? -1:1));
	}
};

Story.prototype.tSort_refreshTiddler = Story.prototype.refreshTiddler;
Story.prototype.refreshTiddler = function(title,template,force,customFields,defaultText){
	var elem = this.tSort_refreshTiddler.apply(this,arguments);
	if(elem){
		var tables = elem.getElementsByTagName("TABLE");
		var c = config.tableSorting;
		for(var i=0; i<tables.length; i++){
			if(hasClass(tables[i],"sortable")){
				var x = null, rev, table = tables[i], thead = table.getElementsByTagName('thead')[0], headers = thead.rows[thead.rows.length-1].cells;
				for (var j=0; j<headers.length; j++){
					var h = headers[j];
					if (hasClass(h,"nosort"))
						continue;
					h.setAttribute("index",j);
					h.onclick = function(){c.sortTable(this); return false;};
					h.ondblclick = stopEvent;
					if(h.getElementsByTagName("span").length == 0)
						createTiddlyElement(h,"span",null,"hidden",c.uarrow); 
					if(!x && hasClass(h,"autosort")) {
						x = j;
						rev = hasClass(h,"reverse");
					}
				}
				if(x)
					c.sortTable(headers[x],rev);		
			}
		}
	}
	return elem; 
};

setStylesheet("table.sortable span.hidden {visibility:hidden;}\n"+
	"table.sortable thead {cursor:pointer;}\n"+
	"table.sortable .nosort {cursor:default;}\n"+
	"table.sortable td.sortedCol {background:#ffc;}","TableSortingPluginStyles");

function stopEvent(e){
	var ev = e? e : window.event;
	ev.cancelBubble = true;
	if (ev.stopPropagation) ev.stopPropagation();
	return false;	
}	

config.macros.nosort={
	handler : function(place){
		addClass(place,"nosort");
	}	
};

config.macros.autosort={
	handler : function(place,m,p,w,pS){
		addClass(place,"autosort"+" "+pS);		
	}	
};
//!END-PLUGIN-CODE
// %/
/***
| Name:|''tagAdder''|
| Created by:|SaqImtiaz|
| Location:|http://tw.lewcid.org/|
| Version:|0.61 (07 Apr-2006)|
| Requires:|~TW2.07|
!About
*provides a drop down list for toggling tags 
*you can specify which tags to list, and have multiple drop downs with different tag lists.

!Demonstration
<<tagAdder>>
{{{<<tagAdder>>}}}

''I recommend using either tagAdder or monkeyTagger, with dropTags and dropTagging in the toolbar:''


!Installation:
*Copy this tiddler to your TW with the systemConfig tag
* copy the following to your ViewTemplate:
#either {{{
<div class='tagged' macro='tagAdder'></div>
}}} to add to next to the tags macro in the viewer area, or
#{{{<div class='toolbar' >
<span style="padding-right:1.75em;" macro='tagAdder'></span>
<span macro='toolbar -closeTiddler closeOthers +editTiddler permalink references jump'></span></div>}}} to add to the toolbar.
(adjust padding to taste)

!Usage:
*by default {{{<<tagAdder>>}}} will display drop down list of all tags, with tags present on the tiddler grouped together.
*to sort alphabetically (ignoring the [x]), use {{{<<tagAdder 'nogroup'>>}}}
*to specify what tags to list, use {{{<<tagAdder 'group/nogroup' 'tiddler'>>}}} where tiddler is a tiddler that is tagged with the tags you want to list. (use one of either group or no group, not both!)
Eg: TagDataBase is my tiddler that is tagged with the tags I want to list, so I will use {{{<<tagAdder 'group' 'TagDataBase'>>}}}
 for a list like this: <<tagAdder 'group' 'TagDataBase'>>
*you can specify a custom label by giving the macro an additional parameter.
Eg: {{{<<tagAdder 'group' 'TagDataBase' 'custom label'>>}}} gives <<tagAdder 'group' 'TagDataBase' 'custom label'>>

!Tips:
*On the tiddler you want to use as your TagsDataBase, add {{{<<tagAdder>>}}} for a drop down list of all tags, so you can easily toggle tags on it!
*You can have as many TagDataBases as you like.

!Notes:
*use css to style to taste
*tags to be removed are preceded by [x]

!To Do:
*Combine with features of normal tags drop down list.(drop tag macro)
*TagsDB manager
*''add exclude tag feature''

!History
*07 Apr-2006, version 0.61
**fixed IE bug with not returning false 

!CODE
***/
//{{{

config.macros.tagAdder= {};
//config.macros.tagAdder.dropdownchar = (document.all?"â–¼":"â–¾"); // the fat one is the only one that works in IE
config.macros.tagAdder.dropdownchar = "â–¼"; // uncomment previous line and comment this for smaller version in FF
config.macros.tagAdder.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
 var arrow=': '+ config.macros.tagAdder.dropdownchar;
 var tAsort = (params[0] && params[0] !='.') ? params[0]: 'group';
 if (params[1]){var tAsource=params[1]};
 if ((tAsource)&&(!store.getTiddler(tAsource)))
 return false;
 var tAlabel= (params[2] && params[2] !='.')? params[2]: 'toggle tags'+arrow;
 var tAtooltip= (params[2] && params[2] !='.')? params[2]: 'toggle tags on this tiddler';

 if(tiddler instanceof Tiddler)
 {
 var title = tiddler.title;
 var lingo = config.views.editor.tagChooser;
 
 var ontagclick = function(e) {
 if (!e) var e = window.event;
 var tag = this.getAttribute("tag");

 var t=store.getTiddler(title);
 if (!t || !t.tags) return;
 if (t.tags.find(tag)==null)
 {t.tags.push(tag)}
 else
 {t.tags.splice(t.tags.find(tag),1)};
 story.saveTiddler(title);
 story.refreshTiddler(title,null,true);
 return false;
 };

 var onclick = function(e) {
 if (!e) var e = window.event;
 var popup = Popup.create(this);
 var t=store.getTiddler(title);
 if (!t) return false;
 var tagsarray = store.getTags();
 var tagsvalue=new Array();

 for (var i=0; i<tagsarray.length; i++){
 var thetagonly= (tagsarray[i][0]);
 tagsvalue.push(thetagonly);}

 if (tAsource)
 {var sourcetiddler=store.getTiddler(tAsource);
 var tagsvalue=sourcetiddler.tags;
 }
 var tagslabel=new Array();
 var tagssorted=new Array();

 for (var i=0;i<tagsvalue.length;i++){
 var temptag=(tagsvalue[i]);
 if (t.tags.find(temptag)==null)
 {var temptagx = '[ ] '+temptag;
 tagslabel.push(temptagx);
 tagssorted.push(temptag);
 }
 else
 {var temptagx ='[x] '+temptag;
 if (tAsort=='group'){
 tagslabel.unshift(temptagx);
 tagssorted.unshift(temptag);}
 else if (tAsort=='nogroup'){
 tagslabel.push(temptagx);
 tagssorted.push(temptag);} }
 ;}


 if(tagsvalue.length == 0)
 createTiddlyText(createTiddlyElement(popup,"li"),lingo.popupNone);
 for (var t=0; t<tagsvalue.length; t++)
 {
 var theTag = createTiddlyButton(createTiddlyElement(popup,"li"),tagslabel[t],"toggle '"+([tagssorted[t]])+"'",ontagclick);
 theTag.setAttribute("tag",tagssorted[t]);
 }
 Popup.show(popup,false);
 e.cancelBubble = true;
 if (e.stopPropagation) e.stopPropagation();
 return(false);
 };
 //createTiddlyButton(place,tAlabel,tAtooltip,onclick);
var createdropperButton = function(place){
var sp = createTiddlyElement(place,"span",null,"tagadderbutton");
var theDropDownBtn = createTiddlyButton(sp,tAlabel,tAtooltip,onclick);
};

createdropperButton(place);
}
};
setStylesheet(
 ".toolbar .tagadderbutton { margin-right:0em; border:0px solid #eee; padding:0px; padding-right:0px; padding-left:0px; }\n"+
 ".tagadderbutton a.button { padding:2px; padding-left:2px; padding-right:2px;}\n"+
// ".tagadderbutton {font-size:150%;}\n"+
 "",
"TagAdderStyles");

//}}}

/***
|Name|TagCloudPlugin|
|Source|http://www.TiddlyTools.com/#TagCloudPlugin|
|Version|0.0.0|
|Author|Clint Checketts|
|License|unknown|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description||

!Usage
<<tagCloud>>

!Code
***/
//{{{
version.extensions.tagCloud = {major: 1, minor: 0 , revision: 0, date: new Date(2006,2,04)};
//Created by Clint Checketts, contributions by Jonny Leroy and Eric Shulman

config.macros.tagCloud = {
 noTags: "No tag cloud created because there are no tags.",
 tooltip: "%1 tiddlers tagged with '%0'"
};

config.shadowTiddlers.TagCloud="<<tagCloud>>";

config.macros.tagCloud.handler = function(place,macroName,params) {
 
var tagCloudWrapper = createTiddlyElement(place,"div",null,"tagCloud",null);

var tags = store.getTags();
for (var t=0; t<tags.length; t++) {
  for (var p=0;p<params.length; p++) if (tags[t][0] == params[p]) tags[t][0] = "";
}

 if(tags.length == 0) 
   createTiddlyElement(tagCloudWrapper,"span",null,null,this.noTags);
 //Findout the maximum number of tags
 var mostTags = 0;
 for (var t=0; t<tags.length; t++) if (tags[t][0].length > 0){
  if (tags[t][1] > mostTags) mostTags = tags[t][1];
 }
 //divide the mostTags into 4 segments for the 4 different tagCloud sizes
 var tagSegment = mostTags / 4;

  for (var t=0; t<tags.length; t++) if (tags[t][0].length > 0){
 var tagCloudElement = createTiddlyElement(tagCloudWrapper,"span",null,null,null);
 tagCloudWrapper.appendChild(document.createTextNode(" "));
 var theTag = createTiddlyButton(tagCloudElement,tags[t][0],this.tooltip.format(tags[t]),onClickTag,"tagCloudtag tagCloud" + (Math.round(tags[t][1]/tagSegment)+1));
  theTag.setAttribute("tag",tags[t][0]);
 }

};

setStylesheet(".tagCloud span{height: 1.8em;margin: 3px;}.tagCloud1{font-size: 1.2em;}.tagCloud2{font-size: 1.4em;}.tagCloud3{font-size: 1.6em;}.tagCloud4{font-size: 1.8em;}.tagCloud5{font-size: 1.8em;font-weight: bold;}","tagCloudsStyles");
//}}}
/***
|Name|TagGridPlugin|
|Source|http://www.TiddlyTools.com/#TagGridPlugin|
|Documentation|http://www.TiddlyTools.com/#TagGridPluginInfo|
|Version|1.7.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Generate a cross-referenced grid of tiddlers, based on tag values|
!!!!!Documentation
>see [[TagGridPluginInfo]]
!!!!!Revisions
<<<
2008.04.21 [1.7.0] added support for "filter:..." param to exclude tiddlers from grid
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.07.24 [1.6.5] corrected handling for @TiddlerName with excluded tags, so that excluded tags are not actually removed from the @TiddlerName source tiddler.
|please see [[TagGridPluginInfo]] for additional revision details|
2006.10.05 [1.0.0] initial release (converted from prototype inline script)
<<<
!!!!!Code
***/
//{{{
version.extensions.tagGrid= {major: 1, minor: 7, revision: 0, date: new Date(2008,4,21)};

config.macros.tagGrid= {
	verbose:false, // display debugging/performance feedback messages
	warn:true,	// display workload warning message before rendering
	threshold:300000, // workload warning threshold (workload=# of comparisons to perform)
	handler:
	function(place,macroName,params) {

		// get columns
		var columntags=params.shift(); var cols=[];
		if ((!columntags)||(columntags=="all")) // no param (or "all") - use all tags
			{ var all=store.getTags(); for (i=0;i<all.length;i++) cols.push(all[i][0]); }
		else if (columntags.substr(0,1)=="+") // get tag list from tiddler content
			{ var t=store.getTiddlerText(columntags.substr(1)); if (t&&t.length) cols=t.readBracketedList(); }
		else if (columntags.substr(0,1)=="@") // get tag list from tiddler tags
			{ var t=store.getTiddler(columntags.substr(1)); if (t&&t.tags) for (i=0;i<t.tags.length;i++) cols.push(t.tags[i]); }
		else if (columntags.substr(0,1)=="=")  // get names of "tagtiddlers" tagged with meta-tag
			{ var t=store.getTaggedTiddlers(columntags.substr(1)); for (i=0;i<t.length;i++) cols.push(t[i].title); }
		else cols=columntags.readBracketedList();
		if (!cols.length) { wikify("~TagGrid: no columns to display\n",place); return; }

		// exclude specific column tags
		if (params[0]&&params[0].substr(0,8)=="exclude:") {
			var ex=params.shift().substr(8).readBracketedList();
			for (x=0; x<ex.length; x++) {
				var i=cols.indexOf(ex[x]);
				if (i!=-1) cols.splice(i,1); // remove excluded tags
			}
		}

		// get rows
		var rowtags=params.shift(); var rows=[];
		if ((!rowtags)||(rowtags=="all")) // no param (or "all") - use all tags
			{ var all=store.getTags(); for (i=0;i<all.length;i++) rows.push(all[i][0]); }
		else if (rowtags.substr(0,1)=="+") // get tag list from tiddler content
			{ var t=store.getTiddlerText(rowtags.substr(1)); if (t&&t.length) rows=t.readBracketedList(); }
		else if (rowtags.substr(0,1)=="@") // get tag list from tiddler tags
			{ var t=store.getTiddler(rowtags.substr(1)); if (t&&t.tags) for (i=0;i<t.tags.length;i++) rows.push(t.tags[i]); }
		else if (rowtags.substr(0,1)=="=")  // get names of "tagtiddlers" tagged with meta-tag
			{ var t=store.getTaggedTiddlers(rowtags.substr(1)); for (i=0;i<t.length;i++) rows.push(t[i].title); }
		else rows=rowtags.readBracketedList();
		if (!rows.length) { wikify("~TagGrid: no rows to display\n",place); return; }

		// exclude specific row tags
		if (params[0]&&params[0].substr(0,8)=="exclude:") {
			var ex=params.shift().substr(8).readBracketedList();
		 	for (x=0; x<ex.length; x++) {
				var i=rows.indexOf(ex[x]);
				if (i!=-1) rows.splice(i,1); // remove excluded tags
			}
		}

		// get optional tiddler filter
		if (params[0]&&params[0].substr(0,7).toUpperCase()=="FILTER:")
			var filter=params.shift().substr(7);

		// get optional flag keywords and/or color gradient endpoints
		var defOpen=false;
		var colorAll=false;
		var sortRows=false;
		var sortColumns=false;
		var showInline=false;
		var p=params.shift();
		while (p) {
			switch (p.toUpperCase()) {
				case "OPEN":
					defOpen=true; break;
				case "COLORALL":
					colorAll=true; break;
				case "SORTROWS":
					sortRows=true; break;
				case "SORTCOLUMNS":
					sortColumns=true; break;
				case "INLINE":
					showInline=true; break;
				default:
					if (startcolor==undefined) var startcolor=p;
					else if (endcolor==undefined) var endcolor=p;
					else alert("unexpected parameter: '"+p+"'");
					break;
			}
			p=params.shift();
		}

		// get the tiddlers
		if (filter&&filter.length)
			var tiddlers=store.filterTiddlers(filter);
		else
			var tiddlers=store.getTiddlers("modified","excludeLists");

		// show "workload warning"... get permission to proceed...
		if (this.warn) {
			var workload=rows.length*cols.length*tiddlers.length;
			var warning="Cross-indexing %0 tiddlers in %1 row%3 by %2 column%4...\n(up to %5 comparisons MAY be needed)\n\n";
			warning+="This may take a while.  It is OK to proceed?";
			warning=warning.format([tiddlers.length,rows.length,cols.length,rows.length!=1?"s":"",cols.length!=1?"s":"",workload]);
			if (workload>this.threshold&&!confirm(warning)) { wikify("~TagGrid: display cancelled by user\n",place); return; }
		}

		// sort row and column tags in decending order, by frequency of use
		if (sortRows||sortColumns) {
			var tags=store.getTags(); var tagcount={}; for (i=0; i<tags.length; i++) tagcount[tags[i][0]]=tags[i][1];
			if (sortRows) rows.sort(function(a,b){return (!tagcount[a]||tagcount[a]<tagcount[b])?+1:(tagcount[a]==tagcount[b]?0:-1);});
			if (sortColumns) cols.sort(function(a,b){return (!tagcount[a]||tagcount[a]<tagcount[b])?+1:(tagcount[a]==tagcount[b]?0:-1);});
		}

		// cross-index tiddlers by tags, building lists of tiddler titles into grid[i][j] (sparse array)
		var time1=new Date();
		var grid=new Array();
		var max=0;  // track maximum cross-index value
		for (var t=0;t<tiddlers.length;t++) { // for each tiddler
			for (var i=0;i<tiddlers[t].tags.length;i++) { // for each tag in tiddler
				var row=rows.indexOf(tiddlers[t].tags[i]); if (row==-1) continue; // this tag not in rows
				if (!grid[row]) grid[row]=new Array(); // create row as needed
				for (var j=0;j<tiddlers[t].tags.length;j++) {  // for each tag in tiddler
					var col=cols.indexOf(tiddlers[t].tags[j]); if (col==-1) continue; // this tag not in columns
					if (!grid[row][col]) grid[row][col]=new Array(); // create cell
					grid[row][col].push("[["+tiddlers[t].title+"]]"); // add tiddler title to cell
					if (max<grid[row][col].length) max=grid[row][col].length; // check for new maximum
				}
			}
		}

		// compute gradient color map
		if (startcolor && endcolor) {
			var digits="0123456789ABCDEF";
			function hexToDec(s) // 2-digit conversion
				{ return digits.indexOf(s.substr(0,1).toUpperCase())*16+digits.indexOf(s.substr(1,1).toUpperCase()); }
			function decToHex(d) // 2-digit conversion
				{ return digits.substr(Math.floor(d/16),1)+digits.substr(d%16,1); }
			var steps=max;
			var startR=hexToDec(startcolor.substr(0,2));
			var startG=hexToDec(startcolor.substr(2,2));
			var startB=hexToDec(startcolor.substr(4,2));
			var endR=hexToDec(endcolor.substr(0,2));
			var endG=hexToDec(endcolor.substr(2,2));
			var endB=hexToDec(endcolor.substr(4,2));
			var rangeR=endR-startR;
			var rangeG=endG-startG;
			var rangeB=endB-startB;
			var stepR=rangeR/steps; if (stepR>0) stepR=Math.floor(stepR); else stepR=Math.ceil(stepR);
			var stepG=rangeG/steps; if (stepG>0) stepG=Math.floor(stepG); else stepG=Math.ceil(stepG);
			var stepB=rangeB/steps; if (stepB>0) stepB=Math.floor(stepB); else stepB=Math.ceil(stepB);
			var colors=[];
			colors[0]=startcolor;
			for (var i=1; i<steps; i++)
				colors[i]=decToHex(startR+stepR*i)+decToHex(startG+stepG*i)+decToHex(startB+stepB*i);
			colors[steps-1]=endcolor; // fixup for roundoff error
		}

		// generate HTML table containing popups (and optional inline links)
		var time2=new Date();
		var out="<html><table cellpadding='0' cellspacing='0' style='border:0;border-collapse:collapse'>";
		// column headings
		out+="<tr style='border:0;'><td style='text-align:right;border:0'>";
		out+="<a href='' style='font-size:80%;'";
		out+="	title='show all column headings'";
		out+="	onclick='return config.macros.tagGrid.toggleAllColumns(this,event,"+defOpen+")'>"+(defOpen?"&lt;&lt;&lt;":"&gt;&gt;&gt;")+"</a>";
		out+="</td>";
		for (var i=0;i<cols.length;i++) {
			out+="<td style='text-align:center;cursor:pointer;border:0;padding-left:2px;padding-right:2px' ";
			out+="	title='show/hide column heading' ";
			out+="	onclick='return config.macros.tagGrid.toggleColumn(this,event)'>";
			out+="<a href='' title='open tag tiddler'";
			if (!defOpen) out+="	style='display:none' ";
			out+="	onclick='story.displayTiddler(this,\""+cols[i]+"\");return false'>"+cols[i]+"</a>";
			out+="</td>";
		}
		out+="</tr>";
		for (var i=0;i<rows.length;i++) {
			// row heading
			var rowlink="<a href='' onclick='story.displayTiddler(this,\""+rows[i]+"\");return false'>"+rows[i]+"</a>";
			out +="<tr style='border:0'>";
			out +="<td style='text-align:right;border:0;padding-right:2px'>"+rowlink+"</td>";
			for (var j=0;j<cols.length;j++) {
				var content="";
				var bgcolor="transparent"; // default empty cell background
				if (colors && colorAll) bgcolor="#"+colors[0]; // empty cell background uses startcolor 
				var bordercolor=""; // default border color (inherits current CSS value)
				if (colors) bordercolor="#"+colors[Math.floor(colors.length/2-1)]; // border uses mid-tone color 
				var linkstyle=""; // use default unless background color is very light or very dark
				var cross=(grid[i]&&grid[i][j])?grid[i][j]:null;
				var hdr=rows[i]+(rows[i]!=cols[j]?(" + "+cols[j]):"");
				if (cross) {
					// cross-tagged list of tiddlers (in a popup)
					var label="<b>"+cross.length+"</b>";
					var tip=hdr;
					var list=cross.sort().join(' ').replace(/'/g,"\\'").replace(/"/g,'&quot;');
					var handler="return config.macros.tagGrid.popup(this,event,\'"+rows[i]+"\',\'"+cols[j]+"\',\'"+list+"\')";
					if (colors) {
						var c=colors[cross.length-1];
						bgcolor="#"+c;
						linkstyle="style='color:#000000 !important'";
						// invert link color if background is very light
						if (c.substr(0,2)<"60" || c.substr(2,2)<"60" || c.substr(4,2)<"60")
							linkstyle="style='color:#FFFFFF !important'";
					}
				} else {
					var label="&nbsp;-&nbsp;";
					var tip="create a new tiddler tagged with: "+hdr;
					var list="";
					var handler="var title=config.macros.newTiddler.title;";
					handler+="story.displayTiddler(this,title,DEFAULT_EDIT_TEMPLATE);";
					handler+="story.setTiddlerTag(title,\'"+rows[i]+"\',+1);";
					handler+="story.setTiddlerTag(title,\'"+cols[j]+"\',+1);";
					handler+="story.focusTiddler(title,\'text\');return(false);";
				}
				if (!showInline || !cross)
					content+='<a href="javascript:;" '+linkstyle+' onclick="'+handler+'" title="'+tip+'">'+label+'</a>';
				if (showInline && cross) {
					content+="<div "+linkstyle+"><span style='white-space:nowrap'>";
					content+=hdr+" ("+label+")";
					content+="</span></div><hr>";
					// list tiddler links inline in table cell
					for (t=0; t<cross.length; t++) {
						var title=cross[t].replace(/\[\[/g,'').replace(/\]\]/g,'');
						var handler="story.displayTiddler(null,'"+title+"');return false;"
						var tid=store.getTiddler(title);
						var author=tid.modifier;
						var date=tid.modified.toLocaleString();
						var tip=config.messages.tiddlerLinkTooltip.format([title,author,date]);
						if (t>0) content+="<br>";
						content+='<a href="javascript:;" '+linkstyle+' onclick="'+handler+'" title="'+tip+'">'+title+'</a>';
					}
					content+="<hr>";
					handler="var tids=\'"+list+"\'.readBracketedList();story.displayTiddlers(this,tids); return(false);"
					tip="display all tiddlers tagged with: "+hdr;
					content+='<a href="javascript:;" '+linkstyle+' onclick="'+handler+'" title="'+tip+'">open all...</a><br>';
					handler="var title=config.macros.newTiddler.title;";
					handler+="story.displayTiddler(this,title,DEFAULT_EDIT_TEMPLATE);";
					handler+="story.setTiddlerTag(title,\'"+rows[i]+"\',+1);";
					handler+="story.setTiddlerTag(title,\'"+cols[j]+"\',+1);";
					handler+="story.focusTiddler(title,'text'); return(false);"
					tip="create a new tiddler tagged with: "+hdr;
					content+='<a href="javascript:;" '+linkstyle+' onclick="'+handler+'" title="'+tip+'">new tiddler...</a>';
				}
				out+="<td style='background-color:"+bgcolor+";border:1px solid "+bordercolor+" !important;text-align:center'>"+content+"</td>";
			}
			out+="</tr>";
		}
		out+="</table>";
		out+="</html>";
		createTiddlyElement(place,"span").innerHTML=out;
		var time3=new Date();
		if (this.verbose) displayMessage("TagGrid: scan="+(time2-time1)+", generate table="+(time3-time2));
	},
	popup:
	function(here,event,row,col,list) {
		var tids=list.replace(/&quot;/g,'"').readBracketedList();
		var hdr=row+(row!=col?(" AND "+col):"");
		if (tids.length) {
			var p=Popup.create(here); if (!p) return;
			createTiddlyText(p,hdr);
			createTiddlyElement(p,'hr');
			for(var t=0; t<tids.length; t++) createTiddlyLink(createTiddlyElement(p,'li'),tids[t],true);
			createTiddlyElement(p,'hr');
			createTiddlyButton(createTiddlyElement(p,'li'),
				"open all...", "display all tiddlers tagged with: "+hdr,
				function(){story.displayTiddlers(null,tids); return(false);});
			var a=createTiddlyButton(createTiddlyElement(p,'li'),
				"new tiddler...", "create a new tiddler tagged with: "+hdr,
				function(){
					var title=config.macros.newTiddler.title;
					story.displayTiddler(this,title,DEFAULT_EDIT_TEMPLATE);
					story.setTiddlerTag(title,this.getAttribute("rowtag"),+1);
					story.setTiddlerTag(title,this.getAttribute("coltag"),+1);
					story.focusTiddler(title,"text");
					return(false);
				});
			a.setAttribute("rowtag",row);
			a.setAttribute("coltag",col);
			Popup.show(p,false);
		}
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
		return(false);
	},
	toggleAllColumns:
	function(here,event,defOpen) {
		if (here.expanded==undefined) here.expanded=defOpen;
		var ex=here.expanded=!here.expanded; 
		here.innerHTML=ex?"&lt;&lt;&lt;":"&gt;&gt;&gt;";
		here.title=ex?'hide all column headings':'show all column headings';
		var cells=here.parentNode.parentNode.getElementsByTagName("td");
		for (i=1; i<cells.length; i++) cells[i].firstChild.style.display=ex?"inline":"none";
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
		return(false);
	},
	toggleColumn:
	function(here,event) {
		here.firstChild.style.display=(here.firstChild.style.display=="none")?"inline":"none";
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
		return(false);
	}
};
//}}}
/***
|Name|TagGridPluginInfo|
|Source|http://www.TiddlyTools.com/#TagGridPlugin|
|Documentation|http://www.TiddlyTools.com/#TagGridPluginInfo|
|Version|1.7.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for TagGridPlugin|
!!!!!Usage
<<<
Specify which tags should be used for the columns and rows of the grid to ''see a particular cross-section'' of your document, or use //all// tags to ''get an instant 'birds-eye' overview of your entire document''.

Each grid cell contains a label with the number of tiddlers in that grid cell.  Click the number to ''show a popup of cross-indexed tiddler titles''.  Grid cells with no matching tiddlers contain a "-" (dash) that can be clicked to ''create new tiddlers automatically pre-tagged with that cell's combination of tags.''

To keep the grid display from getting very wide, the grid tags used as column headings are not initially displayed.  ''Click directly above the column to show/hide that heading'', or toggle all column headings at once by clicking the {{{>>>}}} symbol in the upper-left corner of the grid display.  Clicking a displayed row/column tag heading opens the tiddler whose title is that tag name.

The macro syntax to include a tag grid in your tiddler content is:
{{{
<<tagGrid "columntags" "exclude:tags" "rowtags" "exclude:tags" "filter:tiddlerfilter" startcolor endcolor open inline colorall sortrows sortcolumns>>
}}}
where:

''rowtags/columntags'' are each:
* a ''quoted'' space-separated lists of tags: {{{"tag1 tag2 [[tag3 with spaces]] tag4 ..."}}}
* //or,// a tiddler name preceded by "+": {{{+TiddlerName}}} where the specified tiddler contains a space-separated list of tags (same format as DefaultTiddlers)
* //or,// a tiddler name preceded by "@": {{{@TiddlerName}}} to use the same tags as those that are tagging the specified tiddler (i.e., the tiddler is a representative example of the kind of tags you are interested in cross-indexing)
* //or,// a tag name preceded by "=": {{{=tagName}}} to use the group of tags that are themselves, in turn, tagged with the indicated tagName (i.e., useful when you have defined a 'meta-tag'/classification system, a.k.a. "~TagglyTagging" techniques)
* //or,// keyword: {{{all}}} (use all tags)
* if only columntags are specified, rows display all tags by default
* if no parameters are provided, both rows and columns display all tags
''exclude:tag tag tag''
* This //optional// parameter can be placed immediately following the columntags and/or rowtags parameter to selectively omit certain tags from the grid row or column headings.  You can exclude several tags at once by enclosing the entire parameter in quotes, e.g.: {{{"exclude:tag tag tag"}}}.  This parameter is generally only needed to adjust the set of row/column headings that will be applied when using the {{{@TiddlerName}}} syntax.   Otherwise, you can simply omit the undesired rows/column headings directly from the specified columntags and/or rowstags parameters.
''"filter:tiddlerfilter"''
* By default, all tiddlers in the document are scanned to determine the contents of the grid cells.  The //optional// filter parameter allows you to specify a subset of tiddler to be scanned.  The syntax for this parameter is: {{{"filter:[tag[tagname]]"}}}, which will select only tiddlers with the indicated tag.  For more advanced selection of tiddlers, you can install [[MatchTagsPlugin]], which extends the {{{[tag[...]]}}} filter syntax to permit use of full boolean expressions, e.g., {{{"filter:[tag[NOT tag1]]"}}} or {{{"filter:[tag[tag1 AND NOT tag2]]"}}} or {{{"filter:[tag[(tag1 AND tag2) OR (tag3 AND NOT tag4)]]"}}}, etc.
''startcolor/endcolor''
* describes a ''color gradient'' where the grid cell background color is calculated as a combination of  the starting and ending colors, in proportion to the cell value
* colors are specified using 6-digit hex-coded RGB values (e.g., red="~FF0000", green="00FF00", blue="0000FF")
* the cells with the lowest number use the starting background color
* the cells with the highest number use the ending background color
* if one or both color values are omitted, all cells have //transparent// backgrounds
''open''
* causes the grid column headings to be shown when the grid is initially displayed (you can hide all the column headings using the &lArr; link, or just toggle one heading by clicking //near// the tag text.  (Note: clicking //on// the tag text will open the tiddler with the same name as the tag.
''inline''
* by default, cells with cross-indexed tiddlers display the total number of tiddlers in the cell.  When this number is clicked, a popup is displayed, containing links to the individual tiddlers in that cell.  However, the popup display makes it difficult to compare the contents of two or more cells because only one popup can be displayed at any given time.  To address this, you can use the ''inline'' keyword parameter to ''display the grid contents directly in the cells'', without using any popups.  While this can make the grid display significantly larger (to fit the text of each cell), it also enables quick comparisons between cells.  Inline rendering of the cell contents also makes it possible to print the entire grid contents for easy off-line reporting and analysis.
''colorall''
* by default, cells with no cross-indexed tiddlers have a //transparent// background (e.g., the tiddler's background colors shows through).  However, this can create a 'patchwork' appearance to the grid.  Add the ''colorall'' keyword parameter to force these 'empty' cells to use the specified startcolor instead of a transparent background.
''sortrows/sortcolumns''
* rowtags and columntags are normally displayed in the order specified in the macro parameters, or in alphabetical order when ''all'' is used to generate the list of tags.  Adding the ''sortrows'' and/or ''sortcolumns'' keyword parameters will sort the tags in decending order so that the most frequently used tags are displayed first (i.e., towards the top-left corner).
<<<
!!!!!Examples
<<<
{{{<<tagGrid +FavoriteTags +FavoriteTags eeeeff 3333ff colorall sortrows sortcolumns>>}}}
<<tagGrid +FavoriteTags +FavoriteTags eeeeff 3333ff colorall sortrows sortcolumns>>
<<<
!!!!!Revisions
<<<
2008.04.21 [1.7.0] added support for "filter:..." param to exclude tiddlers from grid
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.07.24 [1.6.5] corrected handling for @TiddlerName with excluded tags, so that excluded tags are not actually removed from the @TiddlerName source tiddler.
2007.07.04 [1.6.4] fix fatal "unterminated string" popup error caused by tiddlers containing double-quotes (now being encoded using "&quot;")
2007.03.08 [1.6.3] use global flag to replace ALL single-quotes in tiddler titles (fixes popups where more than one tiddler title had a ' in it)
2007.03.06 [1.6.2] removed debugging alert()s... D'oh!
2007.03.06 [1.6.1] fix handling for excluding tags (was only removing last tag in list)
2007.03.05 [1.6.0] added "exclude:tag tag tag..." parameter handling for both rows and columns
2006.12.20 [1.5.1] fixed bordercolor calculation and CSS so grid correctly uses midtone-color for table cell borders
2006.12.09 [1.5.0] added 'inline' keyword parameter to display tiddler titles directly in grid cells (in addition to popup)
2006.11.03 [1.4.0] changed {{{=TiddlerName}}} param usage to {{{@TiddlerName}}} and added {{{=tagName}}} usage for specifying TagglyTagging "meta-tagged" groups of tag (based on ideas by GregWolff)
2006.11.03 [1.3.3] performance optimization: calculate maximum cross-index value while building grid (eliminates extra calc during colormapping)
2006.10.29 [1.3.2] fixes for IE: in decToHex and hexToDec, use substr() instead array indexing.  Also, use {{{>>>}}} and {{{<<<}}} instead of {{{&rArr;}}} and {{{&lArr;}}} for 'toggle headings' link text
2006.10.29 [1.3.1] suppress border around table
2006.10.21 [1.3.0] added {{{=TiddlerName}}} and {{{open}}} parameter handling
2006.10.17 [1.2.1] fixed row/column sorting to properly sort undefined tags to the end of the list
2006.10.16 [1.2.0] added optional row/column sorting and improved parameter parsing
2006.10.15 [1.1.0] added features: background gradients, collapsible column headings, eliminated table borders around row/column headings
2006.10.06 [1.0.1] calls to displayTiddler() use 'this' instead of 'null'
2006.10.05 [1.0.0] initial release (converted from prototype inline script)
<<<
/***
|''Name:''|~TaggerPlugin|
|''Version:''|1.0.1 (2006-06-01)|
|''Source:''|http://tw.lewcid.org//#TaggerPlugin|
|''Author:''|SaqImtiaz|
|''Description:''|Provides a drop down listing current tiddler tags, and allowing toggling of tags.|
|''Documentation:''|[[TaggerPluginDocumentation]]|
|''Source Code:''|[[TaggerPluginSource]]|
|''~TiddlyWiki:''|Version 2.0.8 or better|
***/
// /%
config.tagger={defaults:{label:"Tags: ",tooltip:"Manage tiddler tags",taglist:"true",excludeTags:"",notags:"tiddler has no tags",aretags:"current tiddler tags:",toggletext:"add tags:"}};config.macros.tagger={};config.macros.tagger.arrow=(document.all?"â–¼":"â–¾");config.macros.tagger.handler=function(_1,_2,_3,_4,_5,_6){var _7=config.tagger.defaults;var _8=_5.parseParams("tagman",null,true);var _9=((_8[0].label)&&(_8[0].label[0])!=".")?_8[0].label[0]+this.arrow:_7.label+this.arrow;var _a=((_8[0].tooltip)&&(_8[0].tooltip[0])!=".")?_8[0].tooltip[0]:_7.tooltip;var _b=((_8[0].taglist)&&(_8[0].taglist[0])!=".")?_8[0].taglist[0]:_7.taglist;var _c=((_8[0].exclude)&&(_8[0].exclude[0])!=".")?(_8[0].exclude[0]).readBracketedList():_7.excludeTags.readBracketedList();if((_8[0].source)&&(_8[0].source[0])!="."){var _d=_8[0].source[0];}if(_d&&!store.getTiddler(_d)){return false;}var _e=function(e){if(!e){var e=window.event;}var _11=Popup.create(this);var _12=store.getTags();var _13=new Array();for(var i=0;i<_12.length;i++){_13.push(_12[i][0]);}if(_d){var _15=store.getTiddler(_d);_13=_15.tags.sort();}var _16=_6.tags.sort();var _17=function(_18,_19,_1a){var sp=createTiddlyElement(createTiddlyElement(_11,"li"),"span",null,"tagger");var _1c=createTiddlyButton(sp,_18,_1a+" '"+_19+"'",taggerOnToggle,"button","toggleButton");_1c.setAttribute("tiddler",_6.title);_1c.setAttribute("tag",_19);insertSpacer(sp);if(window.createTagButton_orig_mptw){createTagButton_orig_mptw(sp,_19)}else{createTagButton(sp,_19);}};createTiddlyElement(_11,"li",null,"listTitle",(_6.tags.length==0?_7.notags:_7.aretags));for(var t=0;t<_16.length;t++){_17("[x]",_16[t],"remove tag ");}createTiddlyElement(createTiddlyElement(_11,"li"),"hr");if(_b!="false"){createTiddlyElement(_11,"li",null,"listTitle",_7.toggletext);for(var i=0;i<_13.length;i++){if(!_6.tags.contains(_13[i])&&!_c.contains(_13[i])){_17("[ ]",_13[i],"add tag ");}}createTiddlyElement(createTiddlyElement(_11,"li"),"hr");}var _1f=createTiddlyButton(createTiddlyElement(_11,"li"),("Create new tag"),null,taggerOnToggle);_1f.setAttribute("tiddler",_6.title);if(_d){_1f.setAttribute("source",_d);}Popup.show(_11,false);e.cancelBubble=true;if(e.stopPropagation){e.stopPropagation();}return (false);};createTiddlyButton(_1,_9,_a,_e,"button","taggerDrpBtn");};window.taggerOnToggle=function(e){var tag=this.getAttribute("tag");var _22=this.getAttribute("tiddler");var _23=store.getTiddler(_22);if(!tag){var _24=prompt("Enter new tag:","");if(_24!=""&&_24!=null){var tag=_24;if(this.getAttribute("source")){var _26=store.getTiddler(this.getAttribute("source"));_26.tags.pushUnique(_24);}}else{return false;}}if(!_23||!_23.tags){store.saveTiddler(_22,_22,"",config.options.txtUserName,new Date(),tag);}else{if(_23.tags.find(tag)==null){_23.tags.push(tag);}else{if(!_24){_23.tags.splice(_23.tags.find(tag),1);}}store.saveTiddler(_23.title,_23.title,_23.text,_23.modifier,_23.modified,_23.tags);}story.refreshTiddler(_22,null,true);if(config.options.chkAutoSave){saveChanges();}return false;};setStylesheet(".tagger a.button {font-weight: bold;display:inline; padding:0px;}\n"+".tagger #toggleButton {padding-left:2px; padding-right:2px; margin-right:1px; font-size:110%;}\n"+"#nestedtagger {background:#2E5ADF; border: 1px solid #0331BF;}\n"+".popup .listTitle {color:#000;}\n"+"","TaggerStyles");window.lewcidTiddlerSwapTag=function(_27,_28,_29){for(var i=0;i<_27.tags.length;i++){if(_27.tags[i]==_28){_27.tags[i]=_29;return true;}}return false;};window.lewcidRenameTag=function(e){var tag=this.getAttribute("tag");var _2d=prompt("Rename tag '"+tag+"' to:",tag);if((_2d==tag)||(_2d==null)){return false;}if(store.tiddlerExists(_2d)){if(confirm(config.messages.overwriteWarning.format([_2d.toString()]))){story.closeTiddler(_2d,false,false);}else{return null;}}tagged=store.getTaggedTiddlers(tag);if(tagged.length!=0){for(var j=0;j<tagged.length;j++){lewcidTiddlerSwapTag(tagged[j],tag,_2d);}}if(store.tiddlerExists(tag)){store.saveTiddler(tag,_2d);}if(document.getElementById("tiddler"+tag)){var _2f=document.getElementById(story.idPrefix+tag);var _30=story.positionTiddler(_2f);var _31=document.getElementById(story.container);story.closeTiddler(tag,false,false);story.createTiddler(_31,_30,_2d,null);story.saveTiddler(_2d);}if(config.options.chkAutoSave){saveChanges();}return false;};window.onClickTag=function(e){if(!e){var e=window.event;}var _34=resolveTarget(e);var _35=(!isNested(_34));if((Popup.stack.length>1)&&(_35==true)){Popup.removeFrom(1);}else{if(Popup.stack.length>0&&_35==false){Popup.removeFrom(0);}}var _36=(_35==false)?"popup":"nestedtagger";var _37=createTiddlyElement(document.body,"ol",_36,"popup",null);Popup.stack.push({root:this,popup:_37});var tag=this.getAttribute("tag");var _39=this.getAttribute("tiddler");if(_37&&tag){var _3a=store.getTaggedTiddlers(tag);var _3b=[];var li,r;for(r=0;r<_3a.length;r++){if(_3a[r].title!=_39){_3b.push(_3a[r].title);}}var _3d=config.views.wikified.tag;if(_3b.length>0){var _3e=createTiddlyButton(createTiddlyElement(_37,"li"),_3d.openAllText.format([tag]),_3d.openAllTooltip,onClickTagOpenAll);_3e.setAttribute("tag",tag);createTiddlyElement(createTiddlyElement(_37,"li"),"hr");for(r=0;r<_3b.length;r++){createTiddlyLink(createTiddlyElement(_37,"li"),_3b[r],true);}}else{createTiddlyText(createTiddlyElement(_37,"li",null,"disabled"),_3d.popupNone.format([tag]));}createTiddlyElement(createTiddlyElement(_37,"li"),"hr");var h=createTiddlyLink(createTiddlyElement(_37,"li"),tag,false);createTiddlyText(h,_3d.openTag.format([tag]));createTiddlyElement(createTiddlyElement(_37,"li"),"hr");var _40=createTiddlyButton(createTiddlyElement(_37,"li"),("Rename tag '"+tag+"'"),null,lewcidRenameTag);_40.setAttribute("tag",tag);}Popup.show(_37,false);e.cancelBubble=true;if(e.stopPropagation){e.stopPropagation();}return (false);};if(!window.isNested){window.isNested=function(e){while(e!=null){var _42=document.getElementById("contentWrapper");if(_42==e){return true;}e=e.parentNode;}return false;};}config.shadowTiddlers.TaggerPluginDocumentation="The documentation is available [[here.|http://tw.lewcid.org/#TaggerPluginDocumentation]]";config.shadowTiddlers.TaggerPluginSource="The uncompressed source code is available [[here.|http://tw.lewcid.org/#TaggerPluginSource]]";
// %/
''If you want this documentation available offline, copy this tiddler to your TW.''

!Description:
The tagger plugin is a result of combining key features from the dropTags and tagAdder macro's. However, since it departs somewhat from the interface tagAdder users will be familiar with, I'm making this available as a new plugin alongside tagAdder.

Tagger provides a dropdown list of the current tiddler tags, along with the ability to toggle them. Further it can optionally display a list of tags in the dropdown, which can be addded to the tiddler.

*Clicking on ''[x]'' and ''[ ]'' removes and adds the tag respectively.
*Clicking on the tag text displays the tag dropdown for that tag, listing tiddlers tagged with it.
*The ''Create new tag'' lets you quickly type in a new tag not in the list.
*Click on this button to see the dropdown: <<tagger>>

Further note that each tag dropdown has a ''Rename tag'' option. This can be used to quickly rename a tag in the entire TW, also rename it's tiddler if it exists.

//''tagAdder, dropTags and the future''
- tagAdder will no longer will be developed, but will remain available. I encourage all tagAdder users to upgrade to tagger.
- dropTags will still be developed for those users that dont want the 'tag editing' features.//

!Examples & Usage:
*At it's simplest, using tagger is as simple as {{{<<tagger>>}}} <<tagger>>
**This gives a dropdown with the current tiddler tags, followed by all the tags in the TW.
*You can also use a list of specified tags instead of all tags in the TW, by specifying a source tiddler.
**{{{<<tagger source:TagsDB>>}}} <<tagger source:TagDataBase>>
*You can also display ONLY the current tiddler tags
**{{{<<tagger taglist:false>>}}} <<tagger taglist:false>>

*To exclude tags from the list: {{{<<tagger exclude:"excludeLists Tag2 [[Tag with spaces]]">>}}} <<tagger exclude:"excludeLists Tag2 [[Tag with spaces]]">>

*For a custom button label: {{{<<tagger label:"custom label">>}}} <<tagger label:"custom label">>
*For a custom tooltip: {{{<<tagger tooltip:"custom tooltip">>}}} <<tagger tooltip:"custom tooltip">>

!CSS and Styling:
For those wishing to customize the popup appearance:
*the main popup has a class and id of popup has with all other popups.
*the nested tag popups have an id of nestedpopup

!Advanced Users:
You can change the global defaults for tagger, like the button label, the tags to exclude or whether to display the taglist or not, by editing the ''config.tagger.defaults'' section in the code.

!To Do:
*code optimization
*possibly a 'delete this tag' option.

!History
*version 1.0.1 (2006-06-01): fixed conflicts with QuickOpenTag (TagglyTagging) and AutoTagger.
/***
|''Name:''|~TaggerPlugin|
|''Version:''|1.0.1 (2006-06-01)|
|''Source:''|http://tw.lewcid.org//#TaggerPlugin|
|''Author:''|SaqImtiaz|
|''Description:''|Provides a drop down listing current tiddler tags, and allowing toggling of tags.|
|''Documentation:''|[[TaggerPluginDocumentation]]|
|''Source Code:''|[[TaggerPluginSource]]|
|''~TiddlyWiki:''|Version 2.0.8 or better|
***/
//{{{

config.tagger={
       defaults:{
              label: 'Tags: ',
              tooltip: 'Manage tiddler tags',
              taglist: 'true',
              excludeTags: '',
              notags: 'tiddler has no tags',
              aretags: 'current tiddler tags:',
              toggletext: 'add tags:'
       }
};

config.macros.tagger={};
config.macros.tagger.arrow = (document.all?"â–¼":"â–¾"); // the fat one is the only one that works in IE
config.macros.tagger.handler =  function(place,macroName,params,wikifier,paramString,tiddler) {
       var defaults = config.tagger.defaults;
       var nAV = paramString.parseParams('tagman', null, true);
       var label = ((nAV[0].label)&&(nAV[0].label[0])!='.')?nAV[0].label[0]+this.arrow: defaults.label+this.arrow;
       var tooltip = ((nAV[0].tooltip)&&(nAV[0].tooltip[0])!='.')?nAV[0].tooltip[0]: defaults.tooltip;
       var taglist = ((nAV[0].taglist)&&(nAV[0].taglist[0])!='.')?nAV[0].taglist[0]: defaults.taglist;
       var exclude = ((nAV[0].exclude)&&(nAV[0].exclude[0])!='.')?(nAV[0].exclude[0]).readBracketedList(): defaults.excludeTags.readBracketedList();
       if ((nAV[0].source)&&(nAV[0].source[0])!='.')var source = nAV[0].source[0];
       if (source&&!store.getTiddler(source)) return false;

       var onclick = function(e) {
                   if (!e) var e = window.event;
                   var popup = Popup.create(this);
                   var tagsarray = store.getTags();
                   var tags=new Array();

                   for (var i=0; i<tagsarray.length; i++){
                       tags.push(tagsarray[i][0]);}

                   if (source)
                      {var sourcetiddler=store.getTiddler(source);
                       tags=sourcetiddler.tags.sort();}

                   var currentTags = tiddler.tags.sort();

                   var createButtons=function(text,theTag,tooltipPrefix){
                       var sp = createTiddlyElement(createTiddlyElement(popup,"li"),"span",null,"tagger");
                       var theToggle = createTiddlyButton(sp,text,tooltipPrefix+" '"+theTag+"'",taggerOnToggle,"button","toggleButton");
                       theToggle.setAttribute("tiddler",tiddler.title);
                       theToggle.setAttribute("tag",theTag);
                       insertSpacer(sp);
                       if (window.createTagButton_orig_mptw)
                           createTagButton_orig_mptw(sp,theTag);
                       else
                           createTagButton(sp,theTag);
                       }

                   createTiddlyElement(popup,"li",null,"listTitle",(tiddler.tags.length == 0 ? defaults.notags : defaults.aretags));

                   for (var t=0; t<currentTags.length; t++){
                      createButtons("[x]",currentTags[t],"remove tag ");
                       }

                   createTiddlyElement(createTiddlyElement(popup,"li"),"hr");

                   if (taglist!='false')
                      { createTiddlyElement(popup,"li",null,"listTitle",defaults.toggletext);
                        for (var i=0; i<tags.length; i++){
                          if (!tiddler.tags.contains(tags[i])&&!exclude.contains(tags[i]))
                                  {createButtons("[ ]",tags[i],"add tag ");
                                  }
                          }
                          createTiddlyElement(createTiddlyElement(popup,"li"),"hr");
                      }

                   var newTagButton = createTiddlyButton(createTiddlyElement(popup,"li"),("Create new tag"),null,taggerOnToggle);
                   newTagButton.setAttribute("tiddler",tiddler.title);
                   if (source) newTagButton.setAttribute("source",source);

                   Popup.show(popup,false);
                   e.cancelBubble = true;
                   if (e.stopPropagation) e.stopPropagation();
                   return(false);
                   };

       createTiddlyButton(place,label,tooltip,onclick,"button","taggerDrpBtn");
};

window.taggerOnToggle = function(e) {
              var tag = this.getAttribute("tag");
              var title = this.getAttribute("tiddler");
              var tiddler = store.getTiddler(title);
              if (!tag)
                 {
                 var newtag=prompt("Enter new tag:","");
                 if (newtag!=''&&newtag!=null)
                    {
                    var tag=newtag;
                    if (this.getAttribute("source"))
                    {var sourcetiddler =  store.getTiddler(this.getAttribute("source"));
                    sourcetiddler.tags.pushUnique(newtag);}
                    }
                 else
                     {return false;};
                 }
              if (!tiddler || !tiddler.tags)
                 {store.saveTiddler(title,title,'',config.options.txtUserName,new Date(),tag);}
              else
                  {if (tiddler.tags.find(tag)==null)
                     {tiddler.tags.push(tag)}
                  else if(!newtag)
                      {tiddler.tags.splice(tiddler.tags.find(tag),1)};
                  store.saveTiddler(tiddler.title,tiddler.title,tiddler.text,tiddler.modifier,tiddler.modified,tiddler.tags);};
              story.refreshTiddler(title,null,true);
              if(config.options.chkAutoSave)
                  saveChanges();
              return false;
};

setStylesheet(
 ".tagger a.button {font-weight: bold;display:inline; padding:0px;}\n"+
 ".tagger #toggleButton {padding-left:2px; padding-right:2px; margin-right:1px; font-size:110%;}\n"+
 "#nestedtagger {background:#2E5ADF; border: 1px solid #0331BF;}\n"+
 ".popup .listTitle {color:#000;}\n"+
 "",
"TaggerStyles");

window.lewcidTiddlerSwapTag =  function (tiddler, oldTag, newTag){
                    for (var i = 0; i < tiddler.tags.length; i++)
			  if (tiddler.tags[i] == oldTag) {
				  tiddler.tags[i] = newTag;
				  return true;}
                         return false;
}

window.lewcidRenameTag = function(e) {
                    var tag=this.getAttribute("tag");
                    var newtag=prompt("Rename tag '"+tag+"' to:",tag);

                    if ((newtag==tag)||(newtag==null)) {return false;}

                    if(store.tiddlerExists(newtag))
                               {if(confirm(config.messages.overwriteWarning.format([newtag.toString()])))
                                             story.closeTiddler(newtag,false,false);
                               else
                                             return null;}

                    tagged=store.getTaggedTiddlers(tag);
                    if (tagged.length!=0){
                          for (var j = 0; j < tagged.length; j++)
                              lewcidTiddlerSwapTag(tagged[j],tag,newtag);}

                    if (store.tiddlerExists(tag))
                       {store.saveTiddler(tag,newtag);}
                    if (document.getElementById("tiddler"+tag))
                       {var oldTagTiddler =  document.getElementById(story.idPrefix + tag);
                       var before= story.positionTiddler(oldTagTiddler);
                       var place = document.getElementById(story.container);
                       story.closeTiddler(tag,false,false);
                       story.createTiddler(place,before,newtag,null);
                       story.saveTiddler(newtag);}
                    if(config.options.chkAutoSave)
                                                      saveChanges();
                    return false;
}


window.onClickTag=function(e)
{
	if (!e) var e = window.event;
	var theTarget = resolveTarget(e);

        var nested = (!isNested(theTarget));
        if ((Popup.stack.length > 1)&&(nested==true)) {Popup.removeFrom(1);}
        else if(Popup.stack.length > 0 && nested==false) {Popup.removeFrom(0);};

        var theId = (nested==false)? "popup" : "nestedtagger";
        var popup = createTiddlyElement(document.body,"ol",theId,"popup",null);
        Popup.stack.push({root: this, popup: popup});

	var tag = this.getAttribute("tag");
	var title = this.getAttribute("tiddler");
	if(popup && tag)
		{
		var tagged = store.getTaggedTiddlers(tag);
		var titles = [];
		var li,r;
		for(r=0;r<tagged.length;r++)
			if(tagged[r].title != title)
				titles.push(tagged[r].title);
		var lingo = config.views.wikified.tag;
		if(titles.length > 0)
			{
			var openAll = createTiddlyButton(createTiddlyElement(popup,"li"),lingo.openAllText.format([tag]),lingo.openAllTooltip,onClickTagOpenAll);
			openAll.setAttribute("tag",tag);
			createTiddlyElement(createTiddlyElement(popup,"li"),"hr");
			for(r=0; r<titles.length; r++)
				{
				createTiddlyLink(createTiddlyElement(popup,"li"),titles[r],true);
				}
			}
		else
			createTiddlyText(createTiddlyElement(popup,"li",null,"disabled"),lingo.popupNone.format([tag]));
		createTiddlyElement(createTiddlyElement(popup,"li"),"hr");
		var h = createTiddlyLink(createTiddlyElement(popup,"li"),tag,false);
		createTiddlyText(h,lingo.openTag.format([tag]));

		createTiddlyElement(createTiddlyElement(popup,"li"),"hr");

		var renameTagButton = createTiddlyButton(createTiddlyElement(popup,"li"),("Rename tag '"+tag+"'"),null,lewcidRenameTag);
		renameTagButton.setAttribute("tag",tag)
		}
	Popup.show(popup,false);
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
	return(false);
}

if (!window.isNested)
   window.isNested = function(e) {
        while (e != null) {
                var contentWrapper = document.getElementById("contentWrapper");
                if (contentWrapper == e) return true;
                e = e.parentNode;
                }
        return false;
   };

config.shadowTiddlers.TaggerPluginDocumentation="The documentation is available [[here.|http://tw.lewcid.org/#TaggerPluginDocumentation]]";

config.shadowTiddlers.TaggerPluginSource="The uncompressed source code is available [[here.|http://tw.lewcid.org/#TaggerPluginSource]]";
//}}}
/***
|''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
// %/
/***

|Name|TiddlerWithEditPlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#TiddlerWithEditPlugin|
|Version|0.2|
|Requires|~TW2.x|
!Description:
Adds 'doubleclick to edit source' capabilites to the core {{{<<tiddler>>}}} macro.

!Notes:
*because of the rewrite, only clicking on actual embedded text opens the source tiddler for editing. Clicking on any white space opens the containing tiddler for editing.

!History
*29-04-06, version 0.2, rewritten after input from Udo.
*28-04-06, version 0.1, working.

!Code
***/
//{{{
config.macros.tiddler.onTiddlerMacroDblClick = function(e){
        if (!e) var e = window.event;
        var theTarget = resolveTarget(e);
        var title= this.getAttribute("source");
        if ((version.extensions.PartTiddlerPlugin)&&(title.indexOf("/")!=-1))
                 {if (!oldFetchTiddler.call(this, [title]))
                              {title=title.slice(0,title.lastIndexOf("/"))}}   
        story.displayTiddler(theTarget,title,2,false,null)
        e.cancelBubble = true;
        if (e.stopPropagation) e.stopPropagation();
        return false;
        }

var oldTiddlerHandler=config.macros.tiddler.handler;
config.macros.tiddler.handler = function(place,macroName,params){
        oldTiddlerHandler.apply(this,arguments);
        place.lastChild.setAttribute("source",params[0]);
        place.lastChild.ondblclick = this.onTiddlerMacroDblClick;
}
//}}}
!Documentation for TiddlyLightBoxPlugin
''Credits:''
This lightbox implementation is a derivative of Bob Denny's [[DC3.LightBox|http://solo.dc3.com/tw/index.html]] library optimized for a ~TiddlyWiki environment, with an emphasis on ease of use. It also uses some code and ideas from [[LightBox Gone Wild|http://particletree.com/features/lightbox-gone-wild/]] and [[Ibox|http://www.ibegin.com/ibox/]]. For a more feature rich and versatile option, you can't beat the ~DC3 library.


''Concept:''
I needed a light weight lightbox implementation for [[TiddlyThemes|http://tiddlythemes.googlepages.com/index.html]] but none of the existing options fit the bill. The ~DC3 library came closest, so I set out to rewrite it. I believe the result is a quite versatile ~TW plugin. Some of the bells and whistles have been removed though since I find them annoying (animations), and there are some features yet to be implemented, as you can read further on this document. Almost the entire library has been rewritten.


''Installation:''
Copy the TiddlyLightBoxPlugin tiddler to your TW, tag it with systemConfig, save and reload your TW file. You will also need to save [[this|indicator.gif]] 'loading' image to the same folder as your TW. Or you can choose one of many [[here|http://www.ajaxload.info/]]. That's it, you are ready to create some lightboxes!


''Usage:''
There are 3 macros provide to facilitate setting up macros.
1. ''{{{<<imagebox>>}}}''
The imagebox macro is designed to display images in the lightbox. The usage is very easy. Simply create a text or image link to an image using standard TW syntax, and follow it with {{{<<imagebox>>}}}.
Eg: {{{[img[cactus-thumb.jpg]cactus.jpg]]}}}

[img[cactus-thumb.jpg][cactus.jpg]]<<imagebox>>

Let's try a text link: {{{[[click me|triad.jpg]]<<imagebox>>}}}

[[click me|triad.jpg]]<<imagebox>>

This macro also accepts some optional parameters in this order:
2. description text
3. width ( as a number, like 500)
4. height (as a number, like 300)
Also, if width is passed as a word, like "bananas", then it is treated as a css class and the container for the image is given the class "bananas".

Let's try one more, with a title and a custom size:
{{{[img[cubicles-thumb.jpg][cubicles.jpg]]<<imagebox 'Office space' 300 300>>}}}

[img[cubicles-thumb.jpg][cubicles.jpg]]<<imagebox 'Office space' 300 300>>

----

2. ''{{{<<divbox>>}}}''
The divbox macro lets you put the html content of any inline div into a lightbox, you just need the id of the div in question. The idea being to create a hidden div using "display:none" and then displaying it on the click of a link/button.
You can create such a div in any tiddler by wrapping it in html tags, but using the MarkupPostBody tiddler might be the better option.

The macro can create the button for you, or you can use an existing element to launch the lightbox. To create a button, pass the label for the button as the first parameter. To use an existing element, pass the first parameter as ' ' and place the macro immediately after the element. Eg: {{{<<tiddlerbox label>> or <<tiddlerbox ''>>}}}

The next parameter is the id of the div to display: {{{<<tiddlerbox label theID>>}}}
These two parameters are a must for the divbox macro. There are also 3 more optional parameters, just like the imagebox macro:
3. description text
4. width ( as a number, like 500) OR className
5. height (as a number, like 300)
As an example, lets display this hidden div which I have written inline:
{{{<html><div id="testDiv" style="display:none;"><div style="text-align:center;"> Lightboxes have become very cliche, but they can still be useful!</div></div></html><<divbox "Click to see it" "testDiv" "This is a test div">>}}}
<html><div id="testDiv" style="display:none;"><div style="text-align:center"><br><br><br><br> Lightboxes have become very cliche, but they can still be useful!</div></div></html><<divbox "Click to see it" "testDiv" "This is a test div">>

----

3.''{{{<<tiddlerbox>>}}}''
This macro lets you put the wikified contents of any tiddler into a lightbox! So you can put your MainMenu and Sidebar into a lightbox for example, and have handy links to bring them up whenever you need them. (like in say the hovering menu provided by HoverMenuPlugin). It's also very useful for when you are working on something and want to refer to some reference material without having to loose your place in your work.
The parameters for this macro are the same as for the divbox macro, except instead of the id for the div, you use the title of the tiddler.
Let's give it a go:
{{{<<tiddlerbox "menu" "MainMenu" "Thats my main menu, and the links work!">>}}}
<<tiddlerbox "menu" "MainMenu" "Thats my main menu, and the links work!">>
or
{{{<<tiddlerbox "menu" "Sidebar" "Thats my sidebar!" 300 500>>}}}
<<tiddlerbox "sidebar" "Sidebar" "Thats my sidebar!" 300 500>>

-----

''CSS Styling:''
The css rules for the lightbox and its contents are in the TiddlyLightBoxStyles folder. You can edit them to your liking, but I recommend not changing the rules for ~lightBoxOverlay and lightboxprogress. But don't worry, if you break anything, just delete the tiddler. It's a shadow tiddler!

I'll post a diagram showing the structure of the lightbox later, to faciliate css styling.

----

''Features comparison with ~DC3Lightbox:''
Missing:
* IE transparency filters
* ability to create own lightbox containers
*call back functions on closing lightbox

Added:
*macros for TW usage
*optimized for TW environment
*ability to display Tiddlers in lightboxes
*preloading of images, to avoid layout problems
*removed need for manually creating styles tiddler and adding html markup.
*fixed bug with regards to selects displaying over the lightbox!

----

''To Do''
* fixed positioning of lightbox so it scrolls with the page!
*possible light weight animation for images
* optional preloading of images
* resizing of images to fit the viewport when larger.
* optional automatic lightboxing of all links to images.
*grabbing description from image alt text.
* improved support for inline html content.

!!Images in a lightbox:
[img[cactus-thumb.jpg][cactus.jpg]]<<imagebox>>

Let's try a text link:

[[click me|triad.jpg]]<<imagebox>>

----
!Html div in a lightbox:

<html><div id="testDiv" style="display:none;"><div style="text-align:center"><br><br><br><br> Lightboxes have become very cliche, but they can still be useful!</div></div></html><<divbox "Click to see it" "testDiv" "This is a test div">>

----
!Tiddlers in a lightbox:

Let's give it a go:

<<tiddlerbox "menu" "MainMenu" "Thats my main menu, and the links work!">>

<<tiddlerbox "sidebar" "Sidebar" "Thats my sidebar!" 300 500>>

----

[[Full Documentation|TiddlyLightBoxDoc]]
[[TiddlyLightBoxPlugin]]
/***
|''Name:''|TiddlyLightBox|
|''Date:''|Jan 1, 2006|
|''Version:''|1.0 beta|
|''Author:''|Saq Imtiaz|
|''Location:''|http://tw.lewcid.org/#TiddlyLightBoxPlugin|
|''Documentation:''|http://tw.lewcid.org/#TiddlyLightBoxDocs|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''Based on:''|DC3.LightBox<br>Light Box Gone Wild <br>Ibox|

!!Code
***/
//{{{
config.macros.imagebox ={};
config.macros.imagebox.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
    var e = place.lastChild;
    e.onclick = function(){TiddlyLightBox.initBox('image',this,params[1],params[2],params[0]);return false;};
}

config.macros.divbox ={};
config.macros.divbox.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
    if (params[0]!=".")
        createTiddlyButton(place,params[0],params[0],function(){TiddlyLightBox.initBox('html',params[1],params[3],params[4],params[2]);return false;});
    else
        {
        var e = place.lastChild;
        e.onclick = function(){TiddlyLightBox.initBox('html',params[1],params[3],params[4],params[2]);return false;};
        }
}

config.macros.tiddlerbox ={}
config.macros.tiddlerbox.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
    config.macros.divbox.handler(place,macroName,[params[0],"tiddler:"+params[1],params[2],params[3],params[4]]);
    return false;
}

store.addNotification("TiddlyLightBoxStyles",refreshStyles);

if (!window.TiddlyLightBox)
    window.TiddlyLightBox = {};
    var loadingImage = "indicator.gif";
    window.TiddlyLightBox =
    {
    _curBox: null, // [sentinel]

    lightBoxHtml : '<div id="lightBoxOverlay" onclick="TiddlyLightBox.hideBox()" style="display:none"></div><div id="lightboxprogress" style="display:none;"><img src=\''+loadingImage+'\' alt=\'loading\' style="width:128px;height:128px;"></div><div class="lightBox" id="lightBox" style="display:none"><div id="lightBoxContent"></div><div id="lightBoxTitle">This is a title</div><div id="lightBoxClose"><a href:"#" onclick="TiddlyLightBox.hideBox();return false;">Click to close</a></div></div>',

    createBoxWrapper : function()
        {
        var wrapper = createTiddlyElement(document.getElementsByTagName("body")[0],"div","tiddlyLightBoxWrapper");
        wrapper.innerHTML = this.lightBoxHtml;
        },

    initBox : function(contentType,url,w,h,text)
        {
        if (this._curBox)
            return;
        this.showProgress();
        this.hideSelects("hidden");
        this.showBg();
        this._curBox = true;
        this.sizeTheBox(contentType,w,h);
        if (contentType == 'image')
            this.showImage(url,text);
        else if (contentType == 'html')
            this.showHtml(url,text);
        return false;
        },
        
    sizeTheBox : function(contentType,w,h)
        {
        var box = document.getElementById("lightBoxContent");
        if (w && isNaN(parseInt(w)))
            {
            addClass(box,w);
            }
        else if (w ||h || contentType == 'html')
            {
            box.style.width = w? w+ "px" : "450px";
            box.style.height = h? h+ "px" : "280px";
            if (contentType=='image')
                setStylesheet("#lightBoxContent img{height:100%;width:100%;}","lightBoxImageSizeHack");
            }
        },

    showProgress : function()
        {
        var progress = document.getElementById("lightboxprogress");
        progress.style.display='';
        this._center(progress);
        },
    
    hideProgress: function()
        {
        var progress = document.getElementById("lightboxprogress");
        progress.style.display='none';
        },

    //this function lifted from Lightbox Gone Wild
    hideSelects: function(visibility)
        {
        var selects = document.getElementsByTagName('select');
        for(i = 0; i < selects.length; i++)
            {
            selects[i].style.visibility = visibility;
            }
        },

    showBg: function()
        {
        var overlay = document.getElementById('lightBoxOverlay');
        if (config.browser.isIE)
            {
            overlay.style.height = Math.max(document.documentElement.scrollHeight,document.documentElement.offsetHeight);
            overlay.style.width = document.documentElement.scrollWidth;
            }
        overlay.style.display = 'block';
        },

    showImage: function (url,text)
        {
        imgPreloader = new Image();
        imgPreloader.onload = function ()
            {
            var lb = document.getElementById("lightBoxContent");
            lb.innerHTML = "<img src="+url+">";
            lb.onclick = function(){TiddlyLightBox.hideBox();return false;};
            TiddlyLightBox.posBox(text);
            };
        imgPreloader.src = url;
        },
        
    showHtml : function(theID,text)
        {
        var lb = document.getElementById("lightBoxContent");
        if (theID.indexOf("tiddler:")==-1)
             lb.innerHTML = document.getElementById(theID).innerHTML;
        else
            { 
             wikify(store.getTiddlerText(theID.replace("tiddler:","")),lb);
             lb.className='tiddler';
            }
        lb.style.overflow = "auto";
        this.posBox(text);
        },

    posBox: function(text)
       {
       this.setTitle(text);
       this.hideProgress();
       var lb = document.getElementById("lightBox");
       lb.style.display = "";
       lb.style.visibilty = "hidden";
       lb.style.position = "absolute";
       this._center(lb);
       if(!TiddlyLightBox._curBox) return;
       lb.style.visibility = "visible";
       lb.style.display = "block";
       },

     setTitle: function(text)
        {
        document.getElementById("lightBoxTitle").innerHTML=  (text==undefined)? '': text;
        },

    _center: function(lb)
       {
       var lbSize = new TiddlyLightBox.getElementSize(lb);
       lb.style.left = (Math.round(findWindowWidth()/2) - (lbSize.width /2) + findScrollX())+'px';
       lb.style.top = (Math.round(findWindowHeight()/2) - (lbSize.height /2) + findScrollY())+'px';
       },

    //this function lifted from Ibox
    getElementSize : function(elem)
       {
       this.width = elem.offsetWidth || elem.style.pixelWidth;
       this.height = elem.offsetHeight || elem.style.pixelHeight;
       },

     hideBox: function()
         {
         if(!this._curBox)
             return;
         document.getElementById("tiddlyLightBoxWrapper").innerHTML= this.lightBoxHtml;
         setStylesheet("","lightBoxImageSizeHack");
         this._curBox = null;
         return false;
         }
}

TiddlyLightBox.createBoxWrapper();

Story.prototype.findContainingTiddler = function(e)
{
    while(e && (!hasClass(e,"tiddler") || !e.getAttribute("tiddler")))
        e = e.parentNode;
    return(e);
}

config.shadowTiddlers.TiddlyLightBoxStyles="/*{{{*/\n#lightBoxOverlay {\n position:absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 90; \n background-color: #000;\n -moz-opacity: 0.75;\n opacity: .75;\n filter: alpha(opacity=75);\n}\n#lightBoxOverlay[id]{ \n position: fixed;\n}\n\n#lightboxprogress { \n margin:0;padding:0;\n position: absolute;\n z-index:95;\n}\n\ndiv.lightBox {\n background: #fff;\n color: #fff;\n border: 4px solid #525252;\npadding:20px 20px 25px 20px; position:absolute; z-index:99;\n}\n\n#lightBoxClose {text-align:right; color:#000; font-size:1.0em; position:absolute; bottom:6px; right:20px;}\n#lightBoxClose a{color:#666; border-bottom:1px solid #666;cursor:pointer;}\n#lightBoxClose a:hover {color:#111; border-bottom:1px solid #666; cursor:pointer; background:transparent;}\n\n#lightBoxContent {border:1px solid #525252;color:#000; background:#fff;}\n#lightBox .tiddler {background:#fff;}\n\n#lightBoxContent img {border:0;margin:0;padding:0;display:block;cursor:pointer;}\n\n#lightBoxTitle {padding:0px; font-weight:bold; position:absolute; left:20px;bottom:6px; font-size:1.1em; color:#000;}\n\n/*}}}*/";
//}}}
/%
|''URL:''|http://www.TiddlySpot.com|
|''Description:''|Free on-line hosting for your TiddlyWiki documents|
|''Author:''|DanielBaird SimonBaird|
%/
/%
|''URL:''|http://tiddlystyles.com/|
|''Description:''|Clint's collection of TiddlyWiki creations|
|''Author:''|ClintChecketts|
%/
/%
|''URL:''|http://www.tiddlytools.com/|
|''Description:''|Small Tools for Big Ideas!|
|''Author:''|EricShulman|
%/
/%
|''URL:''|http://www.TiddlyWiki.com/|
|''Description:''|Official TiddlyWiki Core Distribution|
|''Author:''|JeremyRuston|
%/
//{{{
//replaces toolbar buttons with icons.
//for each command that you want to use an icon, add a line like the following in a systemConfig tiddler, specifying the icon image location:
//config.commands.editTiddler.imgLoc= "jump.bmp";
//No need to edit the ViewTemplate! If an image location is specified, then the icon will be used for that command!

config.macros.toolbar.createCommand = function(place,commandName,tiddler,theClass)
{
	if(typeof commandName != "string")
		{
		var c = null;
		for(var t in config.commands)
			if(config.commands[t] == commandName)
				c = t;
		commandName = c;
		}
	if((tiddler instanceof Tiddler) && (typeof commandName == "string"))
		{
		var title = tiddler.title;
		var command = config.commands[commandName];
		var ro = tiddler.isReadOnly();
		var shadow = store.isShadowTiddler(title) && !store.tiddlerExists(title);
		var text = ro && command.readOnlyText ? command.readOnlyText : command.text;
		var tooltip = ro && command.readOnlyTooltip ? command.readOnlyTooltip : command.tooltip;
		if((!ro || (ro && !command.hideReadOnly)) && !(shadow && command.hideShadow))
		    {
			    var btn = createTiddlyButton(null,text,tooltip,this.onClickCommand);
			    btn.setAttribute("commandName", commandName);
			    btn.setAttribute("tiddler", title);
			    if(theClass)
				            addClass(btn,theClass);
                             place.appendChild(btn);
                            if(command.imgLoc)
                                   btn.innerHTML = "<img src='"+command.imgLoc+"'>";

		     }
       }
}

setStylesheet(".toolbarImg {vertical-align: middle; cursor:pointer;}\n","commandIconStyles"); 
//}}}
ToolbarIconsPlugin allows you to specify image files to use as icons for toolbar buttons. No need to edit templates etc, just specify the image location and it will be used!
/***
Contains the stuff you need to use Tiddlyspot
Note you must also have UploadPlugin installed
***/
//{{{

// edit this if you are migrating sites or retrofitting an existing TW
config.tiddlyspotSiteId = 'fredgrott';

// 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")

});
//}}}
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 24/05/2008 18:49:20 | YourName | [[/|http://fredgrott.tiddlyspot.com/]] | [[store.cgi|http://fredgrott.tiddlyspot.com/store.cgi]] | . | [[index.html | http://fredgrott.tiddlyspot.com/index.html]] | . | ok |
| 24/05/2008 18:50:39 | FredGrott | [[/|http://fredgrott.tiddlyspot.com/]] | [[store.cgi|http://fredgrott.tiddlyspot.com/store.cgi]] | . | [[index.html | http://fredgrott.tiddlyspot.com/index.html]] | . | ok |
| 24/05/2008 20:24:00 | FredGrott | [[/|http://fredgrott.tiddlyspot.com/]] | [[store.cgi|http://fredgrott.tiddlyspot.com/store.cgi]] | . | [[index.html | http://fredgrott.tiddlyspot.com/index.html]] | . | ok |
| 24/05/2008 21:07:11 | FredGrott | [[/|http://fredgrott.tiddlyspot.com/]] | [[store.cgi|http://fredgrott.tiddlyspot.com/store.cgi]] | . | [[index.html | http://fredgrott.tiddlyspot.com/index.html]] | . |
/***
|''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"
	});
*/
//}}}

/***
|''Name:''|UploadPlugin|
|''Description:''|Save to web a TiddlyWiki|
|''Version:''|4.1.0|
|''Date:''|May 5, 2007|
|''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 (#3125)|
|''Requires:''|PasswordOptionPlugin|
***/
//{{{
version.extensions.UploadPlugin = {
	major: 4, minor: 1, revision: 0,
	date: new Date("May 5, 2007"),
	source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0 (#3125)'
};

//
// 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
		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}
				
			]);
	},
	refreshOptions: function(listWrapper) {
		var uploadOpts = [
			"txtUploadUserName",
			"pasUploadPassword",
			"txtUploadStoreUrl",
			"txtUploadDir",
			"txtUploadFilename",
			"txtUploadBackupDir",
			"chkUploadLog",
			"txtUploadLogMaxLine",
			]
		var opts = [];
		for(i=0; i<uploadOpts.length; i++) {
			var opt = {};
			opts.push()
			opt.option = "";
			n = uploadOpts[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 = 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,null,null,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 = Array(uploadParams[0],rssPath,uploadParams[2],'',uploadParams[4],uploadParams[5]);
		bidix.upload.httpUpload(rssUploadParams,convertUnicodeToUTF8(generateRss()),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 == httpStatus.NotFound)
			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; 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');


/* don't want this for tiddlyspot sites

// Backstage
merge(config.tasks,{
	uploadOptions: {text: "upload", tooltip: "Change UploadOptions and Upload", content: '<<uploadOptions>>'}
});
config.backstageTasks.push("uploadOptions");

*/


//}}}


//{{{
// do not copy this tiddler! you dont need this for HoverMenuPlugin to work!
config.hoverMenu.settings={
               align: 'right',    //align menu to right or left side of screen, possible values are 'right' and 'left'               
               x: 105,              // horizontal distance of menu from side of screen, increase to your liking.
               y: 230            //vertical distance of menu from top of screen at start, increase or decrease to your liking
               };
//}}}
/***
{{{<<writeIt {{'[[Current TW Directory|'+getTiddlyWikiDir()+']]'}}>>}}}
<<writeIt {{'[[Current TW Directory|'+getTiddlyWikiDir()+']]'}}>>

{{{<<writeIt {{"TW Last modified: "+(new Date(document.lastModified)).formatString("DD/MM/YYYY")}}>>}}}
<<writeIt {{"TW Last modified: "+(new Date(document.lastModified)).formatString("DD/MM/YYYY")}}>>


***/
//{{{


config.macros.writeIt = {};
config.macros.writeIt.handler= function(place,macroName,params,wikifier,paramString,tiddler) {
 wikify(params[0],place);

}
//}}}

//{{{
window.getTiddlyWikiDir=getTiddlyWikiDir;
//this function written by Udo
function getTiddlyWikiDir() {
          var path = document.location.toString();
          var i = path.lastIndexOf("/");
          return (i >= 0) ? path.substr(0, i+1) : path;
}

//}}}