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

table {border:2px solid [[ColorPalette::TertiaryDark]];}
th, thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
td, 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:absolute; top:2em; right:0em; margin:0.5em; padding:0.5em; z-index:200;}
*[id='messageArea'] {position:fixed !important; z-index:200;}
.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;}

table {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer 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:50; 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 use a logographic writing system and 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;}

.htmlarea .toolbarHA table {border:1px solid ButtonFace; margin:0em 0em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar {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 closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></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 +saveTiddler -cancelTiddler deleteTiddler'></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
From ages we are looking for a method to manage backup files and I had something like this (http://groups.google.com/group/TiddlyWiki/msg/d8e5d0d6be082ada?hl=en&) on my TodoList for more than a year !

I've now coded a method in [[store.php]] that maintains the size of the backup directory on the web server near a constant size.

Here is how it works. In store.php each time a new backup file is stored, the backup directory is scanned for files with the same prefix as the uploaded file and it holds only :
*the last file of each preceding month,
*the last file for each preceding week of the current month
*the last file for each preceding day of the current  week
*the last file for each preceding hour of the current day
*all the file of the current hour  

Without the files of the current hour, the number of files in the backup directory for the last year is less than 24 + 7 + 5 + 12 = 48. With an average of 1Mo per backup file, the size of the backup folder should never reach 50 Mo for the last year and 12 Mo more for each previous year.

Contact : [[BidiX@bidix.info|mailto:BidiX@BidiX.info]]
URL : [[TiddlyWiki.BidiX.info|http://tiddlywiki.BidiX.info/]]
Donation : [[Donation via Paypal|https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=BidiX%40bidix%2einfo&item_name=TiddlyWikiHacking%20Donations&item_number=Donations&no_shipping=2&no_note=1&tax=0&currency_code=EUR&bn=PP%2dDonationsBF&charset=UTF%2d8]] 
This site is a fresh TiddlyWiki <<version>>.

It includes refactored and rewritten BidiX's extensions compatible with the new TW 2.2 version (build #2223). Currently the available extensions are :
*[[UploadPlugin 4.1]] : a refactored version of UploadPlugin with a Backstage entry.
*[[RSSReaderPlugin|RSSReaderPluginDescription]] : an RSSReader for TiddlyWiki
*[[GenerateRssByTag]] : only tiddlers tagged with a specific tag are added to the RSSFeed 
*[[RSSReaderService]] : Display an RSSFeed in one page
*[[IsDirtyPlugin]] : an indicator for saving. see [[Need to be saved ?]]
*ProxyService : access a remote url even if TiddlyWiki is viewed over HTTP
*DownloadService : a script to download a TiddlyWiki in one click. 
*[[WebDAVSavingPlugin|WebDAVSaving]] : the "save to web" function without script
*[[PasswordOptionPlugin|PasswordOption]] : that extends the core Options with a non encrypted password type

See [[Extension directory]] for a full list.

@@''NEW: ''[[Backup files management in store.php]]@@
----
Subscribe to the RSSFeed [img[http://tiddlyhome.bidix.info/_th/images/feedicon.14.png][http://tiddlylab.bidix.info/index.xml]]: http://TiddlyLab.bidix.info/index.xml 
or read it at http://TiddlyLab.bidix.info/news.php
|''URL:''|http://tiddlywiki.bidix.info/|
|''Description:''|Repository for BidiX's TiddlyWiki Extensions|
|''Author:''|BidiX|
<<rssReader asHTML http://tiddlywiki.bidix.info/BidiXTW.xml>>
<<rssReader asHtml http://tiddlylab.bidix.info/index.xml>>
<<rssReader asHtml http://news.com.com/2547-1_3-0-20.xml>>
BidiXLab
<<tagging Doc>>
#install [[download.php]] as a file on the webserver in the TiddlyWiki folder. Perhaps near by store.php
#Simply put {{{[[download|download.php?]]}}} in the SideBarOptions of TiddlyWiki* 
#download as an attachement in one click on this link when viewed over HTTP

 * If it is named index.html else put {{{[[download|download.php?file=yourTW.html]]}}}
| Name | Type |Version | Date | Core | Requires |
|[[download.php]] | serverside script | 1.0.0 | Mar 8, 2007 | | |
|HttpGetMacro | plugin | 2.0.0 | Mar 18, 2007 | 2.2 | |
|IsDirtyPlugin | plugin | 1.0.2 | Apr 30, 2007 | 2.2 | |
|GenerateRssByTagPlugin | plugin | 1.0.3 | May 17, 2007 | 2.2 (#2223) | |
|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack) | plugin | 1.1.0 | Mar 17, 2007 | 2.2 | |
|[[news.php]] | serverside script | 2.0.1 | May 13, 2007 | | |
|PasswordOptionPlugin | plugin | 1.0.1 | Jan 19, 2007 | 2.2 | |
|[[proxy.php]] | serverside script | 2.1.1 | May 31, 2007 | | [[allowedsites.txt]] |
|RSSReaderPlugin | plugin | 1.1.1 | Apr 21, 2007 | 2.2 | |
|[[store.php]] | serverside script | 1.6.0 | May 17, 2007 | | |
|UploadPlugin | plugin | 4.1.0 | May 5, 2007 | 2.2 (#2223) | PasswordOptionPlugin <<tag UploadService>> |
|UploadPluginLingoEN | plugin | 4.1.0 | May 8, 2007 | 2.2 | UploadPlugin |
|UploadPluginLingoFR | plugin | 4.1.0 | May 8, 2007 | 2.2 | UploadPlugin |
|UploadToFileMacro | plugin | 2.0.1 | Apr 21, 2007 | 2.2 | UploadPlugin |
|UploadToHomeMacro | plugin | 0.0.2 | Apr 21, 2007 | 2.2 (#2125) | UploadPlugin |
|WebDAVSavingPlugin | plugin | 0.2.1 | Apr 21, 2007 | 2.2 |
GenerateRssByTagPlugin overwrite the core generateRSS() function. And defines a txtRssTag option : <<option txtRssTag>> to specify the tag to use (defaulted to ''"toRSS"'' ).

Only tiddlers with this specific tag are inluded in the RSSFeed. If no tiddlers are selected then works with the old behaviour. (see ticket #270: http://trac.tiddlywiki.org/tiddlywiki/ticket/270).

Because the generateRSS mechanism should change in TW 2.3 this enhancement should not go in the core .

Hint : You can add {{{<<option txtRssTag>>}}} in AdvancedOptions
/***
|''Name:''|GenerateRssByTagPlugin|
|''Description:''|Only tiddlers with a specific tag are inluded in the RSSFeed. If no tiddlers are selected then works as before. (see ticket #270: http://trac.tiddlywiki.org/tiddlywiki/ticket/270). <br>RssTag: <<option txtRssTag>>|
|''Version:''|1.0.3|
|''Date:''|May 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#GenerateRssByTagPlugin|
|''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.GenerateRssByTagPlugin = {
	major: 1, minor: 0, revision: 3, 
	date: new Date("May 17, 2007"),
	source: 'http://tiddlywiki.bidix.info/#GenerateRssByTagPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0 (Beta 5)'
};

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

bidix.generateRssByTag = function()
{
	var s = [];
	var d = new Date();
	var u = store.getTiddlerText("SiteUrl");
	// Assemble the header
	s.push("<" + "?xml version=\"1.0\"" + " encoding='UTF-8' " + "?" + ">");
	s.push("<rss version=\"2.0\">");
	s.push("<channel>");
	s.push("<title" + ">" + wikifyPlain("SiteTitle").htmlEncode() + "</title" + ">");
	if(u)
		s.push("<link>" + u.htmlEncode() + "</link>");
	s.push("<description>" + wikifyPlain("SiteSubtitle").htmlEncode() + "</description>");
	s.push("<language>en-us</language>");
	s.push("<copyright>Copyright " + d.getFullYear() + " " + config.options.txtUserName.htmlEncode() + "</copyright>");
	s.push("<pubDate>" + d.toGMTString() + "</pubDate>");
	s.push("<lastBuildDate>" + d.toGMTString() + "</lastBuildDate>");
	s.push("<docs>http://blogs.law.harvard.edu/tech/rss</docs>");
	s.push("<generator>TiddlyWiki " + version.major + "." + version.minor + "." + version.revision + "</generator>");
	// The body
	var tiddlers;
	if (config.options.txtRssTag && store.getTaggedTiddlers(config.options.txtRssTag).length > 0)
		tiddlers = store.getTaggedTiddlers(config.options.txtRssTag,"modified");
	else
		tiddlers = store.getTiddlers("modified","excludeLists");
	var n = config.numRssItems > tiddlers.length ? 0 : tiddlers.length-config.numRssItems;
	for (var t=tiddlers.length-1; t>=n; t--)
		s.push(tiddlers[t].saveToRss(u));
	// And footer
	s.push("</channel>");
	s.push("</rss>");
	// Save it all
	return s.join("\n");
};

//
// Initializations
//
bidix.generateRss = generateRss; // backup core version
generateRss = bidix.generateRssByTag; // install new one
config.options.txtRssTag = "toRSS"; // default RssTag. use <<option txtRssTag>> to overwritte
merge(config.optionsDesc,{txtRssTag: "Only tiddlers with this tag will be included in the RSS Feed."});
//}}}
Above are sites allowed to be accessed
----
<<HttpGet "proxy.php?list" html>>
----
To upload a TiddlyWiki on your web server:
#Import UploadPlugin from BidiXTW aka http://TiddlyWiki.bidix.info/
#Install an UploadService on your web server by configuring one of this scripts [[store.php]] or [[store.cgi]]
#set an {{{<<upload [params]>>}}} button for example in your SideBarOptions with {{{params}}} or UploadOptions as describe in UploadPluginDoc
#click on the <<upload>> button
Or sign at http://TiddlySpot.com/
 
/***
|''Name:''|HttpGetMacro|
|''Description:''|Submit an HttpGet and display the response|
|''Version:''|2.0.0|
|''Date:''|Mar 18, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#HttpGetMacro|
|''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|
***/
//{{{
config.macros.HttpGet = {
	cache: [], 	// url => responseText
	messages: {
		401: "%0 unauthorized (HTTP status:401).",
		403: "%0 forbidden (HTTP status:403).",
		404: "%0 not found (HTTP status:404).",
		405: "Method not allowed to access %0 (HTTP status: 405)."
	},
	
	handler: function(place,macroName,params,wikifier,paramString,tiddler){
		var url = params[0];
		var format = params[1];
		wikify("^^<<HttpGetUpdate "+url+" [[" + tiddler.title + "]]>>^^\n",place);
		var div = createTiddlyElement(place, "div", "HttpGet");
		if (this.cache[url]) {
			this.display(this.cache[url], format, div);
					}
		else {
			this.get(url, format, div);
		}
	},
	
	get: function(url, format, place) {
		var params = {
				format: format,
				place:	place
				};
		var r = loadRemoteFile(url,config.macros.HttpGet.display,params);
		if (typeof r == "string")
			displayMessage(r);
		return r;
	},
	
	display: function(status,params,responseText,url,xhr) {
		if (status) {
	 		if (params['format'] == 'html') {
				wikify("<html>"+responseText+"</html>", params['place']);
			}
			else { //text
				wikify(responseText, params['place']);			
			}
		} else {
			if (config.macros.HttpGet.messages[xhr.status])
				displayMessage(config.macros.HttpGet.messages[xhr.status].format([url]));
			else
				displayMessage("HTTP Error " + xhr.status + " in accessing " + url);
		}
		
	}

};

config.macros.HttpGetUpdate = {
	label: "Update",
	prompt: "Clear the cache and redisplay this tiddler",
	handler: function(place,macroName,params) {
		var url = params[0];
		var tiddlerTitle = params[1];
		createTiddlyButton(place, this.label, this.prompt, 
			function () {
				if (config.macros.HttpGet.cache[url]) {
					config.macros.rssReader.cache[url] = null; 
			}
			story.refreshTiddler(tiddlerTitle,null, true);
		return false;});
	}
};
//}}}
 
/***
|''Name:''|IsDirtyPlugin|
|''Description:''|When the TiddlyWiki needs to be saved the tiddler named IsDirty contains ' * ' else it is empty. IsDirty tiddler is also appended in front of the browser page title.<br>Hint: Put it in front of your SiteTitle in your PageTemplate or in your MainMenu as an indicator.<br>For now IsDirty: <<tiddler IsDirty>>|
|''Version:''|1.0.2|
|''Date:''|Apr 30, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#IsDirtyPlugin|
|''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.IsDirtyPlugin = {
	major: 1, minor: 0, revision: 2, 
	date: new Date("Apr 30, 2007"),
	source: 'http://tiddlywiki.bidix.info/#IsDirtyPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0'
};

if (!window.bidix) window.bidix = {}; // bidix namespace
if (!bidix.core) bidix.core = {};
bidix.setDirty = TiddlyWiki.prototype.setDirty;
bidix.initIsDirty = function()
{
	var tags = "excludeLists excludeSearch";
	var tiddler = store.getTiddler("IsDirty");
	if (!tiddler) {
		tiddler = new Tiddler("IsDirty");
		//tiddler.set(title,text,modifier,modified,tags,created,fields)
		tiddler.set(null,null,null,null,tags,null,null);
		store.addTiddler(tiddler);
	}
	tiddler.set(null,"",null,null,null,null,null);
	return tiddler;
};

TiddlyWiki.prototype.setDirty = function(dirty)
{
	var indic = " * ";
	var oldDirty = this.isDirty ();
	bidix.setDirty.apply(this,arguments);
	var tiddler = bidix.initIsDirty();
	if (dirty)
		tiddler.set(null,indic,null,null,null,null,null);
	else
		tiddler.set(null," ",null,null,null,null,null);
	story.refreshTiddler(tiddler.title);
	store.notify(tiddler.title, true);	
	refreshPageTitle();
};

bidix.refreshPageTitle = function()
{
	document.title = wikifyPlain("IsDirty") + getPageTitle();
};

bidix.core.refreshPageTitle = refreshPageTitle ;
refreshPageTitle  = bidix.refreshPageTitle;
bidix.initIsDirty();
//}}}
Thanks to Saq's nightly build http://nightly.lewcid.org/, I can now publish my recent upgrade based on the latest core enhancements : 
*IsDirtyPlugin v1.0.2 : an indicator for saving. see [[Need to be saved ?]]
*UploadPlugin v4.1.0 : a refactored version of UploadPlugin with a Backstage entry ans its companion UploadPluginLingoFR and UploadPluginLingoEN
*UploadToHomeMacro v0.0.2 : An experimental UploadToHomeMacro using HomeParameters shadowed tiddler.

<<rssReader asText http://www.lemonde.fr/rss/sequence/0,2-3208,1-0,0.xml>>
<<rssReader asHtml http://www.liberation.fr/interactif/rss/actualites/>>
/***
|''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);
}
//}}}
HowToUpload
[[Need to be saved ?]]
[[UploadPlugin 4.1]]
DownloadService
GenerateRssByTag
[[RSSReaderPlugin|RSSReaderPluginDescription]]
RSSReaderService
ProxyService
WebDAVSaving
PasswordOption
----
<<tag [[Latest news]]>>
[[Extension directory]]
[[Documentation|Docs]]
----
BidiX
^^TiddlyWiki <<version>>^^
{{isdirty{<<tiddler IsDirty>>}}}
When the TiddlyWiki needs to be saved the tiddler named IsDirty contains ' * ' else it is empty. IsDirty tiddler is also appended in front of the browser page title.

Hint: Put it in front of your SiteTitle in your PageTemplate or in your MainMenu as an indicator.

@@Try to edit this tiddler.@@

For now IsDirty: <<tiddler IsDirty>>

/***
|Name|NestedSlidersPlugin|
|Source|http://www.TiddlyTools.com/#NestedSlidersPlugin|
|Version|2.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|Slider.prototype.stop|
|Description|Make any tiddler content into an expandable 'slider' panel, without needing to create a separate tiddler to contain the slider content.|

++++!!!!![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
===
++++!!!!![Usage]>
When installed, this plugin adds new wiki syntax for embedding 'slider' panels directly into tiddler content.  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)
*mouse auto rollover
*custom class/label/tooltip/accesskey
*automatic blockquote
*deferred rendering
The complete syntax, using all options, is:
//{{{
++++(cookiename)!!!!!^width^*{{class{[label=key|tooltip]}}}>...
content goes here
===
//}}}
where:
* {{{+++}}} (or {{{++++}}}) and {{{===}}}^^
marks the start and end of the slider definition, respectively.  When the extra {{{+}}} is used, the slider will be open when initially displayed.^^
* {{{(cookiename)}}}^^
saves the slider opened/closed state, and restores this state whenever the slider is re-rendered.^^
* {{{!}}} through {{{!!!!!}}}^^
displays the slider label using a formatted headline (Hn) style instead of a button/link style^^
* {{{^width^}}} (or just {{{^}}})^^
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)^^
* {{{*}}}^^
automatically opens/closes slider on "rollover" as well as when clicked^^
* {{{{{class{[label=key|tooltip]}}}}}}^^
uses custom label/tooltip/accesskey.  {{{{{class{...}}}}}}, {{{=key}}} and {{{|tooltip}}} are optional.  'class' is any valid CSS class name, used to style the slider label text.  'key' must be a ''single letter only''.  Default labels/tootips are: ">" (more) and "<" (less), with no default access key assignment.^^
* {{{">"}}} //(without the quotes)//^^
automatically adds blockquote formatting to slider content^^
* {{{"..."}}} //(without the quotes)//^^
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 combined //(default open, cookie, heading, sized floater, rollover, class, label/tooltip/key, blockquoted, deferred)//
{{{
++++(testcookie)!!!^30em^*{{big{[label=Z|click or press Alt-Z to open]}}}>...
   content
===
}}}
++++(testcookie)!!!^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 slider with more specific info:
   +++^10em^[view details...|click for details]
      put some detail here, which could include a rollover 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 slider with more specific info:
   +++^10em^[view details...|click for details]
      put some detail here, which could include a rollover with a +++^25em^*[glossary definition]explaining technical terms===
   ===
===
===
!!!!!Installation
<<<
import (or copy/paste) the following tiddlers into your document:
''NestedSlidersPlugin'' (tagged with <<tag systemConfig>>)
<<<
!!!!!Revision History
<<<
''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
|please see [[NestedSlidersPluginHistory]] for additional revision details|
''2005.11.03 - 1.0.0'' initial public release
<<<
!!!!!Credits
<<<
This feature was implemented by EricShulman from [[ELS Design Studios|http:/www.elsdesign.com]] with initial research and suggestions from RodneyGomes, GeoffSlocock, and PaulPetterson.
<<<
!!!!!Code
***/
//{{{
version.extensions.nestedSliders = {major: 2, minor: 0, revision: 3, date: new Date(2007,3,30)};
//}}}

//{{{
// 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=false;

// 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)
		{
			// defopen=lookaheadMatch[1]
			// cookiename=lookaheadMatch[2]
			// header=lookaheadMatch[3]
			// panelwidth=lookaheadMatch[4]
			// rollover=lookaheadMatch[5]
			// class=lookaheadMatch[6]
			// label=lookaheadMatch[7]
			// blockquote=lookaheadMatch[8]
			// deferred=lookaheadMatch[9]

			 lookaheadRegExp = new RegExp(this.lookahead,"mg");
			lookaheadRegExp.lastIndex = w.matchStart;
			var lookaheadMatch = lookaheadRegExp.exec(w.source)
			if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
			{
				// location for rendering button and panel
				var place=w.output;

				// default to closed, no cookie, no accesskey
				var show="none"; var title=">"; var tooltip="show"; var cookie=""; var key="";

				// extra "+", default to open
				if (lookaheadMatch[1])
					{ show="block"; title="<"; tooltip="hide"; }

				// cookie, use saved open/closed state
				if (lookaheadMatch[2]) {
					cookie=lookaheadMatch[2].trim().slice(1,-1);
					cookie="chkSlider"+cookie;
					if (config.options[cookie]==undefined)
						{ config.options[cookie] = (show=="block") }
					if (config.options[cookie])
						{ show="block"; title="<"; tooltip="hide"; }
					else
						{ show="none"; title=">"; tooltip="show"; }
				}

				// parse custom label/tooltip/accesskey: [label=X|tooltip]
				if (lookaheadMatch[7]) {
					title = lookaheadMatch[7].trim().slice(1,-1);
					var pos=title.indexOf("|");
					if (pos!=-1) { tooltip = title.substr(pos+1,title.length); title=title.substr(0,pos); }
					if (title.substr(title.length-2,1)=="=") { key=title.substr(title.length-1,1); title=title.slice(0,-2); }
					if (pos==-1) tooltip += " "+title; // default tooltip: "show/hide <title>"
				}

				// create the button
				if (lookaheadMatch[3]) { // use "Hn" header format instead of button/link
					var lvl=(lookaheadMatch[3].length>6)?6:lookaheadMatch[3].length;
					var btn = createTiddlyElement(createTiddlyElement(place,"h"+lvl,null,null,null),"a",null,lookaheadMatch[6],title);
					btn.onclick=onClickNestedSlider;
					btn.setAttribute("href","javascript:;");
					btn.setAttribute("title",tooltip);
				}
				else
					var btn = createTiddlyButton(place,title,tooltip,onClickNestedSlider,lookaheadMatch[6]);

				// set extra button attributes
				btn.sliderCookie = cookie; // save the cookiename (if any) in the button object
				btn.defOpen=lookaheadMatch[1]!=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
				}

				// "non-click" MouseOver open/close slider
				if (lookaheadMatch[5]) btn.onmouseover=onClickNestedSlider;

				// create slider panel
				var panelClass=lookaheadMatch[4]?"floatingPanel":"sliderPanel";
				var panel=createTiddlyElement(place,"div",null,panelClass,null);
				panel.button = btn; // so the slider panel know which button it belongs to
				panel.defaultPanelWidth=(lookaheadMatch[4] && lookaheadMatch[4].length>2)?lookaheadMatch[4].slice(1,-1):""; // save requested panel size
				btn.sliderPanel=panel;
				panel.style.display = show;
				panel.style.width=panel.defaultPanelWidth;

				// render slider (or defer until shown) 
				w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
				if ((show=="block")||!lookaheadMatch[9]) {
					// render now if panel is supposed to be shown or NOT deferred rendering
					w.subWikify(lookaheadMatch[8]?createTiddlyElement(panel,"blockquote"):panel,this.terminator);
					// align slider/floater position with button
					window.adjustSliderPos(place,btn,panel,panelClass);
				}
				else {
					var src = w.source.substr(w.nextMatch);
					var endpos=findMatchingDelimiter(src,"+++","===");
					panel.setAttribute("raw",src.substr(0,endpos));
					panel.setAttribute("blockquote",lookaheadMatch[8]?"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);
	var theLabel = theTarget.firstChild.data;
	var theSlider = theTarget.sliderPanel
	var isOpen = theSlider.style.display!="none";
	// if using default button labels, toggle labels
	if (theLabel==">") theTarget.firstChild.data = "<";
	else if (theLabel=="<") theTarget.firstChild.data = ">";
	// if using default tooltips, toggle tooltips
	if (theTarget.getAttribute("title")=="show")
		theTarget.setAttribute("title","hide");
	else if (theTarget.getAttribute("title")=="hide")
		theTarget.setAttribute("title","show");
	if (theTarget.getAttribute("title")=="show "+theLabel)
		theTarget.setAttribute("title","hide "+theLabel);
	else if (theTarget.getAttribute("title")=="hide "+theLabel)
		theTarget.setAttribute("title","show "+theLabel);
	// deferred rendering (if needed)
	if (theSlider.getAttribute("rendered")=="false") {
		if (config.options.chkDebugLazySliderRender)
			alert("rendering '"+theLabel+"':\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 && (theSlider.className!='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 slider/floater position with target button
	if (!isOpen) window.adjustSliderPos(theSlider.parentNode,theTarget,theSlider,theSlider.className);
	// 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; }
		}
	}
	if (this.sliderCookie && this.sliderCookie.length) {
		config.options[this.sliderCookie]=!isOpen;
		if (config.options[this.sliderCookie]!=this.defOpen)
			saveOptionCookie(this.sliderCookie);
		else { // remove cookie if slider is in default display state
			var ex=new Date(); ex.setTime(ex.getTime()-1000);
			document.cookie = this.sliderCookie+"=novalue; path=/; expires="+ex.toGMTString();
		}
	}
	return false;
}

// 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 Morpher animation handler 'stop' handler so overflow is visible after animation has completed
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); this.element.style.overflow = "visible"; }
}

// adjust panel position based on button position
if (window.adjustSliderPos==undefined) window.adjustSliderPos=function(place,btn,panel,panelClass) {
	if (panelClass=="floatingPanel") {
		var left=0;
		var top=btn.offsetHeight; 
		if (place.style.position!="relative") {
			var left=findPosX(btn);
			var top=findPosY(btn)+btn.offsetHeight;
			var p=place; while (p && p.className!='floatingPanel') p=p.parentNode;
			if (p) { left-=findPosX(p); top-=findPosY(p); }
		}
		if (left+panel.offsetWidth > getWindowWidth()) left=getWindowWidth()-panel.offsetWidth-15;
		panel.style.left=left+"px"; panel.style.top=top+"px";
	}
}

function getWindowWidth() {
	if(document.width!=undefined)
		return document.width; // moz (FF)
	if(document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) )
		return document.documentElement.clientWidth; // IE6
	if(document.body && ( document.body.clientWidth || document.body.clientHeight ) )
		return document.body.clientWidth; // IE4
	if(window.innerWidth!=undefined)
		return window.innerWidth; // IE - general
	return 0; // unknown
}
//}}}
<<tagging News>>
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>>
Password: <<option pasUploadPassword>>
<<option chkSaveBackups>> SaveBackups
<<option chkAutoSave>> AutoSave
<<option chkRegExpSearch>> RegExpSearch
<<option chkCaseSensitiveSearch>> CaseSensitiveSearch
<<option chkAnimate>> EnableAnimations

----
Also see 
AdvancedOptions
UploadOptions
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='IsDirty'></span>
<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='IsDirty'></span>
<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>
<!--}}}-->
PasswordOptionPlugin extends the core Options with a non encrypted password type.

Notice:
*How a style can be specified for a specific option in StyleSheet

----
Test Password: <<option pasPassword myPasOptionInput >>
/***
|''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"
	});
*/
//}}}
!!Why a ProxyService
When a TiddlyWiki is located on the web (view over http), for security reasons, browsers do not allow TiddlyWiki to access a remote page located on a different site.

For example, when views over http a TiddlyWiki is unable to:
*import a plugin using EricShulman's ImportTiddlersPlugin
*access <<tag RSSFeed>> with RSSReaderPlugin
*imbed a remote page in a tiddler
* ...

A first possibility is to bypass the browser check. However, visitors usually are not comfortable with altering the security options of their browser. 

The ProxyService provides an other way. 
!!How it works
ProxyService is mainly a ServerSide script that implements a very simple proxy. [[proxy.php]] is a ProxyService.

The command: {{{proxy.php?url=host.domain.com/some/page.html}}} simply gets and returns the content of the url, provided that this access is allowed. The access is allowed :
*to a list of site contained in a separate file
*to hosts of the same domain.
Nevertheless, this service should not be used for other purpose than as TiddlyWiki companion and under the TiddlyWiki owner's control.
!!Installing [[proxy.php]]
#Upload [[proxy.php]] to your site
#Edit and Upload [[allowedsites.txt]]
#Verify your installation. From your tiddlywiki accessed over HTTP go to :
##[[proxy.php?help|proxy.php?help]]
##[[proxy.php?list|proxy.php?list]]
##[[proxy.php?url=http://www.tiddlywiki.com/|proxy.php?url=http://www.tiddlywiki.com/]]
#Optionally, if you can limit access to proxy.php by requesting basic-auth in your .htaccess file.
!!How to setup in TiddlyWiki
In TiddlyWiki viewed over HTTP, provided that a ProxyService is available, for an access to a remote site (for example {{{http://host.domain.com/some/page.html}}}) , you should use the ProxyService (like {{{proxy.php?url=http://host.domain.com/some/page.html}}}).

Fortunately, LoadRemoteFileThroughProxy appends the content of SiteProxy in front of the url used by the core LoadRemoteFile function only when the TiddlyWiki is viewed over http. With this small extension it is possible to use directly ImportTiddlers when TiddlyWiki is viewed over HTTP. 
!!
Thanks to UploadToFileMacro, [[allowedsites.txt]] can be maintained in TiddlyWiki by editing [[allowedsites.txt]] and using <<uploadToFile allowedsites.txt allowedsites.txt>> macro.
/***
|''Name:''|RSSReaderPlugin|
|''Description:''|This plugin provides a RSSReader for TiddlyWiki|
|''Version:''|1.1.1|
|''Date:''|Apr 21, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#RSSReaderPlugin|
|''Documentation:''|http://tiddlywiki.bidix.info/#RSSReaderPluginDoc|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''Credit:''|BramChen for RssNewsMacro|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
|''OptionalRequires:''|http://www.tiddlytools.com/#NestedSlidersPlugin|
***/
//{{{
version.extensions.RSSReaderPlugin = {
	major: 1, minor: 1, revision: 1,
	date: new Date("Apr 21, 2007"),
	source: "http://TiddlyWiki.bidix.info/#RSSReaderPlugin",
	author: "BidiX",
	coreVersion: '2.2.0'
};

config.macros.rssReader = {
	dateFormat: "DDD, DD MMM YYYY",
	itemStyle: "display: block;border: 1px solid black;padding: 5px;margin: 5px;", //useed  '@@'+itemStyle+itemText+'@@'
	msg:{
		permissionDenied: "Permission to read preferences was denied.",
		noRSSFeed: "No RSS Feed at this address %0",
		urlNotAccessible: " Access to %0 is not allowed"
	},
	cache: [], 	// url => XMLHttpRequest.responseXML
	desc: "noDesc",
	
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var desc = params[0];
		var feedURL = params[1];
		var toFilter = (params[2] ? true : false);
		var filterString = (toFilter?(params[2].substr(0,1) == ' '? tiddler.title:params[2]):'');
		var place = createTiddlyElement(place, "div", "RSSReader");
		wikify("^^<<rssFeedUpdate "+feedURL+" [[" + tiddler.title + "]]>>^^\n",place);
		if (this.cache[feedURL]) {
			this.displayRssFeed(this.cache[feedURL], feedURL, place, desc, toFilter, filterString);
		}
		else {
			var r = loadRemoteFile(feedURL,config.macros.rssReader.processResponse, [place, desc, toFilter, filterString]);
			if (typeof r == "string")
				displayMessage(r);
		}
		
	},

	// callback for loadRemoteFile 
	// params : [place, desc, toFilter, filterString]
	processResponse: function(status, params, responseText, url, xhr) { // feedURL, place, desc, toFilter, filterString) {	
		if (window.netscape){
			try {
				if (document.location.protocol.indexOf("http") == -1) {
					netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
				}
			}
			catch (e) { displayMessage(e.description?e.description:e.toString()); }
		}
		if (xhr.status == httpStatus.NotFound)
		 {
			displayMessage(config.macros.rssReader.noRSSFeed.format([url]));
			return;
		}
		if (!status)
		 {
			displayMessage(config.macros.rssReader.noRSSFeed.format([url]));
			return;
		}
		if (xhr.responseXML) {
			// response is interpreted as XML
			config.macros.rssReader.cache[url] = xhr.responseXML;
			config.macros.rssReader.displayRssFeed(xhr.responseXML, params[0], url, params[1], params[2], params[3]);
		}
		else {
			if (responseText.substr(0,5) == "<?xml") {
				// response exists but not return as XML -> try to parse it 
				var dom = (new DOMParser()).parseFromString(responseText, "text/xml"); 
				if (dom) {
					// parsing successful so use it
					config.macros.rssReader.cache[url] = dom;
					config.macros.rssReader.displayRssFeed(dom, params[0], url, params[1], params[2], params[3]);
					return;
				}
			}
			// no XML display as html 
			wikify("<html>" + responseText + "</html>", params[0]);
			displayMessage(config.macros.rssReader.msg.noRSSFeed.format([url]));
		}
	},

	// explore down the DOM tree
	displayRssFeed: function(xml, place, feedURL, desc, toFilter, filterString){
		// Channel
		var chanelNode = xml.getElementsByTagName('channel').item(0);
		var chanelTitleElement = (chanelNode ? chanelNode.getElementsByTagName('title').item(0) : null);
		var chanelTitle = "";
		if ((chanelTitleElement) && (chanelTitleElement.firstChild)) 
			chanelTitle = chanelTitleElement.firstChild.nodeValue;
		var chanelLinkElement = (chanelNode ? chanelNode.getElementsByTagName('link').item(0) : null);
		var chanelLink = "";
		if (chanelLinkElement) 
			chanelLink = chanelLinkElement.firstChild.nodeValue;
		var titleTxt = "!![["+chanelTitle+"|"+chanelLink+"]]\n";
		var title = createTiddlyElement(place,"div",null,"ChanelTitle",null);
		wikify(titleTxt,title);
		// ItemList
		var itemList = xml.getElementsByTagName('item');
		var article = createTiddlyElement(place,"ul",null,null,null);
		var lastDate;
		var re;
		if (toFilter) 
			re = new RegExp(filterString.escapeRegExp());
		for (var i=0; i<itemList.length; i++){
			var titleElm = itemList[i].getElementsByTagName('title').item(0);
			var titleText = (titleElm ? titleElm.firstChild.nodeValue : '');
			if (toFilter && ! titleText.match(re)) {
				continue;
			}
			var descText = '';
			descElem = itemList[i].getElementsByTagName('description').item(0);
			if (descElem){
				try{
					for (var ii=0; ii<descElem.childNodes.length; ii++) {
						descText += descElem.childNodes[ii].nodeValue;
					}
				}
				catch(e){}
				descText = descText.replace(/<br \/>/g,'\n');
				if (desc == "asHtml")
					descText = "<html>"+descText+"</html>";
			}
			var linkElm = itemList[i].getElementsByTagName("link").item(0);
			var linkURL = linkElm.firstChild.nodeValue;
			var pubElm = itemList[i].getElementsByTagName('pubDate').item(0);
			var pubDate;
			if (!pubElm) {
				pubElm = itemList[i].getElementsByTagName('date').item(0); // for del.icio.us
				if (pubElm) {
					pubDate = pubElm.firstChild.nodeValue;
					pubDate = this.formatDateString(this.dateFormat, pubDate);
					}
					else {
						pubDate = '0';
					}
				}
			else {
				pubDate = (pubElm ? pubElm.firstChild.nodeValue : 0);
				pubDate = this.formatDate(this.dateFormat, pubDate);
			}
			titleText = titleText.replace(/\[|\]/g,'');
			var rssText = '*'+'[[' + titleText + '|' + linkURL + ']]' + '' ;
			if ((desc != "noDesc") && descText){
				rssText = rssText.replace(/\n/g,' ');
				descText = '@@'+this.itemStyle+descText + '@@\n';				
				if (version.extensions.nestedSliders){
					descText = '+++[...]' + descText + '===';
				}
				rssText = rssText + descText;
			}
			var story;
			if ((lastDate != pubDate) && ( pubDate != '0')) {
				story = createTiddlyElement(article,"li",null,"RSSItem",pubDate);
				lastDate = pubDate;
			}
			else {
				lastDate = pubDate;
			}
			story = createTiddlyElement(article,"div",null,"RSSItem",null);
			wikify(rssText,story);
		}
	},
	
	formatDate: function(template, date){
		var dateString = new Date(date);
		// template = template.replace(/hh|mm|ss/g,'');
		return dateString.formatString(template);
	},
	
	formatDateString: function(template, date){
		var dateString = new Date(date.substr(0,4), date.substr(5,2) - 1, date.substr(8,2)
			);
		return dateString.formatString(template);
	}
	
};

config.macros.rssFeedUpdate = {
	label: "Update",
	prompt: "Clear the cache and redisplay this RssFeed",
	handler: function(place,macroName,params) {
		var feedURL = params[0];
		var tiddlerTitle = params[1];
		createTiddlyButton(place, this.label, this.prompt, 
			function () {
				if (config.macros.rssReader.cache[feedURL]) {
					config.macros.rssReader.cache[feedURL] = null; 
			}
			story.refreshTiddler(tiddlerTitle,null, true);
		return false;});
	}
};

//}}}
This plugin provides a RSSReader for TiddlyWiki. If TiddlyWiki is viewed over HTTP, RSSReaderPlugin requires a ProxyService.

See examples : <<tag RSSFeed>>.
See documentation : RSSReaderPluginDoc

if NestedSlidersPlugin is available, item contents are folded. 
//last update: RSSReaderPlugin v 1.1.1//

!Description
This plugin provides a RSSReader for TiddlyWiki
* It accesses asynchronously an RSSFeed
*Depending on the chanel item format, each item could be written as :
**simple text wikified
**html

!Usage
{{{
<<rssReader noDesc|asHtml|asText rssUrl ['filtering string']>>
	noDesc: only title of item is printed

	asHtml: if you know that description contain html (links, img ...), 
		the text is enclosed with <html> </html> tags

 	asText: if the description should not be interpreted as html the 
		description is wikified

	rssUrl: the rssFeed url that could be accessed. 
	
	'filtering string': if present, the rssfeed item title must contained 
		this string to be displayed. 
		If 'filering string' contained space characters only, the tiddler 
		title is used for filtering.

}}}

For security reasons, if the TiddlyWiki is accessed from http, a ProxyService should be used to access an rssFeed from an other site.

!examples
| !reader | !RSSFeed type | !working from |
| BidiXTWRSS | Description asHtml | file: or tiddlywiki.bidix.info |
| [[Le Monde]] | Description asText | file: or tiddlywiki.bidix.info using proxy |
| YahooNewsSport | Description asHtml | file: or tiddlywiki.bidix.info using proxy |
| TiddlyWikiRSS | Description asHtml | file: or tiddlywiki.bidix.info using proxy |
| [[Libération]] | noDesc | file: or tiddlywiki.bidix.info using proxy |
| [[TestComment]] | asText and filters | file: or tiddlywiki.bidix.info using proxy |
see : <<tag RSSFeed>> for the full list.

!Revision history
* V1.1.0 (2207/04/13)
**No more import functions
* V1.0.0 (2006/11/11)
**refactoring using core loadRemoteFile function
**import using new tiddlywiki:tiddler element
**import and presentation preserved without EricShulman's NestedSliderPlugin
**better display of items 
* v0.3.0 (24/08/2006)
** Filter on RSS item title
** Place to display redefined for asynchronous processing
* v0.2.2 (22/08/2006)
**Haloscan feed has no pubDate.
* v0.2.1 (08/05/2006)
* v0.2.0 (01/05/2006)
**Small adapations for del.icio.us feed
* v0.1.1 (28/04/2006)
**Bug : Channel without title 
* v0.1.0 (24/04/2006)
** initial release


[[news.php]] is an RSSFeed reader. It accesses an RSS 2.0 file and displays the feed in a page using a CSS.

The full syntax is :
>news.php[?[rss=<rssfile>[&css=<cssfile>]]
with :
*<rssfile>: a RSSFeed (default index.xml)
*<cssfile>: a CssFile (default embeded css)

Some examples : 
*http://tiddlylab.bidix.info/news.php
*http://tiddlylab.bidix.info/news.php?rss=http://www.tiddlywiki.com/index.xml
*http://tiddlylab.bidix.info/news.php?rss=http://tw.lewcid.org/index.xml
*http://tiddlylab.bidix.info/news.php?rss=http://www.tiddlywiki.com/beta/index.xml&css=news.css (But links are not correct due to http://www.tiddlywiki.com/beta/#SiteUrl )
*http://tiddlylab.bidix.info/news.php?css=news.css
*http://tiddlylab.bidix.info/news.php?rss=http://news.com.com/2547-1_3-0-20.xml
*http://tiddlylab.bidix.info/news.php?rss=http://www.liberation.fr/rss.php

<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal "DD MMM YYYY">><<saveChanges>><<upload>>[[download|download.php?]]<<slider chkSliderOptionsPanel OptionsPanel "options »" "Change TiddlyWiki advanced options">>
proxy.php?url=
Laboratory for BidiX's TiddlyWiki Extensions
BidiXLab
http://tiddlylab.bidix.info/
/*{{{*/
.myPasOptionInput {background:[[ColorPalette::SecondaryPale]]; }

#mainMenu .isdirty {
 padding-top: 1em;
 line-height: 1em;
 font-size: 5em;
 color:[[ColorPalette::SecondaryDark]];
}

.tagged, .tagging { float:left; }
.tagged li, .tagging li { display:inline; } 
.tagged, .tagging { background:transparent !important; border:0 !important; }





/*}}}*/
The Haloscan feed on comments: http://www.haloscan.com/members/rss.php?user=adlister 

!!No Filtering :
<<rssReader asText http://www.haloscan.com/members/rss.php?user=adlister>>
!!Filtering on 'Andrew Lister' :
<<rssReader asText http://www.haloscan.com/members/rss.php?user=adlister 'Andrew Lister'>>
!!Filtering on tiddler.title :
<<rssReader asText http://www.haloscan.com/members/rss.php?user=adlister ' '>>
//{{{
config.macros.version.handler = function(place)
{
	createTiddlyElement(place,"span",null,null,version.major + "." + version.minor + "." + version.revision + (version.beta ? " (beta " + version.beta + ")" : "") + (version.build ? " (build #" + version.build + ")" : ""));
};
readOnly = false;
config.options.chkBackstage = true;
//}}}
|''URL:''|http://www.tiddlywiki.com/|

The current, non-Beta version of TiddlyWiki is at http://www.tiddlywiki.com
<<rssReader asHtml http://www.tiddlywiki.com/index.xml>>
UploadPlugin with <<tag UploadService>> extend TiddlyWiki with @@upload@@ and @@save to web@@ commands. 

See [[HowToUpload]].

[[Upload]] is... <<tagging Upload>>
<<tiddler UploadPluginDoc>>
This form upload any file with an UploadService describe in [[Upload]]
----
<html><center>
<form enctype="multipart/form-data" action="store.php" method="post" target="_blank">
 <input type="hidden" name="MAX_FILE_SIZE" value="3000000" />
This file : <input name="userfile" type="file" /><p>
Options* : <input type="text" name="UploadPlugin" size=80 value="backupDir=BACKUP_DIR;uploaddir=UPLOAD_DIR;user=UPLOAD_USER;password=UPLOAD_PASSWORD;debug=0;" /><p>
 <input type="submit" value="Upload" />
</form></center>
</html>
----
 * Substitute BACKUP_DIR, UPLOAD_DIR, UPLOAD_USER and UPLOAD_PASSWORD with your values. See UploadPlugin for option details. 
For security reason, don't save your password in a tiddler.
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 28/05/2007 13:04:32 | Bidix | [[/|http://tiddlylab.bidix.info/]] | [[store.php|http://tiddlylab.bidix.info/store.php]] | . | [[index.html | http://tiddlylab.bidix.info/index.html]] |  |
| 28/05/2007 13:07:22 | Bidix | [[/|http://tiddlylab.bidix.info/#readOnly:no]] | [[store.php|http://tiddlylab.bidix.info/store.php]] | . | [[index.html | http://tiddlylab.bidix.info/index.html]] |  |
| 28/05/2007 13:08:23 | Bidix | [[/|http://tiddlylab.bidix.info/#readOnly:no]] | [[store.php|http://tiddlylab.bidix.info/store.php]] | . | [[index.html | http://tiddlylab.bidix.info/index.html]] |  |
| 28/05/2007 13:10:47 | Bidix | [[/|http://tiddlylab.bidix.info/]] | [[store.php|http://tiddlylab.bidix.info/store.php]] | . | [[index.html | http://tiddlylab.bidix.info/index.html]] | backup |
| 28/05/2007 22:55:59 | BidiX | [[/|http://tiddlylab.bidix.info/]] | [[store.php|http://tiddlylab.bidix.info/store.php]] | . | [[index.html | http://tiddlylab.bidix.info/index.html]] | backup |
| 30/05/2007 17:09:16 | Bidix | [[/|http://tiddlylab.bidix.info/#%5B%5BBackup%20files%20management%20in%20store.php%5D%5D]] | �[Lrk�����z�tp://tiddlylab.bidix.info/store.php]] | . | [[index.html | http://tiddlylab.bidix.info/index.html]] | backup |
 ��,E��>{�ugQ2�44 | Bidix | [[/|http://tiddlylab.bidix.info/#%5B%5BBackup%20files%20management%20in%20store.php%5D%5D]] | [[store.php|http://tiddlylab.bidix.info/store.php]] | . | [[index.html | http://tiddlylab.bidix.info/index.html]] | backup |
| 31/05/2007 22:28:21 | BidiX | [[/|http://tiddlylab.bidix.info/]] | [[store.php|http://tiddlylab.bidix.info/store.php]] | . | [[index.html | http://tiddlylab.bidix.info/index.html]] | backup | ok |
| 31/05/2007 22:50:16 | BidiX | [[/|http://tiddlylab.bidix.info/#proxy.php]] | [[store.php|http://tiddlylab.bidix.info/store.php]] | . | [[index.html | http://tiddlylab.bidix.info/index.html]] | backup |
| 06/06/2007 18:41:21 | BidiX | [[index.html|file:///C:/Perso/BidiXLab/index.html]] | [[store.php|http://tiddlylab.bidix.info/store.php]] | . | [[index.html | http://tiddlylab.bidix.info/index.html]] | backup |
UploadPlugin uses the following sequence for finding parameters :
#''macro'' parameters
#''Options'' saved in cookies
#''Plugin'' default values
!Options used by UploadPlugin
| Option | Value | Default |
|Upload Username: |<<option txtUploadUserName>>| |
|Upload Password: |<<option pasUploadPassword>>| |
|Url of the UploadService script: |<<option txtUploadStoreUrl urlInput>>| store.php |
|Relative Directory where to store the file: |<<option txtUploadDir urlInput>>| . (the script directory) |
|Filename of the uploaded file: |<<option txtUploadFilename urlInput>>| index.html |
|Directory to backup file on webserver^^(1)^^: |<<option txtUploadBackupDir urlInput>>| //null// (none/no backup) |
|Log in UploadLog |<<option chkUploadLog>> Trace Upload| true |
|Maximum of lines in UploadLog |<<option txtUploadLogMaxLine>>| 10 |

^^(1)^^No backup if Backup Directory is empty, the previous file will be overwritten. Use a '.' to backup in the script directory.

<<upload>> with these options.

!Upload Macro parameters
{{{
<<upload [storeUrl [toFilename [backupDir [uploadDir [username]]]]]>>
 Optional positional parameters can be passed to overwrite UploadOptions. 
}}}

!UploadToFile Macro Macro parameters
{{{
<<uploadTofile [filename [tiddlerTitle]]>>
 tiddlerTitle, filename: if omitted the title of the current tiddler
}}}

<<uploadToFile allowedsites.txt allowedsites.txt>>
/***
|''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');


// Backstage
merge(config.tasks,{
	uploadOptions: {text: "upload", tooltip: "Change UploadOptions and Upload", content: '<<uploadOptions>>'}
});
config.backstageTasks.push("uploadOptions");


//}}}

I'm pleased to announce UploadPlugin 4.1.

!!It works as it did ...
First this new version is a ''refactored version''. That is to say that UploadPlugin works as it did before. But thanks to a number of enhancements in TiddlyWiki <<version>>, now it is based on the core HTTP functions for the low level AJAX and it does no more core hijacking. It also uses only core functions for the HTML and RSS file generation. So UploadPlugin will stay compatible with future evolution of StoreArea, ExtendedFields, FileTemplates ... 

!!... but even better
In addition to the {{{<<upload>>}}} macro, an entry in Backstage is also provided. An experimental UploadToHomeMacro using HomeParameters shadowed tiddler is also released, for now, as a separate plugin.

A lot of small enhancements (better messages, debugMode ...) and better reliability.

And the good news are that UploadLog :
*is optional,
*is automatically truncated,
*stores only the last uploads.

This new release includes also new versions of : UploadOptions, UploadPluginDoc, UploadForm, UploadPluginLingoFR, UploadPluginLingoEN. All tagged <<tag Upload>>

UploadPlugin requires PasswordOptionPlugin in your TiddlyWiki and an UploadService on the WebServer to store the TiddlyWiki file. Even if UploadPlugin 4.1 is compatible with previous store scripts, the easiest script to set up is [[store.php]] version 1.6.0 

Since TiddlyWiki 2.2 is in beta stage, you will find this release at http://tiddlylab.bidix.info/#Upload and also in the SVN repository at http://trac.tiddlywiki.org/tiddlywiki/browser/Trunk/contributors/BidiX

Comments and suggestions are welcome.

Enjoy,

-- BidiX
http://tiddlywiki.bidix.info

//last update: UploadPlugin v 4.0.2//

!Description
UploadPlugin with <<tag UploadService>> extend TiddlyWiki with @@upload@@ and @@save to web@@ commands. 
UploadPlugin uses Username and Password from UploadOptions stored in cookies to authenticate itself to [[store.php]] or [[store.cgi]].
French translation available as a separate tiddler UploadPluginMsgFR

!!UploadPlugin
*If the TiddlyWiki is viewed @@from local disk@@ :
**{{{<<upload ...>>}}}
***display as '''upload'''
***after saving to disk, upload to a website.
*If the TiddlyWiki is viewed @@from a website@@ :
**{{{<<upload ...>>}}}
***display as '''save to web'''
***save to the same website.
*If GenerateAnRssFeed in AdvancedOptions is set :
**generate the content of the RSSFeed 
**upload the RssFile
**Caution : use the SiteUrl tiddler to specify the right url of the TiddlyWiki in the generated RssFile
*DisplayMessage
*If a backupDir is specified
**and if a file already exists in the uploadDir withe the same fielname, move it in the backup dir and rename it with a timestamp
*if UploadLog is activated every upload action is logged in UploadLog
**only the last maxLines are stored
**if maxLine = -1 no truncation will occured 
hint : if UploadLog is the first tiddler in the TimelineTab, no tiddler has been changed since last upload.

!![[store.php]]
*UserVariables to set :
//{{{
$AUTHENTICATE_USER = true; // true | false
$USERS = array(
 'UserName1'=>'Password1', 
 'UserName2'=>'Password2', 
 'UserName3'=>'Password3'); // set usernames and strong passwords
$DEBUG = false; // true | false
//}}}
*method GET
**display an information page
*method POST
**if $~AUTHENTICATE_USER is ''true''
***presence and value of user and password are checked with $USER and $PASSWORD 
**if toFilename already exists and backDir parameter specified
***rename toFilename to backupDir/toFilename.AAAAMMDD.HHSS.html
**copy temporaryUploadedFile toFilename
**return status

!![[store.cgi]]
*UserVariables to set :
//{{{
CONFIG = {
 :users => {
 'UserName1'=>'Password1', 
 'UserName2'=>'Password2', 
 'UserName3'=>'Password3')
 },
 :authenticateUser => true,
 :backupExistingFile => true,
 :withUploadDir => true
}
//}}}
*same processing as store.php above

!Usage : 
{{{
<<upload>>
 uses UploadOptions saved in cookies :
 txtUploadUserName: username
 pasUploadPassword : password
 txtUploadStoreUrl : store script
 txtUploadDir : relative path for upload directory
 txtUploadFilename : upload filename
 txtUploadBackupDir : relative path for backup directory

<<upload [storeUrl [toFilename [backupDir [uploadDir [username]]]]]>>
 Optional positional parameters can be passed to overwrite 
 UploadOptions. 
}}}

Suggestion: Install the {{{<<upload ... >>}}} macro in SideBarOptions just below {{{<<saveChanges>>}}} macro.


!User manual
See HowToUpload

!Installation :
*Install the UploadPlugin as usual
*Upload the [[store.php]] file on your php aware webserver in your TiddlyWiki directory
*Protect your server against malicious upload. Two approaches :
**set $~AUTHENTICATE_USER to true in the [[store.php]] script
***configure $USER and $PASSWORD in the [[store.php]] script on your webserver
***set UploadOptions in conformity with [[store.php]]
**Use server protection :
***for Apache web server ([[for detail see Apache documentation|http://httpd.apache.org/docs/1.3/howto/htaccess.html]]) : 
****configure and upload the [[.htaccess]] [[.passwd]]
***for other web servers see the appropriate documentation
*Configure an upload button, for example in the SideBarOptions
!Suppported Browser
*Firefox and Gecko based browser: tested Ok
*Internet Explorer : tested Ok
*Safari : tested ok on OS X
*Others : Not tested, please report status.

!Revision history
<<tiddler UploadPluginRevisionHistory>>


/***
|''Name:''|UploadPluginLingoEN|
|''Description:''|English Translation|
|''Version:''|4.1.0|
|''Date:''|May 8, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#UploadPluginLingoEN|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''CoreVersion:''|2.2.0|
|''Requires:''|UploadPlugin UploadToHomeMacro|
***/
//{{{
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"
};

merge(config.macros.uploadOptions, {
	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'} 
			]}
	});


bidix.upload.messages = {
	//from saving
	invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki",
	backupSaved: "Backup saved on web",
	backupFailed: "Failed to save backup file on web",
	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."
};

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)"
});

merge(config.tasks,{
	uploadOptions: {text: "upload", tooltip: "Change UploadOptions and Upload", content: '<<uploadOptions>>'}
});

//}}}

//{{{
/*
 * UploadToHomeMacro Lingo
 */
if (config.macros.uploadToHome) {
	merge(config.macros.uploadToHome,{messages: {
			homeParamsTiddler: "HomeParameters",
			prompt: "Save and Upload this TiddlyWiki using parameters in  '%0' tiddler",
			tiddlerNotFound: "Tiddler %0 not found"
		}});
	merge(config.tasks,{
				uploadToHome: {text: "uploadToHome", tooltip: "Upload using '" + config.macros.uploadToHome.messages.homeParamsTiddler + "' tiddler",
				action: config.macros.uploadToHome.action}
		});
}

//}}}
/***
|''Name:''|UploadPluginLingoFR|
|''Description:''|French Translation|
|''Version:''|4.1.0|
|''Date:''|May 8, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#UploadPluginLingoFR|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
|''Requires:''|UploadPlugin UploadToHomeMacro|
***/
//{{{
config.macros.upload.label = {
	promptOption: "Sauvegarde et télécharge ce TiddlyWiki avec les UploadOptions",
	promptParamMacro: "Sauvegarde et télécharge ce TiddlyWiki vers %0",
	saveLabel: "sauvegarde sur le web", 
	saveToDisk: "sauvegarde sur le disque",
	uploadLabel: "Télécharge vers le web" 
};

config.macros.upload.messages = {
	noStoreUrl: "Pas de 'store URL' dans les paramètres ou dans les options",
	usernameOrPasswordMissing: "nom d'utilisateur ou mot de passe absent"
};

merge(config.macros.uploadOptions, {
	wizardTitle: "Télécharge avec les options",
	step1Title: "Ces options sont sauvegardées dans des cookies de votre navigateur",
	step1Html: "<input type='hidden' name='markList'></input><br>",
	cancelButton: "Annuler",
	cancelButtonPrompt: "Arrête l'action en cours et ferme le panneau",
	listViewTemplate: {
		columns: [
			{name: 'Description', field: 'description', title: "Description", type: 'WikiText'},
			{name: 'Option', field: 'option', title: "Option", type: 'String'},
			{name: 'Nom', field: 'name', title: "Nom", type: 'String'}
			],
		rowClasses: [
			{className: 'lowlight', field: 'lowlight'} 
			]}
	});

bidix.upload.messages = {
	//from saving
	invalidFileError: "Le fichier '%0' d'origine ne semble pas être un TiddlyWiki valide",
	backupSaved: "backup enegistré sur le web",
	backupFailed: "Echec de l'enregistrement du backup sur le web",
	rssSaved: "Flux RSS a été téléchargé",
	rssFailed: "Echec du téléchargement du flux RSS",
	emptySaved: "Fichier de base 'empty.html' téléchargé",
	emptyFailed: "Echec du téléchargement du fichier de base 'empty.html'",
	mainSaved: "Fichier principal TiddlyWiki téléchargé",
	mainFailed: "Echec du téléchargement du fichier principal TiddlyWiki. Vos modifications n'ont pas été téléchargées",
	//specific upload
	loadOriginalHttpPostError: "Le fichier d'origine n'a pas pu être accédé",
	aboutToSaveOnHttpPost: "Préparation du téléchargement du TiddlyWiki vers %0 ...",
	storePhpNotFound: "Le script de téléchargement '%0' n'a pas pu être trouvé."
};

merge(config.optionsDesc,{
	txtUploadStoreUrl: "Url du script du Service de Téléchargement (defaut : store.php)",
	txtUploadFilename: "Nom du fichier à télécharger vers le web (defaut : in index.html)",
	txtUploadDir: "Repertoire relatif où télécharger le fichier (defaut : . (répertoire du Service de Téléchargement))",
	txtUploadBackupDir: "Repertoire relatif où sauvegarder le fichier précédent. Si vide il n'y aura pas de sauvegarde. (defaut : '' (néant))",
	txtUploadUserName: "Nom d'utilisateur pour le Téléchargement",
	pasUploadPassword: "Mot de passe pour le Téléchargement",
	chkUploadLog: "Enregistre une trace dans UploadLog (defaut: true)",
	txtUploadLogMaxLine: "Nomnre maximum de lignes dans UploadLog (defaut: 10)"
});

merge(config.tasks,{
	uploadOptions: {text: "télécharge", tooltip: "Edite les options et télécharge vers le seveur", content: '<<uploadOptions>>'}
});
//}}}

//{{{
/*
 * UploadToHomeMacro Lingo
 */

if (config.macros.uploadToHome) {
	merge(config.macros.uploadToHome,{messages: {
			homeParamsTiddler: "HomeParameters",
			prompt: "Sauvegarde et télécharge ce TiddlyWiki en utilisant les paramètres du tiddler '%0'",
			tiddlerNotFound: "Tiddler %0 non trouvé"
		}});
	merge(config.tasks,{
			uploadToHome: {text: "téléchargeVersMaison", tooltip: "Télécharge en utilisant le tiddler '" + config.macros.uploadToHome.messages.homeParamsTiddler + "'", action: config.macros.uploadToHome.action}
		});
}

//}}}
*V 4.0.2 (2007/04/21)
**Compatibilty with TW 2.2 beta5
*V 4.0.0 Beta 0 (2007/02/28)
**Code refactoring for using the core HTTP and Options functions
**PasswordOptionPlugin required
**UploadLog is optional and stores only a maxLine number of lines (see UploadOptions)
**the bidix.debugMode variable set to true activates debug both in UploadPlugin and in UploadService
**Enhancements and better reliability
**GroupAuthoring is pull out of UploadPlugin
**No more saveChanges hijacking
----
*V 3.4.5 (2006/10/15)
**Force checkAutoSave to false for http protocol only (thanks to SimonBaird)
*V 3.4.4 (2006/09/30)
**PasswordTweak V 1.0.3
***add class attribute specific on each option input (thanks to ClintChecketts)
**UploadOptions width set by styleSheet
*V 3.4.3 (2006/09/19)
**Add classname to input for options (thanks to ClintChecketts)
**Force checkAutoSave to false
**Alert if password is empty before Uploading
*V 3.4.2 (2006/09/04)
**add functions to format displayMessages (thanks to LucDeschenaux)
**take return values from store.cgi of destfile and backupfile for displayMessages 
*V 3.4.1 (2006/08/19)
**Error management improvement
*V 3.4.0 (2006/07/25)
**Manage Lock parameters for GroupAuthoring
**Small code refactoring for new PluginFormat in TW 2.1
*V 3.3.3 (2006/06/30)
**reinstall saveChanges Hijacking
*V 3.3.2 (2006/06/26)
** make "save to disk" disappear when TiddlyWiki is located on the web
** small reformatting of post headers for store.cgi compatibility
*V 3.3.1 (2006/03/30)
**bug in backup folder when uploading rssfile fixed
*V 3.3.0 (2006/03/12)
**Code refactoring
**suppress saveChanges hijacking
*V3.2.2 (2006/02/25)
**Use PasswordTweak 1.0.1
**uploaddir is a relative path
**backupdir is a relative path
*V3.2.1 (2006/02/13)
**name and password added to open.request (Thanks to TedPavlic)
*V3.2.0 (2006/02/14)
**Use PassworDTweak (http://tiddlyWiki.bidix.info/#PasswordTweak) for password
*V3.1.0 (2006/02/12)
**UploadOptions in Cookies
**Username and password from UploadOptions pass to store.php script for authentification check
*V3.0.3 (2006/02/03)
**Firefox 1.5.0.1 crashes due to global var fixed
*V3.0.2 (2006/01/25/)
**HTTPS compatible
*V3.0.1 (2006/01/18)
**UTF8toUnicode conversion problem in Firefox
*V3.0.0 (2006/01/15)
**Asynchronous upload
**Synchronous upload before unload of the page
**All strings extracted in macro config
**Compatibility checked with TW 2.0.2 & TW 1.2.39 for both FF 1.5 and IE 6
*V2.0.2 (2006/01/08)
**conversion of SiteTitle and SiteSubtitle in web page Title
*V2.0.1 (2006/01/08)
**Compatibilty with TiddlyWiki 2.0.1
*V2.0.0 (2006/01/03)
**Save to web
**Compatibilty with TiddlyWiki 1.2.39 and TiddlyWiki 2.0.0 Beta 6
*v1.1.0 (2005/12/27)
**Upload RSS File
*v1.0.3 (2005/12/26)
**UploadLog tiddler
*v1.0.2 (2005/12/24)
**Optional parameter toFilename
**Optional parameter backupDir
*v1.0.1 (2005/12/23)
**reformatting code
* v1.0.0 (2005/12/17)
** first public working version

/***
|''Name:''|UploadToFileMacro|
|''Description:''|Upload a tiddler as a file using UploadPlugin context. Used with the SimonBaird's HideWhenPlugin ViewTemplate provides a new command in the tiddler toolbar.|
|''Version:''|2.0.1|
|''Date:''|Apr 21, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#UploadToFileMacro|
|''Usage:''|{{{<<uploadTofile [filename [tiddlerTitle]]>>}}}<br>{{{tiddlerTitle, filename: if omitted the title of the current tiddler}}}|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''CoreVersion:''|2.2.0|
|''Requires:''|UploadPlugin|
***/
//{{{
version.extensions.UploadToFileMacro = {
	major: 2, minor: 0, revision: 1, 
	date: new Date("Apr 21, 2007"),
	source: 'http://tiddlywiki.bidix.info/#UploadToFilePlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0'
};

// require UploadPlugin 4.0.0 or better
config.macros.uploadToFile = {
	label: "upload %0 to file %1",
	prompt: "upload tiddler '%0' to file '%1' ",
	warning: "Are you sure you want to upload '%0'?",
	messages: {
		fileUploaded: "tiddler '%0' uploaded to file '%1'",
		fileNotUploaded: "tiddler '%0' NOT uploaded"
	},

	handler: function(place, macroName, params, wikifier,paramString, tiddler) {
		// parameters initialization
		var toFilename = params[0];
		var tiddlerTitle = params[1];
		if (!tiddlerTitle) { 
			tiddlerTitle = tiddler.title;
		} else {
			tiddler = store.getTiddler(tiddlerTitle);
		}
		if (!toFilename) { 
			toFilename = tiddlerTitle;
		} 
		var prompt = this.prompt.format(