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

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

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

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

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

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

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

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#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 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0 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:0 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 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

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

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

.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding: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 0;}
.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 0 0 0.5em;}
.tab {margin:0 0 0 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 0 14em;}

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

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

.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:0 0.25em; padding:0 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 0; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}

.fieldsetFix {border:0; padding:0; margin: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;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding:0.1em 0.4em; margin:0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin-left:3em; padding:1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding: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;}
noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
}
/*}}}*/
<!--{{{-->
<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 excludeLists'></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>>
How it is done:
*a grey layer ({{{modalNode}}}) is placed above the current window view
*the prompt to display (e.g. a form - {{{formNode}}}) is placed at the center of the window view
*following scrolling and resizing events, the layer position/size and the prompt position are updated

In the code example, clicking anywhere on the layer terminates the modal prompt.

The code, using jQuery:
{{{
var $ = jQuery;

var windowNode = $(window);
var modalNode = $('<div/>');
var formNode = $('<div/>').html("Cheap modal form").css({
	'background-color': '#FFFFFF',
	position: 'absolute',
	'z-index': '2001',
	border: '1px solid #888888',
	'border-radius': '10px',
	padding: '20px'
});
var refreshPrompt = function() {
	var box = {
		left: $(this).scrollLeft(),
		top: $(this).scrollTop(),
		width: modalNode.outerWidth(),
		height: modalNode.outerHeight()
	};
	modalNode.css({
		left: box.left + 'px',
		top: box.top + 'px'
	});
	formNode.css({
		left: (box.left + box.width/2 - formNode.outerWidth()/2) + 'px',
		top: (box.top + box.height/2 - formNode.outerHeight()/2) + 'px'
	});
};

modalNode.css({
	'background-color': '#BBBBBB',
	opacity: '0.7',
	position: 'absolute',
	'z-index': '2000',
	width: '100%',
	height: '100%'
}).click(function() {
	windowNode.unbind('scroll resize', refreshPrompt);
	$(this).remove();
	formNode.remove();
});
windowNode.bind('scroll resize', refreshPrompt);
$('body').append(modalNode, formNode);
refreshPrompt.apply(windowNode);
}}}
[[Devel]]
!Plugins
!!~ToDo list
Some plugins can be used to provide a ~ToDo list feature in ~TiddlyWiki, like [[CheckboxPlugin|http://www.tiddlytools.com/#CheckboxPlugin]], [[ToDoList|http://www.tiddlytools.com/#ToDoList]] and [[TaskOrganizerPlugin|http://www.math.ist.utl.pt/~psoares/addons_2.4.html#TaskOrganizerPlugin]]. There even exist alternate versions of the original ~TiddlyWiki.
However none met my needs: either the plugin does not provide enough features, requires to create a tiddler for each task, or requires to edit the tiddler manually to add a task.

And so, here is a new [[ToDo list plugin|ToDoListPlugin]], along with its [[documentation|ToDoListPluginDocumentation]]. This one provides tools to manage the tasks, does not require a tiddler for each added task, and allows ~TiddlyWiki formatting in tasks description.
When upgrading to newer versions of this plugin, it may be necessary to update ~ToDo list created with previous versions using the dedicated [[update plugin|ToDoListPlugin]]

!!Table of Contents
There are some plugins that can be used to generate a table of contents, like:
*[[DcTableOfContentsPlugin|http://devpad.tiddlyspot.com/#DcTableOfContentsPlugin]]
**Pros
***Adds a link to go back to the ~ToC in each heading
***~ToC style (CSS) can be overridden in [[StyleSheet]]
**Cons
***Does not work well if heading text uses ~TiddlyWiki formatting
***Links are only based on heading text, which is an issue when using the same text in different headings
***Overrides formatters, which may be an issue with newer versions of ~TiddlyWiki
***~ToC is generated according to tiddler original text, thus headings generated by macro are not listed
*[[SectionLinksPlugin|http://www.tiddlytools.com/#SectionLinksPlugin]]: 
**Pros
***Works even if heading text uses ~TiddlyWiki formatting, but discards it in the ~ToC
***~ToC is generated according to the headings found in the displayed tiddler, thus headings generated by macro are listed
***Can be used in [[ViewTemplate]] to be applied to all tiddlers
***Provides other features to make links between tiddlers
**Cons
***Does not have links to go back to the ~ToC in headings
***Links are only based on heading text, which is an issue when using the same text in different headings
***Generates the ~ToC in the displayed tiddler, which may cause troubles when embedding tiddlers
***~ToC style (CSS) cannot be overridden

So here is another [[Table of Contents plugin|TiddlerToCPlugin]]:
*Pros
**Keeps headings ~TiddlyWiki formatting when generating the ~ToC
**Links are based on inspected elements, and do work if different headings use the same text
**~ToC is generated according to the headings found in the displayed tiddler, thus headings generated by macro are listed
**Adds a link to go back to the ~ToC in each heading
**Can be used in [[ViewTemplate]] to be applied to all tiddlers
**~ToC style (CSS) can be overridden in [[StyleSheet]]
**Generates ~ToC for the enclosing tiddler (which may be embedded), and does not analyze embedded tiddlers
*Cons
**Does not generate ~ToC for embedded tiddlers: this can be fixed by adding the macro in the embedded tiddler
**Since it uses the displayed headings, it may not always work as expected if the headings are altered by other plugins

!!Google Analytics tracker
Following how to do it with the [[legacy tracking method|http://blog.spacelag.com/2007/10/tracking-tiddlywiki-with-google.html]], here is the [[asynchronous version|GATrackerPlugin]] with its persistent configuration handling.


!Notes
How to create a [[Cheap modal prompt]].
/***
|Name|GATrackerPlugin|
|Description|Google Analytics tracker|
|Author|Julien Coloos|
|Version|1.2.0|
|Date|2011-05-18|
|Status|stable|
|Source|http://julien.coloos.free.fr/TiddlyWiki-dev/#GATrackerPlugin|
|License|[img[CC BY-SA 3.0|http://i.creativecommons.org/l/by-sa/3.0/80x15.png][http://creativecommons.org/licenses/by-sa/3.0/]]|
|CoreVersion|2.6.2|
|Documentation|http://julien.coloos.free.fr/TiddlyWiki-dev/#GATrackerPlugin|

!Description
This plugin enables Google Analytics tracking inside TiddlyWiki.

The version used is the asynchronous one ({{{ga.js}}}).
The plugin comes with its own configuration, which is stored persistently inside the (hidden) [[SystemSettings]] tiddler.
The configuration has to be set before being effective: it can be done in the plugin tiddler (see below) if TiddlyWiki is not in read-only mode. Tracking works if an account ID has been set, tracking has been enabled, and TiddlyWiki access is non-local.

Tracking can be reported as either:
* page views
** pages are named {{{/#Tiddler name}}}
* events
** Category: {{{Tiddlers}}}
** Action: {{{Open}}}, {{{Refresh}}}, {{{Edit}}}, {{{Search}}}, {{{Close}}} or {{{CloseAll}}}
** Label
*** for {{{CloseAll}}} action: excluded tiddler
*** for {{{Search}}} action: searched text
*** otherwise, tiddler name on which action is performed
** Value: for the {{{CloseAll}}} action, the number of closed tiddlers
** Note: Google Analytics script limits the number of events (1 every 5 seconds, with a burst limit of 10)
Tracking can be globally disabled, or enabled per action on each tiddler:
* //Open//: when tiddler was not yet displayed
** Note: default tiddlers do not trigger this action when accessing TiddlyWiki
* //Refresh//: when tiddler was already displayed
** Note: this action is automatically triggered after editing a tiddler
* //Edit//: when editing (or viewing in read-only mode) the tiddler
* //Close//: when tiddler was displayed
** this action is never tracked in //pages views// tracking
** the //CloseAll// action is triggered by the TiddyWiki links //close all// and //close others// if at least one tiddler was closed; individual tiddlers closed are not tracked as //Close// actions
* //Search//: when searching in tiddlers
** this action is never tracked in //pages views// tracking
** {{{CloseAll}}} and {{{Open}}} actions are not taken into account while search is performed: TiddlyWiki automically closes opened tiddlers before searching and opens tiddler that match the searched text


!Configuration
<<GATrackerConfig>>


!Revision History
!!v1.2.0 (2011-05-18)
Enhancements:
* do not trigger {{{CloseAll}}} and {{{Open}}} actions when search is performed
* added the {{{Search}}} action

!!v1.1.0 (2011-05-17)
Enhancements:
* do not trigger {{{Open}}} action when displaying default tiddlers
* added the {{{CloseAll}}} action

!!v1.0.0 (2011-05-14)
Initial release.


!Code
***/
//{{{
/* Google Analytics queue object. Needs to be global. */
var _gaq = _gaq || [];

if (!config.extensions.GATracker) {(function($) {

version.extensions.GATrackerPlugin = {major: 1, minor: 2, revision: 0, date: new Date(2011, 5, 18)};

/* Prepare overridden TiddlyWiki displaying */
var trackOptions = {};
var displayDefault = 0, closingAll = 0, searching = 0;
var pl = config.extensions.GATracker = {
getOption: function(optKey) {
	return (config.optionsSource && (config.optionsSource[optKey] == "setting")) ? config.options[optKey] : null;
},
setOption: function(optKey, value) {
	config.options[optKey] = value;
	config.optionsSource[optKey] = "setting";
	saveOption(optKey);
},
loadOptions: function() {
	var gaTrack = (pl.getOption("txt_GATracker_track") || "1,0,1,1,1,0,0").split(",");
	trackOptions = {
		id: pl.getOption("txt_GATracker_id"),
		enabled: parseInt(gaTrack[0] || "1"),
		type: parseInt(gaTrack[1] || "0"),
		events: {
			open: parseInt(gaTrack[2] || "1"),
			refresh: parseInt(gaTrack[3]) || "1",
			edit: parseInt(gaTrack[4] || "1"),
			close: parseInt(gaTrack[5] || "0"),
			search: parseInt(gaTrack[6] || "0")
		}
	};
	if (trackOptions.id && !trackOptions.id.length) {
		trackOptions.id = null;
	}
},
saveOptions: function() {
	var opts = trackOptions.enabled && "1" || "0";
	opts += "," + trackOptions.type;
	for (var ev in trackOptions.events) {
		opts += "," + (trackOptions.events[ev] && "1" || "0");
	}
	pl.setOption("txt_GATracker_id", trackOptions.id || "");
	pl.setOption("txt_GATracker_track", opts);
},
track: function() {
	_gaq.push.apply(_gaq, arguments);
},
trackAndDisplayDefaultTiddlers: function() {
	displayDefault = 1;
	try { pl.displayDefaultTiddlers.apply(this, arguments) } catch(e){};
	displayDefault = 0;
},
trackAndDisplayTiddler: function(srcElement, tiddler, template, animate, unused, customFields, toggle, animationSrc) {
	if (!displayDefault) {
		var trackEvent, title = (tiddler instanceof Tiddler) ? tiddler.title : tiddler;
		if (story.getTiddler(title)) {
			/* Tiddler is already displayed */
			if (toggle === true) {
				/* Closing tiddler: tracked in separate function */
			}
			else if (template === DEFAULT_EDIT_TEMPLATE) {
				if (trackOptions.events.edit) trackEvent = "Edit";
			}
			else if (trackOptions.events.refresh) trackEvent = "Refresh";
		}
		else if (trackOptions.events.open && !searching) trackEvent = "Open";

		if (trackEvent) pl.track(trackOptions.type ? ["_trackPageview", "/#" + title] : ["_trackEvent", "Tiddlers", trackEvent, title]);
	}
	pl.displayTiddler.apply(this, arguments);
},
trackAndCloseTiddler: function(title, animate, unused) {
	if (closingAll) closingAll++;
	else pl.track(["_trackEvent", "Tiddlers", "Close", title]);
	pl.closeTiddler.apply(this, arguments);
},
trackAndCloseAllTiddlers: function(excluded) {
	closingAll = 1;
	try { pl.closeAllTiddlers.apply(this, arguments) } catch(e){};
	if ((closingAll > 1) && !searching) pl.track(["_trackEvent", "Tiddlers", "CloseAll", excluded, closingAll - 1]);
	closingAll = 0;
},
trackAndSearch: function(text, useCaseSensitive, useRegExp) {
	if (!trackOptions.type && trackOptions.events.search) pl.track(["_trackEvent", "Tiddlers", "Search", text]);
	searching = 1;
	try { pl.search.apply(this, arguments) } catch(e){};
	searching = 0;
}
};

pl.loadOptions();

/* Only track in non-local mode */
var local = "file:" == document.location.protocol;
if (!local && trackOptions.id && trackOptions.enabled) {
	/* Insert script tag to load GA */
	$("head").eq(0).prepend($("<script/>").attr({type: "text/javascript", async: "true", src: ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js"}));

	/* Override TiddlyWiki display */
	pl.displayTiddler = story.displayTiddler;
	story.displayTiddler = pl.trackAndDisplayTiddler;
	pl.displayDefaultTiddlers = story.displayDefaultTiddlers;
	story.displayDefaultTiddlers = pl.trackAndDisplayDefaultTiddlers;
	if (!trackOptions.type && trackOptions.events.close) {
		pl.closeTiddler = story.closeTiddler;
		story.closeTiddler = pl.trackAndCloseTiddler;
		pl.closeAllTiddlers = story.closeAllTiddlers;
		story.closeAllTiddlers = pl.trackAndCloseAllTiddlers;
	}
	pl.search = story.search;
	story.search = pl.trackAndSearch;

	/* Initialize tracking */
	pl.track(["_setAccount", trackOptions.id], ["_trackPageview"]);
}

config.macros.GATrackerConfig = {
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
	$(createTiddlyElement(place, "div")).html("Tracking status: <span style='color:" + (trackOptions.id && trackOptions.enabled ? "green'>enabled" : "red'>disabled") + "</span> and <span style='color:" + (local ? "red'>" : "green'>non-") + "local</span>");
	if (readOnly) {
		$(createTiddlyElement(place, "div")).html("Configuration is not available in read-only mode");
		return;
	}
	var formNode = $(createTiddlyElement(place, "div")).html("<div>Google Analytics plugin configuration:</div><table><tr><td>Account ID:</td><td><input id='ga_id' type='text'/></td></tr><tr><td>Tracking:</td><td><input id='ga_enabled' type='checkbox'/>Enabled<br/><br/>How: <select id='ga_track'><option value='0'>Events</option><option value='1'>Pages</option></select><br/><br/>What:<br/><input id='ga_track_open' type='checkbox'/>Open<br/><input id='ga_track_refresh' type='checkbox'/>Refresh<br/><input id='ga_track_edit' type='checkbox'/>Edit<br/><input id='ga_track_close' type='checkbox'/>Close<br/><input id='ga_track_search' type='checkbox'/>Search<br/></td></tr></table><input id='ga_action_submit' type='submit' value='Apply'/>");
	$("#ga_id", formNode).val(trackOptions.id);
	$("#ga_enabled", formNode)[0].checked = trackOptions.enabled;
	$("#ga_track option", formNode).eq(trackOptions.type)[0].selected = true;
	for (var ev in trackOptions.events) {
		$("#ga_track_" + ev, formNode)[0].checked = trackOptions.events[ev];
	}
	$("#ga_action_submit", formNode).click(function() {
		trackOptions.id = $("#ga_id", formNode).val();
		if (!trackOptions.id.length) trackOptions.id = null;
		trackOptions.enabled = $("#ga_enabled", formNode)[0].checked;
		trackOptions.type = parseInt($("#ga_track", formNode).val());
		for (var ev in trackOptions.events) {
			trackOptions.events[ev] = $("#ga_track_" + ev, formNode)[0].checked;
		}
		pl.saveOptions();

		var nodeDisplay = story.findContainingTiddler(place);
		var tiddlerDisplay;
		if (nodeDisplay) tiddlerDisplay = store.getTiddler(nodeDisplay.getAttribute("tiddler"));
		story.refreshTiddler(tiddlerDisplay ? tiddlerDisplay.title : tiddler.title, null, true);
	});
}
};

})(jQuery);}
//}}}
[[Devel]]
[[GettingStarted]]

Cyrius' ~TiddlyWiki dev
txt_GATracker_id: UA-23188652-1
txt_GATracker_track: 1%2C0%2C1%2C1%2C1%2C1%2C1
/***
|Name|TiddlerToCPlugin|
|Description|Tiddler Table of Contents generator|
|Author|Julien Coloos|
|Version|1.1.0|
|Date|2011-06-12|
|Status|stable|
|Source|http://julien.coloos.free.fr/TiddlyWiki-dev/#TiddlerToCPlugin|
|License|[img[CC BY-SA 3.0|http://i.creativecommons.org/l/by-sa/3.0/80x15.png][http://creativecommons.org/licenses/by-sa/3.0/]]|
|CoreVersion|2.6|
|Documentation|http://julien.coloos.free.fr/TiddlyWiki-dev/#TiddlerToCPlugin|

{{tw_ttoc{}}}
!Description
This plugin adds the {{{TiddlerToC}}} macro to generate a ~ToC inside a tiddler.
The generated ~ToC entries list the visible headings found in the tidder, each entry being preceded by a number representing its level and index (e.g.: //1.2.1//). Those numbers link to the corresponding heading.
Found headings are also altered to display a link back to the ~ToC.

The ~ToC does not reference tiddlers embedded using the {{{tiddler}}}, {{{slider}}} or {{{tabs}}} macro.

The ~ToC is either generated at a given target, or at the beginning of the place it was dropped in. If there are less headings than a given minimum (default being 2), the ~ToC is not displayed.
The ~ToC title can be clicked to hide/display the ~ToC content.


!Notes
The {{{TiddlerToC}}} macro searches for the HTML headings ({{{h1}}} to {{{h6}}} tags) in the place where it is inserted. Each heading is then converted to a ~ToC entry, preserving inner text format.
The macro thus has to be inserted at the end of the tiddler: content has been generated and the ~ToC can be populated.


!Usage
The {{{TiddlerToC}}} macro is intended to be inserted at the end of a tiddler.

By default the ~ToC is generated at the beginning of the place the macro was inserted in.
However a target can be used: if the place contains an element which class is {{{tw_ttoc}}}, this element will be replaced by the ~ToC.
Such an element can be generated by dropping one of the following inside the tiddler:
* using a ~TiddlyWiki macro
{{{
{{tw_ttoc{}}}
}}}
* inserting an explicit HTML tag; the advantage here is that attributes can be specified
{{{
<html><div class="tw_ttoc" min-entries="3"/></html>
}}}


The macro and/or target element can also be used in [[ViewTemplate]] to be applied to all tiddlers:
{{{
...
<!-- Wikified tiddler content -->
<div class='viewer' macro='view text wikified'>
	<!-- Insert ToC right before tiddler content -->
	<div class='tw_ttoc'></div>
</div>
<!-- ToC generator, to use at the end of the tiddler -->
<div macro='TiddlerToC min-entries:3'></div>
}}}

!!Parameters
The following parameters are available:
* {{{min-entries}}} (optional)
** minimum number of entries needed to display the ~ToC
** can be specified as macro parameter, and can be overridden in the target tag (needs explicit HTML tag; see before)
** default value is {{{2}}}

!!Examples
Without target:
{{{
Tiddler content.
...

<<TiddlerToC min-entries:3>>
}}}

With a target:
{{{
Beginning of the tiddler.
...

Where to generate the ToC:
{{tw_ttoc{}}}
Or, with a minimum number of entries specified:
<html><div class="tw_ttoc" min-entries="3"/></html>

Tiddler continues ...

<<TiddlerToC min-entries:3>>
}}}


!Styling
~ToC content uses some classes which style can be overriden using CSS. Those classes are:
* {{{tw_ttoc}}}: ~ToC
* {{{tw_ttoc_title}}}: title ({{{Table of Contents}}})
* {{{tw_ttoc_level}}}: sub-level entry indentation
* {{{tw_ttoc_entry}}}: entry
* {{{tw_ttoc_id}}}: entry number
* {{{tw_ttoc_top}}}: heading link back to the ~ToC

Default style can be found in the code below, and can be overridden in the [[StyleSheet]] tiddler.


!Revision History
!!v1.1.0 (2011-06-12)
Changes:
* by default, ~ToC is now displayed only if it contains more than one entry

Enhancements:
* added a macro parameter to give the minimum number of entries needed to display the ~ToC
** the parameter can be overridden in the ~ToC target

Fixes:
* do not list headings that are not //displayed//

!!v1.0.1 (2011-05-29)
Changes:
* if there is none, adds a {{{br}}} tag after the ~ToC

!!v1.0.0 (2011-05-28)
Initial release.


!Code
***/
//{{{
if (!config.macros.TiddlerToC) {(function($) {

version.extensions.TiddlerToCPlugin = {major: 1, minor: 1, revision: 0, date: new Date(2011, 6, 12)};

var hTag = /^h([1-6])$/i;

setStylesheet(".tw_ttoc {background-color: #F8F8F8; padding: 10px; border: 1px #CCCCCC solid;} .tw_ttoc_title {text-align:center; font-weight: bold; margin: 5px 0px 20px 0px;} .tw_ttoc_level {padding-left: 20px;} .tw_ttoc_id {margin-right: 6px;} .tw_ttoc_top {float: right; font-size: 0.5em;}", "TiddlerToCPlugin");

function cloneNodeWithEvents(node) {
	var clone = node.cloneNode(true);
	var n1 = [node].concat(Array.prototype.slice.call(node.getElementsByTagName('*')));
	var n2 = [clone].concat(Array.prototype.slice.call(clone.getElementsByTagName('*')));

	for (var i=0 ; i<n1.length ; i++) {
		for (var j in n1[i]) {
			if (j.substr(0,2) != "on") continue;
			n2[i][j] = n1[i][j];
		}
	}

	return clone;
}

var pl = config.macros.TiddlerToC = {
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
	var namedParams = paramString.parseParams(null, null, true), paramMinEntries = getParam(namedParams, "min-entries"), minEntries = paramMinEntries ? parseInt(paramMinEntries) : 2;

	if ($(place).hasClass("viewer") || $(place).parents(".viewer").size()) pl.generate(place, minEntries);
	else {
		/* the macro is not used inside a tiddler content but probably in a template */
		var t = story.findContainingTiddler(place);
		if (!t) return;
		pl.generate(t, minEntries);
	}
},
getElements: function(place) {
	var els = $();

	$(place).children().each(function(i, n) {
		/* exclude embedded tiddlers */
		if ($(n).attr("tiddler") || $(n).hasClass("sliderPanel") || $(n).hasClass("tabsetWrapper")) return;
		/* include headings and ToC target */
		if (hTag.test(n.tagName) || $(n).is(".tw_ttoc")) els = els.add(n);
		/* recurse */
		els = els.add(pl.getElements(n));
	});

	return els;
},
generate: function(place, minEntries) {
	var els = pl.getElements(place);

	/* get ToC target, or insert it as first element */
	var toc = els.filter(".tw_ttoc");
	if (toc.size()) {
		if (toc.size() > 1) {
			/* More than one target; happens when using ViewTemplate while
			 * tiddler already contains a ToC target. In any case, it is best
			 * to keep the last one and remove others.
			 */
			toc.not(toc.last()).remove();
			toc = toc.last();
		}
		/* check the ToC was not already generated */
		if (toc[0].toc && toc[0].toc.generated) return;
		/* check if the minimum number of entries is overridden */
		if (toc.attr("min-entries")) minEntries = parseInt(toc.attr("min-entries"));
		/* rebuild target tag */
		toc = toc.empty().wrapInner("<div class='tw_ttoc'/>").children("div").unwrap();
	}
	else toc = $("<div class='tw_ttoc'/>").prependTo(place);

	var hLevelCurrent = 0, hLevel;
	var tocInner = $("<div/>"), listCurrent = tocInner[0], listId = "1";
	toc.hide().append($("<div class='tw_ttoc_title'><a href='javascript:;'>Table of Contents</a></div>"), tocInner);
	$(".tw_ttoc_title a", toc).click(function() {
		if (tocInner.is(":visible")) tocInner.hide("fast");
		else tocInner.show("fast");
	});

	var headings = $();
	els.each(function(i, c) {
		/* check we got a visible heading */
		var match = hTag.exec(c.tagName);
		if (!match || !$(c).is(":visible")) return;
		hLevel = parseInt(match[1]);

		/* check the heading level */
		if (!hLevelCurrent) hLevelCurrent = hLevel;
		if (hLevel < hLevelCurrent) {
			/* have to go up */
			while ((hLevel <= --hLevelCurrent) && listCurrent.parentNode) {
				listCurrent = listCurrent.parentNode.parentNode;
				ids = listId.split(".");
				ids.pop();
				listId = ids.join(".");
			}
		}
		else if (hLevel > hLevelCurrent) {
			/* have to go down */
			while (hLevel >= ++hLevelCurrent) {
				$(listCurrent.lastChild).append(listCurrent = $("<div class='tw_ttoc_level'/>")[0]);
				ids = listId.split(".");
				ids.push(1);
				listId = ids.join(".");
			}
		}
		/* determine this heading index */
		ids = listId.split(".");
		ids[ids.length-1] = $(listCurrent).children("div.tw_ttoc_entry").size() + 1;
		listId = ids.join(".");

		/* clone the heading content to insert it in the ToC */
		$(cloneNodeWithEvents(c)).wrapInner("<div class='tw_ttoc_entry'/>").children("div").unwrap().prepend($("<a class='tw_ttoc_id' href='javascript:;'/>").html(listId).click({target: c}, function(ev){window.scrollTo(0,findPosY(ev.data.target))})).appendTo(listCurrent);

		headings = headings.add(c);

		hLevelCurrent = hLevel;
	});
	toc[0].toc = {generated: true};

	if (headings.size() >= minEntries) {
		/* display ToC */
		/* Note: jQuery 'next' does not take into account text nodes */
		var sibling = toc.show()[0].nextSibling;
		if (sibling && (sibling.nodeName != "BR")) toc.after("<br/>");

		/* insert a 'ToC' link in the headings */
		headings.append($("<span class='tw_ttoc_top'><a href='javascript:;' title='Go to Table of Contents'>[ToC]</a></span>")).find(".tw_ttoc_top a").click(function() {window.scrollTo(0,findPosY(toc[0]))});
	}
}
};

})(jQuery);}
//}}}
/***
<<TiddlerToC>>
***/
/***
|Name|ToDoListPlugin|
|Description|ToDo list contained in a tiddler|
|Author|Julien Coloos|
|Version|1.4.0|
|Date|2011-06-17|
|Status|stable|
|Source|http://julien.coloos.free.fr/TiddlyWiki-dev/#ToDoListPlugin|
|License|[img[CC BY-SA 3.0|http://i.creativecommons.org/l/by-sa/3.0/80x15.png][http://creativecommons.org/licenses/by-sa/3.0/]]|
|CoreVersion|2.6|
|Documentation|http://julien.coloos.free.fr/TiddlyWiki-dev/#ToDoListPluginDocumentation|
!Code
***/
//{{{
if(!config.macros.ToDoList){(function($){
version.extensions.ToDoListPlugin={major:1,minor:4,revision:0,date:new Date(2011,6,17)};
var tooltip=$("<div/>").css({display:"none",opacity:"0.85",position:"absolute","background-color":"#EEEEEE",border:"1px solid #888888","border-radius":"10px","box-shadow":"6px 6px 3px #CCCCCC",padding:"4px"})
,pl=config.macros.ToDoList={
handler:function(place,macroName,params,wikifier,paramString,tiddler){
	var tiddlerDisp,todoCount=0,doneCount=0,namedParams=paramString.parseParams(null,null,true),title=tiddler.title,taskList=pl.getValue(title,null,"list"),rootNode=createTiddlyElement(place,"div"),menuNode=$("<div/>")[0],table=0,v=0,tableNode=createTiddlyElement(rootNode,"div"),node=story.findContainingTiddler(place),paramTable=getParam(namedParams,"table"),tasks=taskList?taskList.split(","):[],paramCats=getParam(namedParams,"categories"),cats=paramCats&&(paramCats!="0")?{list:[],map:{}}:null,paramUpd=getParam(namedParams,"updateTiddler"),paramHLvl=getParam(namedParams,"headingLevel"),hLvl=parseInt(paramHLvl||"2"),rows;
	if(node) tiddlerDisp=store.getTiddler(node.getAttribute("tiddler"));
	if(!tiddlerDisp) tiddlerDisp=tiddler;
	$(menuNode).html("<a id='tdl_menu_access'>Edit ToDo list</a><div id='tdl_action_menu' style='display:none'><a id='tdl_action_add'>Add</a><br/><a id='tdl_action_update'>Update</a><br/><a id='tdl_action_rearrange'>Rearrange</a><br/><a id='tdl_action_migrate'>Migrate</a><br/><a id='tdl_action_remove'>Remove</a><br/><a id='tdl_action_purge'>Purge</a><br/></div><div id='tdl_action_message' style='display:none'/><div id='tdl_task_entry_form' style='display:none'><table><tr><td>Category:</td><td><select id='tdl_task_cat'><option value='-1'>Uncategorized</option><option value='-2'>New category</option><option value=''>----------</option></select><span id='tdl_task_applycat'><input type='checkbox'/><span/></span><br/><input id='tdl_task_newcat' type='text' style='width:99%;display:none'/></td></tr><tr><td>Label:</td><td style='width:100%'><input id='tdl_task_lbl' type='text' style='width:99%'/></td></tr><tr><td>Description:</td><td><textarea id='tdl_task_desc' rows='15' style='width:99%'></textarea></td></tr></table><a id='tdl_preview'>Preview</a></div><div id='tdl_action_submit_form' style='display:none'><input id='tdl_action_submit' type='submit'/><input id='tdl_action_cancel' type='submit' value='Cancel'/></div>").find("a").attr({href:"javascript:;"});
	$("body").append(tooltip);
	if(!cats) $("#tdl_task_entry_form table tr",menuNode).eq(0).hide();

	node=tableNode;
	if(paramTable&&(paramTable!="0")){
		table=1;
		v=paramTable.toLowerCase()=="v";
		var th="<th"+(v?"":" style='width:50%'")+" class='tdl_section'/>",td="<td style='vertical-align:top'/>";
		$(node).html("<table><tr>"+th+(v?"<td/>":th)+"</tr>"+(v?"<tr>"+th+"<td/></tr>":(cats?"":"<tr>"+td+td+"</tr>"))+"</table>");
	}

	$.each(tasks,function(i,id){
		var cat=pl.getValue(title,id,"category")||"Uncategorized",completed=pl.getDate(title,id,"completed");
		(completed?doneCount++:todoCount++);

		if(cats&&!cats.map[cat]){
			cats.list.push(cat);
			cats.map[cat]=[$("<div/>")[0],table?$("<div/>")[0]:null];
		}

		$(node=createTiddlyElement(cats?cats.map[cat][table&&completed?1:0]:table?$("td",tableNode)[completed?1:0]:tableNode,"div","tdl_"+id+"_anchor_list","tdl_task_entry")).html("<a href='javascript:;'><tt>[ ]</tt></a>").children("a").click(function(){return pl.actionLink(rootNode,pl.taskNode(this))}).mouseover(function(){pl.showTooltip($("#tdl_"+pl.taskNode(this).tdl.id+"_anchor",rootNode).clone(),$(this))}).mouseout(function(){tooltip.hide().html("")});
		node.tdl={id:id};
		$(createTiddlyCheckbox(node,pl.getValue(title,id,"label"),completed?"checked":"")).click({id:id,completed:completed},function(ev){
			store.suspendNotifications();
			pl.setValue(title,ev.data.id,{"completed":ev.data.completed?null:new Date().getTime(),"completor":ev.data.completed?null:config.options.txtUserName});
			pl.updTiddler(rootNode,title);
			pl.resumeNotifications(title);
			pl.refresh(title,tiddlerDisp.title);
		});
	});
	if(table){
		$("th",tableNode).eq(0).html("To do ("+todoCount+")");
		$("th",tableNode).eq(1).html("Done ("+doneCount+")");
	}
	if(cats) $.each(cats.list.sort(function(a,b){
		a=pl.plain(a).toLowerCase();
		b=pl.plain(b).toLowerCase();
		return a==b?0:(a<b?-1:1);
	}),function(i,c){
		todoCount=$(cats.map[c][0]).children().size();
		if(table) doneCount=$(cats.map[c][1]).children().size();
		if(!table){
			$(tableNode).append(node=$("<p/>"));
			wikify(c+" ("+todoCount+")",node[0]);
			node.append(cats.map[c][0]);
		}else if(v){
			if(todoCount){
				$("th.tdl_section",tableNode).eq(1).parent().before(node=$("<tr><th/></tr><tr><td/></tr>"));
				wikify(c+" ("+todoCount+")",$("th",node)[0]);
				$("td",node).append(cats.map[c][0]);
				i=$("th.tdl_section",tableNode).eq(0);
				if((rows=parseInt(i.attr("rowspan")||"1"))==1){
					i.next().replaceWith(node.eq(0).detach().children());
					rows--;
				}
				i.attr("rowspan",rows+2);
			}
			if(doneCount){
				$("table",tableNode).append(node=$("<tr><th/></tr><tr><td/></tr>"));
				wikify(c+" ("+doneCount+")",$("th",node)[0]);
				$("td",node).append(cats.map[c][1]);
				i=$("th.tdl_section",tableNode).eq(1);
				if((rows=parseInt(i.attr("rowspan")||"1"))==1){
					i.next().replaceWith(node.eq(0).detach().children());
					rows--;
				}
				i.attr("rowspan",rows+2);
			}
		}else{
			$("table",tableNode).append(node=$("<tr><th colspan='2'/></tr><tr><td style='vertical-align:top'/><td style='vertical-align:top'/></tr>"));
			wikify(c+" ("+(todoCount+doneCount)+")",$("th",node)[0]);
			$("td",node).eq(0).append(cats.map[c][0]);
			$("td",node).eq(1).append(cats.map[c][1]);
		}
	});

	rootNode.appendChild(menuNode);
	rootNode.tdl={title:title,titleDisp:tiddlerDisp?tiddlerDisp.title:undefined,menuNode:menuNode,tableNode:tableNode,action:pl.Action.NONE,cats:cats,updTiddler:!paramUpd||paramUpd!="0"};

	$("#tdl_menu_access",menuNode).mouseenter(function(){
		$("#tdl_menu_access",menuNode).hide();
		$("#tdl_action_menu",menuNode).mouseleave(function(){pl.hideActionMenu(menuNode)}).show();
	});
	$("#tdl_action_cancel",menuNode).click(function(){
		var action=rootNode.tdl.action,tasks=rootNode.tdl.tasks;
		rootNode.tdl.action=pl.Action.NONE;
		pl.hideActionMenu(menuNode);
		$("#tdl_action_message",menuNode).hide();
		$("#tdl_task_entry_form",menuNode).hide();
		$("#tdl_action_submit_form",menuNode).hide();
		if(tasks){
			if(action==pl.Action.UPDATE) pl.triggerEntryActionLink(pl.taskNode(rootNode,tasks),0);
			else if(action==pl.Action.REARRANGE) pl.refresh(null,tiddlerDisp.title);
			else if(action==pl.Action.REMOVE||action==pl.Action.MIGRATE) $.each(tasks,function(i,id){pl.triggerEntryActionLink(pl.taskNode(rootNode,id),0)});
			rootNode.tdl.tasks=undefined;
		}
	});
	$("#tdl_action_add",menuNode).click({rootNode:rootNode,action:pl.Action.ADD},pl.taskAction);
	$("#tdl_action_update",menuNode).click({rootNode:rootNode,action:pl.Action.UPDATE},pl.taskAction);
	$("#tdl_action_rearrange",menuNode).click({rootNode:rootNode,action:pl.Action.REARRANGE},pl.taskAction);
	$("#tdl_action_migrate",menuNode).click({rootNode:rootNode,action:pl.Action.MIGRATE},pl.taskAction);
	$("#tdl_action_remove",menuNode).click({rootNode:rootNode,action:pl.Action.REMOVE},pl.taskAction);
	$("#tdl_action_purge",menuNode).click({rootNode:rootNode,action:pl.Action.PURGE},pl.taskAction);
	$("#tdl_preview",menuNode).mouseover(function(){
		var data=pl.taskFormData(menuNode,cats);
		pl.showTooltip($(pl.taskSection(rootNode,hLvl,rootNode.tdl.tasks,cats?data.cat||"Uncategorized":null,data.lbl,data.desc)),$(this));
	}).mouseout(function(){tooltip.hide().html("")});

	$.each(tasks,function(i,id){$(pl.taskSection(rootNode,hLvl,id,cats?pl.getValue(title,id,"category")||"Uncategorized":null,pl.getValue(title,id,"label"),pl.getValue(title,id,"description"))).attr({id:"tdl_"+id+"_anchor"}).addClass("tdl_task").appendTo(rootNode)});
	if(cats) $.each(cats.list,function(i,c){if(c!="Uncategorized") $("<option/>").html(pl.plain(c)).val(i).appendTo($("#tdl_task_cat",menuNode))});
	$("#tdl_task_cat",menuNode).change(function(){
		if($("#tdl_task_cat",menuNode).val()=="") $("#tdl_task_cat option",menuNode).eq(0).attr({selected:"selected"});
		if($("#tdl_task_cat",menuNode).val()==-2) $("#tdl_task_newcat",menuNode).show("fast");
		else $("#tdl_task_newcat",menuNode).hide("fast");
		if((rootNode.tdl.action==pl.Action.UPDATE)&&rootNode.tdl.tasks) $("#tdl_task_applycat",menuNode).show("fast");
	});
},
showTooltip:function(node,rel){
	tooltip.append(node.show()).find(".tdl_nopreview").remove();
	var pos=rel.offset(),vTop=$(window).scrollTop(),vBottom=vTop+$(window).height();
	pos.left+=rel.width()+5;
	if((pos.top-=5)+tooltip.outerHeight()>vBottom) {
		if((pos.top=vBottom-tooltip.outerHeight())<vTop) pos.top=vTop;
	}
	tooltip.css(pos).show();
},
taskSection:function(rootNode,hLvl,id,cat,lbl,desc){
	var title=rootNode.tdl.title,created=pl.getDate(title,id,"created")||new Date(),creator=pl.getValue(title,id,"creator"),updated=pl.getDate(title,id,"updated"),updator=pl.getValue(title,id,"updator"),completed=pl.getDate(title,id,"completed"),completor=pl.getValue(title,id,"completor"),section="!",node;
	while(--hLvl>0) section+="!";
	wikify(section+lbl,node=createTiddlyElement(null,"div"));
	if(!desc) $(node).hide();
	$(createTiddlyButton(createTiddlyElement(node,"div",null,"tdl_nopreview"),"Go to list")).attr({href:"javascript:;"}).click({id:"tdl_"+id+"_anchor_list"},function(ev){
		pl.scrollTo($("#"+ev.data.id,rootNode)[0]);
		return false;
	});
	section="";
	if(cat) section+="''Category'': "+cat+"\n";
	section+="''Created'': {{{"+created.toLocaleString()+"}}}"+(creator?" by [["+creator+"]]":"")+"\n";
	if(updated) section += "''Updated'': {{{"+updated.toLocaleString()+"}}}"+(updator?" by [["+updator+"]]":"")+"\n";
	section += "''Completed'': {{{"+(completed?completed.toLocaleString():"not yet")+"}}}"+(completed&&completor?" by [["+completor+"]]":"")+"\n";
	section += "''Description'':"+(desc?"\n\n"+desc:" none");
	wikify(section,node);
	$(node).append("<br class='tdl_nopreview'/>");
	return node;
},
taskFormData:function(menuNode,cats){
	var cat;
	if((cat=$("#tdl_task_cat",menuNode).val())==-1) cat=null;
	else if(cat==-2) {if((cat=$("#tdl_task_newcat",menuNode).val())=="") cat=undefined}
	else cat=cats.list[parseInt($("#tdl_task_cat",menuNode).val())];
	return {cat:cat,lbl:$("#tdl_task_lbl",menuNode).val(),desc:$("#tdl_task_desc",menuNode).val()};
},
hideActionMenu:function(menuNode){
	$("#tdl_action_menu",menuNode).unbind("mouseleave").hide();
	$("#tdl_menu_access",menuNode).show();
},
showTaskForm:function(rootNode,id){
	var add=rootNode.tdl.action==pl.Action.ADD,title=rootNode.tdl.title,menuNode=rootNode.tdl.menuNode,taskList=pl.getValue(title,null,"list"),cats=rootNode.tdl.cats,cat,i,lbl,desc;
	if(id){
		cat=pl.getValue(title,id,"category");
		lbl=pl.getValue(title,id,"label");
		desc=pl.getValue(title,id,"description");
	}

	i=cats&&cat?$.inArray(cat,cats.list):-1;
	$("#tdl_task_cat option",menuNode).eq(i>=0?i+3:0).attr({selected:"selected"});
	$("#tdl_task_newcat",menuNode).val("");
	$("#tdl_task_lbl",menuNode).val(lbl||"");
	$("#tdl_task_desc",menuNode).val(desc||"");
	$("#tdl_action_submit",menuNode).val((add?"Add":"Update")+" task").unbind("click").click(function(){
		if(add) id=parseInt(pl.getValue(title,null,"nextId")||"1");
		var data=pl.taskFormData(menuNode,cats),applycat=$("#tdl_task_applycat input",menuNode)[0].checked;
		if(!data.lbl||!id||(data.cat===undefined)) return false;

		store.suspendNotifications();
		if(add) pl.setValue(title,id,{"created":new Date().getTime(),"creator":config.options.txtUserName});
		else pl.setValue(title,id,{"updated":new Date().getTime(),"updator":config.options.txtUserName});
		pl.setValue(title,id,{"category":data.cat,"label":data.lbl,"description":data.desc});
		if(add) pl.setValue(title,null,{"nextId":id+1,"list":(taskList?taskList+",":"")+id});
		else if(applycat&&(data.cat!==cat)) $.each(taskList.split(","),function(i,id){if(pl.getValue(title,id,"category")===cat) pl.setValue(title,id,{"category":data.cat})});
		pl.updTiddler(rootNode,title);
		pl.resumeNotifications(title);
		pl.refresh(title,rootNode.tdl.titleDisp);
	});
	$("#tdl_task_applycat",menuNode).hide().find("span").html(id?"Apply category ("+pl.plain(cat||"Uncategorized")+") change to other tasks":"");
	$("#tdl_task_applycat input",menuNode).attr({checked:""});
	$("#tdl_task_entry_form",menuNode).show("fast");
	$("#tdl_action_submit_form",menuNode).show("fast");
},
removeTask:function(rootNode,id,orphans){
	var title=rootNode.tdl.title,taskList=pl.getValue(title,null,"list"),ntasks,asked=[],links={};
	if(!taskList) return;

	if(orphans){
		$(".tdl_task .tiddlyLinkExisting",rootNode).each(function(){
			var t=$(this).attr("tiddlylink");
			if(links[t]) links[t]++;
			else links[t]=1;
		});
		$("#tdl_"+id+"_anchor",rootNode).remove().find(".tiddlyLinkExisting").each(function(){
			var t=$(this).attr("tiddlylink");
			if(asked.contains(t)||--links[t]) return;
			asked.push(t);
			if(!store.getReferringTiddlers(t).length&&!store.getTiddler(t).isTagged("excludeLists")&&confirm("Remove possibly orphan tiddler ?\n"+t)){
				if(store.getTiddler(t).isTagged("systemConfig")&&!confirm("Tiddler has systemConfig tag, remove it anyway ?\n"+t)) return;
				store.removeTiddler(t);
				story.closeTiddler(t,true);
			}
		});
	}

	$.each(taskList.split(","),function(i,v){
		if(v==id) return;
		ntasks=(ntasks?ntasks+",":"")+v;
	});
	store.setValue(title,"tdl.t"+id,null);
	pl.setValue(title,null,{"list":ntasks});
},
taskAction:function(ev){
	var rootNode=ev.data.rootNode,action=ev.data.action,title=rootNode.tdl.title,menuNode=rootNode.tdl.menuNode,taskList=pl.getValue(title,null,"list"),tasks=taskList?taskList.split(","):[];

	if(action==pl.Action.PURGE){
		if(!confirm("Remove all tasks?")) return false;
		store.suspendNotifications();
		store.setValue(title,"tdl",null);
		pl.updTiddler(rootNode,title);
		pl.resumeNotifications(title);
		pl.refresh(title,rootNode.tdl.titleDisp);
		return false;
	}

	rootNode.tdl.action=action;
	$("#tdl_action_menu",menuNode).unbind("mouseleave").hide();
	var childNode=$("#tdl_action_message",menuNode);
	if(action==pl.Action.ADD){
		childNode.html("Please fill the task details");
		pl.showTaskForm(rootNode);
	}else if(action==pl.Action.UPDATE){
		childNode.html("Please select the task to update");
		pl.showTaskForm(rootNode);
	}else if(action==pl.Action.REARRANGE){
		childNode.html("Please select the task to move, then the one to move to");
		$("#tdl_action_submit",menuNode).unbind("click").val("Apply").click(function(){
			if(!rootNode.tdl.tasks) return false;
			store.suspendNotifications();
			pl.setValue(title,null,{"list":rootNode.tdl.tasks[1].join(",")});
			pl.updTiddler(rootNode,title);
			pl.resumeNotifications(title);
			pl.refresh(title,rootNode.tdl.titleDisp);
		});
		$("#tdl_action_submit_form",menuNode).show("fast");
	}else if(action==pl.Action.MIGRATE){
		var tiddlers=store.getTiddlers("title","excludeLists");
		childNode.html("Please select the task(s) to migrate and the destination tiddler<div><select id='tdl_migrate_tiddler'/></div>");
		$.each(tiddlers,function(i,t){if(t.title!=title) $("<option value='"+i+"'/>").html(t.title.htmlEncode()).appendTo($("#tdl_migrate_tiddler",childNode))});
		$("#tdl_action_submit",menuNode).unbind("click").val("Migrate task(s)").click(function(){
			var stasks=rootNode.tdl.tasks,ntitle=tiddlers[$("#tdl_migrate_tiddler option:selected",childNode).val()].title,ntaskList=pl.getValue(ntitle,null,"list");
			if(!stasks||!stasks.length) return;

			store.suspendNotifications();
			$.each(stasks.sort(function(a,b){return $.inArray(a,tasks)-$.inArray(b,tasks)}),function(i,id){
				nid=parseInt(pl.getValue(ntitle,null,"nextId")||"1");
				pl.setValue(ntitle,nid,{"created":pl.getValue(title,id,"created"),"creator":pl.getValue(title,id,"creator"),"updated":pl.getValue(title,id,"updated"),"updator":pl.getValue(title,id,"updator"),"completed":pl.getValue(title,id,"completed"),"completor":pl.getValue(title,id,"completor"),"category":pl.getValue(title,id,"category"),"label":pl.getValue(title,id,"label"),"description":pl.getValue(title,id,"description")});
				pl.setValue(ntitle,null,{"nextId":nid+1,"list":ntaskList=(ntaskList?ntaskList+",":"")+nid});
				pl.removeTask(rootNode,id,0);
			});
			pl.updTiddler(rootNode,title);
			pl.updTiddler(rootNode,ntitle);
			pl.resumeNotifications(title);
			store.notify(ntitle,true);
			pl.refresh(title,rootNode.tdl.titleDisp);
		});
		$("#tdl_action_submit_form",menuNode).show("fast");
	}else if(action==pl.Action.REMOVE){
		childNode.html("Please select the task(s) to remove");
		$("#tdl_action_submit",menuNode).unbind("click").val("Remove task(s)").click(function(){
			var stasks=rootNode.tdl.tasks,message="Removing:";
			if(!stasks||!stasks.length) return;

			$.each(stasks,function(i,id){message+="\n - "+pl.plain(pl.getValue(title,id,"label"))});
			if(!confirm(message)) return false;
			store.suspendNotifications();
			$.each(stasks,function(i,id){pl.removeTask(rootNode,id,1)});
			pl.updTiddler(rootNode,title);
			pl.resumeNotifications(title);
			pl.refresh(title,rootNode.tdl.titleDisp);
		});
		$("#tdl_action_submit_form",menuNode).show("fast");
	}
	childNode.show("fast");
	return false;
},
triggerEntryActionLink:function(taskNode,selected){$("tt",taskNode).first().html(selected?"[X]":"[ ]")},
actionLink:function(rootNode,taskNode){
	var action=rootNode.tdl.action,tasks=rootNode.tdl.tasks,id=taskNode.tdl.id;
	if(action==pl.Action.UPDATE){
		if(tasks) pl.triggerEntryActionLink(pl.taskNode(rootNode,tasks),0);
		pl.triggerEntryActionLink(taskNode,1);
		tasks=id;
		pl.showTaskForm(rootNode,id);
	}else if(action==pl.Action.REARRANGE){
		if(tasks){
			var sNode=pl.taskNode(rootNode,tasks[0]);
			if(tasks[0]==id){
				pl.triggerEntryActionLink(sNode,0);
				tasks[0]=null;
			}else if(tasks[0]){
				var m=tasks[1];
				var pos1=$.inArray(tasks[0],m);
				var pos2=$.inArray(id,m);
				if(pos1<pos2){
					$($(sNode).nextAll().get().reverse()).each(function(i,n){
						if($.inArray(n.tdl.id,m)<=pos2){
							$(sNode).detach().insertAfter(n);
							return false;
						}
					});
				}else{
					$($(sNode).prevAll().get().reverse()).each(function(i,n){
						if($.inArray(n.tdl.id,m)>=pos2){
							$(sNode).detach().insertBefore(n);
							return false;
						}
					});
				}
				tasks[1].splice(pos2,0,tasks[1].splice(pos1,1)[0]);
				pl.triggerEntryActionLink(sNode,0);
				tasks[0]=null;
			}else{
				pl.triggerEntryActionLink(taskNode,1);
				tasks[0]=id;
			}
		}else{
			pl.triggerEntryActionLink(taskNode,1);
			tasks=[id,pl.getValue(rootNode.tdl.title,null,"list").split(",")];
		}
	}else if(action==pl.Action.REMOVE||action==pl.Action.MIGRATE){
		var alreadySelected=0;
		if(tasks){
			$.each(tasks,function(i,v){
				if(v==id){
					alreadySelected=1;
					tasks.splice(i,1);
					return false;
				}
			});
		}else tasks=[];

		if(!alreadySelected){
			pl.triggerEntryActionLink(taskNode,1);
			tasks.push(id);
		}else pl.triggerEntryActionLink(taskNode,0);
	}else pl.scrollTo($("#tdl_"+id+"_anchor:visible",rootNode)[0]);
	rootNode.tdl.tasks=tasks;
	return false;
},
taskNode:function(node,id){
	var r;
	if(!id) r=$(node).parents(".tdl_task_entry")[0];
	else $(".tdl_task_entry",node.tdl.tableNode).each(function(i){
		if(this.tdl.id==id){
			r=this;
			return false;
		}
	});
	return r;
},
plain:function(t){
	var node=$("<span/>")[0];
	wikify(t,node);
	return $(node).text();
},
getDate:function(title,id,field){
	var dateV=pl.getValue(title,id,field);
	return dateV?new Date(parseInt(dateV)):undefined;
},
getValue:function(title,id,field){return store.getValue(title,"tdl."+(id?"t"+id+".":"")+field)},
setValue:function(title,id,fields){for(var f in fields){store.setValue(title,"tdl."+(id?"t"+id+".":"")+f,fields[f])}},
refresh:function(title,disp){if(disp!=title) story.refreshTiddler(disp,null,true)},
resumeNotifications:function(title){
	store.resumeNotifications();
	store.notify(title,true);
},
updTiddler:function(rootNode,title){
	if(!rootNode.tdl.updTiddler) return;
	var t=store.getTiddler(title);
	t.assign(undefined,undefined,undefined,new Date(),t.tags);
	store.setDirty(true);
},
scrollTo:function(a){if(a) window.scrollTo(0,findPosY(a))}
};
pl.Action={NONE:0,ADD:1,UPDATE:2,REARRANGE:3,REMOVE:4,PURGE:5,MIGRATE:6};
})(jQuery);}
//}}}
|Name|ToDoListPluginDocumentation|
|Description|~ToDo list contained in a tiddler|
|Author|Julien Coloos|
|Version|1.4.0|
|Date|2011-06-17|
|Status|stable|
|Source|http://julien.coloos.free.fr/TiddlyWiki-dev/#ToDoListPlugin|
|License|[img[CC BY-SA 3.0|http://i.creativecommons.org/l/by-sa/3.0/80x15.png][http://creativecommons.org/licenses/by-sa/3.0/]]|
|~CoreVersion|2.6|
|Documentation|http://julien.coloos.free.fr/TiddlyWiki-dev/#ToDoListPluginDocumentation|

!Description
This plugin adds the {{{ToDoList}}} macro to insert a ~ToDo list inside a tiddler.
The list is composed of tasks, which associated data are:
*label: short description
**mandatory
**~TiddlyWiki style
*description
**optional
**~TiddlyWiki style
*category
**optional (//Uncategorized// by default)
**~TiddlyWiki style
**available only if enabled
*creation date and actor
**automatically set upon task adding
*last update date and actor
**automatically set upon task editing
*completion date and actor
**automatically set upon task status switching
Upon displaying, dates are formatted using the locale settings.

When the macro is inserted in a tiddler, the following elements are displayed:
*a table listing tasks labels
*an action menu
*tasks full description (if any)

The tasks labels are displayed either:
*in the order the tasks were created or rearranged, by category, which is the default behaviour
*ordered by status (//to do// / //done//) and category in a table
Categories are sorted by plaintext alphabetical order.
Each label is preceded by:
*a link
**when the mouse is over, the task details are displayed in a (simple) transparent tooltip
**the link is used to trigger an action which differs according to the currently selected action
***//Update//: selects the task to edit
***//Rearrange//: first selects a task to move, then selects the task to move to
***//Migrate//: selects a task to migrate
***//Remove//: selects a task to remove
***otherwise, goes to the task description (if any)
*a checkbox which represents the task status, and by which it can be switched
**//to do// if unchecked
**//done// if checked

The action menu, which is displayed when the mouse is over the {{{Edit ToDo list}}} link, proposes the following actions:
*//Add//: adds a new task
**a form asking for the task data is shown
**task details can be previewed in a (simple) transparent tooltip
*//Update//: edit a task
**a form allowing to edit the task data is shown
**task details can be previewed in a (simple) transparent tooltip
**category change can be applied to the other tasks in the same category
*//Rearrange//: change the order in which tasks are displayed
**to move a task, user first selects the task to move, then the task to move to
**only the order of tasks is changed, status and category are not altered: thus trying to move a task to another status or category will not result in the expected result
**changes are not applied until explicitely requested by the user; thus current changes are lost (without warning) upon refreshing the page
**considering the order in which tasks are listed (and thus displayed, leaving aside status and categories), when moving task //A// to task //B//
***if //A// is above //B//, then //A// is moved right below //B//
***if //A// is below //B//, then //A// is moved right above //B//
*//Migrate//: migrate tasks
**user selects the tasks to migrate and the destination tiddler
**listed tiddlers are sorted by name, excluding the origin tiddler and those with the {{{excludeLists}}} tag
*//Remove//: remove tasks
**user is requested to confirm the action before removing the selected tasks
*//Purge//: remove all tasks
**user is requested to confirm the action
When a task is deleted (//Remove// or //Purge// action), user is also asked whether to remove possibly orphan associated tiddlers. Note that tiddlers linked to from whithin macro are not seen as referenced by ~TiddlyWiki; as such the plugin can only check standard references and whether remaining tasks from the ~ToDo list still reference it.

To be visible in the timeline view, tiddler last update date is modified upon changes in the tasks list. This behaviour can be disabled.

Each task description is displayed in a level-2 heading, and has a link which leads to the corresponding entry in the tasks labels table. Heading level can be given as macro parameter.


!Notes
The ~ToDo list data are stored in the tiddler fields (in dedicated //namespaces//):
*global fields
**{{{tdl.nextId}}}: the next available task id
**{{{tdl.list}}}: the list of currently known task ids (separated by comma)
*fields associated to a given task //id// (note: //namespace// nodes cannot start with a number)
**{{{tdl.t}}}//{{{id}}}//{{{.category}}}: associated category
**{{{tdl.t}}}//{{{id}}}//{{{.label}}}: label
**{{{tdl.t}}}//{{{id}}}//{{{.description}}}: long description
**{{{tdl.t}}}//{{{id}}}//{{{.created}}}: creation date
**{{{tdl.t}}}//{{{id}}}//{{{.creator}}}: creation actor
**{{{tdl.t}}}//{{{id}}}//{{{.updated}}}: last update date
**{{{tdl.t}}}//{{{id}}}//{{{.updator}}}: last update actor
**{{{tdl.t}}}//{{{id}}}//{{{.completed}}}: completion date
**{{{tdl.t}}}//{{{id}}}//{{{.completor}}}: completion actor


!Usage
The {{{ToDoList}}} macro is intended to be inserted inside a tiddler.

!!Parameters
The following parameters are available:
*{{{categories}}} (optional)
**if not given, or set to {{{0}}}, a user-defined category cannot be associated to tasks
**otherwise, a user-defined category can be associated to tasks
*{{{headingLevel}}} (optional)
**indicates the heading level (from 1 to 6) to use for task full description
**default value is {{{2}}}
*{{{table}}} (optional)
**if not given, or set to {{{0}}}, the tasks labels are displayed in their creation order
**if set to {{{v}}}, the tasks labels are displayed inside a vertical table
**otherwise, the tasks labels are displayed inside an horizontal table
*{{{updateTiddler}}} (optional)
**if set to {{{0}}}, tiddler last update date is not update upon changes
**otherwise, last update date is modified

!!Examples
Without table and without categories:
{{{
<<ToDoList headingLevel:3>>
}}}
<<ToDoList headingLevel:3>>

Without table and with categories:
{{{
<<ToDoList headingLevel:3 categories:1>>
}}}
<<ToDoList headingLevel:3 categories:1>>

With vertical table and without categories:
{{{
<<ToDoList headingLevel:3 table:v>>
}}}
<<ToDoList headingLevel:3 table:v>>

With vertical table and with categories:
{{{
<<ToDoList headingLevel:3 table:v categories:1>>
}}}
<<ToDoList headingLevel:3 table:v categories:1>>

With horizontal table and without categories:
{{{
<<ToDoList headingLevel:3 table:h>>
}}}
<<ToDoList headingLevel:3 table:h>>

With horizontal table and with categories:
{{{
<<ToDoList headingLevel:3 table:h categories:1>>
}}}
<<ToDoList headingLevel:3 table:h categories:1>>


!Revision History
!!v1.4.0 (2011-06-17)
Changes:
*//migrate// action now processes tasks in their listed order (which can be changed with //rearrange// action)
*data are now stored in tiddler fields using //namespaces//
**@@color: red;Important note:@@ ~ToDo list created with previous versions of the plugin are thus not recognised; to update those data to the newer version, please use the dedicated [[ToDoListUpdatePlugin]] update plugin

Enhancements:
*boost up upon modifications: by default ~TiddlyWiki is refreshed each time a field is changed, which can be time and cpu consuming with some systems when many fields are concerned (e.g. with //remove// action); this mechanism is now temporarily disabled and performed once after user action completion

Fixes:
*//rearrange// action was broken since v1.2.0

!!v1.3.0 (2011-05-29)
Changes:
*upon changes, modifies the tiddler last update date

Enhancements:
*added macro parameter to specify task full description heading level
*actor is now associated to task (creation, modification, completion)

!!v1.2.0 (2011-05-21)
Enhancements:
*if necessary the tooltip is moved upward so that it does not go beyond the viewport bottom
**if tooltip height exceeds viewport height, tooltip is displayed at the top of the view
*upon task update, category change can be applied to the other tasks in the same category
*tasks can now be migrated to another tiddler

!!v1.1.0 (2011-05-15)
Enhancements:
*when user asks to also remove what appears to be an orphan tiddler associated to a task being removed, a second confirmation is requested if the tiddler has the {{{systemConfig}}} tag
**it's a cheap security check against removal errors, since tiddlers with {{{systemConfig}}} tag may still be needed while not being referenced by any other tiddler
*a preview (using the transparent tooltip) is now available in the task form (add/update action)

!!v1.0.0 (2011-05-06)
Initial release.
/***
|Name|ToDoListUpdatePlugin|
|Description|Updates ToDo list data when upgrading ToDoListPlugin|
|Author|Julien Coloos|
|Version|1.4.0|
|Date|2011-06-17|
|Status|stable|
|Source|http://julien.coloos.free.fr/TiddlyWiki-dev/#ToDoListUpdatePlugin|
|License|[img[CC BY-SA 3.0|http://i.creativecommons.org/l/by-sa/3.0/80x15.png][http://creativecommons.org/licenses/by-sa/3.0/]]|
|CoreVersion|2.6|
|Documentation|http://julien.coloos.free.fr/TiddlyWiki-dev/#ToDoListUpdatePlugin|

!Description
This plugin can be used to update ToDo list data created by previous versions of [[ToDoListPlugin]] when upgrading to newer versions.
Update is triggered manually; see below.

!!From first versions to version 1.4.0
Starting with version 1.4.0, data are stored in dedicated fields //namespaces//:
* global fields are now stored in {{{tdl}}} //namespace//, and are thus named {{{tdl.}}}//{{{xxx}}}// instead of {{{tdl_}}}//{{{xxx}}}//
* fields associated to a given task //id// are now stored in {{{tdl.t}}}//{{{id}}}// //namespace// (//namespace// nodes cannot start with a number), and are thus named {{{tdl.t}}}//{{{id.xxx}}}// instead of {{{tdl_}}}//{{{id_xxx}}}//


!Update
To update data, please use the following button:
<<ToDoListUpdate>>


!Revision History
!!v1.4.0 (2011-06-17)
Initial release, to upgrade to [[ToDoListPlugin]] version 1.4.0.


!Code
***/
//{{{
if (!config.macros.ToDoListUpdate) {(function($) {

version.extensions.ToDoListUpdatePlugin = {major: 1, minor: 4, revision: 0, date: new Date(2011, 6, 17)};

var pl = config.macros.ToDoListUpdate = {
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
	$(createTiddlyElement(place, "div")).html("<input id='tdlu_action_submit' type='submit' value='Update ToDo list data'/>").find("#tdlu_action_submit").click(function() {
		var titles = [];

		/* process each tiddler */
		$.each(store.getTiddlers("title"), function(i, t) {
			var title = t.title;
			/* check there is something to do */
			var taskList = pl.getValue_v1_0_0(title, null, "list");
			if (!taskList) return;
			titles.push(title);

			store.suspendNotifications();

			/* update all fields */
			$.each(taskList.split(","), function(i, id) {
				$.each(["created", "creator", "updated", "updator", "completed", "completor", "category", "label", "description"], function(i, field) {
					pl.setValue_v1_4_0(title, id, field, pl.getValue_v1_0_0(title, id, field));
					pl.setValue_v1_0_0(title, id, field, null);
				});
			});
			$.each(["list", "nextId"], function(i, field) {
				pl.setValue_v1_4_0(title, null, field, pl.getValue_v1_0_0(title, null, field));
				pl.setValue_v1_0_0(title, null, field, null);
			});

			store.resumeNotifications();
			store.notify(title, true);
		});

		var message = titles.length ? "Updated tiddlers:\n - " + titles.join("\n - ") : "No tiddler was updated";
		alert(message);
	});
},
getValue_v1_0_0: function(title, id, field) {
	return store.getValue(title, "tdl_" + (id ? id + "_" : "") + field);
},
setValue_v1_0_0: function(title, id, field, value) {
	store.setValue(title, "tdl_" + (id ? id + "_" : "") + field, value);
},
setValue_v1_4_0: function(title, id, field, value) {
	store.setValue(title, "tdl." + (id ? "t" + id + "." : "") + field, value);
}
};

})(jQuery);}
//}}}