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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

----
Also see [[AdvancedOptions]]
<<importTiddlers>>
/***
|Name|CoreTweaks|
|Source|http://www.TiddlyTools.com/#CoreTweaks|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.2.0|
|Type|plugin|
|Description|a small collection of overrides to TW core functions|
This tiddler contains small changes to TW core functions that correct or enhance standard features or behaviors.
***/
//{{{
// calculate TW version number - used to determine which tweaks should be applied
var ver=version.major+version.minor/10+version.revision/100;
//}}}
/***
----

***/
// // to be fixed in 2.6.0:
// // {{block{
/***
!!!1151 adjust popup placement when root element is in scrolled DIV
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/1151
When a popup link is placed inside a DIV with style "overflow:scroll" or "overflow:auto" and that DIV is then scrolled, the position of the resulting popup appears further down the page that intended, because it is not adjusting for the relative scroll offset of the containing DIV.  This tweak patches the Popup.place() function to calculate and subtract the current scroll offset from the computed popup position, so that it appears in the correct location on the page.

Test case: //(scroll to the bottom of this DIV and click on "test popup")//
{{groupbox{
 <<tiddler ScrollBox with: CoreTweaks##1151test 12em>>}}}/%
!1151test
<<tiddler About>>
<<showPopup tiddler:About label:"test popup" tip:About popupClass:sticky>>
!end
%/
***/
//{{{
window.findScrollOffsetX=function(obj) {
	var x=0;
	while(obj) {
		if (obj.scrollLeft && obj.nodeName!='HTML')
			x+=obj.scrollLeft;
		obj=obj.parentNode;
	}
	return -x;
}

window.findScrollOffsetY=function(obj) {
	var y=0;
	while(obj) {
		if (obj.scrollTop && obj.nodeName!='HTML')
			y+=obj.scrollTop;
		obj=obj.parentNode;
	}
	return -y;
}

var fn=Popup.place.toString();
if (fn.indexOf('findScrollOffsetX')==-1) { // only once
	fn=fn.replace(/var\s*rootLeft\s*=/,'var rootLeft = window.findScrollOffsetX(root) +');
	fn=fn.replace(/var\s*rootTop\s*=/,'var rootTop = window.findScrollOffsetY(root) +');
	eval('Popup.place='+fn);
}
//}}}
// // }}}}}}// // {{block{
/***
!!!1147 tiddler macro with params does not refresh
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/1147
when the {{{<<tiddler SomeTiddler>>}}} macro is handled, the resulting span has extra attributes: {{{refresh='content'}}} and {{{tiddler='SomeTiddler'}}}.  If SomeTiddler is changed, {{{store.notify('SomeTiddler')}}} triggers {{{refreshDisplay()}}}, which automatically re-renders transcluded content in any span that has these extra attributes.  However, when additional arguments are passed by using {{{<<tiddler SomeTiddler with: arg arg arg ...>>}}} then the resulting span does NOT get the extra attributes noted above and, as a consequence, the transcluded content is not being refreshed, even though the underlying tiddler has changed

To correct this, in {{{config.macros.tiddler.handler}}}:
*set the 'refresh' and 'tiddler' attributes even when arguments are present in the macro
*store the arguments themselves in an attribute (e.g, 'args'), using as a space-separated, bracketed list
Then, in {{{config.refreshers.content}}}:
*retrieve the stored arguments (if any) and the tiddler source
*substitute arguments into source and re-render the span with the updated content

***/
//{{{
config.refreshers.content=function(e,changeList) {
		var title = e.getAttribute("tiddler");
		var force = e.getAttribute("force");
		var args = e.getAttribute("args"); // ADDED
		if(force != null || changeList == null || changeList.indexOf(title) != -1) {
			removeChildren(e);
//			wikify(store.getTiddlerText(title,""),e,null,store.fetchTiddler(title)); // REMOVED
			config.macros.tiddler.transclude(e,title,args); // ADDED
			return true;
		} else
			return false;
};

config.macros.tiddler.handler=function(place,macroName,params,wikifier,paramString,tiddler) {
	params = paramString.parseParams("name",null,true,false,true);
	var names = params[0]["name"];
	var tiddlerName = names[0];
	var className = names[1] || null;
	var args = params[0]["with"];
	var wrapper = createTiddlyElement(place,"span",null,className);
//	if(!args) { // REMOVED
		wrapper.setAttribute("refresh","content");
		wrapper.setAttribute("tiddler",tiddlerName);
// 	} // REMOVED
	if(args!==undefined) wrapper.setAttribute("args",'[['+args.join(']] [[')+']]'); // ADDED
	this.transclude(wrapper,tiddlerName,args); // REFACTORED TO ...tiddler.transclude
}

// REFACTORED FROM ...tiddler.handler
config.macros.tiddler.transclude=function(wrapper,tiddlerName,args) {
	var text = store.getTiddlerText(tiddlerName); if (!text) return;
	var stack = config.macros.tiddler.tiddlerStack;
	if(stack.indexOf(tiddlerName) !== -1) return;
	stack.push(tiddlerName);
	try {
		if (typeof args == "string") args=args.readBracketedList(); // ADDED
		var n = args ? Math.min(args.length,9) : 0;
		for(var i=0; i<n; i++) {
			var placeholderRE = new RegExp("\\$" + (i + 1),"mg");
			text = text.replace(placeholderRE,args[i]);
		}
		config.macros.tiddler.renderText(wrapper,text,tiddlerName,null); // REMOVED UNUSED 'params'
	} finally {
		stack.pop();
	}
};
//}}}
// // }}}}}}// // {{block{
/***
!!!1134 allow leading whitespace in section headings / TBD handle shadow tiddler sections
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/1134
This tweak REPLACES and extends {{{store.getTiddlerText()}}} so it can return sections defined in shadow tiddlers as well as permitting use of leading whitespace in section headings.
***/
//{{{
TiddlyWiki.prototype.getTiddlerText = function(title,defaultText)
{
	if(!title) return defaultText;
	var parts = title.split(config.textPrimitives.sectionSeparator);
	var title = parts[0];
	var section = parts[1];
	var parts = title.split(config.textPrimitives.sliceSeparator);
	var title = parts[0];
	var slice = parts[1]?this.getTiddlerSlice(title,parts[1]):null;
	if(slice) return slice;
	var tiddler = this.fetchTiddler(title);
	var text = defaultText;
	if(this.isShadowTiddler(title))
		text = this.getShadowTiddlerText(title);
	if(tiddler)
		text = tiddler.text;
	if(!section) return text;
	var re = new RegExp("(^!{1,6}[ \t]*" + section.escapeRegExp() + "[ \t]*\n)","mg");
	re.lastIndex = 0;
	var match = re.exec(text);
	if(match) {
		var t = text.substr(match.index+match[1].length);
		var re2 = /^!/mg;
		re2.lastIndex = 0;
		match = re2.exec(t); //# search for the next heading
		if(match)
			t = t.substr(0,match.index-1);//# don't include final \n
		return t;
	}
	return defaultText;
};
//}}}
// // }}}}}}// // {{block{
/***
!!!824 ~WindowTitle - alternative to combined ~SiteTitle/~SiteSubtitle in window titlebar
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/824 - OPEN
This tweak allows definition of an optional [[WindowTitle]] tiddler that, when present, provides alternative text for display in the browser window's titlebar, instead of using the combined text content from [[SiteTitle]] and [[SiteSubtitle]] (which will still be displayed as usual in the TiddlyWiki document header area).

Note: this ticket replaces http://trac.tiddlywiki.org/ticket/401 (closed), which proposed using a custom [[PageTitle]] tiddler for this purpose.  ''If you were using the previous '401 ~PageTitle' tweak, you will need to rename [[PageTitle]] to [[WindowTitle]] to continue to use your custom window title text''
***/
//{{{
config.shadowTiddlers.WindowTitle='<<tiddler SiteTitle>> - <<tiddler SiteSubtitle>>';
window.getPageTitle=function() { return wikifyPlain('WindowTitle'); }
store.addNotification('WindowTitle',refreshPageTitle); // so title stays in sync with tiddler changes
//}}}
// // }}}}}}// // {{block{
/***
!!!471 'creator' field for new tiddlers
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/471 - OPEN
This tweak HIJACKS the core's saveTiddler() function to automatically add a 'creator' field to a tiddler when it is FIRST created. You can use """<<view creator>>""" (or """<<view creator wikified>>""" if you prefer) to show this value embedded directly within the tiddler content, or {{{<span macro="view creator"></span>}}} in the ViewTemplate and/or EditTemplate to display the creator value in each tiddler.  
***/
//{{{
// hijack saveTiddler()
TiddlyWiki.prototype.CoreTweaks_creatorSaveTiddler=TiddlyWiki.prototype.saveTiddler;
TiddlyWiki.prototype.saveTiddler=function(title,newTitle,newBody,modifier,modified,tags,fields)
{
	var existing=store.tiddlerExists(title);
	var tiddler=this.CoreTweaks_creatorSaveTiddler.apply(this,arguments);
	if (!existing) store.setValue(title,'creator',config.options.txtUserName);
	return tiddler;
}
//}}}
// // }}}}}}
// // fixed in ~TW2.4.3
// // {{block{
/***
!!!444 'tiddler' and 'place' - global variables for use in computed macro parameters
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/444 - CLOSED:FIXED - TW2.4.3 - http://trac.tiddlywiki.org/changeset/8367
When invoking a macro, this tweak makes the current containing tiddler object and DOM rendering location available as global variables (window.tiddler and window.place, respectively).  These globals can then be used within //computed macro parameters// to retrieve tiddler-relative and/or DOM-relative values or perform tiddler-specific side-effect functionality.
***/
//{{{
if (ver<2.43) {
window.coreTweaks_invokeMacro = window.invokeMacro;
window.invokeMacro = function(place,macro,params,wikifier,tiddler) {
	var here=story.findContainingTiddler(place);
	window.tiddler=here?store.getTiddler(here.getAttribute('tiddler')):tiddler;
	window.place=place;
	window.coreTweaks_invokeMacro.apply(this,arguments);
}
}
//}}}
// // }}}}}}
// // fixed in ~TW2.4.2:
// // {{block{
/***
!!!823 apply option values via paramifiers (e.g. #chk...and #txt...)
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/823 - CLOSED:FIXED - TW2.4.2 http://trac.tiddlywiki.org/changeset/7988
This tweak extends and ''//replaces//'' the core {{{invokeParamifier()}}} function to support use of ''option paramifiers'' that set TiddlyWiki option values on-the-fly, directly from a document URL.

If a paramifier begins with 'chk' (checkbox) or 'txt' (text field), it's value will be automatically stored in {{{config.options.*}}}, adding to or overriding any existing 'chk' or 'txt' option values that may have already been loaded from browser cookies and/or assigned by the TW core or plugin initialization functions using hard-coded default values.  Note: option values that have been overriden by paramifiers are only applied during the current document session, and are not //automatically// retained.  However, if you edit an overridden option value during that session, then the modified value is, of course, saved in a browser cookie, as usual.
***/
//{{{
if (ver<2.42) {
function invokeParamifier(params,handler)
{
	if(!params || params.length == undefined || params.length <= 1)
		return;
	for(var t=1; t<params.length; t++) {
		var p = config.paramifiers[params[t].name];
		if(p && p[handler] instanceof Function)
			p[handler](params[t].value);
		else { // not a paramifier with handler()... check for an 'option' prefix
			var h=config.optionHandlers[params[t].name.substr(0,3)];
			if (h && h.set instanceof Function)
				h.set(params[t].name,params[t].value);
		}
	}
}
}
//}}}
// // }}}}}}
// // closed: won't fix //(leave as core tweaks)//
// // {{block{
/***
!!!637 TiddlyLink tooltip - custom formatting
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/637 - CLOSED: WON'T FIX
This tweak modifies the tooltip format that appears when you mouseover a link to a tiddler.  It adds an option to control the date format, as well as displaying the size of the tiddler (in bytes)

Tiddler link tooltip format:
{{stretch{<<option txtTiddlerLinkTootip>>}}}
^^where: %0=title, %1=username, %2=modification date, %3=size in bytes, %4=description slice^^
Tiddler link tooltip date format:
{{stretch{<<option txtTiddlerLinkTooltipDate>>}}}
***/
//{{{
config.messages.tiddlerLinkTooltip='%0 - %1, %2 (%3 bytes) - %4';
config.messages.tiddlerLinkTooltipDate='DDD, MMM DDth YYYY 0hh12:0mm AM';

config.options.txtTiddlerLinkTootip=
	config.options.txtTiddlerLinkTootip||config.messages.tiddlerLinkTooltip;
config.options.txtTiddlerLinkTooltipDate=
	config.options.txtTiddlerLinkTooltipDate||config.messages.tiddlerLinkTooltipDate;

Tiddler.prototype.getSubtitle = function() {
	var modifier = this.modifier;
	if(!modifier) modifier = config.messages.subtitleUnknown;
	var modified = this.modified;
	if(modified) modified = modified.formatString(config.options.txtTiddlerLinkTooltipDate);
	else modified = config.messages.subtitleUnknown;
	var descr=store.getTiddlerSlice(this.title,'Description')||'';
	return config.options.txtTiddlerLinkTootip.format([this.title,modifier,modified,this.text.length,descr]);
};
//}}}
// // }}}}}}// // {{block{
/***
!!!607 add HREF link on permaview command
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/607 - CLOSED: WON'T FIX
This tweak automatically sets the HREF for the 'permaview' sidebar command link so you can use the 'right click' context menu for faster, easier bookmarking.  Note that this does ''not'' automatically set the permaview in the browser's current location URL... it just sets the HREF on the command link.  You still have to click the link to apply the permaview.
***/
//{{{
config.macros.permaview.handler = function(place)
{
	var btn=createTiddlyButton(place,this.label,this.prompt,this.onClick);
	addEvent(btn,'mouseover',this.setHREF);
	addEvent(btn,'focus',this.setHREF);
};
config.macros.permaview.setHREF = function(event){
	var links = [];
	story.forEachTiddler(function(title,element) {
		links.push(String.encodeTiddlyLink(title));
	});
	var newURL=document.location.href;
	var hashPos=newURL.indexOf('#');
	if (hashPos!=-1) newURL=newURL.substr(0,hashPos);
	this.href=newURL+'#'+encodeURIComponent(links.join(' '));
}
//}}}
// // }}}}}}// // {{block{
/***
!!!458 add permalink-like HREFs on internal TiddlyLinks
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/458 - CLOSED: WON'T FIX
This tweak assigns a permalink-like HREF to internal Tiddler links (which normally do not have any HREF defined).  This permits the link's context menu (right-click) to include 'open link in another window/tab' command.  Based on a request from Dustin Spicuzza.
***/
//{{{
window.coreTweaks_createTiddlyLink=window.createTiddlyLink;
window.createTiddlyLink=function(place,title,includeText,theClass,isStatic,linkedFromTiddler,noToggle)
{
	// create the core button, then add the HREF (to internal links only)
	var link=window.coreTweaks_createTiddlyLink.apply(this,arguments);
	if (!isStatic)
		link.href=document.location.href.split('#')[0]+'#'+encodeURIComponent(String.encodeTiddlyLink(title));
	return link;
}
//}}}
// // }}}}}}
// // open tickets:
// // {{block{
/***
!!!608/609/610 toolbars - toggles, separators and transclusion
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/608 - OPEN (more/less toggle)
http://trac.tiddlywiki.org/ticket/609 - OPEN (separators)
http://trac.tiddlywiki.org/ticket/610 - OPEN (wikify tiddler/slice/section content)

This combination tweak extends the """<<toolbar>>""" macro to add use of '<' to insert a 'less' menu command (the opposite of '>' == 'more'), as well as use of '*' to insert linebreaks and "!" to insert a vertical line separator between toolbar items.  In addition, this tweak add the ability to use references to tiddlernames, slices, or sections and render their content inline within the toolbar, allowing easy creation of new toolbar commands using TW content (such as macros, links, inline scripts, etc.)

To produce a one-line style, with "less" at the end, use
| ViewToolbar| foo bar baz > yabba dabba doo < |
or to use a two-line style with more/less toggle:
| ViewToolbar| foo bar baz > < * yabba dabba doo |
***/
//{{{
merge(config.macros.toolbar,{
	moreLabel: 'more\u25BC',
	morePrompt: 'Show additional commands',
	lessLabel: '\u25C4less',
	lessPrompt: 'Hide additional commands',
	separator: '|'
});
config.macros.toolbar.onClickMore = function(ev) {
	var e = this.nextSibling;
	e.style.display = 'inline'; // show menu
	this.style.display = 'none'; // hide button
	return false;
};
config.macros.toolbar.onClickLess = function(ev) {
	var e = this.parentNode;
	var m = e.previousSibling;
	e.style.display = 'none'; // hide menu
	m.style.display = 'inline'; // show button
	return false;
};
config.macros.toolbar.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
	for(var t=0; t<params.length; t++) {
		var c = params[t];
		switch(c) {
			case '!':  // ELS - SEPARATOR (added)
				createTiddlyText(place,this.separator);
				break;
			case '*':  // ELS - LINEBREAK (added)
				createTiddlyElement(place,'BR');
				break;
			case '<': // ELS - LESS COMMAND (added)
				var btn = createTiddlyButton(place,
					this.lessLabel,this.lessPrompt,config.macros.toolbar.onClickLess,'moreCommand');
				break;
			case '>':
				var btn = createTiddlyButton(place,
					this.moreLabel,this.morePrompt,config.macros.toolbar.onClickMore,'moreCommand');
				var e = createTiddlyElement(place,'span',null,'moreCommand');
				e.style.display = 'none';
				place = e;
				break;
			default:
				var theClass = '';
				switch(c.substr(0,1)) {
					case '+':
						theClass = 'defaultCommand';
						c = c.substr(1);
						break;
					case '-':
						theClass = 'cancelCommand';
						c = c.substr(1);
						break;
				}
				if(c in config.commands)

					this.createCommand(place,c,tiddler,theClass);
				else { // ELS - WIKIFY TIDDLER/SLICE/SECTION (added)
					if (c.substr(0,1)=='~') c=c.substr(1); // ignore leading ~
					var txt=store.getTiddlerText(c);
					if (txt) {
						// trim any leading/trailing newlines
						txt=txt.replace(/^\n*/,'').replace(/\n*$/,'');
						// trim PRE format wrapper if any
						txt=txt.replace(/^\{\{\{\n/,'').replace(/\n\}\}\}$/,'');
						// render content into toolbar
						wikify(txt,createTiddlyElement(place,'span'),null,tiddler);
					}
				} // ELS - end WIKIFY CONTENT
				break;
		}
	}
};
//}}}
// // }}}}}}// // {{block{
/***
!!!529 IE fixup - case-sensitive element lookup of tiddler elements
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/529 - OPEN
This tweak hijacks the standard browser function, document.getElementById(), to work-around the case-INsensitivity error in Internet Explorer (all versions up to and including IE7) //''Note: This tweak is only applied when using IE, and only for lookups of rendered tiddler elements within the containing 'tiddlerDisplay' element.''//
***/
//{{{
if (config.browser.isIE) {
document.coreTweaks_coreGetElementById=document.getElementById;
document.getElementById=function(id) {
	var e=document.coreTweaks_coreGetElementById(id);
	if (!e || !e.parentNode || e.parentNode.id!='tiddlerDisplay') return e;
	for (var i=0; i<e.parentNode.childNodes.length; i++)
		if (id==e.parentNode.childNodes[i].id) return e.parentNode.childNodes[i];
	return null;
};
}
//}}}
// // }}}}}}// // {{block{
/***
!!!890 add conditional test to """<<tiddler>>""" macro
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/890 - OPEN
This tweak extends the {{{<<tiddler>>}}} macro syntax so you can include a javascript-based //test expression// to determine if the tiddler transclusion should be performed:
{{{
<<tiddler TiddlerName if:{{...}} with: param param etc.>>
}}}
If the test is ''true'', then the tiddler is transcluded as usual.  If the test is ''false'', then the transclusion is skipped and //no output is produced//.
***/
//{{{
config.macros.tiddler.if_handler = config.macros.tiddler.handler;
config.macros.tiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	params = paramString.parseParams('name',null,true,false,true);
	if (!getParam(params,'if',true)) return;
	this.if_handler.apply(this,arguments);
};
//}}}
// // }}}}}}// // {{block{
/***
!!!831 backslash-quoting for embedding newlines in 'line-mode' formats
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/831 - OPEN
This tweak pre-processes source content to convert 'double-backslash-newline' into {{{<br>}}} before wikify(), so that literal newlines can be embedded in line-mode wiki syntax (e.g., tables, bullets, etc.)
***/
//{{{
window.coreWikify = wikify;
window.wikify = function(source,output,highlightRegExp,tiddler)
{
	if (source) arguments[0]=source.replace(/\\\\\n/mg,'<br>');
	coreWikify.apply(this,arguments);
}
//}}}
// // }}}}}}// // {{block{
/***
!!!683 FireFox3 Import bug: 'browse' button replacement
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/683 - OPEN
The web standard 'type=file' input control that has been used as a local path/file picker for TiddlyWiki no longer works as expected in FireFox3, which has, for security reasons, limited javascript access to this control so that *no* local filesystem path information can be revealed, even when it is intentional and necessary, as it is with TiddlyWiki.  This tweak provides alternative HTML source that patches the backstage import panel.  It replaces the 'type=file' input control with a text+button combination of controls that invokes a system-native secure 'file-chooser' dialog box to provide TiddlyWiki with access to a complete path+filename so that TW functions properly locate user-selected local files.
>Note: ''This tweak also requires http://trac.tiddlywiki.org/ticket/604 - cross-platform askForFilename()''
***/
//{{{
if (window.Components) {
	var fixhtml='<input name="txtBrowse" style="width:30em"><input type="button" value="..."'
		+' onClick="window.browseForFilename(this.previousSibling,true)">';
	var cmi=config.macros.importTiddlers;
	cmi.step1Html=cmi.step1Html.replace(/<input type='file' size=50 name='txtBrowse'>/,fixhtml);
}

merge(config.messages,{selectFile:'Please enter or select a file'}); // ready for I18N translation

window.browseForFilename=function(target,mustExist) { // note: both params are optional
	var msg=config.messages.selectFile;
	if (target && target.title) msg=target.title; // use target field tooltip (if any) as dialog prompt text
	// get local path for current document
	var path=getLocalPath(document.location.href);
	var p=path.lastIndexOf('/'); if (p==-1) p=path.lastIndexOf('\\'); // Unix or Windows
	if (p!=-1) path=path.substr(0,p+1); // remove filename, leave trailing slash
	var file=''
	var result=window.askForFilename(msg,path,file,mustExist); // requires #604
	if (target && result.length) // set target field and trigger handling
		{ target.value=result; target.onchange(); }
	return result; 
}
//}}}
// // }}}}}}// // {{block{
/***
!!!604 cross-platform askForFilename()
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/604 - OPEN
invokes a system-native secure 'file-chooser' dialog box to provide TiddlyWiki with access to a complete path+filename so that TW functions properly locate user-selected local files.
***/
//{{{
window.askForFilename=function(msg,path,file,mustExist) {
	var r = window.mozAskForFilename(msg,path,file,mustExist);
	if(r===null || r===false)
		r = window.ieAskForFilename(msg,path,file,mustExist);
	if(r===null || r===false)
		r = window.javaAskForFilename(msg,path,file,mustExist);
	if(r===null || r===false)
		r = prompt(msg,path+file);
	return r||'';
}

window.mozAskForFilename=function(msg,path,file,mustExist) {
	if(!window.Components) return false;
	try {
		netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
		var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
		var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
		picker.init(window, msg, mustExist?nsIFilePicker.modeOpen:nsIFilePicker.modeSave);
		var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
		thispath.initWithPath(path);
		picker.displayDirectory=thispath;
		picker.defaultExtension='html';
		picker.defaultString=file;
		picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
		if (picker.show()!=nsIFilePicker.returnCancel)
			var result=picker.file.path;
	}
	catch(ex) { displayMessage(ex.toString()); }
	return result;
}

window.ieAskForFilename=function(msg,path,file,mustExist) {
	if(!config.browser.isIE) return false;
	try {
		var s = new ActiveXObject('UserAccounts.CommonDialog');
		s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
		s.FilterIndex=3; // default to HTML files;
		s.InitialDir=path;
		s.FileName=file;
		return s.showOpen()?s.FileName:'';
	}
	catch(ex) { displayMessage(ex.toString()); }
	return result;
}

window.javaAskForFilename=function(msg,path,file,mustExist) {
	if(!document.applets['TiddlySaver']) return false;
	// TBD: implement java-based askFile(...) function
	try { return document.applets['TiddlySaver'].askFile(msg,path,file,mustExist); } 
	catch(ex) { displayMessage(ex.toString()); }
}
//}}}
// // }}}}}}// // {{block{
/***
!!!657 wrap tabs onto multiple lines
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/657 - OPEN
This tweak inserts an extra space element following each tab, allowing them to wrap onto multiple lines if needed.
***/
//{{{
config.macros.tabs.handler = function(place,macroName,params)
{
	var cookie = params[0];
	var numTabs = (params.length-1)/3;
	var wrapper = createTiddlyElement(null,'div',null,'tabsetWrapper ' + cookie);
	var tabset = createTiddlyElement(wrapper,'div',null,'tabset');
	tabset.setAttribute('cookie',cookie);
	var validTab = false;
	for(var t=0; t<numTabs; t++) {
		var label = params[t*3+1];
		var prompt = params[t*3+2];
		var content = params[t*3+3];
		var tab = createTiddlyButton(tabset,label,prompt,this.onClickTab,'tab tabUnselected');
		createTiddlyElement(tab,'span',null,null,' ',{style:'font-size:0pt;line-height:0px'}); // ELS
		tab.setAttribute('tab',label);
		tab.setAttribute('content',content);
		tab.title = prompt;
		if(config.options[cookie] == label)
			validTab = true;
	}
	if(!validTab)
		config.options[cookie] = params[1];
	place.appendChild(wrapper);
	this.switchTab(tabset,config.options[cookie]);
};
//}}}
// // }}}}}}// // {{block{
/***
!!!628 hide 'no such macro' errors
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/628 - OPEN
When invoking a macro that is not defined, this tweak prevents the display of the 'error in macro... no such macro' message.  This is useful when rendering tiddler content or templates that reference macros that are defined by //optional// plugins that have not been installed in the current document.

<<option chkHideMissingMacros>> hide 'no such macro' error messages
***/
//{{{
if (config.options.chkHideMissingMacros===undefined)
	config.options.chkHideMissingMacros=false;

window.coreTweaks_missingMacro_invokeMacro = window.invokeMacro;
window.invokeMacro = function(place,macro,params,wikifier,tiddler) {
	if (!config.macros[macro] || !config.macros[macro].handler)
		if (config.options.chkHideMissingMacros) return;
	window.coreTweaks_missingMacro_invokeMacro.apply(this,arguments);
}
//}}}
// // }}}}}}
// // <<foldHeadings>>
/***
|''Navn:''|DanishTranslationPlugin|
|''Beskrivelse:''|Translation of TiddlyWiki into Danish|
|''Forfatter:''|MartinBudden (mjbudden (at) gmail (dot) com)|
|''Kilde:''|www.example.com |
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/association/locales/core/en/locale.en.js |
|''Version:''|0.3.7|
|''Dato:''|Jul 6, 2007|
|''Kommentarer:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''Licens:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]] |
|''~CoreVersion:''|2.4|
***/

//{{{
//--
//-- Translateable strings
//--

// Strings in "double quotes" should be translated; strings in 'single quotes' should be left alone

config.locale = "da"; // W3C language tag

if (config.options.txtUserName == 'YourName') // do not translate this line, but do translate the next line
	merge(config.options,{txtUserName: "DitNavn"});

merge(config.tasks,{
	save: {text: "gem", tooltip: "Gem dine ændringer til denne TiddlyWiki", action: saveChanges},
	sync: {text: "synk", tooltip: "Synkronisér ændringer med andre TiddlyWiki filer og servere", content: '<<sync>>'},
	importTask: {text: "importér", tooltip: "Importér tiddlers og plugins fra andre TiddlyWiki filer og servere", content: '<<importTiddlers>>'},
	tweak: {text: "Tilpas", tooltip: "Tilpas TiddlyWikis udseende og opførsel", content: '<<options>>'},
	upgrade: {text: "upgradér", tooltip: "Upgrader TiddlyWikis kerne kode", content: '<<upgrade>>'},
	plugins: {text: "udvidelser", tooltip: "Administrér installerede udvidelser", content: '<<plugins>>'}
});

// Options that can be set in the options panel and/or cookies
merge(config.optionsDesc,{
	txtUserName: "Brugernavn til signering af dine ændringer",
	chkRegExpSearch: "Avend almindelige udtryk til søgninger",
	chkCaseSensitiveSearch: "Forskel på store og små bogstaver",
	chkIncrementalSearch: "Bogstav for bogstav-søgning",
	chkAnimate: "Anvend animationer",
	chkSaveBackups: "Gem en backupfil når der gemmes ændringer",
	chkAutoSave: "Gem automatisk ændringer",
	chkGenerateAnRssFeed: "Lav et RSS feed når der gemmes ændringer",
	chkSaveEmptyTemplate: "Lav en tom skabelon når der gemmes ændringer",
	chkOpenInNewWindow: "Åben internet links i et nyt vindue",
	chkToggleLinks: "Når man klikker på et link i åbne tiddlers lukkes de",
	chkHttpReadOnly: "Skjul redigeringsværktøjer når den vises over HTTP",
	chkForceMinorUpdate: "Opdatér ikke brugernavn og dato når tiddlers bliver ændrede",
	chkConfirmDelete: "Bed om bekræftelse før tiddlers slettes",
	chkInsertTabs: "Brug tab tasten til at indsætte tab tegn istedet for at hoppe imellem felter",
	txtBackupFolder: "Navn på mappe til brug for backups",
	txtMaxEditRows: "Maximum antal af rækker i edit bokse",
	txtFileSystemCharSet: "Default tegnsæt til at gemme ændringer (Kun i Firefox/Mozilla)"});

merge(config.messages,{
	customConfigError: "Der opstod problemer ved loading af udvidelser. Se PluginManager for detaljer",
	pluginError: "Fejl: %0",
	pluginDisabled: "Ikke udført fordi det er slået fra via 'systemConfigDisable' tag",
	pluginForced: "Udført fordi det er tvunget via 'systemConfigForce' tag",
	pluginVersionError: "Ikke udført fordi denne udvidelse kræver en nyere udgave af TiddlyWiki",
	nothingSelected: "Intet er valgt. Du er nødt til at vælge en eller flere ting først",
	savedSnapshotError: "Det ser ud som om denne TiddlyWiki er blevet gemt forkert. Se venligst http://www.tiddlywiki.com/#DownloadSoftware for details",
	subtitleUnknown: "(ukendt)",
	undefinedTiddlerToolTip: "Tiddleren '%0' findes ikke endnu",
	shadowedTiddlerToolTip: "Tiddleren '%0' findes ikke endnu, men har en foruddefineret skygge værdi",
	tiddlerLinkTooltip: "%0 - %1, %2",
	externalLinkTooltip: "Internet link til %0",
	noTags: "Der er ingen taggede tiddlere",
	notFileUrlError: "Du er nødt til at gemme denne TiddlyWiki til en fil før du kan gemme ændringer",
	cantSaveError: "Det er ikke muligt at gemme ændringer. Mulige grunde indbefatter:\n- din browser understøtter det ikke (Firefox, Internet Explorer, Safari og Opera virker alle fint hvis de er konfigurerede korrekt)\n- stien til din TiddlyWiki fil indeholder ulovlige tegn\n- TiddlyWiki HTML filen er blevet flyttet eller omdøbt",
	invalidFileError: "Den originale fil '%0' lader ikke til at være en rigtig TiddlyWiki",
	backupSaved: "Backup gemt",
	backupFailed: "Det lykkedes IKKE at gemme en backup fil",
	rssSaved: "RSS feed gemt",
	rssFailed: "Det lykkedes IKKE at gemme et RSS feed",
	emptySaved: "Tom skabelon gemt",
	emptyFailed: "Det lykkedes IKKE at gemme en tom skabelon",
	mainSaved: "Hoved TiddlyWiki fil gemt",
	mainFailed: "Det lykkedes IKKE at gemme hoved TiddlyWiki filen. Dine ændringer er IKKE blevet gemt",
	macroError: "Fejl i makro <<\%0>>",
	macroErrorDetails: "Fejl ved udførsel af makro <<\%0>>:\n%1",
	missingMacro: "Ingen sådan makro",
	overwriteWarning: "En tiddler med navnet '%0' findes allerede. Vælg OK for at overskrive den",
	unsavedChangesWarning: "ADVARSEL! Der er ugemte æmdringer i TiddlyWikien\n\nVælg OK for at gemme\nVælg FORTRYD for at afvise",
	confirmExit: "--------------------------------\n\nDer er ugemte ændringer i TiddlyWikien. Hvis du fortsætter vil du miste disse ændringer\n\n--------------------------------",
	saveInstructions: "GemÆndringer",
	unsupportedTWFormat: "Ikke understøttet TiddlyWiki format '%0'",
	tiddlerSaveError: "Fejl ved forsøg på at gemme tiddler '%0'",
	tiddlerLoadError: "Fejl ved load af tiddler '%0'",
	wrongSaveFormat: "Kan ikke gemme med formatet '%0'. Bruger standard format til at gemme.",
	invalidFieldName: "Ikke tilladt feltnavn %0",
	fieldCannotBeChanged: "Felt '%0' kan ikke ændres",
	loadingMissingTiddler: "Forsøger at hente tiddleren '%0' fra '%1' serveren ved:\n\n'%2' i arbejdsområdet '%3'",
	upgradeDone: "Opgradering til version %0 er nu fuldført\n\nKlik 'OK' for at genopfriske den nyligt opgraderede TiddlyWiki"});

merge(config.messages.messageClose,{
	text: "luk",
	tooltip: "luk dette meddelelsesområde"});

config.messages.backstage = {
	open: {text: "bagscenen", tooltip: "Åben bagsceneområdet for at ændre på nogle grundlæggende indstillinger"},
	close: {text: "luk", tooltip: "Luk bagsceneområdet"},
	prompt: "bagscenen: ",
	decal: {
		edit: {text: "edit", tooltip: "Redigér tiddleren '%0'"}
	}
};

config.messages.listView = {
	tiddlerTooltip: "Klik for at se hele denne tiddlers tekst",
	previewUnavailable: "(forhåndsvisning er ikke tilgængelig)"
};

config.messages.dates.months = ["Januar", "Februar", "Marts", "April", "Maj", "Juni", "Juli", "August", "September", "Oktober", "November","December"];
config.messages.dates.days = ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag"];
config.messages.dates.shortMonths = ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"];
config.messages.dates.shortDays = ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør"];
// suffixes for dates, eg "1ste","2den","3die"..."30te","31te"
config.messages.dates.daySuffixes = ["ste","den","die","te","te","te","te","te","te","te",
		"te","te","te","te","te","te","te","te","te","te",
		"ste","den","die","te","te","te","te","te","te","te",
		"te"];
config.messages.dates.am = "formiddag";
config.messages.dates.pm = "eftermiddag";

merge(config.messages.tiddlerPopup,{
	});

merge(config.views.wikified.tag,{
	labelNoTags: "ingen tags",
	labelTags: "tags: ",
	openTag: "Åben tag '%0'",
	tooltip: "Vis tiddlere der er taggede med '%0'",
	openAllText: "Åben alle",
	openAllTooltip: "Åben alle disse tiddlere",
	popupNone: "Ingen andre tiddlere er taggede med '%0'"});

merge(config.views.wikified,{
	defaultText: "Tiddleren '%0' findes ikke endnu. Dobbelt-klik for at lave den",
	defaultModifier: "(mangler)",
	shadowModifier: "(indbygget skygge tiddler)",
	dateFormat: "DD MMM YYYY", // use this to change the date format for your locale, eg "YYYY MMM DD", do not translate the Y, M or D
	createdPrompt: "lavet"});

merge(config.views.editor,{
	tagPrompt: "Skriv tags delt med mellemrum, [[brug 2 dobbelte firkantede klammer]] om nødvendigt, eller tilføj allerede eksisterende",
	defaultText: "Skriv teksten til '%0'"});

merge(config.views.editor.tagChooser,{
	text: "tags",
	tooltip: "Vælg eksisterende tags som tilføjelse til denne tiddler",
	popupNone: "Der er ikke defineret nogen tags",
	tagTooltip: "Tilføj tagget '%0'"});

merge(config.messages,{
	sizeTemplates:
		[
		{unit: 1024*1024*1024, template: "%0\u00a0GB"},
		{unit: 1024*1024, template: "%0\u00a0MB"},
		{unit: 1024, template: "%0\u00a0KB"},
		{unit: 1, template: "%0\u00a0B"}
		]});

merge(config.macros.search,{
	label: "søg",
	prompt: "Søg i denne TiddlyWiki",
	accessKey: "F",
	successMsg: "Der er fundet %0 tiddlere som matcher %1",
	failureMsg: "Der er ikke fundet nogen tiddlere som matcher %0"});

merge(config.macros.tagging,{
	label: "tagger: ",
	labelNotTag: "tagger ikke",
	tooltip: "Liste over tiddlere der er taggede med '%0'"});

merge(config.macros.timeline,{
	dateFormat: "DD MMM YYYY"});// use this to change the date format for your locale, eg "YYYY MMM DD", do not translate the Y, M or D

merge(config.macros.allTags,{
	tooltip: "Vis tiddlere der er taggede med '%0'",
	noTags: "Der er ingen taggede tiddlere"});

config.macros.list.all.prompt = "Alle tiddlere i alfabetisk orden";
config.macros.list.missing.prompt = "Tiddlere der linkes til men som ikke er definerede";
config.macros.list.orphans.prompt = "Tiddlere som der ikke linkes til fra nogen andre tiddlere";
config.macros.list.shadowed.prompt = "Tiddlere som er skyggede med grundlæggende indhold";
config.macros.list.touched.prompt = "Tiddlere som er blevet ændret lokalt ";

merge(config.macros.closeAll,{
	label: "luk alle",
	prompt: "Luk alle viste tiddlere (bortset fra dem, der aktuelt er åbne for redigering)"});

merge(config.macros.permaview,{
	label: "vis permalink",
	prompt: "Lav et link til en URL som henter alle de netop nu synlige tiddlere"});

merge(config.macros.saveChanges,{
	label: "gem ændringer",
	prompt: "Gem alle tiddlere for at lave en ny TiddlyWiki",
	accessKey: "S"});

merge(config.macros.newTiddler,{
	label: "ny tiddler",
	prompt: "Lav en ny tiddler",
	title: "Ny Tiddler",
	accessKey: "N"});

merge(config.macros.newJournal,{
	label: "ny journal",
	prompt: "Lav en ny tiddler ud fra nuværende dato og tid",
	accessKey: "J"});

merge(config.macros.options,{
	wizardTitle: "Tilpas avancerede muligheder",
	step1Title: "Disse muligheder gemmes i cookies i din browser",
	step1Html: "<input type='hidden' name='markList'></input><br><input type='checkbox' checked='false' name='chkUnknown'>Show unknown options</input>",
	unknownDescription: "//(ukendt)//",
	listViewTemplate: {
		columns: [
			{name: 'Option', field: 'option', title: "Option", type: 'String'},
			{name: 'Description', field: 'description', title: "Description", type: 'WikiText'},
			{name: 'Name', field: 'name', title: "Name", type: 'String'}
			],
		rowClasses: [
			{className: 'lowlight', field: 'lowlight'}
			]}
	});

merge(config.macros.plugins,{
	wizardTitle: "Administrer udvidelser",
	step1Title: "Aktive udvidelser",
	step1Html: "<input type='hidden' name='markList'></input>", // DO NOT TRANSLATE
	skippedText: "(Denne udvidelse er ikke blevet aktiveret fordi den først er blevet tilføjet efter start)",
	noPluginText: "Der er ikke installeret nogen udvidelser",
	confirmDeleteText: "Er du sikker på at du vil slette disse udvidelser:\n\n%0",
	removeLabel: "Fjern systemConfig tag",
	removePrompt: "Fjern systemConfig tag",
	deleteLabel: "slet",
	deletePrompt: "Slet disse tiddlere permanent",
	listViewTemplate: {
		columns: [
			{name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
			{name: 'Tiddler', field: 'tiddler', title: "Tiddler", type: 'Tiddler'},
			{name: 'Size', field: 'size', tiddlerLink: 'size', title: "Size", type: 'Size'},
			{name: 'Forced', field: 'forced', title: "Forced", tag: 'systemConfigForce', type: 'TagCheckbox'},
			{name: 'Disabled', field: 'disabled', title: "Disabled", tag: 'systemConfigDisable', type: 'TagCheckbox'},
			{name: 'Executed', field: 'executed', title: "Loaded", type: 'Boolean', trueText: "Yes", falseText: "No"},
			{name: 'Startup Time', field: 'startupTime', title: "Startup Time", type: 'String'},
			{name: 'Error', field: 'error', title: "Status", type: 'Boolean', trueText: "Error", falseText: "OK"},
			{name: 'Log', field: 'log', title: "Log", type: 'StringList'}
			],
		rowClasses: [
			{className: 'error', field: 'error'},
			{className: 'warning', field: 'warning'}
			]}
	});

merge(config.macros.toolbar,{
	moreLabel: "mere",
	morePrompt: "Vis flere muligheder"
	});

merge(config.macros.refreshDisplay,{
	label: "genopfrisk",
	prompt: "Genopfrisk hele TiddlyWikiens udseende"
	});

merge(config.macros.importTiddlers,{
	readOnlyWarning: "Du kan ikke importere til en låst TiddlyWiki fil. Prøv at åbne den fra en fil:// URL",
	wizardTitle: "Importer tiddlere fra en anden fil eller server",
	step1Title: "Trin 1: Find serveren eller TiddlyWiki filen",
	step1Html: "Vælg servertypen: <select name='selTypes'><option value=''>Choose...</option></select><br>Indskriv webadresse eller sti her: <input type='text' size=50 name='txtPath'><br>...eller søg efter en fil: <input type='file' size=50 name='txtBrowse'><br><hr>...eller vælg et forudbestemt feed: <select name='selFeeds'><option value=''>Vælg...</option></select>",
	openLabel: "åbn",
	openPrompt: "Åbn forbindelsen til denne fil eller server",
	openError: "Der var problemer med at hente tiddlywiki filen",
	statusOpenHost: "Forbinder til hosten",
	statusGetWorkspaceList: "Henter en liste over tilgængelige arbejdsområder",
	step2Title: "Trin 2: Vælg arbejdsområde",
	step2Html: "Indskriv et navn på arbejdsområdet: <input type='text' size=50 name='txtWorkspace'><br>...eller vælg et der allerede er der: <select name='selWorkspace'><option value=''>Choose...</option></select>",
	cancelLabel: "fortryd",
	cancelPrompt: "Fortryd denne import",
	statusOpenWorkspace: "Åben arbejdsområdet",
	statusGetTiddlerList: "Henter listen over tilgængelige tiddlere",
	errorGettingTiddlerList: "Fejl ved hentning af liste over tiddlere, klik Fortryd for at prøve igen",
	step3Title: "Trin 3: Vælg hvilke tiddlere der skal importeres",
	step3Html: "<input type='hidden' name='markList'></input><br><input type='checkbox' checked='true' name='chkSync'>Keep these tiddlers linked to this server so that you can synchronise subsequent changes</input><br><input type='checkbox' name='chkSave'>Save the details of this server in a 'systemServer' tiddler called:</input> <input type='text' size=25 name='txtSaveTiddler'>",
	importLabel: "importer",
	importPrompt: "Importer disse tiddlere",
	confirmOverwriteText: "Er du sikker på at du vil overskrive disse tiddlere:\n\n%0",
	step4Title: "Trin 4: Importerer %0 tiddler(e)",
	step4Html: "<input type='hidden' name='markReport'></input>", // DO NOT TRANSLATE
	doneLabel: "udført",
	donePrompt: "Luk denne wizard",
	statusDoingImport: "Importerer tiddlere",
	statusDoneImport: "Alle tiddlere er importede",
	systemServerNamePattern: "%2 on %1",
	systemServerNamePatternNoWorkspace: "%1",
	confirmOverwriteSaveTiddler: "Tiddleren '%0' findes allerede. Klik 'OK' for at overskrive den med detaljerne fra denne server, eller 'Fortryd' for at efterlade uændret",
	serverSaveTemplate: "|''Type:''|%0|\n|''URL:''|%1|\n|''Workspace:''|%2|\n\nDenne tiddler blev lavet automatisk for at skrive denne servers detaljer",
	serverSaveModifier: "(System)",
	listViewTemplate: {
		columns: [
			{name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
			{name: 'Tiddler', field: 'tiddler', title: "Tiddler", type: 'Tiddler'},
			{name: 'Size', field: 'size', tiddlerLink: 'size', title: "Size", type: 'Size'},
			{name: 'Tags', field: 'tags', title: "Tags", type: 'Tags'}
			],
		rowClasses: [
			]}
	});

merge(config.macros.upgrade,{
	wizardTitle: "Opgrader TiddlyWikis kerne kode",
	step1Title: "Opdater eller reparer denne TiddlyWiki til sidste nye udgivelse",
	step1Html: "Du er ved at opgradere til sidste nye udgave af TiddlyWikis kerne kode (from <a href='%0' class='externalLink' target='_blank'>%1</a>). Dit indhold vil blive bibeholdt under opgraderinen.<br><br>Bemærk at opgraderinger kan konfikte med gamle udvidelser. Hvis du får problemer med den opgraderede fil se her <a href='http://www.tiddlywiki.org/wiki/CoreUpgrades' class='externalLink' target='_blank'>http://www.tiddlywiki.org/wiki/CoreUpgrades</a>",
	errorCantUpgrade: "Kan ikke opgradere denne TiddlyWiki. Du kan kun opgradere en TiddlyWiki fil som er gemt lokalt på en pc",
	errorNotSaved: "Du skal gemme ændringer før du kan gennemføre en opgradering",
	step2Title: "Bekræft opgraderingsdetaljer",
	step2Html_downgrade: "Du er ved at nedgradere til TiddlyWiki version %0 fra %1.<br><br>Nedgradering til en ældre udgave af kerne koden er IKKE tilrådeligt",
	step2Html_restore: "Denne tiddlyWike bruger allerede den sidste nye kerne kode (%0).<br><br>Du kan fortsætte med opgraderingen for at sikre dig at koden ikke er blevet ødelagt",
	step2Html_upgrade: "Du er ved at opgradere til TiddlyWiki version %0 fra %1",
	upgradeLabel: "opgrader",
	upgradePrompt: "Forbered opgraderingsprocessen",
	statusPreparingBackup: "Forbereder backup",
	statusSavingBackup: "Gemmer backup fil",
	errorSavingBackup: "Der var problemer med at gemme backup filen",
	statusLoadingCore: "Loader kernekoden",
	errorLoadingCore: "Fejl ved load af kernekoden",
	errorCoreFormat: "Fejl ved den nye kernekode",
	statusSavingCore: "Gemmer den nye kernekode",
	statusReloadingCore: "Genloader den nye kernekode",
	startLabel: "start",
	startPrompt: "Start opgraderingsprocessen",
	cancelLabel: "fortryd",
	cancelPrompt: "Fortryd opgraderingsprocessen",
	step3Title: "Opgradering afbrudt",
	step3Html: "Du har afbrudt opgraderingsprocessen"
	});

merge(config.macros.sync,{
	listViewTemplate: {
		columns: [
			{name: 'Selected', field: 'selected', rowName: 'title', type: 'Selector'},
			{name: 'Tiddler', field: 'tiddler', title: "Tiddler", type: 'Tiddler'},
			{name: 'Server Type', field: 'serverType', title: "Server type", type: 'String'},
			{name: 'Server Host', field: 'serverHost', title: "Server host", type: 'String'},
			{name: 'Server Workspace', field: 'serverWorkspace', title: "Server workspace", type: 'String'},
			{name: 'Status', field: 'status', title: "Synchronisation status", type: 'String'},
			{name: 'Server URL', field: 'serverUrl', title: "Server URL", text: "View", type: 'Link'}
			],
		rowClasses: [
			],
		buttons: [
			{caption: "Synkronisér disse tiddlere", name: 'sync'}
			]},
	wizardTitle: "Synkroniser med internet servere og filer",
	step1Title: "Vælg hvilke tiddlere du vil synkronisere",
	step1Html: "<input type='hidden' name='markList'></input>", // DO NOT TRANSLATE
	syncLabel: "synk",
	syncPrompt: "Synkronisér disse tiddlere",
	hasChanged: "Ændret imens den var koblet fra",
	hasNotChanged: "Uændret imens den var koblet fra",
	syncStatusList: {
		none: {text: "...", color: "gennemsigtig", display:null},
		changedServer: {text: "Ændret på serveren", color: '#8080ff', display:null},
		changedLocally: {text: "Ændret imens den var koblet fra", color: '#80ff80', display:null},
		changedBoth: {text: "ændret imens den var koblet fra også på serveren", color: '#ff8080', display:null},
		notFound: {text: "Ikke fundet på serveren", color: '#ffff80', display:null},
		putToServer: {text: "Gemt update på serveren", color: '#ff80ff', display:null},
		gotFromServer: {text: "Hentet update fra serveren", color: '#80ffff', display:null}
		}
	});

merge(config.commands.closeTiddler,{
	text: "luk",
	tooltip: "Luk denne tiddler"});

merge(config.commands.closeOthers,{
	text: "luk andre",
	tooltip: "Luk alle andre tiddlere"});

merge(config.commands.editTiddler,{
	text: "redigér",
	tooltip: "Redigér denne tiddler",
	readOnlyText: "se",
	readOnlyTooltip: "Se denne tiddlers kilde"});

merge(config.commands.saveTiddler,{
	text: "færdig",
	tooltip: "Gem ændringer til denne tiddler"});

merge(config.commands.cancelTiddler,{
	text: "fortryd",
	tooltip: "Fortryd ændringer til denne tiddler",
	warning: "Er du sikker på at du vil fortryde dine ændringer til  '%0'?",
	readOnlyText: "færdig",
	readOnlyTooltip: "Se tiddlere normalt"});

merge(config.commands.deleteTiddler,{
	text: "slet",
	tooltip: "Slet denne tiddler",
	warning: "Er du sikker på at du vil slette '%0'?"});

merge(config.commands.permalink,{
	text: "permalink",
	tooltip: "Permalink til denne tiddler"});

merge(config.commands.references,{
	text: "referencer",
	tooltip: "Vis tiddlere som linker til denne tiddler",
	popupNone: "Ingen referencer"});

merge(config.commands.jump,{
	text: "spring",
	tooltip: "Spring til en anden tiddler"});

merge(config.commands.syncing,{
	text: "synkroniserer",
	tooltip: "Kontroller synkronisering af denne tiddler med en server eller en fil",
	currentlySyncing: "<div>Currently syncing via <span class='popupHighlight'>'%0'</span> to:</"+"div><div>host: <span class='popupHighlight'>%1</span></"+"div><div>workspace: <span class='popupHighlight'>%2</span></"+"div>", // Note escaping of closing <div> tag
	notCurrentlySyncing: "Sykroniserer ikke lige nu",
	captionUnSync: "Stop synkronisering af denne tiddler",
	chooseServer: "Synkronisér denne tiddler med en anden server:",
	currServerMarker: "\u25cf ",
	notCurrServerMarker: "  "});

merge(config.commands.fields,{
	text: "felter",
	tooltip: "Vis denne tiddlers udvidede felter",
	emptyText: "Der er ingen udvidede felter til rådighed for denne tiddler",
	listViewTemplate: {
		columns: [
			{name: 'Field', field: 'field', title: "Field", type: 'String'},
			{name: 'Value', field: 'value', title: "Value", type: 'String'}
			],
		rowClasses: [
			],
		buttons: [
			]}});

merge(config.shadowTiddlers,{
	DefaultTiddlers: "[[Kom i gang]]",
	MainMenu: "[[Kom i gang]]\n\n\n^^~TiddlyWiki version <<version>>\n© 2007 [[UnaMesa|http://www.unamesa.org/]]^^",
	"Kom i gang": "For at komme i gang med denne tomme tiddlywiki, skal du ændre på de følgende tiddlere:\n* SiteTitle & SiteSubtitle: Sidens titel og undertitel, som vist øverst (efter de er gemt, vil de også vise sig i browserens titelmenu)\n* MainMenu: er hovedmenuen (er oftest placeret til venstre)\n* DefaultTiddlers: Indeholder navnene på de tiddlere du vilhave skal starte op når du åbner TiddlyWiki\nDu skal også skrive dit brugernavn for at signere dine redigeringer: <<option txtUserName>>",
	SiteTitle: "Min TiddlyWiki",
	SiteSubtitle: "en genbrugelig ikke-liniær personlig web notesbog",
	SiteUrl: "http://www.tiddlywiki.com/",
	OptionsPanel: "Disse muligheder for at ændre på TiddlyWiki bliver gemt i din browser\n\nDit brugernavn til at signere dine ændringer. Skriv det som et WikiOrd (f.eks. PerPoulsen)\n<<option txtUserName>>\n\n<<option chkSaveBackups>> Gem backups\n<<option chkAutoSave>> Gem automatisk\n<<option chkRegExpSearch>> Regexp search\n<<option chkCaseSensitiveSearch>> Søg m forskel på store og små bogstaver\n<<option chkAnimate>> Tillad animationer\n\n----\nSe også [[Avancerede muligheder|AdvancedOptions]]",
	SideBarOptions: '<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal "DD MMM YYYY" "journal">><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel "muligheder \u00bb" "Ændre på TiddlyWikis avancerede muligheder">>',
	SideBarTabs: '<<tabs txtMainTab "Tidslinie" "Tidslinie" TabTimeline "Alle" "Alle tiddlere" TabAll "Tags" "Alle tags" TabTags "Flere" "Flere lister" TabMore>>',
	TabMore: '<<tabs txtMoreTab "Manglende" "Manglende tiddlere" TabMoreMissing "Uden tilknytning" "Tiddlere" TabMoreOrphans "Skyggede" "Skyggede tiddlere" TabMoreShadowed>>'
	});

merge(config.annotations,{
	AdvancedOptions: "Denne skygge tiddler giver adgang til flere avancerede muligheder",
	ColorPalette: "Disse værdier i denne skyggetiddler bestemmer hvilket farveskema, der bliver brugt til ~TiddlyWikis brugerflade",
	DefaultTiddlers: "Tiddlere som er listede i denne skyggetiddler vil automatisk blive vist når ~TiddlyWiki starter op",
	EditTemplate: "HTML skabelonen i denne skyggetiddler bestemmer hvordan tiddlere ser ud når de bliver redigerede",
	GettingStarted: "Denne skyggetiddler giver instruktioner om grundlæggende anvendelse",
	ImportTiddlers: "Denne skyggetiddler giver mulighed for at importere tiddlere",
	MainMenu: "Denne tiddler bliver brugt til at definere indholdet af hoved menuen i venstre side af skærmen",
	MarkupPreHead: "Denne tiddler bliver indsat i toppen af <head> sektionen på TiddlyWiki HTML filen",
	MarkupPostHead: "Denne tiddler bliver indsat i bunden af <head> sektionen på TiddlyWiki HTML filen",
	MarkupPreBody: "Denne tiddler bliver indsat i toppen af<body> sektionen på TiddlyWiki HTML filen",
	MarkupPostBody: "Denne tiddler bliver indsat i slutningen af  <body> sektionen på TiddlyWiki HTML filen umiddelbart efter script blokken",
	OptionsPanel: "Denne skyggetiddler bliver brugt til indholdet af muligheder skydepanelet i højre side",
	PageTemplate: "HTML skabelonen i denne skyggetiddler bestemmer det overordnede ~TiddlyWiki layout",
	PluginManager: "Denne skyggetiddler giver adgang til udvidelsesadministrationen",
	SideBarOptions: "Denne skyggetiddler bruges til indholdet af muligheder panelet i højre sidemenu",
	SideBarTabs: "Denne skyggetiddler bruges til indholdet af fanebladspanelet i højre sidemenu",
	SiteSubtitle: "Denne skyggetiddler bruges som anden del af sidens titel",
	SiteTitle: "Denne skyggetiddler bruges som første del af sidens titel",
	SiteUrl: "Denne skyggetiddler bør sættes til den fulde mål-URL til publikation",
	StyleSheetColors: "Denne skyggetiddler indeholder CSS definitionerne der bestemmer farverne på side elementerne. ''REDIGÉR IKKE DENNE TIDDLER'', lav i stedet dine ændringer i StyleSheet skyggetiddleren",
	StyleSheet: "Denne tiddler kan indeholde specialle CSS definitioner",
	StyleSheetLayout: "Denne skyggetiddler indeholder CSS definitioner der bestemmer layoutet på side elementer. ''REDIGÉR IKKE DENNE TIDDLER'', lav i stedet dine ændringer i StyleSheet skyggetiddleren",
	StyleSheetLocale: "Denne skyggetiddler indeholder CSS definitioner relateret til lokale oversættelser",
	StyleSheetPrint: "Denne skyggetiddler indeholder CSS definitioner til print",
	TabAll: "Denne skyggetiddler indeholder hvad der er i 'Alle' fanen i højre sidemenu",
	TabMore: "Denne skyggetiddler indeholder  hvad der er i 'Flere' fanen i højre sidemenu",
	TabMoreMissing: "Denne skyggetiddler indeholder  hvad der er i 'Mangler' fanen i højre sidemenu",
	TabMoreOrphans: "Denne skyggetiddler indeholder  hvad der er i  'Mangler tilknytning' fanen i højre sidemenu",
	TabMoreShadowed: "Denne skyggetiddler indeholder  hvad der er i 'Skyggede' fanen i højre sidemenu",
	TabTags: "Denne skyggetiddler indeholder  hvad der er i 'Tags' fanen i højre sidemenu",
	TabTimeline: "Denne skyggetiddler indeholder hvad der er i 'Tidslinie' fanen i højre sidemenu",
	ToolbarCommands: "Denne skyggetiddler bestemmer hvilke værktøjer der vises i tiddleres værktøjslinier",
	ViewTemplate: "HTML skabelonen i denne skyggetiddler bestemmer hvordan tiddlere ser ud"
	});

//}}}
<<pasteUp DefaultPageHeader x:0in y:0in   w:8in h:1in>>
<<pasteUp DefaultPageFooter x:0in y:9.7in w:8in h:1in>>
{{center{''@@font-family:"Arial Black,Gadget,sans-serif";Et sidehoved@@''}}}
[[MainMenu]]
/***
|Name|[[EditSectionPlugin]]|
|Source|http://www.TiddlyTools.com/#EditSectionPlugin|
|Documentation|http://www.TiddlyTools.com/#EditSectionPlugin|
|Version|1.6.8|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|invoke popup 'section editor' for specified section of a tiddler|
!!!!!Usage
<<<
{{{
<<editSection TiddlerName##sectionname label tooltip>>
}}}
where:
* ''~TiddlerName##sectionname'' specifies the tiddler and section you want to edit.
** If you omit the "##sectionname" portion (i.e., only enter "~TiddlerName"), the entire content of the indicated tiddler is edited.
** If you omit the "~TiddlerName" portion (i.e., only enter "##sectionname"), the current containing tiddler (if any) is assumed.
** Changing the section name in the popup editor //renames// that section within the tiddler.
** Changing the tiddler title in the popup editor //copies// that section to another tiddler.
** If the indicated tiddler and/or section does not yet exist, it will be created when you press 'save'.
* ''label'' and ''tooltip'' (both //optional//) specify the link label and mouseover help text for the 'edit section' command link.
Note: when a document is viewed in 'readOnly' mode, the macro is bypassed and a command link is not rendered.
<<<
!!!!!Sample
<<<
This is an example section for you to try
<<<
!!!!!Example
<<<
{{{
<<editSection ##Sample>>
}}}
<<editSection ##Sample>>
<<<
!!!!!Configuration
<<<
To customize and/or translate the HTML form layout used to render the section editor, edit the [[EditSectionTemplate]] shadow tiddler.
<<<
!!!!!Revisions
<<<
2011.10.28 1.6.8 fixed getMX()/getMY() for Chrome scroll offset handling
2011.09.02 1.6.7 more refactoring and cleanup of default form init/save handlers
2011.08.02 1.6.6 major code refactor to allow customization of form handling for type-specific [[PasteUpHelperPlugin]] extensions
2011.07.30 1.6.5 in removePanel(), call Popup.remove() so 'child' popups are closed when panel is closed
2011.07.24 1.6.4 refactored save() to provide updateTiddler() entry point for use with PasteUpHelperPlugin 'quickmenu' commands. Added getMX() and getMY() for cross-browser mouse coordinates
2011.06.05 1.6.3 added TiddlySpace cloneFields() to delete and save handlers so editing sections automatically copies/owns an included tiddler
2011.05.05 1.6.2 renamed delete() to deleteSection() to avoid javascript keyword errors
2011.05.04 1.6.1 in delete(), use removeTiddler() for proper notification handling
2011.05.01 1.6.0 added delete() functionality
2011.01.09 1.5.1 in handler(), don't render command link if document is readOnly
2010.12.24 1.5.0 replace use of core Popups with custom panel handling (bypass core interactions and errors)
2010.11.07 1.4.0 in popup(), render HTML form from EditSectionTemplate, and then applyHtmlMacros() to render wiki-syntax macro-generated form elements (e.g., {{{<<option>>, <<select>>}}}, etc.).  Also, refactored form init/save handling to add customization 'hooks'
2010.10.25 1.3.0 added support for editing complete tiddlers using "~TiddlerName" syntax (omit "##sectionname")
2010.07.15 1.2.0 added confirmation when section rename will overwrite other section
2010.07.13 1.1.1 added 'dirty flag' confirmation to popup handling to avoid discarding unsaved changes
2010.07.11 1.1.0 fixed handling for creating new sections in existing tiddlers. Copied StickyPopupPlugin to eliminate dependency. Added Popup.showHere()
2010.05.24 1.0.2 in save(), escape regexp chars in section titles (e.g. "!SectionNameWith?InIt")
2009.09.07 1.0.1 documentation/code cleanup
2009.09.01 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.EditSectionPlugin= {major: 1, minor: 6, revision: 8, date: new Date(2011,10,28)};

config.macros.editSection = {
	label: 'edit section...',
	tip: 'edit %0',
	sectionfmt: '{{hidden{\n!%0\n%1\n!end\n}}}',
	sectionerr: 'Invalid tiddler/section name: %0',
	newtiddlertxt: '',
	discardmsg: 'Discard unsaved changes for %0?',
	deletemsg: 'Are you sure you want to delete %0?',
	overwritemsg: '%0##%2 already exists. Choose OK to overwrite it',
	template: 'EditSectionTemplate', // DEFAULT FORM TEMPLATE
//}}}
// // PLUGIN INITIALIZATION
//{{{
	init: function() {
		// SHADOW PAYLOAD FOR DEFAULT EditSectionTemplate FORM DEFINITION
		config.shadowTiddlers[this.template]
			=store.getTiddlerText('EditSectionPlugin##HTML','');

		// CLOSE PANELS IF CLICK on other than POPUP OR EDITOR PANEL
		addEvent(document,'click',function(ev) {
			var p=resolveTarget(ev||window.event);
			while (p) {
				if (hasClass(p,'editSectionPanel')) break;
				if (hasClass(p,'popup')) break;
				p=p.parentNode;
			}
			if (!p) config.macros.editSection.removeAllPanels();
			return true;
		});

		// HIJACK QuickEditPlugin's getField() to support use with editSectionPanel
		if (config.quickEdit) {
			config.quickEdit.getTiddlerField=config.quickEdit.getField;
			config.quickEdit.getField=function(where) {
				var e=where; while(e) {	if (hasClass(e,'editSectionPanel')) break; e=e.parentNode; }
				return e?e.getElementsByTagName('textarea')[0]:this.getTiddlerField(where);
			}

		}
	},
//}}}
// // GENERAL UTILITIES
//{{{
	ok: function(ev) { var ev=ev||window.event;
		ev.cancelBubble=true;
		if(ev.stopPropagation)ev.stopPropagation();
		return false;
	},
	getMX: function(ev) { var ev=ev||window.event; // GET MOUSE X
		if (config.browser.isIE)	return ev.clientX+findScrollX();// IE
		if (config.userAgent.indexOf('chrome')!=-1) return ev.pageX;	// Chrome
		if (config.browser.isSafari) 	return ev.pageX+findScrollX(); 	// Webkit
		else				return ev.pageX;		// Firefox/other
	},
	getMY: function(ev) { var ev=ev||window.event; // GET MOUSE Y
		if (config.browser.isIE)	return ev.clientY+findScrollY();// IE
		if (config.userAgent.indexOf('chrome')!=-1) return ev.pageY;	// Chrome
		if (config.browser.isSafari) 	return ev.pageY+findScrollY();	// Webkit
		else				return ev.pageY;		// Firefox/other
	},
	cloneFields: function(fields) { // for TIDDLYSPACE compatibility
		var f=merge({},fields); // copy object
		if (f["server.workspace"]!=config.defaultCustomFields["server.workspace"]) {
			f=merge(f,config.defaultCustomFields); // overwrite with defaults
			f["server.permissions"] = "read, write, create, delete";
			delete f["server.page.revision"];
			delete f["server.title"];
			delete f["server.etag"];
		}
		return f;
	},
//}}}
// // MACRO/CLICK HANDLER
//{{{
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if (readOnly) return;
		var here=story.findContainingTiddler(place);
		var tid=params[0];
		var label=params[1]||this.label.format([tid]);
		var tip=params[2]||this.tip.format([tid]);
		var btn=createTiddlyButton(place,label,tip,this.click);
		btn.setAttribute('tid',tid);
	},
	click: function(ev,type) { // note: optional 'type' is passed in from PasteUpPluginHelper
		var parts=this.getAttribute('tid').split('##');
		var title=parts[0]; var section=parts[1];
		var here=story.findContainingTiddler(this);
		if (!title&&here) title=here.getAttribute('tiddler');
		if (!title) return false;
		var tid=title; if (section&&section.length) tid=[title,section].join('##');
		return config.macros.editSection.createPanel(this,ev,tid,title,section,type);
	},
//}}}
// // EDITOR PANEL HANDLER
//{{{
	createPanel: function(here,ev,tid,title,section,type) {
		if (!this.removeAllPanels()) return this.ok(ev);
		var p=createTiddlyElement(document.body,"ol",
			"editSectionPanel","popup smallform editSectionPanel");
		p.root=here; 
		p.setAttribute('dirty',null);
		p.setAttribute('message',this.discardmsg.format([tid]));
		p.innerHTML=store.getRecursiveTiddlerText(this.getForm(tid,type),'',10);
		applyHtmlMacros(p,store.getTiddler(title));
		var f=p.getElementsByTagName('form')[0];
		f.panel=p;
		f.title.value=title;
		f.section.value=section||'';
		f.init=this.getInitForm(tid,type);
		f.save=this.getSaveForm(tid,type);
		f.init(here,f,title,section,type);
		this.showPanel(p,here,ev);
		return this.ok(ev);
	},
	showPanel: function(p,here,ev) {
		var x=this.getMX(ev); var y=this.getMY(ev);
		var winw=findWindowWidth();
		var scrollw=winw-document.body.offsetWidth;
		if(p.offsetWidth>winw*0.75) p.style.width=winw*0.75 + "px";
		if(x+p.offsetWidth>winw-scrollw-1) x=winw-p.offsetWidth-scrollw-1;
		var s=p.style; s.left=x+'px'; s.top=y+'px'; s.display='block';
		if(config.options.chkAnimate && anim)	anim.startAnimating(new Scroller(p));
		else					window.scrollTo(0,ensureVisible(p));
	},
	removePanel: function(p) {
		Popup.remove(); // child popup (if any) is closed when panel is closed
		if (!p || p.getAttribute('dirty')!='true' || confirm(p.getAttribute('message')))
			{ if (p) removeNode(p); return true; }
		return false;
	},
	removeAllPanels: function() {
		var ok=true;
		jQuery('.editSectionPanel').each(function(index){
			var f=this.getElementsByTagName('form')[0];
			if (f.content) f.content.blur(); // force onchange (sets 'dirty' flag as needed)
			ok=config.macros.editSection.removePanel(this);
			return true;
		});
		return ok; // FALSE if panels remain
	},

//}}}
// // EDITOR FORM HANDLER
//{{{
	getForm:	function(tid,type) { return this.template; }, // see PasteUpHelperPlugin
	getInitForm:	function(tid,type) { return this.initForm; }, // see PasteUpHelperPlugin
	getSaveForm:	function(tid,type) { return this.saveForm; }, // see PasteUpHelperPlugin
	initForm: function(here,form,title,section,type) { // SET FORM CONTENT FROM TIDDLER SECTION
		var tid=title; if (section) tid=[title,section].join('##');
		form.newsection.value=tid; // target for output
		form.content.value=store.getTiddlerText(tid,'');
		if (version.extensions.TextAreaPlugin) new window.TextAreaResizer(form.content);
	},
	saveForm: function(here,ev) { // GET SECTION CONTENT FROM FORM (DEFAULT=TEXT CONTENT ONLY)
		var f=here.form;

		// GET TARGET TITLE/SECTION
		var tid=f.newsection.value;
		var parts=tid.split('##');
		var title=parts[0];
		var section=parts[1];
		var oldsection=f.section.value;
		var where=f.panel.root;
		if (!title) title=story.findContainingTiddler(where).getAttribute('tiddler');
		if (!title) {
			displayMessage(this.sectionerr.format([f.newsection.value]));
			f.newsection.focus(); f.newsection.select(); return false;
		}
		// CHECK FOR TIDDLER OVERWRITE
		if (!section && title!=f.title.value && store.tiddlerExists(title)) {
			if (!confirm(config.messages.overwriteWarning.format([title])))
				{ f.newsection.focus(); f.newsection.select(); return this.ok(ev); }

		}
		// WRITE TIDDLER CONTENT and CLOSE PANEL
		this.updateTiddler(f.content.value,title,section,oldsection);
		f.panel.setAttribute('dirty',null); this.removePanel(f.panel);
		return this.ok(ev);
	},
	changed: function(here,ev) {
		here.form.panel.setAttribute('dirty','true');
		return this.ok(ev);
	},
	cancel: function(here,ev) {
		this.removePanel(here.form.panel);
		return this.ok(ev);
	},
	remove: function(here,ev) {
		var f=here.form;
		var title=f.title.value;
		var section=f.section.value;
		var tid=title; if (section.length) tid=[title,section].join('##');
		var msg=this.deletemsg.format([tid]);
		if (!confirm(msg)) return this.ok(ev);
		this.deleteSection(title,section);
		f.panel.setAttribute('dirty',null);
		this.removePanel(f.panel);
		return this.ok(ev);
	},
//}}}
// // TIDDLER I/O
//{{{
	updateTiddler: function(txt,title,section,oldsection) {
		// GET (or CREATE) TIDDLER
		var t=store.getTiddler(title);
		var who =t&&config.options.chkForceMinorUpdate?t.modifier:config.options.txtUserName;
		var when=t&&config.options.chkForceMinorUpdate?t.modified:new Date();
		if (!t) {
			t=new Tiddler(); t.text=store.getTiddlerText(title,'');
			if (section&&!t.text.length) t.text=this.newtiddlertxt.format([title,section]);
		}
		// ADD/REVISE/RENAME SECTION CONTENT (if any)
		if (section) {
			// GET SECTION VALUES
			if (!oldsection) var oldsection=section;
			var oldval=store.getTiddlerText(title+'##'+oldsection); // previous section value
			var newval=txt; // revised section value
			var existingval=store.getTiddlerText(title+'##'+section); // existing section value
			// REVISE TIDDLER TEXT
			var txt=t.text; // default tiddler text = unchanged
			var pattern=new RegExp('(.*!{1,6})'+oldsection.escapeRegExp()+'\\n'
				+(oldval||'').escapeRegExp()+'((?:\\n!{1,6}|$).*)');
			var altpattern=this.sectionfmt.format([oldsection,oldval||'']);
			if (section!=oldsection && existingval) { // rename overwrites another section...
				if (!confirm(this.overwritemsg.format([title,section])))
					return this.ok(ev);
				txt=txt.replace(altpattern,''); // REMOVE old section (auto-generated)
				txt=txt.replace(pattern,'$2');  // REMOVE old section (generic format)
				// TARGET new section name and value
				pattern=new RegExp('(.*!{1,6})'+section.escapeRegExp()+'\\n'
					+existingval.escapeRegExp()+'((?:\\n!{1,6}|$).*)');
				oldval=existingval;
			}
			if (typeof oldval=="string") // section exists... update/rename it
				txt=txt.replace(pattern,'$1'+section+'\n'+newval+'$2');
			else // otherwise, append a new section to end of tiddler
				txt=txt+this.sectionfmt.format([section,newval]);
		}
		// SAVE TIDDLER
		var fields=this.cloneFields(t.fields);
		store.saveTiddler(title,title,txt,who,when,t.tags,fields);
		story.refreshTiddler(title,null,true);
	},
	deleteSection: function(title,section) {
		// GET TIDDLER
		var t=store.getTiddler(title); if (!t) return;
		var who =t&&config.options.chkForceMinorUpdate?t.modifier:config.options.txtUserName;
		var when=t&&config.options.chkForceMinorUpdate?t.modified:new Date();
		if (!section) { // REMOVE TIDDLER
			store.removeTiddler(title);
		} else { // REMOVE SECTION FROM TIDDLER
			var val=store.getTiddlerText(title+'##'+section); // CURRENT SECTION VALUE
			if (typeof val=="string") { // section exists
				var txt=t.text; // default tiddler text = unchanged
				var pattern=new RegExp('(.*!{1,6})'+section.escapeRegExp()+'\\n'
					+(val||'').escapeRegExp()+'((?:\\n!{1,6}|$).*)');
				var altpattern=this.sectionfmt.format([section,val||'']);
				txt=txt.replace(altpattern,''); // REMOVE old section (auto-generated)
				txt=txt.replace(pattern,'$2');  // REMOVE old section (generic format)
				var fields=this.cloneFields(t.fields);
				store.saveTiddler(title,title,txt,who,when,t.tags,fields);
				story.refreshTiddler(title,null,true);
			}
		}
	}
}
//}}}
/***
//{{{
!HTML
<!--{{{-->
<!--
|Name|EditSectionTemplate|
|Source||
|Version||
|Author||
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|template|
|Requires|EditSectionPlugin|
|Description|popup editor form template used by EditSectionPlugin|
-->
<form action='javascript:;' style="white-space:nowrap">
<input type="hidden" name="title" value="">
<input type="hidden" name="section" value="">
<input type="text" name="newsection" value="" autocomplete="off" style="width:61%"
	onchange="return config.macros.editSection.changed(this,event);">
<input type=button value="save" style="width:12%"
	onclick="return config.macros.editSection.saveForm(this,event)">
<input type=button value="cancel" style="width:12%"
	onclick="return config.macros.editSection.cancel(this,event)">
<input type=button value="delete" style="width:12%"
	onclick="return config.macros.editSection.remove(this,event)">
<div macro="tiddler QuickEditToolbar"></div>
<textarea name="content" rows="15" cols="80" autocomplete="off"
	onchange="return config.macros.editSection.changed(this,event)"></textarea>
</form>
<!--}}}-->
!end
//}}}
***/
 
<<pasteUp DefaultPageHeader x:0in y:0in w:8in h:0.4in>>
<<pasteUp DefaultPageFooter x:0in y:9.7in w:8in h:0.4in>>
<<pasteUp Video x:27px y:51px w:723px h:502px>>
/***
|Name|GotoPlugin|
|Source|http://www.TiddlyTools.com/#GotoPlugin|
|Documentation|http://www.TiddlyTools.com/#GotoPluginInfo|
|Version|1.9.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|view any tiddler by entering it's title - displays list of possible matches|
''View a tiddler by typing its title and pressing //enter//.''  As you type, a list of possible matches is displayed.  You can scroll-and-click (or use arrows+enter) to select/view a tiddler, or press escape to close the listbox to resume typing.  When the listbox is not displayed, pressing //escape// clears the current input.
!!!Documentation
>see [[GotoPluginInfo]]
!!!Configuration
<<<
*Match titles only after {{twochar{<<option txtIncrementalSearchMin>>}}} or more characters are entered.<br>Use down-arrow to start matching with shorter input.  //Note: This option value is also set/used by [[SearchOptionsPlugin]]//.
*To set the maximum height of the listbox, you can create a tiddler tagged with <<tag systemConfig>>, containing:
//{{{
config.macros.gotoTiddler.listMaxSize=10;  // change this number
//}}}
<<<
!!!Revisions
<<<
2009.05.22 [1.9.2] use reverseLookup() for IncludePlugin
|please see [[GotoPluginInfo]] for additional revision details|
2006.05.05 [0.0.0] started
<<<
!!!Code
***/
//{{{
version.extensions.GotoPlugin= {major: 1, minor: 9, revision: 2, date: new Date(2009,5,22)};

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

if (config.options.txtIncrementalSearchMin===undefined) config.options.txtIncrementalSearchMin=3;

config.macros.gotoTiddler= { 
	listMaxSize: 10,
	listHeading: 'Found %0 matching title%1...',
	searchItem: "Search for '%0'...",
	handler:
	function(place,macroName,params,wikifier,paramString,tiddler) {
		var quiet	=params.contains("quiet");
		var showlist	=params.contains("showlist");
		var search	=params.contains("search");
		params = paramString.parseParams("anon",null,true,false,false);
		var instyle	=getParam(params,"inputstyle","");
		var liststyle	=getParam(params,"liststyle","");
		var filter	=getParam(params,"filter","");
		var html=this.html;
		var keyevent=window.event?"onkeydown":"onkeypress"; // IE event fixup for ESC handling
		html=html.replace(/%keyevent%/g,keyevent);
		html=html.replace(/%search%/g,search);
		html=html.replace(/%quiet%/g,quiet);
		html=html.replace(/%showlist%/g,showlist);
		html=html.replace(/%display%/g,showlist?'block':'none');
		html=html.replace(/%position%/g,showlist?'static':'absolute');
		html=html.replace(/%instyle%/g,instyle);
		html=html.replace(/%liststyle%/g,liststyle);
		html=html.replace(/%filter%/g,filter);
		if (config.browser.isIE) html=this.IEtableFixup.format([html]);
		var span=createTiddlyElement(place,'span');
		span.innerHTML=html; var form=span.getElementsByTagName("form")[0];
		if (showlist) this.fillList(form.list,'',filter,search,0);
	},
	html:
	'<form onsubmit="return false" style="display:inline;margin:0;padding:0">\
		<input name=gotoTiddler type=text autocomplete="off" accesskey="G" style="%instyle%"\
			title="Enter title text... ENTER=goto, SHIFT-ENTER=search for text, DOWN=select from list"\
			onfocus="this.select(); this.setAttribute(\'accesskey\',\'G\');"\
			%keyevent%="return config.macros.gotoTiddler.inputEscKeyHandler(event,this,this.form.list,%search%,%showlist%);"\
			onkeyup="return config.macros.gotoTiddler.inputKeyHandler(event,this,%quiet%,%search%,%showlist%);">\
		<select name=list style="display:%display%;position:%position%;%liststyle%"\
			onchange="if (!this.selectedIndex) this.selectedIndex=1;"\
			onblur="this.style.display=%showlist%?\'block\':\'none\';"\
			%keyevent%="return config.macros.gotoTiddler.selectKeyHandler(event,this,this.form.gotoTiddler,%showlist%);"\
			onclick="return config.macros.gotoTiddler.processItem(this.value,this.form.gotoTiddler,this,%showlist%);">\
		</select><input name="filter" type="hidden" value="%filter%">\
	</form>',
	IEtableFixup:
	"<table style='width:100%;display:inline;padding:0;margin:0;border:0;'>\
		<tr style='padding:0;margin:0;border:0;'><td style='padding:0;margin:0;border:0;'>\
		%0</td></tr></table>",
	getItems:
	function(list,val,filter) {
		if (!list.cache || !list.cache.length || val.length<=config.options.txtIncrementalSearchMin) {
			// starting new search, fetch and cache list of tiddlers/shadows/tags
			list.cache=new Array();
			if (filter.length) {
				var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
				var tiddlers=store.sortTiddlers(fn.apply(store,[filter]),'title');
			} else 
				var tiddlers=store.reverseLookup('tags','excludeLists');
			for(var t=0; t<tiddlers.length; t++) list.cache.push(tiddlers[t].title);
			if (!filter.length) {
				for (var t in config.shadowTiddlers) list.cache.pushUnique(t);
				var tags=store.getTags();
				for(var t=0; t<tags.length; t++) list.cache.pushUnique(tags[t][0]);
			}
		}
		var found = [];
		var match=val.toLowerCase();
		for(var i=0; i<list.cache.length; i++)
			if (list.cache[i].toLowerCase().indexOf(match)!=-1) found.push(list.cache[i]);
		return found;
	},
	getItemSuffix:
	function(t) {
		if (store.tiddlerExists(t)) return "";  // tiddler
		if (store.isShadowTiddler(t)) return " (shadow)"; // shadow
		return " (tag)"; // tag 
	},
	fillList:
	function(list,val,filter,search,key) {
		if (list.style.display=="none") return; // not visible... do nothing!
		var indent='\xa0\xa0\xa0';
		var found = this.getItems(list,val,filter); // find matching items...
		found.sort(); // alpha by title
		while (list.length > 0) list.options[0]=null; // clear list
		var hdr=this.listHeading.format([found.length,found.length==1?"":"s"]);
		list.options[0]=new Option(hdr,"",false,false);
		for (var t=0; t<found.length; t++) list.options[list.length]=
			new Option(indent+found[t]+this.getItemSuffix(found[t]),found[t],false,false);
		if (search)
			list.options[list.length]=new Option(this.searchItem.format([val]),"*",false,false);
		list.size=(list.length<this.listMaxSize?list.length:this.listMaxSize); // resize list...
		list.selectedIndex=key==38?list.length-1:key==40?1:0;
	},
	keyProcessed:
	function(ev) { // utility function
		ev.cancelBubble=true; // IE4+
		try{event.keyCode=0;}catch(e){}; // IE5
		if (window.event) ev.returnValue=false; // IE6
		if (ev.preventDefault) ev.preventDefault(); // moz/opera/konqueror
		if (ev.stopPropagation) ev.stopPropagation(); // all
		return false;
	},
	inputEscKeyHandler:
	function(event,here,list,search,showlist) {
		if (event.keyCode==27) {
			if (showlist) { // clear input, reset list
				here.value=here.defaultValue;
				this.fillList(list,'',here.form.filter.value,search,0);
			}
			else if (list.style.display=="none") // clear input
				here.value=here.defaultValue;
			else list.style.display="none"; // hide list
			return this.keyProcessed(event);
		}
		return true; // key bubbles up
	},
	inputKeyHandler:
	function(event,here,quiet,search,showlist) {
		var key=event.keyCode;
		var list=here.form.list;
		var filter=here.form.filter;
		// non-printing chars bubble up, except for a few:
		if (key<48) switch(key) {
			// backspace=8, enter=13, space=32, up=38, down=40, delete=46
			case 8: case 13: case 32: case 38: case 40: case 46: break; default: return true;
		}
		// blank input... if down/enter... fall through (list all)... else, and hide or reset list
		if (!here.value.length && !(key==40 || key==13)) {
			if (showlist) this.fillList(here.form.list,'',here.form.filter.value,search,0);
			else list.style.display="none";
			return this.keyProcessed(event);
		}
		// hide list if quiet, or below input minimum (and not showlist)
		list.style.display=(!showlist&&(quiet||here.value.length<config.options.txtIncrementalSearchMin))?'none':'block';
		// non-blank input... enter=show/create tiddler, SHIFT-enter=search for text
		if (key==13 && here.value.length) return this.processItem(event.shiftKey?'*':here.value,here,list,showlist);
		// up or down key, or enter with blank input... shows and moves to list...
		if (key==38 || key==40 || key==13) { list.style.display="block"; list.focus(); }
		this.fillList(list,here.value,filter.value,search,key);
		return true; // key bubbles up
	},
	selectKeyHandler:
	function(event,list,editfield,showlist) {
		if (event.keyCode==27) // escape... hide list, move to edit field
			{ editfield.focus(); list.style.display=showlist?'block':'none'; return this.keyProcessed(event); }
		if (event.keyCode==13 && list.value.length) // enter... view selected item
			{ this.processItem(list.value,editfield,list,showlist); return this.keyProcessed(event); }
		return true; // key bubbles up
	},
	processItem:
	function(title,here,list,showlist) {
		if (!title.length) return;
		list.style.display=showlist?'block':'none';
		if (title=="*")	{ story.search(here.value); return false; } // do full-text search
		if (!showlist) here.value=title;
		story.displayTiddler(null,title); // show selected tiddler
		return false;
	}
}
//}}}
/***
|Name|ImageSizePlugin|
|Source|http://www.TiddlyTools.com/#ImageSizePlugin|
|Version|1.2.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|adds support for resizing images|
This plugin adds optional syntax to scale an image to a specified width and height and/or interactively resize the image with the mouse.
!!!!!Usage
<<<
The extended image syntax is:
{{{
[img(w+,h+)[...][...]]
}}}
where ''(w,h)'' indicates the desired width and height (in CSS units, e.g., px, em, cm, in, or %). Use ''auto'' (or a blank value) for either dimension to scale that dimension proportionally (i.e., maintain the aspect ratio). You can also calculate a CSS value 'on-the-fly' by using a //javascript expression// enclosed between """{{""" and """}}""". Appending a plus sign (+) to a dimension enables interactive resizing in that dimension (by dragging the mouse inside the image). Use ~SHIFT-click to show the full-sized (un-scaled) image. Use ~CTRL-click to restore the starting size (either scaled or full-sized).
<<<
!!!!!Examples
<<<
{{{
[img(100px+,75px+)[images/meow2.jpg]]
}}}
[img(100px+,75px+)[images/meow2.jpg]]
{{{
[<img(34%+,+)[images/meow.gif]]
[<img(21% ,+)[images/meow.gif]]
[<img(13%+, )[images/meow.gif]]
[<img( 8%+, )[images/meow.gif]]
[<img( 5% , )[images/meow.gif]]
[<img( 3% , )[images/meow.gif]]
[<img( 2% , )[images/meow.gif]]
[img(  1%+,+)[images/meow.gif]]
}}}
[<img(34%+,+)[images/meow.gif]]
[<img(21% ,+)[images/meow.gif]]
[<img(13%+, )[images/meow.gif]]
[<img( 8%+, )[images/meow.gif]]
[<img( 5% , )[images/meow.gif]]
[<img( 3% , )[images/meow.gif]]
[<img( 2% , )[images/meow.gif]]
[img(  1%+,+)[images/meow.gif]]
{{tagClear{
}}}
<<<
!!!!!Revisions
<<<
2010.07.24 [1.2.2] moved tip/dragtip text to config.formatterHelpers.imageSize object to enable customization
2009.02.24 [1.2.1] cleanup width/height regexp, use '+' suffix for resizing
2009.02.22 [1.2.0] added stretchable images
2008.01.19 [1.1.0] added evaluated width/height values
2008.01.18 [1.0.1] regexp for "(width,height)" now passes all CSS values to browser for validation
2008.01.17 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.ImageSizePlugin= {major: 1, minor: 2, revision: 2, date: new Date(2010,7,24)};
//}}}
//{{{
var f=config.formatters[config.formatters.findByField("name","image")];
f.match="\\[[<>]?[Ii][Mm][Gg](?:\\([^,]*,[^\\)]*\\))?\\[";
f.lookaheadRegExp=/\[([<]?)(>?)[Ii][Mm][Gg](?:\(([^,]*),([^\)]*)\))?\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg;
f.handler=function(w) {
	this.lookaheadRegExp.lastIndex = w.matchStart;
	var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
	if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
		var floatLeft=lookaheadMatch[1];
		var floatRight=lookaheadMatch[2];
		var width=lookaheadMatch[3];
		var height=lookaheadMatch[4];
		var tooltip=lookaheadMatch[5];
		var src=lookaheadMatch[6];
		var link=lookaheadMatch[7];

		// Simple bracketted link
		var e = w.output;
		if(link) { // LINKED IMAGE
			if (config.formatterHelpers.isExternalLink(link)) {
				if (config.macros.attach && config.macros.attach.isAttachment(link)) {
					// see [[AttachFilePluginFormatters]]
					e = createExternalLink(w.output,link);
					e.href=config.macros.attach.getAttachment(link);
					e.title = config.macros.attach.linkTooltip + link;
				} else
					e = createExternalLink(w.output,link);
			} else 
				e = createTiddlyLink(w.output,link,false,null,w.isStatic);
			addClass(e,"imageLink");
		}

		var img = createTiddlyElement(e,"img");
		if(floatLeft) img.align="left"; else if(floatRight) img.align="right";
		if(width||height) {
			var x=width.trim(); var y=height.trim();
			var stretchW=(x.substr(x.length-1,1)=='+'); if (stretchW) x=x.substr(0,x.length-1);
			var stretchH=(y.substr(y.length-1,1)=='+'); if (stretchH) y=y.substr(0,y.length-1);
			if (x.substr(0,2)=="{{")
				{ try{x=eval(x.substr(2,x.length-4))} catch(e){displayMessage(e.description||e.toString())} }
			if (y.substr(0,2)=="{{")
				{ try{y=eval(y.substr(2,y.length-4))} catch(e){displayMessage(e.description||e.toString())} }
			img.style.width=x.trim(); img.style.height=y.trim();
			config.formatterHelpers.addStretchHandlers(img,stretchW,stretchH);
		}
		if(tooltip) img.title = tooltip;

		// GET IMAGE SOURCE
		if (config.macros.attach && config.macros.attach.isAttachment(src))
			src=config.macros.attach.getAttachment(src); // see [[AttachFilePluginFormatters]]
		else if (config.formatterHelpers.resolvePath) { // see [[ImagePathPlugin]]
			if (config.browser.isIE || config.browser.isSafari) {
				img.onerror=(function(){
					this.src=config.formatterHelpers.resolvePath(this.src,false);
					return false;
				});
			} else
				src=config.formatterHelpers.resolvePath(src,true);
		}
		img.src=src;
		w.nextMatch = this.lookaheadRegExp.lastIndex;
	}
}

config.formatterHelpers.imageSize={
	tip: 'SHIFT-CLICK=show full size, CTRL-CLICK=restore initial size',
	dragtip: 'DRAG=stretch/shrink, '
}

config.formatterHelpers.addStretchHandlers=function(e,stretchW,stretchH) {
	e.title=((stretchW||stretchH)?this.imageSize.dragtip:'')+this.imageSize.tip;
	e.statusMsg='width=%0, height=%1';
	e.style.cursor='move';
	e.originalW=e.style.width;
	e.originalH=e.style.height;
	e.minW=Math.max(e.offsetWidth/20,10);
	e.minH=Math.max(e.offsetHeight/20,10);
	e.stretchW=stretchW;
	e.stretchH=stretchH;
	e.onmousedown=function(ev) { var ev=ev||window.event;
		this.sizing=true;
		this.startX=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX());
		this.startY=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY());
		this.startW=this.offsetWidth;
		this.startH=this.offsetHeight;
		return false;
	};
	e.onmousemove=function(ev) { var ev=ev||window.event;
		if (this.sizing) {
			var s=this.style;
			var currX=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX());
			var currY=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY());
			var newW=(currX-this.offsetLeft)/(this.startX-this.offsetLeft)*this.startW;
			var newH=(currY-this.offsetTop )/(this.startY-this.offsetTop )*this.startH;
			if (this.stretchW) s.width =Math.floor(Math.max(newW,this.minW))+'px';
			if (this.stretchH) s.height=Math.floor(Math.max(newH,this.minH))+'px';
			clearMessage(); displayMessage(this.statusMsg.format([s.width,s.height]));
		}
		return false;
	};
	e.onmouseup=function(ev) { var ev=ev||window.event;
		if (ev.shiftKey) { this.style.width=this.style.height=''; }
		if (ev.ctrlKey)  { this.style.width=this.originalW; this.style.height=this.originalH; }
		this.sizing=false;
		clearMessage();
		return false;
	};
	e.onmouseout=function(ev) { var ev=ev||window.event;
		this.sizing=false;
		clearMessage();
		return false;
	};
}
//}}}
On søn 26 jun 2011 22:48:15 CEST, Daniel Jankowski imported 1 tiddler from
[[http://klasser.tiddlyspace.com|http://klasser.tiddlyspace.com]]:
<<<
#[[TrashPlugin_da]] - added
<<<

----
On søn 26 jun 2011 21:52:27 CEST, Daniel Jankowski imported 4 tiddlers from
[[http://pasteup-da.tiddlyspot.com/|http://pasteup-da.tiddlyspot.com/]]:
<<<
#[[LoadRemoteFileThroughProxy]] - added
#[[PasswordOptionsPlugin]] - added
#[[TspotSetupPlugin]] - added
#[[UploadPlugin]] - added
<<<

----
On søn 26 jun 2011 21:08:38 CEST, Daniel Jankowski imported 1 tiddler from
[[http://tw-abc.tiddlyspot.com|http://tw-abc.tiddlyspot.com]]:
<<<
#[[Danish]] - added
<<<

----
On søn 26 jun 2011 21:00:47 CEST, Daniel Jankowski imported 18 tiddlers from
[[http://kvik.tiddlyspace.com/|http://kvik.tiddlyspace.com/]]:
<<<
#[[QuickEditPackage]] - replaces QuickEditPackage - 2/21/2009 15:23:00 by ELSDesignStudios
#[[QuickEditPlugin]] - replaces QuickEditPlugin - 2/14/2011 15:16:00 by ELSDesignStudios
#[[QuickEditToolbar]] - replaces QuickEditToolbar - 12/27/2010 06:52:00 by ELSDesignStudios
#[[QuickEdit_align]] - replaces QuickEdit_align - 6/11/2009 22:24:00 by ELSDesignStudios
#[[QuickEdit_color]] - replaces QuickEdit_color - 6/11/2009 22:23:00 by ELSDesignStudios
#[[QuickEdit_convert]] - replaces QuickEdit_convert - 6/11/2009 22:24:00 by ELSDesignStudios
#[[QuickEdit_custom]] - replaces QuickEdit_custom - 6/11/2009 22:24:00 by ELSDesignStudios
#[[QuickEdit_customList]] - replaces QuickEdit_customList - 6/9/2009 23:54:00 by ELSDesignStudios
#[[QuickEdit_font]] - replaces QuickEdit_font - 6/11/2009 22:24:00 by ELSDesignStudios
#[[QuickEdit_fontList]] - replaces QuickEdit_fontList - 3/22/2008 20:01:00 by ELSDesignStudios
#[[QuickEdit_format]] - replaces QuickEdit_format - 6/11/2009 22:24:00 by ELSDesignStudios
#[[QuickEdit_image]] - replaces QuickEdit_image - 6/15/2009 21:58:00 by ELSDesignStudios
#[[QuickEdit_insert]] - replaces QuickEdit_insert - 6/11/2009 22:23:00 by ELSDesignStudios
#[[QuickEdit_link]] - replaces QuickEdit_link - 6/11/2009 22:23:00 by ELSDesignStudios
#[[QuickEdit_macro]] - replaces QuickEdit_macro - 6/11/2009 22:23:00 by ELSDesignStudios
#[[QuickEdit_replace]] - replaces QuickEdit_replace - 12/27/2010 06:40:00 by ELSDesignStudios
#[[QuickEdit_sort]] - replaces QuickEdit_sort - 6/11/2009 22:23:00 by ELSDesignStudios
#[[QuickEdit_split]] - replaces QuickEdit_split - 6/11/2009 22:23:00 by ELSDesignStudios
<<<

----
On søn 26 jun 2011 20:56:53 CEST, Daniel Jankowski imported 8 tiddlers from
[[http://tiddlytools.com/|http://tiddlytools.com/]]:
<<<
#[[EditSectionPlugin]] - replaces EditSectionPlugin - 1/9/2011 17:41:00 by ELSDesignStudios
#[[PasteUpConfig]] - replaces PasteUpConfig - 1/16/2011 04:13:00 by ELSDesignStudios
#[[PasteUpHelperPlugin]] - replaces PasteUpHelperPlugin - 12/30/2010 10:31:00 by ELSDesignStudios
#[[PasteUpPlugin]] - replaces PasteUpPlugin - 2/22/2011 20:01:00 by ELSDesignStudios
#[[PasteUpPluginInfo]] - replaces PasteUpPluginInfo - 1/12/2011 12:11:00 by ELSDesignStudios
#[[SearchOptionsPlugin]] - replaces SearchOptionsPlugin - 5/3/2010 16:50:00 by ELSDesignStudios
#[[StoryViewerPluginInfo]] - replaces StoryViewerPluginInfo - 1/24/2011 10:19:00 by ELSDesignStudios
#[[UnsavedChangesPlugin]] - replaces UnsavedChangesPlugin - 12/5/2010 14:10:00 by ELSDesignStudios
<<<
!!!Viewing this document
<<<
* basic viewing instructions
<<<
!!!Editing page content
<<<
* adjusting layouts with mouse
** move
** stretch
* click to edit content
** adjust part x,y,w,h values
** enter part content (text with TiddlyWiki formatting)
** select fontsize and/or style
** select image
** enter/adjust image x,y,w,h values (relative to part)
<<<
!!!Creating page layouts
<<<
* defining DefaultPage
* add a page
* defining DefaultPart
* add a part
** enter a part name
** part is added to upper left of current page
** move/stretch new part for desired x,y,w,h
** or, click to edit part and enter values for x,y,w,h
<<<
!!!Basic ~TiddlyWiki formatting syntax
<<<
<<<
!!!Advanced setup
<<<
<<<
/***
|''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);
}
//}}}
{{floatright{<<tiddler {{if (readOnly) place.style.display='none';'';}}>>[[redigér default side|DefaultPage]]}}}<<tiddler StoryMenu##newpage>>{{menubuttons{<<list filter [tag[pasteup]]>>}}}
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<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' ondblclick='clearMessage();return false;'></div>
	<table style='margin:auto;'><tr><td>
	<div id='storyMenu' class='storyMenu' refresh='content' force='true' tiddler='StoryMenu'></div>
	<div id='tiddlerDisplay'></div>
	</td></tr></table>
</div>
<!--}}}-->
/***
|''Name:''|PasswordOptionPlugin|
|''Description:''|Extends TiddlyWiki options with non encrypted password option.|
|''Version:''|1.0.2|
|''Date:''|Apr 19, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#PasswordOptionPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.PasswordOptionPlugin = {
	major: 1, minor: 0, revision: 2, 
	date: new Date("Apr 19, 2007"),
	source: 'http://tiddlywiki.bidix.info/#PasswordOptionPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
	coreVersion: '2.2.0 (Beta 5)'
};

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

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

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

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

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

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

merge(config.optionsDesc,{
		pasPassword: "Test password"
	});
*/
//}}}
|Name|[[PasteUpCommands]]|
|Source|http://www.TiddlyTools.com/#PasteUpCommands|
|Version|1.4.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Type|plugin|
|Requires|PasteUpPlugin PasteUpHelperPlugin EditSectionPlugin|
|Description|commands for use with PasteUp documents|
|See also|PasteUpToolbar StoryMenu|
!Navigation, Help and Printing (StoryMenu):
<<<
!!!contents
<<tiddler ToggleLeftSidebar with: "&#x25C4;contents" "show/hide main menu" "button nowrap">>
!!!toggleSidebar
<<tiddler ToggleRightSidebar with: "sidebar&#x25BA;" "show/hide sidebar functions" "button nowrap">>
!!!home
<html><nowiki><a href='javascript:;' class='button nowrap' title='redisplay starting page(s)'
onclick='story.closeAllTiddlers(); restart(); return false;'>&#x25C4;home</a></html>
!!!pages
<<tag pasteup "pages" "view pasteup pages">>
!!!help
<html><nowiki><a class='button nowrap' title="Instructions for using this document" onclick="
	story.displayTiddler(null,'Instructions');
	return false;
">help</a></html>
!!!printall
<html><nowiki><a class='button nowrap' title="print all pages" onclick="
	var storyname=store.getTiddlerText('PasteUpConfig::SlideshowList');
	var list=config.macros.storyViewer.getStory(storyname);
	if (!list.length) list.push('DefaultPage');
	story.closeAllTiddlers();
	story.displayTiddlers(null,list);
	window.print();
	return false;
">print</a></html>
!!!!!end
<<<
!!!Slideshow mode (StoryMenu):
<<<
!!!slideshow
<html><nowiki><a class='button nowrap' title="start/stop automatic slideshow" onclick="
	if (config.macros.storyViewer.started || this.savedHTML) {
		this.innerHTML=this.savedHTML; this.savedHTML=null;
		config.macros.option.propagateOption('chkSlideshow','checked',false,'input');
		config.macros.storyViewer.started=false;
		story.refreshAllTiddlers(true);
	} else {
		var chk='<input type=\x22checkbox\x22 checked style=\x22margin:0;padding:0;\x22>';
		this.savedHTML=this.innerHTML; this.innerHTML=chk+this.innerHTML;
		var storyname=store.getTiddlerText('PasteUpConfig::SlideshowList');
		var list=config.macros.storyViewer.getStory(storyname);
		if (!list.length) list.push('DefaultPage');
		window.readOnly=true;
		config.macros.option.propagateOption('chkHttpReadOnly','checked',true,'input');
		config.macros.option.propagateOption('chkSinglePageMode','checked',true,'input');
		config.macros.option.propagateOption('chkSlideshow','checked',true,'input');
		config.macros.storyViewer.started=true;
		story.closeAllTiddlers();
		story.switchTheme(config.options.txtTheme);
		store.notifyAll();
		story.displayTiddler(null,list[0]);
	}
	return false;
">slides</a></html><<tiddler {{
	var e=place.lastChild.getElementsByTagName('a')[0];
	if (config.macros.storyViewer.started && e.innerHTML.indexOf('checkbox')==-1) {
		var chk='<input type=\x22checkbox\x22 checked style=\x22margin:0;padding:0;\x22>';
		e.savedHTML=e.innerHTML;
		e.innerHTML=chk+e.innerHTML;
	}
'';}}>>
!!!slideshow_toolbar
<<storyViewer
	{{store.getTiddlerText('PasteUpConfig::SlideshowList')}}
	list allbuttons
	prompt:{{store.getTiddlerText('PasteUpConfig::SlideshowPrompt')}}>>/%
%/<<storyViewer
	{{store.getTiddlerText('PasteUpConfig::SlideshowList')}}
	timer:{{store.getTiddlerText('PasteUpConfig::SlideshowTimer')}}>>
!!!!!end
<<<
!Editing (StoryMenu):
<<<
!!!toggleEdit
<html><nowiki><span class="button nowrap" style="cursor:pointer"
	title="enable/disable editing of this document"
	onclick="this.getElementsByTagName('input')[0].click();">
<input type='checkbox' style="margin:0;padding:0;cursor:pointer" onclick="
	window.readOnly=!this.checked;
	config.macros.option.propagateOption('chkHttpReadOnly','checked',window.readOnly,'input');
	config.macros.option.propagateOption('chkSinglePageMode','checked',window.readOnly,'input');
	config.macros.option.propagateOption('chkSlideshow','checked',false,'input');
	config.macros.storyViewer.started=false;
	if (!config.extensions.tiddlyspace) { // DON'T HIDE BACKSTAGE FOR TIDDLYSPACE
		window.showBackstage=!window.readOnly;
		if(showBackstage && !backstage.area) backstage.init();
		backstage.button.style.display=showBackstage?'block':'none';
		backstage.hide();
	}
	story.switchTheme(config.options.txtTheme); store.notifyAll(); story.refreshAllTiddlers(true);
	return false;
">edit</span></html><<tiddler {{
	var e=place.lastChild.getElementsByTagName('input')[0];
	e.checked=!window.readOnly;
'';}}>>
!!!unsavedChanges
{{nowrap{<<unsavedChanges command "%0 unsaved change%2">>}}}
!!!undo
{{nowrap{<<undo label:"undo">>}}}
!!!save
{{nowrap{<<saveChanges "save" "save changes to this document">>}}}
!!!saveAs
{{nowrap{<<saveAs "label:save as">>}}}
!!!download
<html><nowiki><a class="button nowrap" href="" title="download a local copy of this document" onmouseover="
	if (config.extensions.tiddlyspace)
		this.href='/?download='+config.extensions.tiddlyspace.currentSpace.name+'.html';
	else
		this.href=document.location.href.replace(/^https?/,'ftp');
">download</a></html>
!!!setup
<<slider closed PasteUpConfig##setupmenu
	"setup" "configure PasteUp settings for this document">>
!!!!!end
<<<
!Editing (MainMenu and PasteUpToolbar)
<<<
!!!defaultpage
<html><nowiki><a class='button nowrap' title="edit default page layout" onclick="
	story.displayTiddler(null,'DefaultPage');
	return false;
">edit default page...</a></html>
!!!addpart
<html><nowiki><a class='button nowrap' title="add a part to this page" onclick="
	var here=story.findContainingTiddler(this);
	var tid=here?here.getAttribute('tiddler'):'';
	return config.macros.pasteUpHelper.popupPicker(this,event,tid,'part',
		'create a new part...', 'DefaultPart',
		'Please enter a part name:', 'or, add an existing part:');
">add a part...</a></html>
!!!addpage
<html><nowiki><a class='button nowrap' title="create a new pasteup page" onclick="
	return config.macros.pasteUpHelper.popupPicker(this,event,null,'pasteup',
		'create a new page...',	'DefaultPage',
		'Please enter a page name:', 'or, copy an existing page:');
">add a page...</a></html>
!!!deletepage
<html><nowiki><a class='button nowrap' title="delete this pasteup page" onclick="
	var tid=story.findContainingTiddler(this).getAttribute('tiddler');
	config.commands.deleteTiddler.handler(event,this,tid);
	return false;
">delete this page...</a></html>
!!!!!end
<<<
|Name|[[PasteUpConfig]]|
|Source|http://www.TiddlyTools.com/#PasteUpConfig|
|Version|1.1.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Requires|PasteUpPlugin PasteUpHelperPlugin EditSectionPlugin|
|Type|data|
|Description|configuration options and data for PasteUpPlugin and PasteUpHelperPlugin|
!!!Usage
<<<
This tiddler contains sections with configuration data for use by PasteUpPlugin and PasteUpHelperPlugin.  Although you may directly edit the content of this tiddler to add/remove/modify the data, this is ''not recommended'', as you must be very careful to ''avoid changing any of the //required// syntax'' that surrounds the actual data values.  To ensure that only the desired tiddler data content is changed, you can use the following menu of commands to easily view/modify the separate configuration sections without needing to edit the tiddler as a whole:
| ''<<tiddler PasteUpConfig##setupmenu>>'' |
where:
* ''CSS'' - custom-defined CSS class definitions used to format pasteup part content
* ''fonts, styles, images'' - ~PasteUpHelper droplist definitions, one item per line:
** Each item is a name/value pair, separated by "=" (e.g, name=value)
** The name is displayed in the droplist, and the value is assigned when the item is selected.
** If the "=value" portion of an item is omitted, the item text is display and also used as the assigned value.
** An item with a trailing "=", //with no value specified//, clears the droplist selection.
** The values for font/style droplist items are CSS classnames.  The values for image droplist items are the path and filename of the respective image files.
** If a value currently assigned to a pasteup element does not match any values in the corresponding droplist, an "other: ...." item is automatically added to the list.
** Blank lines within a list definition are ignored.
* ''pagesize'' - the width and height of pasteup layout pages (use CSS units)
* ''partsize'',''imagesize'' - the default position/size for adding new parts/images (use CSS units)
* ''title, subtitle, menu'' - document title, subtitle, and main (home) menu
* ''startup'' - a space-separated list of tiddlers to display at startup (i.e., DefaultTiddlers)
* ''default page, default part'' - content for creating new pasteup pages and parts
* ''advanced'' - systemConfig-based advanced settings and tweaks to plugin internal values
Note: you can embed this menu in another tiddler by writing:
{{{
<<tiddler PasteUpConfig##setupmenu>>
}}}
<<<
{{hidden{
!!!setupmenu
{{small{
	  [[title|SiteTitle]]/%
%/ &nbsp; [[subtitle|SiteSubtitle]]/%
%/ &nbsp; [[menu|MainMenu]]/%
%/ &nbsp; [[startup|DefaultTiddlers]]/%
%/ &nbsp; [[default page|DefaultPage]]/%
%/ &nbsp; [[default part|DefaultPart]]/%
%/ &nbsp; [[advanced|StartupSettings]]
<<editSection PasteUpStyleSheet		 CSS		"custom CSS style definitions">>/%
%/<<editSection PasteUpFontList	 	 fonts		"font sizes">>/%
%/<<editSection PasteUpStyleList 	 styles		"text formatting styles">>/%
%/<<editSection PasteUpImageList 	 images		"embeddable images">>/%
%/<<editSection PasteUpConfig##pagesize	 pagesize	"pasteup layout height/width">>/%
%/<<editSection PasteUpConfig##partsize	 partsize	"default position/size for adding new parts">>/%
%/<<editSection PasteUpConfig##imagesize imagesize	"default position/size for adding new images">>/%
%/<<editSection PasteUpConfig##slideshow slideshow	"slideshow list source and timer duration">>/%
%/}}}
!end
}}}
!!!pagesize
<<<
Total page size, top margin size, pasteup layout size:
----
~PageWidth: 8.5in
~PageHeight: 11in
~MarginTop: .5in
Width: 8in
Height: 10in
----
notes:
* ~PageWidth/~PageHeight //includes// the space used for margins.
* Width/Height is the size of the //printed// area of each actual page of content, //excluding// the margins.
<<<
!!!partsize
<<<
Initial position/size for //creating new parts// with the ''add part'' toolbar command:
----
~PartLeft: 100px
~PartTop: 100px
~PartWidth: 200px
~PartHeight: 100px
----
notes:
*new parts should be placed near the top-left corner of the current pasteup page and given a default size so they are easy to locate and adjust after being added.
<<<
!!!imagesize
<<<
Initial position/size/adjustability for //adding an image within a part//:
----
~ImageLeft: 0px
~ImageTop: 0px
~ImageWidth: 100%
~ImageHeight: auto
~ImageAdjust: false
----
notes:
* position is specified as an x-offset and y-offset, relative to the upper-left corner of the containing part.
* width/height can be fixed values (e.g., px, in) and/or percentages, relative to the width/height of the containing part.  If both values are "100%", images are stretched to fit the containing part dimensions.  If either the width or height is set to "auto", images are scaled ''proportionally'' in that dimension.  When both values are set to "auto", images are rendered full-sized, without scaling.
* if set to 'false', the relative position/size of a newly added image is 'frozen' within the containing part.  To allow changes to the position/size for a specific image, you can select the 'adjust' checkbox in the PasteUpHelper image editor popup.  Setting ~ImageAdjust to "true" automatically enables 'adjustabilty' for all new images by default.
<<<
!!!slideshow
<<<
Source list and timer setting for automatic slideshows:
----
~SlideshowList: pasteup
~SlideshowTimer: 20
~SlideshowPrompt: pasteup pages...
----
notes:
* ~SlideshowList can be either a tag value to match (e.g. "pasteup") or the name of a tiddler containing links to the desired slides (e.g, "MainMenu", "DefaultTiddlers", etc.).
* ~SlideshowTimer specifies the number of seconds to display each slide before advancing to the next.
* ~SlideshowPrompt is the text label that appears as the first item in the slideshow droplist.
<<<
/***
|Name|[[PasteUpHelperPlugin]]|
|Source|http://www.TiddlyTools.com/#PasteUpHelperPlugin|
|Version|1.7.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Type|plugin|
|Requires|[[PasteUpPlugin]] [[EditSectionPlugin]]|
|Description|extends [[PasteUpPlugin]] popup editor with enhanced form controls|
!!!Documentation
> see [[PasteUpPluginInfo]]
!!!Example
<<<
<<tiddler PasteUpHelperPlugin##test style:"border:1px solid blue;color:black;background:white;" edit adjust x:1.2in y:-18px w:318px h:74px>>/%
!test
test ~PasteUpHelper test
line 2
line 3
line 4
!end
%/
<<<
!!!Configuration
<<<
<<option chkPasteUpHelper>>enable PasteUpHelper menu (use SHIFT-click to bypass)
{{{<<option chkPasteUpHelper>>}}}
<<option chkPasteUpNoMenuLink>>disable menu heading link to part tiddler
{{{<<option chkPasteUpNoMenuLink>>}}}
<<option chkPasteUpHelperAutoName>>automatically name/number new pages/parts (e.g, Page01, Part01, etc.)
{{{<<option chkPasteUpHelperAutoName>>}}}
Also see [[PasteUpPlugin]], [[PasteUpConfig]] and related shadow tiddlers: [[DefaultPage]], [[DefaultPart]], [[PasteUpStyleSheet]], [[PasteUpHelperTemplate]], [[PasteUpCommands]]
<<<
!!!Revisions
<<<
2011.11.25 1.7.3 remove extra trailing "," after last function declaration (fixes IE7 error).  Also, revised "add image" dialog layout and input validation handling
2011.09.15 1.7.2 in renderMenu(), cleanup LI creation when menu items are suppressed
2011.09.13 1.7.1 in renderMenu(), suppress menu items if corresponding label is null (or blank)
2011.09.12 1.7.0 added csrf_token to "add image" form (for TiddlySpace binary file upload)
2011.09.09 1.6.0 added support for autonaming: pagenamePattern, partnamePattern and getNextName()
2011.09.08 1.5.0 added popupPicker() to support 'add part' and 'add page' list interface
2011.09.04 1.4.0 replaced 'behind text' image option with 'layer' placement (z-index) control for all elements.  Added "add image" interface: addImagePanel()+HTML Template (shadow)
2011.09.02 1.3.0 major interface changes: replaced big 'helper' form with type-specific forms and handlers.  Rewrote modifyPart() to handle *all* part changes.  SHIFT-CLICK now bypasses helper and shows RAW part definition (all syntax visible)
2011.08.02 1.2.3 added support for multiple listbox definition tiddlers (e.g,. multiple image lists)
2011.08.02 1.2.2 moved renderMenu() from PasteUpPlugin.  Changed menu text and added type-specific commands
2011.07.31 1.2.1 refactored form template and init/save handlers to use getForm(), getInitForm(), and getSaveForm() access functions to support type-specific forms (see also: [[EditSectionPlugin]])
2011.07.24 1.2.0 Added handling for '[edit this list...]'.  Hijack renderMenu() and added popupList() and modifyPart() for fontsize/style 'quick menu' handling.  Added confirmation (optional) to removePart() handling.
2011.06.19 1.1.3 moved default/example user-defined pasteup styles from PageUpConfig##css to [[PasteUpStyleSheet]] shadow and add notification trigger for style changes.  Also, minor wording changes in PasteUpHelperTemplate.
2011.06.18 1.1.2 in initForm(), added "\\r?" to all regexp for IE7 newline handling
2011.06.08 1.1.1 in HTML template, changed "delete" to "remove" and use removePart() (see PasteUpPlugin) instead of editSection() (see EditSectionPlugin)
2011.05.15 1.1.0 added imagePopup() image thumbnail display and selection handling
2011.05.06 1.0.8 fixed default tiddler names sizeList, styleList, and fontList
2011.05.05 1.0.7 in HTML template, use deleteSection() (see EditSectionPlugin)
2011.05.03 1.0.6 HTML template layout changes for 'advanced' checkbox.  Also, moved default config for fonts, styles, and images to separate tiddlers for easier 'overlay' customizations.
2010.12.30 1.0.5 added 'image lock' feature
2010.12.25 1.0.4 removed use of IDs in HTML template and related code (for finding helper elements).  Added transclusion of QuickEditToolbar (optional)
2010.12.18 1.0.3 added 'image behind text' feature
2010.12.12 1.0.2 added "show/hide dimensions" to helper form
2010.11.27 1.0.1 added PasteUpConfig defaults for position/size of new parts and images
2010.11.21 1.0.0 initial release
2010.11.01 0.9.5 helper form and handlers split from PasteUpPlugin
| Please see [[PasteUpPluginInfo]] for previous revision details |
2010.07.21 0.7.5 alpha prototype (for review - do not distribute)
<<<
!!!Code
***/
// // PLUGIN VERSION
//{{{
version.extensions.PasteUpHelperPlugin= {major: 1, minor: 7, revision: 3, date: new Date(2011,11,25)};
//}}}
// // OPTIONS (COOKIES)
//{{{
if (config.options.chkPasteUpHelper===undefined)	config.options.chkPasteUpHelper=true;
if (config.options.chkPasteUpNoMenuLink===undefined)	config.options.chkPasteUpNoMenuLink=false;
if (config.options.chkPasteUpHelperAutoName===undefined)config.options.chkPasteUpHelperAutoName=false;
//}}}
// // HARD-CODED DEFAULTS
//{{{
config.macros.pasteUpHelper = {
	sizeList:	'PasteUpFontList',
	styleList:	'PasteUpStyleList',
	imageList:	'PasteUpImageList',
	styleSheet:	'PasteUpStyleSheet',
	uploadScript:	'http://www.tiddlytools.com/showargs.php',
	uploadPath:	'http://www.servername.com/images/',
	thumbsize:	'100px',
	templates: {	// HTML template SHADOW tiddlers (forms for popup editor)
		text:	  'PasteUpHelperTemplate_Text',		// edit text
		image:	  'PasteUpHelperTemplate_Image',	// select image, x,y,w,h,adjust
		addimage: 'PasteUpHelperTemplate_AddImage',	// add image to list (w/upload)
		place:	  'PasteUpHelperTemplate_Placement'	// x,y,w,h
	},
	MWtag: 'mediawiki',
	MWmsg: 'This part uses MediaWiki-formatted content.  To add an image, please edit the part text and use MediaWiki\'s standard image-embedding syntax.',
//}}}
// // TRANSLATE
//{{{
	sizeListAnnotation:	'List paste up font sizes, one per line (use CSS classnames defined in PasteUpStyleSheet)',
	styleListAnnotation:	'List paste up styles, one per line (use CSS classnames defined in PasteUpStyleSheet)',
	imageListAnnotation:	'List image URLs, one per line (use "name=URL..." to create short names for long URLs)',
	styleSheetAnnotation:	'Add/edit custom styles (CSS) here, then add list entries in PasteUpFontList and/or PasteUpStyleList',
	editTextMenuTxt:	'text...',
	editTextMenuTip:	'Enter TEXT content for this part',
	selectImageMenuTxt:	'image...',
	selectImageMenuTip:	'Choose an IMAGE for this part',
	selectStyleMenuTxt:	'style...',
	selectStyleMenuTip:	'Change the STYLE of this part',
	selectFontMenuTxt:	'font...',
	selectFontMenuTip:	'Change the FONT of this part',
	adjustMenuTxt:		'placement...',
	adjustMenuTip:		'Change the POSITION and/or SIZE of this part',
	removeMenuTxt:		'remove part...',
	removeMenuTip:		'Remove this part from the current page',
	deleteMenuTxt:		'delete part...',
	deleteMenuTip:		'Delete this part definition from the document',
//}}}
// // PLUGIN INIT
//{{{
	init: function() {
		if (!config.macros.pasteUp) return;
		if (!config.macros.editSection) return;

		// override PasteUpPlugin click action to add popup menu
		config.macros.pasteUp.clickAction=this.clickAction;

		// override default EditSectionPlugin forms and handlers
		var cme=config.macros.editSection; // ABBREV
		cme.getForm=this.getForm;
		cme.getInitForm=this.getInitForm;
		cme.getSaveForm=this.getSaveForm;

		// deliver SHADOW HTML form definitions (PasteUpHelper...Template)
		for (var i in this.templates) {
			var tid=this.templates[i];
			config.shadowTiddlers[tid]=store.getTiddlerText('PasteUpHelperPlugin##'+tid,'');
		}

		// deliver SHADOW example/default user-defined pasteup styles (PasteUpStyleSheet)
		var tid=this.styleSheet;
		config.shadowTiddlers[tid]=
			'/*{{{*/\n'
			+store.getTiddlerText('PasteUpHelperPlugin##css','')
			+'\n/*}}}*/';;
		config.annotations[tid]=this.styleSheetAnnotation;
		store.addNotification(tid,refreshStyles);

		// set annotation 'help text' for configuration tiddlers (NOTE: *NO* SHADOWS)
		function annotate(t,a) {
			var tids=t.readBracketedList();
			for (var i=0;i<tids.length;i++) config.annotations[tids[i]]=a;
		}
		annotate(this.styleList,this.styleListAnnotation);
		annotate(this.imageList,this.imageListAnnotation);
		annotate(this.sizeList, this.sizeListAnnotation);
	},
//}}}
// // POPUP MENU (extends PasteUpPlugin default popup menu)
//{{{
	clickAction: function(here,ev) {
		if (config.options.chkPasteUpHelper&&!ev.shiftKey) {
			var cmp=config.macros.pasteUp; // abbrev
			config.macros.pasteUpHelper.renderMenu(Popup.create(here),here);
			var x=cmp.getMX(ev)-findPosX(here);
			var y=cmp.getMY(ev)-findPosY(here);
			Popup.show('top','left',{x:x,y:y});
			return cmp.ok(ev);
		}
		else return config.macros.editSection.click.call(here,ev,'raw');
	},
	renderMenu: function(p,target) {
		var cmp=config.macros.pasteUpHelper; // ABBREV
		var tid=target.getAttribute('tid');
		var txt =store.getTiddlerText(tid);
		cmp.currentTarget=target; // NOTE: GLOBAL STATE VARIABLE!

		// HEADING
		var tip='';
		var s=target.style; var a='auto'; // abbreviations
		var t=target.getAttribute('tiddler'); // source title
		var c=target.className.replace(/ ?pasteUpBorder/,'').replace(/ ?pasteUp/,''); // classname
		if (c.length) tip+=' class="'+c+'", ';
		tip+='x='+(s.left||a)+', y='+(s.top||a);
		tip+=((s.zIndex!=0&&s.zIndex!=1)?', z='+s.zIndex:'')
		tip+=', w='+(s.width||a)+', h='+(s.height||a);
		var li=createTiddlyElement(p,'li'); li.title=tip;
		if (config.options.chkPasteUpNoMenuLink) var head=createTiddlyText(li,t);
		else { var head=createTiddlyLink(li,t); head.innerHTML=t; head.title=tip; }
		createTiddlyElement(p,'hr');

		// GET CURRENT FONTSIZE/STYLE from "class:..." macro param
		var size=''; var classname=''; // FIRST CLASSNAME IS FONTSIZE, REST IS STYLENAME
		var pat='<<(?:pasteUp|tiddler)\\s+\\[\\[.+##content\\]\\]\\s+class:"([^"]*)".*?>>';
		var re=new RegExp(pat);	var m=re.exec(txt);
		if (m) { var t=m[1].split(' '); size=t.shift(); classname=t.join(' '); }
		else { // FALLBACK: GET FONTSIZE/STYLE from CSS class wrapper
			var pat="\\{\\{([^\\{]+)\\{\\r?\\n((?:.|\\n)*)\\r?\\n\\}\\}\\}$";
			var re=new RegExp(pat); var m=re.exec(txt);
			if (m) { var t=m[1].split(' '); size=t.shift(); classname=t.join(' '); }
			else { // FALLBACK: GET FONTSIZE/STYLE from HTML div
				var pat='<html><div class="([^"]+)">\\r?\\n((?:.|\\n)*)\\r?\\n</div></html>$';
				var re=new RegExp(pat); var m=re.exec(txt);
				if (m) { var t=m[1].split(' '); size=t.shift(); classname=t.join(' '); }
			}
		}

		// EDIT TEXT...
		var label=this.editTextMenuTxt; var tip=this.editTextMenuTip;
		if (label&&label.length) createTiddlyButton(
			createTiddlyElement(p,'li'),label,tip,function(ev){
			Popup.remove();
			config.macros.editSection.click.call(
				config.macros.pasteUpHelper.currentTarget,ev,'text');
			return config.macros.pasteUp.ok(ev);
		});

		// SELECT IMAGE...
		var label=this.selectImageMenuTxt; var tip=this.selectImageMenuTip;
		if (label&&label.length) createTiddlyButton(
			createTiddlyElement(p,'li'),label,tip,function(ev){
			var cmp=config.macros.pasteUpHelper; // ABBREV
			Popup.remove();
			var t=store.getTiddler(this.getAttribute('tid'));
			if (t&&t.isTagged(cmp.MWtag)) alert(cmp.MWmsg);
			else config.macros.editSection.click.call(cmp.currentTarget,ev,'image');
			return config.macros.pasteUp.ok(ev);
		},null,null,null,{tid:tid});

		// SET STYLE...
		var label=this.selectStyleMenuTxt; var tip=this.selectStyleMenuTip;
		if (label&&label.length) createTiddlyButton(
			createTiddlyElement(p,'li'),label,tip,cmp.popupList,
			null,null,null,{mode:'style',tid:tid,val:classname});

		// SET FONTSIZE...
		var label=this.selectFontMenuTxt; var tip=this.selectFontMenuTip;
		if (label&&label.length) createTiddlyButton(
			createTiddlyElement(p,'li'),label,tip,cmp.popupList,
			null,null,null,{mode:'size',tid:tid,val:size});

		// ADJUST PART...
		if (target.adjustable) {
			var label=this.adjustMenuTxt; var tip=this.adjustMenuTip;
			if (label&&label.length) createTiddlyButton(
				createTiddlyElement(p,'li'),label,tip,function(ev){
				Popup.remove();
				config.macros.editSection.click.call(
					config.macros.pasteUpHelper.currentTarget,ev,'place');
				return config.macros.pasteUp.ok(ev);
			});
		}

		// SEPARATOR
		if (this.removeMenuTxt || this.deleteMenuTxt)
			createTiddlyElement(p,'hr');

		// REMOVE PART...
		var label=this.removeMenuTxt; var tip=this.removeMenuTip;
		if (label&&label.length) createTiddlyButton(
			createTiddlyElement(p,'li'),label,tip,function(ev){
			var cmp=config.macros.pasteUp; // abbrev
			Popup.remove();
			cmp.removePart(config.macros.pasteUpHelper.currentTarget);
			return cmp.ok(ev);
		});

		// DELETE PART...
		var label=this.deleteMenuTxt; var tip=this.deleteMenuTip;
		if (label&&label.length) createTiddlyButton(
			createTiddlyElement(p,'li'),label,tip,function(ev){
			var cmp=config.macros.pasteUp; // abbrev
			var cmh=config.macros.pasteUpHelper; // abbrev
			var cme=config.macros.editSection; // abbrev
			Popup.remove();
			var tid=cmh.currentTarget.getAttribute('tid');
			var title=tid.split('##')[0]; var section=tid.split('##')[1];
			if (confirm(cme.deletemsg.format([tid]))) {
				cmp.removePart(cmh.currentTarget,true); // NO EXTRA WARNING
				cme.deleteSection(title,section);
				displayMessage(tid+' deleted');
			}
			return cme.ok(ev);
		});
	},
//}}}
// // LISTBOXES
//{{{
	popupList: function(ev) { ev=ev||window.event;
		var cmp=config.macros.pasteUpHelper; // ABBREV
		var mode=this.getAttribute('mode');
		var tid =this.getAttribute('tid');
		var val =this.getAttribute('val');

		// RENDER POPUP LIST
		var p=Popup.create(this,null,'popup smallform'); p.style.padding='0';
		Popup.show('top','right'); 
		var s=createTiddlyElement(p,'select');
		if (mode=='style') cmp.setList(s,cmp.styleList,val,'select a style...');
		if (mode=='size')  cmp.setList(s,cmp.sizeList, val,'select a font...');
		s.size=s.length; s.style.width='100%';
		s.setAttribute('tid',tid); s.setAttribute('mode',mode); s.setAttribute('val',val);
		s.onkeyup=function(ev) {
			var k=(ev||window.event).keyCode;
			if (k==13) this.onclick();
			if (k==27) Popup.remove();
		};
		s.onclick=function(){
			if (!this.selectedIndex) return; // ignore click on prompt
			var cmp =config.macros.pasteUpHelper; // ABBREV
			var mode=this.getAttribute('mode');
			var tid =this.getAttribute('tid');
			var val =this.getAttribute('val');
			if (this.value=='_edit')
				story.displayTiddler(null,this.getAttribute('src'),DEFAULT_EDIT_TEMPLATE);
			else if (this.value!=val) {
				var txt=store.getTiddlerText(tid); // CURRENT CONTENT
				txt=cmp.modifyPart(tid,txt,mode,this.value); // REVISED CONTENT
				var title=tid.split('##')[0]; var section=tid.split('##')[1];
				config.macros.editSection.updateTiddler(txt,title,section);
			}
			Popup.remove();
			return config.macros.pasteUp.ok(ev);
		};
		s.focus();
		return config.macros.pasteUp.ok(ev);
	},
	setList: function(list,src,val,prompt) { // SET SIZE, STYLE, and IMAGE LISTS
		if (prompt) list.options[0]=new Option(prompt,''); // OVERRIDE DEFAULT PROMPT
		while (list.length>1) list.options[list.length-1]=null; // empty list (leave prompt)
		var tids=src.readBracketedList(); var txt=[];
		for (var i=0;i<tids.length;i++) txt.push(store.getTiddlerText(tids[i],''));
		var items=txt.join('\n').split('\n');
		var found=false;
		for (var i=0; i<items.length; i++) { // fmt: "value" or "name=value"
			var t=items[i]; var v=t; if (!t.length) continue;
			if (items[i].indexOf('=')!=-1) 
				{ var t=items[i].split('=')[0]; var v=items[i].split('=')[1]||''; }
			var sel=val.length&&(v==val); found=found||sel;
			list.options[list.length]=new Option(t,v,sel,sel);
		}
		if (!found && val.length)
			list.options[list.length]=new Option('other: '+val,val,true,true);
		list.options[list.length]=new Option('[edit this list...]','_edit');
		list.setAttribute('src',tids[0]); list.setAttribute('val',val);
		if (!list.onchange_saved) list.onchange_saved=list.onchange
		list.onchange=function() {
			if (this.value=='_edit') {
				config.macros.editSection.removeAllPanels();
				if (!jQuery('.editSectionPanel').length) // CLOSE PANEL STOPPED BY USER
					story.displayTiddler(null,this.getAttribute('src'),DEFAULT_EDIT_TEMPLATE);
			} else if (list.onchange_saved) list.onchange_saved.apply(this,arguments);
		}
	},
	popupPicker: function(root,ev,tid,tag,createlabel,createval,createmsg,selectmsg) {
		var p=Popup.create(root,null,'popup smallform'); p.style.padding='0';
		var tids=store.getTaggedTiddlers(tag,'excludeLists');
		var s=createTiddlyElement(p,'select');
		s.setAttribute('tid',tid); // TARGET TIDDLER
		s.setAttribute('msg',createmsg); // POPUP MSG (ASK FOR NAME)
		var indent='';
		if (createlabel&&createlabel.length) {
			s.options[s.length]=new Option(createlabel,createval);
			var indent='\xa0\xa0';
		}
		if (tids.length)
			s.options[s.length]=new Option(selectmsg,'');
		for (var t=0; t<tids.length; t++) { if (tids[t].title==createval) continue;
			s.options[s.length]=new Option(indent+tids[t].title,tids[t].title);
			s.options[s.length-1].title=tids[t].getSubtitle();
		}
		s.size=Math.min(s.length,10);
		s.onkeyup=function(ev){ var k=(ev||window.event).keyCode;
			if (k==13) this.onclick();
			if (k==27) Popup.remove();
			return config.macros.pasteUp.ok(ev);
		}
		if (tag=='part') {
			s.onclick=function(ev) {
				if (!this.value.length) return false;
				var tid=this.getAttribute('tid');
				var msg=this.getAttribute('msg');
				var p=this.value;
				var cmh=config.macros.pasteUpHelper; // abbrev
				if (p=='DefaultPart') {
					p=config.macros.pasteUpHelper.getNextName(tid,'part');
					if (!config.options.chkPasteUpHelperAutoName) p=prompt(msg,p);
				}
				if (p && p.length) config.macros.pasteUp.addPart(tid,p);
				Popup.remove(); return config.macros.pasteUp.ok(ev);
			}
		} else {
			s.onclick=function(ev){
				if (!this.value.length) return false;
				var tid=config.macros.pasteUpHelper.getNextName('','pasteup');
				var msg=this.getAttribute('msg');
				if (!config.options.chkPasteUpHelperAutoName) tid=prompt(msg,tid);
				var msg=config.messages.overwriteWarning.format([tid||'']);
				if (tid && (!store.tiddlerExists(tid)||confirm(msg))) {
					// CREATE NEW PAGE
					var src=this.value;
					var who=config.options.txtUserName;
					var when=new Date();
					var text=store.getTiddlerText(src,'');
					var tags=['pasteup'];
					var fields=config.defaultCustomFields
					store.saveTiddler(tid,tid,text,who,when,tags,fields);
					story.displayTiddler(null,tid);
					displayMessage('Created '+tid+' from '+src);
					// ADD TO DEFAULT TIDDLERS
					if (confirm('Automatically display \x22'+tid+'\x22 at startup?')) {
						var tid2='DefaultTiddlers'; var t=store.getTiddler(tid2);
						var text=store.getTiddlerText(tid2)+'\n[['+tid+']]';
						store.saveTiddler(tid2,tid2,text,who,when,t?t.tags:[],
							config.macros.pasteUp.cloneFields(t?t.fields:{}));
						displayMessage('Added '+tid+' to '+tid2);
					}
				}
				Popup.remove(); return config.macros.pasteUp.ok(ev);
			}
		}
		if (tids.length) { Popup.show(); s.focus(); }
		else { p.style.display='none'; s.onclick.call(s,ev); }
		return config.macros.pasteUp.ok(ev);
	},
	pagenamePattern: 'Page%1',	// %0=next number
	partnamePattern: '%0_Part%1',	// %1=current page name
	getNextName: function(tid,tag) {
		var pat=tag=='part'?this.partnamePattern:this.pagenamePattern;
		var prefix=pat.format([tid,'']);
		var tids=store.getTaggedTiddlers(tag,'excludeLists');
		for (var t=tids.length-1; t>=0; t--)	// find last matching title
			if (tids[t].title.startsWith(prefix)) { var found=tids[t].title; break }
		var next=1;
		if (found) var match=/([0-9]+)$/.exec(found);
		if (match) next=parseInt(match[1])+1;
		return pat.format([tid,next]);
	},
//}}}
// // THUMBNAIL BROWSER
//{{{
	imagePopup: function(event,list) {
		var p=Popup.create(list); if (!p) return false;
		config.macros.pasteUpHelper.renderThumbs(p,list);
		Popup.show('top','left');
		event.cancelBubble=true; if(event.stopPropagation)event.stopPropagation(); return false;
	},
	renderThumbs: function(p,list) {
		if (!list.id) list.id=new Date().getTime()+Math.random();
		var size=config.macros.pasteUpHelper.thumbsize; var rowsize=4;
		var thumb='<td style="width:%1;height:%1;text-align:center;border:1px solid transparent" '
			+'onmouseover="this.style.border=\'1px solid black\'" '
			+'onmouseout=" this.style.border=\'1px solid transparent\'">'
			+'<img src="%0" title="%0" '
			+'style="border:1px solid #999;max-width:%1;max-height:%1;cursor:pointer" '
			+'onclick="var v=this.title; var list=document.getElementById(\''+list.id+'\'); '
			+'Popup.remove(Popup.stack.length-1); '
			+'list.value=v; list.focus(); return list.onchange.call(list,event);"></td>';
		var out=[];
		var c=0;
		for (var i=0; i<list.options.length; i++) { var src=list.options[i].value;
			if (src==''||src=='_edit') continue;
			if (c && c%rowsize==0) out.push('</tr><tr>');
			if (src.length) { out.push(thumb.format([src,size])); c++; }
		}
		p.innerHTML+="<a href='javascript:;' style='float:right' "
			+" onclick='Popup.remove(Popup.stack.length-1);return false;'>close</a>"
			+" choose an image:<hr>";
		out=out.join('');
		if (out.length) p.innerHTML+='<table><tr>'+out+'</tr></table>';
	},
	addImagePanel: function(ev,root) {
		var cmp=config.macros.pasteUpHelper;
		var cme=config.macros.editSection;
		var p=createTiddlyElement(document.body,"ol",
			"addImagePanel","popup smallform editSectionPanel");
		p.root=root; 
		p.innerHTML=store.getRecursiveTiddlerText(cmp.templates['addimage'],'',10);
		var f=p.getElementsByTagName('form')[0];
		// initialize internal form values
		f.panel=p;
		f.action=cmp.uploadScript;
		f.targetlist.value=cmp.imageList.readBracketedList()[0];
		f.uploadpath.value=cmp.uploadPath;
		if (config.extensions.tiddlyspace!==undefined)
			f.csrf_token.value=config.extensions.tiddlyspace.getCSRFToken();

		// display panel
		var x=findPosX(root); var y=findPosY(root);
		var winw=findWindowWidth(); var scrollw=winw-document.body.offsetWidth;
		if(p.offsetWidth>winw*0.75) p.style.width=winw*0.75 + "px";
		if(x+p.offsetWidth>winw-scrollw-1) x=winw-p.offsetWidth-scrollw-1;
		var s=p.style; s.left=x+'px'; s.top=y+'px'; s.display='block';
		if(config.options.chkAnimate && anim)	anim.startAnimating(new Scroller(p));
		else					window.scrollTo(0,ensureVisible(p));
		return cme.ok(ev);
	},
//}}}
// // TYPE-SPECIFIC FORM HANDLING OVERRIDES FOR EditSectionPlugin
//{{{
	getForm: function(tid,type) {
		var cmp=config.macros.pasteUpHelper;
		var cme=config.macros.editSection;
		return cmp.templates[type]||cme.template;
	},
	getInitForm: function(tid,type) {
		var cmp=config.macros.pasteUpHelper;
		var cme=config.macros.editSection;
		return cmp.templates[type]?cmp.initForm:cme.initForm;
	},
	getSaveForm: function(tid,type) {
		var cmp=config.macros.pasteUpHelper;
		var cme=config.macros.editSection;
		return cmp.templates[type]?cmp.saveForm:cme.saveForm;
	},
	initForm: function(elem,form,title,section,type) {
		var cmp=config.macros.pasteUpHelper; // ABBREV
		var tid=title; if (section) tid=[title,section].join('##');
		var txt=store.getTiddlerText(tid,'');
		form.title.value=title;
		form.section.value=section||'';
		form.rawContent.value=txt;
		form.newsection.value=tid;

		// EXTRACT IMAGE SRC
		var imgsrc='';
		var pat='/%[.\\s]*?\\r?\\nimage:\\s*\\[img\\(.*,.*\\)\\[(.*)\\]\\]\\r?\\n[.\\s]*?%/';
		var re=new RegExp(pat);	var m=re.exec(txt); txt=txt.replace(re,'');
		if (m) imgsrc=m[1];

		// EXTRACT IMAGE PASTEUP POS/SIZE/ADJUST
		var imgleft=''; var imgtop=''; var imgwidth=''; var imgheight=''; var adjust=false;
		var pat='<<(?:pasteUp|tiddler)\\s+\\[\\[.+::image\\]\\].*?>>';
		var re=new RegExp(pat);	var m=re.exec(txt); txt=txt.replace(re,'');
		if (m) {
			function getXYWH(p) {
				var re=new RegExp(p+'\:([^\\s>]+)'); var ex=re.exec(m[0]); return ex?ex[1]:'';
			}
			imgleft=getXYWH('x');	imgtop=getXYWH('y');
			imgwidth=getXYWH('w');	imgheight=getXYWH('h');
			var adjust=m[0].indexOf(' noadjust')==-1; // 'adjust' CHECKBOX
		}

		// EXTRACT FONTSIZE AND STYLE 
		var size=''; var classname=''; // FIRST CLASSNAME IS FONTSIZE, REST IS STYLENAME
		var pat='<<(?:pasteUp|tiddler)\\s+\\[\\[.+##content\\]\\]\\s+class:"([^"]*)".*?>>';
		var re=new RegExp(pat);	var m=re.exec(txt); txt=txt.replace(re,'');
		if (m) { var t=m[1].split(' '); size=t.shift(); classname=t.join(' '); }

		// EXTRACT CONTENT FROM HIDDEN SECTION (IMAGE BEHIND TEXT)
		var content=txt;
		var pat='/%\\r?\\n!content\\r?\\n((?:.|\\n)*)\\r?\\n!end\\r?\\n%/';
		var re=new RegExp(pat); content=txt.replace(re,'$1');
		if (content==txt) { // FALLBACK: EXTRACT CONTENT FROM CLASS WRAPPER (IMAGE IN FRONT)
			var pat='(.*\\{\\{[^\\{]+\\{\\r?\\n)((?:.|\\n)*)(\\r?\\n\\}\\}\\}.*)';
			var re=new RegExp(pat); content=txt.replace(re,'$2');
			if (content==txt) { // FALLBACK: EXTRACT CONTENT FROM HTML DIV
				var pat='(.*<html><div class="[^"]+">\\r?\\n)((?:.|\\n)*)(\\r?\\n</div></html>.*)';
				var re=new RegExp(pat); content=txt.replace(re,'$2');
			}
		}

		if (form.type) type=form.type.value;
		switch (type) {
			case 'text': // SET TEXT CONTENT
				form.content.value=content;
				if (version.extensions.TextAreaPlugin) new window.TextAreaResizer(form.content);
				break;
			case 'image': // SET IMAGE SRC,X,Y,W,H
				cmp.setList(form.image,cmp.imageList,imgsrc);
				form.imgleft.value	=imgleft;
				form.imgtop.value	=imgtop;
				form.imgwidth.value	=imgwidth;
				form.imgheight.value	=imgheight;
				form.imgadjust.checked	=adjust;
				jQuery('.pasteUpImageAdjust',form).each(
					function(){this.style.display=adjust?'':'none';});
				// SET IMAGE PREVIEW // TBD: BRITTLE DOM REFERENCES
				var td=form.image.parentNode.parentNode;
				var i=td.getElementsByTagName('img')[0];
				if (i) {
					var p=i.parentNode.parentNode;
					var trim=jQuery(form.image.parentNode).height()+2;
					p.style.height=jQuery(td).height()-trim+'px';
					p.style.width=jQuery(td).width()-2+'px';
					cmp.setImagePreview(i,imgsrc,form);
				}
				break;
			case 'place': // SET ELEMENT POSITION/SIZE INPUTS
				var s=elem.style; var a='auto';
				form.left.defaultValue  =form.left.value  =s.left||a;
				form.top.defaultValue   =form.top.value   =s.top||a;
				form.width.defaultValue =form.width.value =s.width||a;
	 			form.height.defaultValue=form.height.value=s.height||a;
	 			form.zindex.defaultValue=form.zindex.value=s.zIndex||a;
				break;
		}
	},
	saveForm: function(here,ev) {	// RETURN CONTENT TO EditSectionPlugin FOR STORAGE
		var cmp=config.macros.pasteUpHelper; // ABBREV
		var cme=config.macros.editSection; // ABBREV
		var f=here.form; var elem=f.panel.root;

		// GET TARGET TITLE/SECTION
		var tid=f.newsection.value;
		var title=tid.split('##')[0];
		var section=tid.split('##')[1];
		var oldsection=f.section.value;
		if (!title) title=story.findContainingTiddler(elem).getAttribute('tiddler');
		if (!title) {
			displayMessage(cme.sectionerr.format([f.newsection.value]));
			f.newsection.focus(); f.newsection.select(); return false;
		}

		// CHECK FOR TIDDLER OVERWRITE
		if (!section && title!=f.title.value && store.tiddlerExists(title)) {
			if (!confirm(config.messages.overwriteWarning.format([title])))
				{ f.newsection.focus(); f.newsection.select(); return cme.ok(ev); }

		}

		// GET NEW TIDDLER/SECTION CONTENT
		var type=f.type?f.type.value:'';
		var txt=f.rawContent.value;
		if (type=='place') { // UPDATE ELEMENT POSITION/SIZE (if changed)
			var left=f.left.value; var top=f.top.value;
			var width=f.width.value; var height=f.height.value;
			var zindex=f.zindex.value;
			var changed=left!=f.left.defaultValue  || top!=f.top.defaultValue
				|| width!=f.width.defaultValue || height!=f.height.defaultValue
				|| zindex!=f.zindex.defaultValue;
			if (changed) config.macros.pasteUp.dragsave(elem,left,top,width,height,zindex);
		} else if (type=='image') {	// UPDATE IMAGE SRC,X,Y,W,H
			txt=cmp.modifyPart(tid,txt,'image',{
				title: f.title.value, src: f.image.value,
				adjust: f.imgadjust.checked, 
				x: f.imgleft.value,  y:f.imgtop.value,
				w: f.imgwidth.value, h:f.imgheight.value });
			cme.updateTiddler(txt,title,section,oldsection);
		} else if (type=='text') {	// UPDATE TEXT
			txt=cmp.modifyPart(tid,txt,'text',f.content.value);
			cme.updateTiddler(txt,title,section,oldsection);
		}
		f.panel.setAttribute('dirty',null); cme.removePanel(f.panel); // CLEAR FLAG AND CLOSE PANEL
		return cme.ok(ev);
	},
	setImagePreview: function(view,src,form) {
		view.src=src;
		view.parentNode.href=view.src;
		view.parentNode.title=src?'CLICK to view \x22'+src+'\x22':'select an image...';
		function setdef(e,def) { e.value=e.value||def; } // SET DEFAULT VALUE (IF BLANK INPUT)
		setdef(form.imgleft,  store.getTiddlerText('PasteUpConfig::ImageLeft',  '0px'));
		setdef(form.imgtop,   store.getTiddlerText('PasteUpConfig::ImageTop',   '0px'));
		setdef(form.imgwidth, store.getTiddlerText('PasteUpConfig::ImageWidth', 'auto'));
		setdef(form.imgheight,store.getTiddlerText('PasteUpConfig::ImageHeight','auto'));
	},
//}}}
// // PART DATA HANDLING
//{{{
	modifyPart: function(tid,txt,mode,val) {
		// DEBUG alert('modifyPart() before=\n'+txt);

		// DETECT HTML or MEDIAWIKI PART (= separate tiddler, tagged with 'html' or 'mediawiki')
		var t=store.getTiddler(tid);
		var isHTML=t && t.isTagged('html')||t.isTagged('mediawiki');

		var contentRE	// CONTENT IN EMBEDDED HIDDEN SECTION
			=/(.*\!content\r?\n)(.*)(\r?\n!end.*)/;
		var classRE	// FONTSIZE, STYLE IN EMBED
			=/(<<(?:pasteUp|tiddler)\s+\[\[.+##content\]\]\s+class:")([^"]*)(".*?>>)/;

		var wrapperRE	// FONTSIZE, STYLE, AND CONTENT IN CLASS WRAPPER
			=/(.*)(\{\{)([^\{]+)(\{\r?\n)((?:.|\r?\n)*)(\r?\n\}\}\})(.*)/;
		var wrapperOut
			='{{%0 %1{\n%2\n}}}';

		var divRE	// FONTSIZE, STYLE, AND CONTENT IN HTML DIV
			=/(.*)(<html><div class=")([^"]+)(">\r?\n)((?:.|\r?\n)*)(\r?\n<\/div><\/html>)(.*)/;
		var divOut
			='<html><div class="%0 %1">\n%2\n</div></html>';

		var imageRE	// IMAGE
			=/(<<(?:pasteUp|tiddler).*?>>\/%[.\s]*?\r?\nimage:\s*\[img\(.*,.*\)\[)(.*)(\]\]\r?\n[.\s]*?%\/)/;
		var imageOut	// IMAGE OUTPUT FORMAT (for new images)
			='<<pasteUp [[%0::image]] noedit%6 x:%2 y:%3 w:%4 h:%5>>/%\nimage: [img(100%,100%)[%1]]\n%/';


		switch(mode) {
		case "text":
			var m=contentRE.exec(txt); // CONTENT IN SECTION
			if (m) txt=txt.replace(contentRE,'$1'+val+'$3');
			else { // FALLBACK: CONTENT IN WRAPPER
				var m=imageRE.exec(txt); var i=(m?m[0]:'');	// GET IMAGE SYNTAX
				txt=txt.replace(imageRE,'');			// REMOVE IMAGE SYNTAX
				var m=wrapperRE.exec(txt);
				if (m) txt=txt.replace(wrapperRE,'$1$2$3$4'+val+'$6$7');
				else { // FALLBACK: CONTENT IN HTML DIV
					var m=divRE.exec(txt);
					if (m) txt=txt.replace(divRE,'$1$2$3$4'+val+'$6$7');
					else txt=val;	// FALLBACK: NO DIV, NO WRAPPER, NO SECTION
				}
				txt=i+txt;	// RESTORE IMAGE SYNTAX (if any)
			}
			break;
		case "image":
			var cfg='PasteUpConfig::'; // abbrev
			var x=val.x||store.getTiddlerText(cfg+'ImageLeft',  '0px');
			var y=val.y||store.getTiddlerText(cfg+'ImageTop',   '0px');
			var w=val.w||store.getTiddlerText(cfg+'ImageWidth', '100%');
			var h=val.h||store.getTiddlerText(cfg+'ImageHeight','auto');
			var m=imageRE.exec(txt);
			if (!m && val.src.length) {				// ADD IMAGE SYNTAX
				var noadjust=store.getTiddlerText(cfg+'ImageAdjust','')!='true';
				var i=imageOut.format([val.title,val.src,x,y,w,h,noadjust?' noadjust':'']);
				txt=i+txt;
			} else if (m && !val.src.length) {			// REMOVE IMAGE SYNTAX
				txt=txt.replace(imageRE,'');
			} else if (m && val.src.length) {			// REVISE IMAGE SYNTAX
				var i=m[1]+val.src+m[3];			//  CHANGE IMAGE SRC
				i=i.replace(/\s+[xywh]\:[^\s>]*/g,'');		//  REMOVE OLD xywh PARAMS
				// INSERT NEW xywh PARAMS
				i=i.replace(/>>/,' x:%0 y:%1 w:%2 h:%3>>'.format([x,y,w,h]));
				// REMOVE OLD noadjust AND ADD NEW noadjust (if 'adjust' not checked)
				i=i.replace(/ noedit noadjust/,' noedit');
				if (!val.adjust) i=i.replace(/ noedit/,' noedit noadjust');
				txt=txt.replace(imageRE,i); // UPDATE IMAGE SYNTAX
			}
			break;
		case "style":
		case "size":
			var m=imageRE.exec(txt); var i=(m?m[0]:'');	// GET IMAGE SYNTAX (if any)
			txt=txt.replace(imageRE,'');			// REMOVE IMAGE SYNTAX
			var s=''; var c='';
			var m=classRE.exec(txt); if (m) {
				var t=m[2].split(' '); s=t.shift(); c=t.join(' ');
				if (mode=='size') s=val; if (mode=='style') c=val;
				txt=txt.replace(classRE,'$1'+s+' '+c+'$3');
			} else { // FALLBACK: GET FONTSIZE/STYLE from CSS WRAPPER or HTML DIV (if any)
				var re=wrapperRE; m=re.exec(txt); if (!m) { re=divRE; m=re.exec(txt); }
				if (m) { var t=m[3].split(' '); var s=t.shift(); var c=t.join(' '); }
				if (mode=='size') s=val; if (mode=='style') c=val;
				if (s||c) {
					if (m)	txt=txt.replace(re,'$1$2'+s+' '+c+'$4$5$6$7'); // UPDATE
					else	txt=(isHTML?divOut:wrapperOut).format([s,c,txt]); // ADD
				} else {
					if (m)	txt=txt.replace(re,'$1$5$7'); // REMOVE
					else	txt=txt; // NO CHANGE!
				}
			}
			txt=i+txt;	// RESTORE IMAGE SYNTAX (if any)
			break;
		}
		// DEBUG alert('modifyPart() after=\n'+txt);
		return txt;
	}
}
//}}}
/***
!!!Form definitions for PasteUpHelper popup editor.
>note: modify shadow tiddlers to customize and/or translate forms
''Edit Text''
//{{{
!PasteUpHelperTemplate_Text
<!--{{{-->
<!--
|Name|PasteUpHelperTemplate_Text|
|Source|http://www.TiddlyTools.com/#PasteUpHelperPlugin|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|template|
|Requires|EditSectionPlugin, PasteUpPlugin|
|Description|enhanced popup editor template used by PasteUpHelperPlugin|
-->
<form action="javascript:;" autocomplete="off" style="white-space:nowrap">
<input type="hidden" name="type" value="text"><!--REQUIRED-->
<input type="hidden" name="title" value=""><!--REQUIRED-->
<input type="hidden" name="section" value=""><!--REQUIRED-->
<input type="hidden" name="rawContent" value=""><!--REQUIRED-->
<!-- HEADING/BUTTONS -->
<table style="padding:0;margin:0;border:0;border-collapse:collapse;width:100%;"><tr><td>
	<div style="font-size:80%;font-style:italic">edit text for:</div>
	<input type="text" name="newsection" value="" style="width:98%;margin:0;padding:0;border:0;background:none;" disabled>
</td><td style="text-align:right;">
	<input type="button" style="width:5em;" value="ok"	onclick="return this.form.save(this,event)">
	<input type="button" style="width:5em;" value="cancel"	onclick="return config.macros.editSection.cancel(this,event)">
</td></tr></table><hr>
<!-- CONTROLS -->
<div macro="tiddler QuickEditToolbar"></div>
<textarea name="content" rows="10" cols="80" style="width:98%"
	onchange="return config.macros.editSection.changed(this,event)"></textarea>
</div></form>
<!--}}}-->
!end
//}}}

''Select Image''
//{{{
!PasteUpHelperTemplate_Image
<!--{{{-->
<!--
|Name|PasteUpHelperTemplate_Image|
|Source|http://www.TiddlyTools.com/#PasteUpHelperPlugin|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|template|
|Requires|EditSectionPlugin, PasteUpPlugin|
|Description|enhanced popup editor template used by PasteUpHelperPlugin|
-->
<form action="javascript:;" autocomplete="off" style="white-space:nowrap">
<input type="hidden" name="type" value="image"><!--REQUIRED-->
<input type="hidden" name="title" value=""><!--REQUIRED-->
<input type="hidden" name="section" value=""><!--REQUIRED-->
<input type="hidden" name="rawContent" value=""><!--REQUIRED-->
<!-- HEADING/BUTTONS -->
<table style="padding:0;margin:0;border:0;border-collapse:collapse;width:100%;"><tr><td>
	<div style="font-size:80%;font-style:italic">select image for:</div>
	<input type="text" name="newsection" value="" style="width:98%;margin:0;padding:0;border:0;background:none;" disabled>
</td><td style="text-align:right;">
	<input type="button" style="width:5em;" value="ok"	onclick="return this.form.save(this,event)">
	<input type="button" style="width:5em;" value="cancel"	onclick="return config.macros.editSection.cancel(this,event)">
</td></tr></table><hr>
<!-- CONTROLS -->
<table style="border-collapse:collapse;width:100%;"><tr valign="top"><td xstyle="width:80%">
	<div>
	<select name="image" size="1" style="width:60%;" onchange="
		if (this.value=='_edit') return false;
		var i=this.parentNode.parentNode.getElementsByTagName('img')[0]
		config.macros.pasteUpHelper.setImagePreview(i,this.value,this.form);
		return config.macros.editSection.changed(this,event);
	"><option value="">select an image...</option>
	</select><input type="button" style="width:20%" value="select" onclick="
		return config.macros.pasteUpHelper.imagePopup(event,this.form.image);
	"><input type="button" style="width:20%" value="add" onclick="
		return config.macros.pasteUpHelper.addImagePanel(event,this.form.image);
	"><br>
	</div>
	<div style="border:1px solid gray;background-color:#ccc;overflow:hidden;min-height:85px;">
		<center><a href="" target="_blank" onclick="
			if (this.href==document.location) { // no image
				var td=this.parentNode.parentNode.parentNode;
				td.getElementsByTagName('select')[0].focus();
				return false;
			}
		"><img src="" style="height:100%;margin:0;padding:0;display:block;">
		</a></center>
	</div>
	<input name='imgadjust' type="checkbox" onclick="
		var vis=this.checked?'':'none';
		jQuery('.pasteUpImageAdjust',this.form).each(function(){this.style.display=vis;});
	">adjustable&nbsp;
</td><td class="pasteUpImageAdjust" style="display:none;padding-top:3px;">
	x-offset<br><input type="text" name="imgleft" style="width:5em"
		onchange="return config.macros.editSection.changed(this,event);"><br>
	y-offset<br><input type="text" name="imgtop" style="width:5em"
		onchange="return config.macros.editSection.changed(this,event);"><br>
	width<br><input type="text" name="imgwidth" style="width:5em"
		onchange="return config.macros.editSection.changed(this,event);"><br>
	height<br><input type="text" name="imgheight" style="width:5em"
		onchange="return config.macros.editSection.changed(this,event);"><br>
</td></tr></table>
</div></form>
<!--}}}-->
!end
//}}}

''Add Image''
//{{{
!PasteUpHelperTemplate_AddImage
<!--{{{-->
<!--
|Name|PasteUpHelperTemplate_AddImage|
|Source|http://www.TiddlyTools.com/#PasteUpHelperPlugin|
|Version|1.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|template|
|Requires|EditSectionPlugin, PasteUpPlugin|
|Description|enhanced popup editor template used by PasteUpHelperPlugin|
-->
<form action="" target="_serverresponse" method="post" enctype="multipart/form-data"
	autocomplete="off" style="white-space:nowrap" class="smallform">
<!-- HEADING/BUTTONS -->
<table style="padding:0;margin:0;border:0;border-collapse:collapse;width:100%;"><tr><td>
	<div style="font-size:80%;font-style:italic">add a new image to:</div>
	<input type="text" name="targetlist" value="PasteUpImageList" style="width:98%;margin:0;padding:0;border:0;background:none;" disabled>
</td><td style="text-align:right;">
	<input type="button" name="add" value="ok" style="width:5em;"
		title="add item to image list" onclick="
		var cmp=config.macros.pasteUpHelper; // ABBREV
		var f=this.form; // ABBREV
		var tid=f.targetlist.value;
		var t=store.getTiddlerText(tid,'');
		var label=f.label.value;
		if (!label.length || label==f.label.defaultValue) {
			alert('Please enter a name for this image');
			f.label.focus(); f.label.select();
			return false;
		}
		if (label.length && t.indexOf(label+'=')!=-1) {
			alert('\x22'+label+'\x22 is already in use.\nPlease enter a different name.');
			f.label.focus(); f.label.select();
			return false;
		}
		var url=f.url.value;
		if (!url.length) {
			alert('Please enter an image location or upload an image file');
			f.url.focus();
			return false;
		}
		var item='\n'+(label.length?label+'=':'')+url;
		var who=config.options.txtUserName; var when=new Date();
		if (config.options.chkForceMinorUpdate) { who=t.modifier||who; when=t.modified||when; }
		store.saveTiddler(tid,tid,t+item,who,when,t.tags,
			config.macros.pasteUp.cloneFields(t.fields));
		displayMessage('New image added to '+tid);
		cmp.setList(f.panel.root,cmp.imageList,url);
		f.panel.root.onchange(event);
		f.panel.root.focus();
		f.panel.parentNode.removeChild(f.panel);
		return false;
	">
	<input type="button" name="cancel" value="cancel" style="width:5em;" onclick="
		this.form.panel.root.focus();
		this.form.panel.parentNode.removeChild(this.form.panel);
		return false;
	">
</td></tr></table><hr>
<!-- CONTROLS -->
<div>
<input type="hidden" name="uploadpath" value=""><!-- REQUIRED -->
<input type="hidden" name="csrf_token" value=""><!-- REQUIRED (TIDDLYSPACE) -->
enter a new image name/location:<br>
<input type="text" name="label" size="15" value="name (for listbox)">
<input type="text" name="url" size="33" value="URL or path/filename" onchange="var f=this.form;
	if (this.value==this.defaultValue) return false; // ignore
	if (!f.label.value || f.label.value==f.label.defaultValue) {
		var slash='/'; if (this.value.indexOf('\\')!=-1) slash='\\';
		var parts=this.value.split(slash); var filename=parts[parts.length-1];
		f.label.value=filename.split('.')[0];
	}
"><br>
or, upload a local image file to this workspace:<br>
<input type="file" name="file" size="30" onchange=" var f=this.form;
	var slash='/'; if (this.value.indexOf('\\')!=-1) slash='\\';
	var parts=this.value.split(slash); var filename=parts[parts.length-1];
	if (!f.label.value || f.label.value==f.label.defaultValue)
		f.label.value=filename.split('.')[0];
	f.url.value=f.uploadpath.value+filename;
	f.url.onchange();
	if (confirm('Start uploading now?')) f.upload.click();
"><input type="button" name="upload" value="upload" style="display:inline"
	title="upload file to remote host" onclick="
	this.parentNode.nextSibling.style.display='inline';
	this.form.submit();
	this.form.add.focus();
	return false;
"><br>
</div><div style="display:none">
<a href="javascript:;" style="float:right" onclick="
	this.parentNode.style.display='none'; return false;
">hide</a>server response:<br>
<iframe name="_serverresponse" id="_serverresponse" style="width:100%;height:10em;background:white"></iframe>
</div>
</form>
<!--}}}-->
!end
//}}}

''Place Part''
//{{{
!PasteUpHelperTemplate_Placement
<!--{{{-->
<!--
|Name|PasteUpHelperTemplate_Placement|
|Source|http://www.TiddlyTools.com/#PasteUpHelperPlugin|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|template|
|Requires|EditSectionPlugin, PasteUpPlugin|
|Description|enhanced popup editor template used by PasteUpHelperPlugin|
-->
<form action="javascript:;" autocomplete="off" style="white-space:nowrap">
<input type="hidden" name="type" value="place"><!--REQUIRED-->
<input type="hidden" name="title" value=""><!--REQUIRED-->
<input type="hidden" name="section" value=""><!--REQUIRED-->
<input type="hidden" name="rawContent" value=""><!--REQUIRED-->
<!-- HEADING/BUTTONS -->
<table style="padding:0;margin:0;border:0;border-collapse:collapse;width:100%;"><tr><td>
	<div style="font-size:80%;font-style:italic">set position/size/layer for:</div>
	<input type="text" name="newsection" value="" style="width:98%;margin:0;padding:0;border:0;background:none;" disabled>
</td><td style="text-align:right;">
	<input type="button" style="width:5em;" value="ok"	onclick="return this.form.save(this,event)">
	<input type="button" style="width:5em;" value="cancel"	onclick="return config.macros.editSection.cancel(this,event)">
</td></tr></table><hr>
<!-- CONTROLS -->
<table style="border-collapse:collapse;padding:0;margin:0;border:0;width:100%;"><tr style="vertical-align:bottom"><td style="width:20%">
	left (x)<br>
	<input type="text" name="left" value="x" style="width:7em;margin:0;"
		onchange="return config.macros.editSection.changed(this,event);">
</td><td style="width:20%">
	top (y)<br>
	<input type="text" name="top" value="y" style="width:7em;margin:0;"
		onchange="return config.macros.editSection.changed(this,event);">
</td><td style="width:20%">
	width<br>
	<input type="text" name="width" value="w" style="width:7em;margin:0;"
		onchange="return config.macros.editSection.changed(this,event);">
</td><td style="width:20%">
	height<br>
	<input type="text" name="height" value="h" style="width:7em;margin:0;"
		onchange="return config.macros.editSection.changed(this,event);">
</td><td style="width:20%">
	layer (z-index)<br>
	<input type="text" name="zindex" value="z" style="width:7em;margin:0;"
		onchange="return config.macros.editSection.changed(this,event);">
</td></tr></table>
</form>
<!--}}}-->
!end
//}}}

Default/example CSS for user-defined pasteup styles
^^note: modify [[PasteUpStyleSheet]], [[PasteUpStyleList]] and/or [[PasteUpFontList]] to customize.^^
//{{{
!css
.bigger
	{ font-size:200%; line-height:100%; }
.biggest
	{ font-size:300%; line-height:100%; }
.headline
	{ text-align:center; font-weight:bold; }
.border
	{ border:1px solid; }
!end
//}}}
***/
 
/***
|Name|[[PasteUpPlugin]]|
|Source|http://www.TiddlyTools.com/#PasteUpPlugin|
|Version|1.2.8|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Type|plugin|
|~SeeAlso|[[EditSectionPlugin]] [[PasteUpHelperPlugin]]|
|Description|position/size embedded content with edit-in-place popup editor|
!!!Documentation
> see [[PasteUpPluginInfo]]
!!!Example/Test
<<<
{{{<<tiddler PasteUpPlugin##test style:"border:1px solid blue;color:black;background:white;" edit adjust x:115px y:18px w:190px h:75px>>}}}
<<tiddler PasteUpPlugin##test style:"border:1px solid blue;color:black;background:white;" edit adjust x:115px y:18px w:190px h:75px>>/%
!test
test this content
line 2
line 3
line 4
!end
%/
<<<
!!!Configuration
<<<
<<option chkPasteUpConfirmRemove>>ask for confirmation before removing a part from a page
{{{<<option chkPasteUpConfirmRemove>>}}}
<<option chkPasteUpBoundaryWarning>>warn when an element is moved/sized outside it's container
{{{<<option chkPasteUpBoundaryWarning>>}}}
<<option chkPasteUpEditAll>>automatically enable editing for all embedded content (unless ''noedit'' is used)
{{{<<option chkPasteUpEditAll>>}}}

Also see:
*[[PasteUpConfig]] and related shadows:
**[[DefaultPage]], [[DefaultPart]], [[PasteUpStyleSheet]]
*[[EditSectionPlugin]] (optional, recommended) and related shadows:
**[[EditSectionTemplate]]
*[[PasteUpHelperPlugin]] (optional, recommended) and related shadows:
**[[PasteUpHelperTemplate]], [[PasteUpStyleList]], [[PasteUpFontList]], [[PasteUpImageList]]
<<<
!!!Revisions
<<<
2011.09.06 1.2.8 in removePart(), added 'force' param (for use by PasteUpHelperPlugin)
2011.09.04 1.2.7 in dragSave(), support setting of non-default z-Index (default index is "1")
2011.09.03 1.2.6 in setCursor() and isStretch(), only resize if inside pasteup element (i.e, not within an overflow child element)
2011.08.05 1.2.5 in addPasteUpPart(), use "window.readOnly" for IE compatibility
2011.08.02 1.2.4 refactored click() handler and added clickAction(). Moved createMenu() and renderMenu() to [[PasteUpHelperPlugin]]
2011.08.02 1.2.3 in click(), check for existing popup and close it instead (i.e., 'toggle popup display')
2011.08.01 1.2.2 refactored form handling (see [[EditSectionPlugin]]) to support type-specific forms by [[PasteUpHelperPlugin]]
2011.07.23 1.2.1 added chkPasteUpNoMenuLink option and misc code cleanup
2011.07.23 1.2.0 Use edge/corner detect for resize.  Added popup menu.  Cleanup cursor handling.  Fix getMX/getMY for Safari/Webkit
2011.06.19 1.1.3 internal CSS shadow renamed to PasteUpPluginStyles
2011.06.13 1.1.2 in mousedown(), use removeAllPanels instead of Popup.remove
2011.06.10 1.1.1 in dragsave(), skip 'outofbounds' check if message text is blank
2011.06.08 1.1.0 added removePart() handler
2011.06.05 1.0.14 added TiddlySpace cloneFields() to save handlers so editing content automatically copies/owns an included tiddler
2011.05.17 1.0.13 in dragsave(), don't check for out of bounds if container is a pasteUp part itself
2011.05.05 1.0.12 in dragsave(), added custom undo messages (requires UndoPlugin)
2011.05.01 1.0.11 in dragsave(), added "out of bounds" confirmation
2011.02.23 1.0.10 mousetracking: in capture(), invoke release() first (fix for Chrome 'sticky drag' problem?)
2011.02.08 1.0.9 when saving new tiddlers, use config.defaultCustomFields for TiddlySpace compatibility
2011.01.30 1.0.8 in addPart(), retain existing tags when adding part to current tiddler
2011.01.12 1.0.7 in handler(), make sure tiddler element was actually rendered
| Please see [[PasteUpPluginInfo]] for previous revision details |
2010.07.21 0.7.5 alpha prototype (for review - do not distribute)
<<<
!!!Code
***/
// // PLUGIN VERSION
//{{{
version.extensions.PasteUpPlugin= {major: 1, minor: 2, revision: 8, date: new Date(2011,9,6)};
//}}}
// // OPTIONS
//{{{
if (config.options.chkPasteUpEditAll===undefined)		config.options.chkPasteUpEditAll=false;
if (config.options.chkPasteUpConfirmRemove===undefined)		config.options.chkPasteUpConfirmRemove=true;
if (config.options.chkPasteUpBoundaryWarning===undefined)	config.options.chkPasteUpBoundaryWarning=false;

//}}}
// // MACRO DEFINITION
//{{{
config.macros.pasteUp = {
	editMenuTxt:	'edit part...',
	editMenuTip:	'Edit the content for this part',
	removeMenuTxt:	'remove part...',
	removeMenuTip:	'Remove this part from the current page',
	outofboundsmsg: 'Item is outside the visible area of the layout.  Press OK to allow.',
	confirmremovemsg: 'Are you sure you want to remove part "%0" from page "%1"?',
	edgeDetect:	10,	// PIXELS FOR CORNER/BORDER DETECT
	quiet:		false,	// TRUE = SHOW POS/SIZE DURING DRAG
	debug:		false,	// TRUE = SHOW POS/SIZE AFTER DRAG
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var cmp=config.macros.pasteUp; // abbrev

		// UNPACK PARAMS
		var edit=params.contains('edit')||macroName=='pasteUp'||config.options.chkPasteUpEditAll;
		var noedit=params.contains('noedit');
		var adjust=params.contains('adjust')||macroName=='pasteUp';
		var noadjust=params.contains('noadjust');
		var nopopup=params.contains('nopopup');
		var p=paramString.parseParams('name',null,true,false,true);
		var style=getParam(p,'style');
		var CSSclass=getParam(p,'class');
		var x=getParam(p,'x');
		var y=getParam(p,'y');
		var z=getParam(p,'z');
		var w=getParam(p,'w');
		var h=getParam(p,'h');

		// FIXUP for '##section' references (use current tiddler, if any)
		var sep='##'; var parts=params[0].split(sep);
		var tid=parts[0]; var sec=parts[1];
		var pasteupParams=paramString; // save unmodified params
		if (!tid && sec) {
			var here=story.findContainingTiddler(place)
			var tid=here?here.getAttribute('tiddler'):tiddler?tiddler.title:'';
			arguments[2][0]=tid+sep+sec;
			arguments[4]=paramString.replace(new RegExp(sep+sec),tid+sep+sec);
		}

		// RENDER CONTENT (CORE HANDLER) and GET RESULTING OBJECTS
		cmp.core_handler.apply(config.macros.tiddler,arguments);
		var e=place.lastChild; // rendered tiddler element
		if (!e || !e.getAttribute) return; // element not rendered!
		var t=e.getAttribute('tiddler'); // source title
		if (!t) return; // not a tiddler element!
		var s=e.style; // CSS styles
		e.setAttribute('tid',t); // needed by EditSectionPlugin

		// SET optional CUSTOM CLASS, STYLES, and/or DIRECT POS/SIZE
		if (CSSclass) addClass(e,CSSclass);
		if (style) {
			var parts=style.split(';');
			for (var i=0; i<parts.length; i++) {
				var name=(parts[i].split(':')[0]||'').trim();
				var val =(parts[i].split(':')[1]||'').trim();
				if (name.length && val.length) jQuery(e).css(name,val);
			}
		}
		s.left=x||s.left; s.top=y||s.top; s.zIndex=z||s.zIndex||1;
		s.width=w||s.width; s.height=h||s.height;

		// PASTEUP or NON-DEFAULT POSITION
		function def(e,a) { return (['auto','0px',''].contains(jQuery(e).css(a))); }
		if (macroName=='pasteUp' || !def(e,'left') || !def(e,'top')) {
			e.style.position='absolute'; // ALLOW ELEMENT TO BE POSITIONED
			if (e.parentNode.style.position!='absolute') // FIXUP PARENT FOR RELATIVE OFFSETS
				e.parentNode.style.position='relative';
		}

		// PASTEUP = ALLOW EDIT/ADJUST BY DEFAULT
		if (macroName=='pasteUp') { edit=true; adjust=true; }

		e.editable=edit&&!noedit;
		e.adjustable=adjust&&!noadjust;
		if (readOnly) return; // READONLY = DONE

		// TOOLTIP, CURSOR DEFAULT CONTENT, OUTLINE on hover, add PASTEUP CLASS
		if (e.editable||e.adjustable) {
			e.title=cmp.tooltip(e);				// TOOLTIP = source name
			e.style.cursor='pointer';			// DEFAULT CURSOR = pointer
			if (e.innerHTML=='') wikify('[['+t+']]',e);	// DEFAULT CONTENT = [[source]]
			e.onmouseover=cmp.mouseover;			// SHOW OUTLINE
			e.onmousemove=cmp.mousemove;			// SET CURSOR
			e.onmouseout =cmp.mouseout;			// HIDE OUTLINE
			addClass(e,'pasteUp');
		}

		// EDITABLE = CLICK/DOUBLE-CLICK
		e.helptext='';
		if (e.editable) {
			e.nopopup=nopopup||!config.macros.editSection;
			e.onclick    =cmp.click;	// EDIT-IN-PLACE
			e.ondblclick =cmp.dblclick;	// EDIT IN SEPARATE TIDDLER
			if (e.nopopup)
				e.helptext+=', DOUBLE-CLICK=edit';
			else if (config.options.chkPasteUpQuickMenu)
				e.helptext+=', CLICK=menu, SHIFT-CLICK=edit';
			else
				e.helptext+=', CLICK=edit';
		}

		// ADJUSTABLE = DRAG/SHIFT-DRAG
		if (e.adjustable) {
			e.pasteupParams=pasteupParams; // used in dragsave() to find matching macro
			e.onmousedown=cmp.mousedown;	// DRAG = MOVE/STRETCH
			e.helptext+=', DRAG=move, LOWER-RIGHT CORNER or SHIFT-DRAG=resize';
		}
		e.title+=e.helptext;
	},
//}}}
// // GENERAL UTILITIES
//{{{
	tooltip: function(e) { // tooltip for embedded elements shows source name
		return e.getAttribute('tiddler'); // source title
	},
	getCSS: function(e,px,css) { // CONVERT element px values into CSS units
		var u=css.replace(/[0-9\.-]*/,''); if (u=='auto'||u=='') u='px'; // get CSS units
		var t=createTiddlyElement(e.parentNode,'div');
		t.style.width='1'+u;
		var r=Math.round(px/t.offsetWidth*10)/10; // round to one decimal place
		t.parentNode.removeChild(t);
		return r+u;
	},
	getMX: function(ev) { ev=ev||window.event; // GET MOUSE X
		if (config.browser.isIE)	return ev.clientX+findScrollX();// IE
		if (config.browser.isSafari) 	return ev.pageX+findScrollX(); 	// Webkit
		else				return ev.pageX;		// Firefox/other
	},
	getMY: function(ev) { ev=ev||window.event; // GET MOUSE Y
		if (config.browser.isIE)	return ev.clientY+findScrollY();// IE
		if (config.browser.isSafari) 	return ev.pageY+findScrollY();	// Webkit
		else				return ev.pageY;		// Firefox/other
	},
	ok: function(ev) { ev=ev||window.event; // HANDLE EVENT
		ev.cancelBubble=true; if(ev.stopPropagation) ev.stopPropagation(); return false;
	},
	getTrack: function(here) { // GET DRAG ELEMENT
		var track=here; // if 'capture' not supported, track in element only
		if (document.body.setCapture) var track=document.body; // IE
		if (window.captureEvents) var track=window; // moz
		return track;
	},
	capture: function () { // CAPTURE MOUSE
		this.release(); // make sure we aren't already tracking
		if (document.body.setCapture) document.body.setCapture(); // IE
		if (window.captureEvents) window.captureEvents(Event.MouseMove|Event.MouseUp,true); // moz
	},
	release: function () { // RELEASE MOUSE
		if (document.body.releaseCapture) document.body.releaseCapture(); // IE
		if (window.releaseEvents) window.releaseEvents(Event.MouseMove|Event.MouseUp); // moz
	},
	setCursor: function(here,ev) { ev=ev||window.event; // SET CURSOR FOR ELEMENT
		var x=this.getMX(ev); var y=this.getMY(ev);
		var left=findPosX(here); var top=findPosY(here);
		var width=here.offsetWidth; var height=here.offsetHeight; var size=this.edgeDetect;
		var isB=(top+height-y>0 && top+height-y<size);
		var isR=(left+width-x>0 && left+width-x<size);
		var c=((isB&&isR)||ev.shiftKey)?'se-resize':isB?'s-resize':isR?'e-resize':'pointer';
		here.style.cursor=c;
	},
	isStretch: function(here,ev) { ev=ev||window.event; // LOWER-RIGHT CORNER FOR STRETCH
		var x=this.getMX(ev); var y=this.getMY(ev);
		var left=findPosX(here); var top=findPosY(here);
		var width=here.offsetWidth; var height=here.offsetHeight; var size=this.edgeDetect;
		var isB=(top+height-y>0 && top+height-y<size);
		var isR=(left+width-x>0 && left+width-x<size);
		return isB||isR||ev.shiftKey;
	},
//}}}
// // MOUSE HANDLERS (click/dblclick,mouseover/mousemove/mouseout)
//{{{
	click: function(ev) { ev=ev||window.event; // EDIT IN PLACE (using EditSectionPlugin)
		var cmp=config.macros.pasteUp; // abbrev
		cmp.release(); // stop tracking mousemove
		if (Popup.stack.length) { Popup.remove(); return cmp.ok(ev); } // close popup (if any)
		if (this.nopopup || ev.ctrlKey) { this.changed=false; return true; }
		if (!this.changed) cmp.clickAction(this,ev); // ignore click if after move/stretch
		this.changed=false;
		return cmp.ok(ev);
	},
	clickAction: function(here,ev) {
		config.macros.editSection.click.call(here,ev,'all');
	},
	dblclick: function(ev) { ev=ev||window.event; // EDIT IN TIDDLER (normal edit)
		var t=this.getAttribute('tiddler').split('##')[0];
		story.displayTiddler(story.findContainingTiddler(this),t,DEFAULT_EDIT_TEMPLATE);
		return config.macros.pasteUp.ok(ev);
	},
	mouseover: function(ev) { ev=ev||window.event; // SHOW OUTLINE
		addClass(this,'pasteUpBorder');
		return config.macros.pasteUp.ok(ev);
	},
	mousemove: function(ev) { ev=ev||window.event; // SET CURSOR
		config.macros.pasteUp.setCursor(this,ev);
		return true; // NOTE: ALLOW EVENT TO BUBBLE
	},
	mouseout: function(ev) { ev=ev||window.event; // HIDE OUTLINE
		removeClass(this,'pasteUpBorder');
		return config.macros.pasteUp.ok(ev);
	},
//}}}
// // MOUSE DRAG HANDLERS (down,move,up,keyup)
//{{{
	mousedown: function(ev) { ev=ev||window.event; // MOVE/STRETCH
		var cmp=config.macros.pasteUp; // abbrev

		// if popup is showing, close popup and ignore click 
		if (jQuery('.editSectionPanel').length)
			{ config.macros.editSection.removeAllPanels(); return cmp.ok(ev); }

		// ADD DRAG HANDLERS
		var track=cmp.getTrack(this);
		if (!track.save_onmousemove) track.save_onmousemove=track.onmousemove;
		if (!track.save_onkeyup)     track.save_onkeyup    =track.onkeyup;
		if (!track.save_onmouseup)   track.save_onmouseup  =track.onmouseup;
		track.onmousemove=cmp.dragmove;
		track.onkeyup  =cmp.dragkeyup;
		track.onmouseup=cmp.dragup;

		if (this.parentNode.style.position!='absolute') // fixup parent so OFFSETS ARE RELATIVE
			this.parentNode.style.position='relative';

		// INITIAL STATE
		this.changed=false;		// set true when moved/stretched
		track.elem=this;		// tiddler element
		track.stretch=cmp.isStretch(this,ev);
		track.start={
			X: cmp.getMX(ev),	// mouse position
			Y: cmp.getMY(ev),
			T: this.offsetTop,	// element position/size (pixels)
			L: this.offsetLeft,
			W: jQuery(this).width(),
			H: jQuery(this).height(),
			css: {			// original element css values
				T: this.style.top,
				L: this.style.left,
				W: this.style.width,
				H: this.style.height
			}
		}
		return cmp.ok(ev);
	},
	dragmove: function(ev) { ev=ev||window.event; // DRAG: MOVE/STRETCH
		var cmp=config.macros.pasteUp; // abbrev
		cmp.capture(); // capture mouse events during drag
		var e=this.elem; var s=e.style;
		var dX=cmp.getMX(ev)-this.start.X;
		var dY=cmp.getMY(ev)-this.start.Y;
		e.changed=e.changed||(Math.abs(dX)>1)||(Math.abs(dY)>1); // MINIMUM 2px MOVEMENT
		if (!e.changed) return cmp.ok(ev);
		e.style.position='absolute'; // ensure element is MOVEABLE
		if (this.stretch||ev.shiftKey) { // resize
			s.width =cmp.getCSS(e,this.start.W+dX,this.start.css.W);
			s.height=cmp.getCSS(e,this.start.H+dY,this.start.css.H);
		} else { // move
			s.top =cmp.getCSS(e,this.start.T+dY,this.start.css.T);
			s.left=cmp.getCSS(e,this.start.L+dX,this.start.css.L);
		}
		if (!cmp.quiet) {
			var a='auto';
			var msg='[[%0]] x:%1 y:%2 w:%3 h:%4'.format(
				[e.getAttribute('tiddler'),s.left||a,s.top||a,s.width||a,s.height||a]);
			clearMessage(); displayMessage(msg);
		}
		return cmp.ok(ev);
	},
	dragkeyup: function(ev) { ev=ev||window.event; // DRAG: CANCEL (ESC key)
		var cmp=config.macros.pasteUp; // abbrev
		cmp.setCursor(this.elem,ev);
		if (ev.keyCode==27) {
			cmp.dragcancel(this.elem);
			return this.onmouseup(ev);
		}
		return cmp.ok(ev);
	},
	dragup: function(ev) { ev=ev||window.event; // DRAG: END
		var cmp=config.macros.pasteUp; // abbrev
		cmp.release(); // stop tracking mouse
		this.onmousemove=this.save_onmousemove;
		this.onkeyup    =this.save_onkeyup;
		this.onmouseup  =this.save_onmouseup;
		clearMessage();
		var e=this.elem; var s=e.style;
		cmp.setCursor(e,ev);
		if (e.changed) cmp.dragsave(e,s.left,s.top,s.width,s.height,s.zIndex);
		return cmp.ok(ev);
	},
	dragcancel: function(elem) {
		var orig=config.macros.pasteUp.getTrack(elem).start.css;
		elem.style.top   =orig.T;
		elem.style.left  =orig.L;
		elem.style.width =orig.W;
		elem.style.height=orig.H;
		elem.changed     =false;
		displayMessage('move/size cancelled');
		cmp.setCursor(e,ev);
	},
//}}}
// // DRAGSAVE -  Update embedded {{{<<pasteUp>>}}} or {{{<<tiddler>>}}} macro
//{{{
	cloneFields: function(fields) { // for TIDDLYSPACE compatibility
		var f=merge({},fields); // copy object
		if (f["server.workspace"]!=config.defaultCustomFields["server.workspace"]) {
			f=merge(f,config.defaultCustomFields); // overwrite with defaults
			f["server.permissions"] = "read, write, create, delete";
			delete f["server.page.revision"];
			delete f["server.title"];
			delete f["server.etag"];
		}
		return f;
	},
	dragsave: function(elem,left,top,width,height,zIndex) {
		var cmp=config.macros.pasteUp; // abbrev

		// FIND CONTAINER (the tiddler/section that transcludes this one)
		var c=elem.parentNode;
		while(c && c.getAttribute('tiddler')==undefined) c=c.parentNode;
		if (!c) return;
		var target=c.getAttribute('tiddler');	
		var txt=store.getTiddlerText(target,'');
		var parts=target.split('##');
		var title=parts[0];
		var section=parts[1];

		// CHECK FOR 'OUT OF BOUNDS'
		if (!hasClass(c,'pasteUp') && cmp.outofboundsmsg.length && config.options.chkPasteUpBoundaryWarning) {
			var w=jQuery(c).width(); var h=jQuery(c).height();
			var l=jQuery(elem).position().left; var r=l+jQuery(elem).width();
			var t=jQuery(elem).position().top;  var b=t+jQuery(elem).height();
			if (l<0 || t<0 || r>w || b>h) if (!confirm(cmp.outofboundsmsg)) {
				cmp.dragcancel(elem); elem.changed=true; // ignore following click
				return;
			}
		}
	
		// FIND <<pasteUp>> or <<tiddler>> MACRO and UPDATE PARAMS
		if (cmp.debug) displayMessage('updating '+target);
		var a='auto'; var fmt=' x:%0 y:%1 w:%2 h:%3';
		if (zIndex!==undefined && zIndex!=1) fmt=' x:%0 y:%1 z:%4 w:%2 h:%3';
		var newparams=fmt.format([left||a,top||a,width||a,height||a,zIndex]);
		var newtxt=''; var pos=0; var t=elem.pasteupParams.escapeRegExp();
		var re=new RegExp('<<(pasteUp|tiddler)\\s+'+t+'>>','mg');
		var matches=re.exec(txt);
		if (!matches) { // NO MATCH = POSSIBLE TIDDLER NAME FIXUP (i.e, '##section')
			var here=story.findContainingTiddler(elem);
			var tid=here?here.getAttribute('tiddler'):'';
			var t=elem.pasteupParams.escapeRegExp().replace(new Regexp(tid),''); // REMOVE FIXUP TIDDLER NAME
			var re=new RegExp('<<(pasteUp|tiddler)\\s+'+t+'>>','mg'); // TRY AGAIN
			var matches=re.exec(txt);
		}
		while (matches) { var m=matches[0];
			newtxt+=txt.substr(pos,re.lastIndex-m.length-pos); // before match
			var parts=m.substr(0,m.length-2).split(' with: ');
			parts[0]=parts[0].replace(/\s+[xyzwh]\:[^\s>]*/g,''); // remove old x,y,z,w,h params
			parts[1]=parts[1]?' with: '+parts[1]+'>>':'>>';
			m=parts[0]+newparams+parts[1];
			if (cmp.debug) displayMessage(m);
			newtxt+=m; pos=re.lastIndex; matches=re.exec(txt);
		}
		newtxt+=txt.substr(pos,txt.length); // remainder 

		// SAVE TIDDLER
		var t=store.getTiddler(title); if (!t) {
			t=new Tiddler();
			t.text=store.getTiddlerText(title,'');
			t.fields=config.defaultCustomFields;
		}
		if (section) { // revise section text
			var oldval=store.getTiddlerText(target).escapeRegExp();
			var pattern=new RegExp('(.*!{1,6}'+section+'\\n)'+oldval+'((?:\\n!{1,6}|$).*)');
			newtxt=t.text.replace(pattern,'$1'+newtxt+'$2');
		}
		var who=config.options.txtUserName; var when=new Date();
		if (config.options.chkForceMinorUpdate) { who=t.modifier||who; when=t.modified||when; }
		store.saveTiddler(title,title,newtxt,who,when,t.tags,cmp.cloneFields(t.fields));
		if (config.macros.undo) {
			var partname=elem.pasteupParams.split(' ')[0];
			config.macros.undo.setmsg('move/resize '+partname);
		}
		story.refreshTiddler(tid,null,true);
	},
//}}}
// // ADDPART - Add an embedded {{{<<pasteUp>>}}} part to a tiddler
//{{{
	addPart: function(tid,partname) {
		var cmp=config.macros.pasteUp; // abbrev
		// GET PART TiddlerTitle OR TiddlerTitle##sectionname
		partname=partname.replace(/ /g,'_');
		var title=partname.split('##')[0]||tid;
		var section=partname.split('##')[1];
		var part=title+(section?'##'+section:'');
		// GET CONTAINING TIDDLER
		var t=store.getTiddler(tid); if (!t) {
			t=new Tiddler();
			t.text=store.getTiddlerText(tid,'');
			t.fields=config.defaultCustomFields;
		}
		// APPEND PART PASTEUP
		var y=store.getTiddlerText('PasteUpConfig::PartTop',   '0px');
		var x=store.getTiddlerText('PasteUpConfig::PartLeft',  '0px');
		var w=store.getTiddlerText('PasteUpConfig::PartWidth', 'auto');
		var h=store.getTiddlerText('PasteUpConfig::PartHeight','auto');
		var fmt='%0<<pasteUp %1 x:%2 y:%3 w:%4 h:%5>>';
		var txt=t.text+fmt.format([t.text.length?'\n':'',part,x,y,w,h]);
		// SAVE CONTAINER
		var who=config.options.txtUserName; var when=new Date();
		if (config.options.chkForceMinorUpdate)
			{ who=t.modifier||who; when=t.modified||when; }
		store.saveTiddler(tid,tid,txt,who,when,t.tags,cmp.cloneFields(t.fields));
		if (config.macros.undo) config.macros.undo.setmsg('remove '+part+' from '+tid);
		story.refreshTiddler(tid,null,true);
		// CREATE PART IF NEEDED
		if (!store.getTiddlerText(part)) {
			var t=store.getTiddler(title); if(!t) {
				t=new Tiddler();
				t.text=store.getTiddlerText(title,'');
				t.fields=config.defaultCustomFields;
			}
			var txt=store.getTiddlerText('DefaultPart',part).replace(/DefaultPart/g,part);
			if (section) txt='{{hidden{\n!'+section+'\n'+txt+'\n!end '+section+'\n}}}';
			if (!section) t.tags.pushUnique('part');
			store.saveTiddler(title,title,t.text+txt,who,when,t.tags,cmp.cloneFields(t.fields));
			story.refreshTiddler(title,null,true);
			displayMessage('created new part: '+part);
		}
		displayMessage(part+' added to '+tid);
		return false;
	},
	removePart: function(elem,force) {
		var cmp=config.macros.pasteUp; // abbrev
		// FIND CONTAINER (the tiddler/section that transcludes this one)
		var c=elem.parentNode;
		while(c && c.getAttribute('tiddler')==undefined) c=c.parentNode;
		if (!c) return false; // NOTHING REMOVED
		var target=c.getAttribute('tiddler');	
		var txt=store.getTiddlerText(target,'');
		var parts=target.split('##');
		var title=parts[0];
		var section=parts[1];

		// ASK FOR CONFIRMATION (if not FORCE)
		var msg=cmp.confirmremovemsg.format([elem.getAttribute('tid'),target]);
		if (!force && config.options.chkPasteUpConfirmRemove && !confirm(msg)) return false;

		// FIND <<pasteUp>> or <<tiddler>> MACRO 
		if (cmp.debug) displayMessage('updating '+target);
		var newtxt=''; var pos=0; var t=elem.pasteupParams.escapeRegExp();
		var re=new RegExp('<<(pasteUp|tiddler)\\s+'+t+'>>','mg');
		var matches=re.exec(txt);
		if (!matches) { // NO MATCH = POSSIBLE TIDDLER NAME FIXUP (i.e, '##section')
			var here=story.findContainingTiddler(elem);
			var tid=here?here.getAttribute('tiddler'):'';
			var t=elem.pasteupParams.escapeRegExp().replace(new Regexp(tid),''); // REMOVE FIXUP TIDDLER NAME
			var re=new RegExp('<<(pasteUp|tiddler)\\s+'+t+'>>','mg'); // TRY AGAIN
			var matches=re.exec(txt);
		}

		// REMOVE MACROS
		while (matches) { var m=matches[0];
			newtxt+=txt.substr(pos,re.lastIndex-m.length-pos); // before match
			if (cmp.debug) displayMessage('removing '+m);
			pos=re.lastIndex; matches=re.exec(txt);
		}
		newtxt+=txt.substr(pos,txt.length); // remainder 

		// SAVE TIDDLER
		var t=store.getTiddler(title); if (!t) return;
		if (section) { // revise section text
			var oldval=store.getTiddlerText(target).escapeRegExp();
			var pattern=new RegExp('(.*!{1,6}'+section+'\\n)'+oldval+'((?:\\n!{1,6}|$).*)');
			newtxt=t.text.replace(pattern,'$1'+newtxt+'$2');
		}
		var who=config.options.txtUserName; var when=new Date();
		if (config.options.chkForceMinorUpdate)
			{ who=t.modifier||who; when=t.modified||when; }
		store.saveTiddler(title,title,newtxt,who,when,t.tags,cmp.cloneFields(t.fields));

		if (config.macros.undo) {
			var partname=elem.pasteupParams.split(' ')[0];
			config.macros.undo.setmsg('restore part '+partname+' in '+title);
		}
		story.refreshTiddler(title,null,true);
		displayMessage(partname+' removed from '+title);
		return true; // PART REMOVED SUCCESSFULLY
	}
}
//}}}
// // HIJACK {{{<<tiddler>>}}} handler
//{{{
config.macros.pasteUp.core_handler=config.macros.tiddler.handler;
config.macros.tiddler.handler=config.macros.pasteUp.handler;
//}}}
// // MACRO: addPasteUpPart
//{{{
config.macros.addPasteUpPart = {
	label: 'add part',
	prompt: 'add a part to this page',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if (window.readOnly) return;
		var label=params[0]||this.label;
		var prompt=params[1]||this.prompt;
		createTiddlyButton(place,label,prompt,this.click);
	},
	click: function(ev) {
		var tid=story.findContainingTiddler(this).getAttribute('tiddler');
		var partname=prompt('Please enter a part name:','NewPart');
		if (partname) config.macros.pasteUp.addPart(tid,partname);
		return config.macros.pasteUp.ok(ev);
	}
};
//}}}
// // TOOLBAR COMMAND: addPasteUpPart
//{{{
config.commands.addPasteUpPart = {
	text: 'add part',
	hideReadOnly: true,
	tooltip: 'add a part to this page',
	handler: function(ev,src,title) {
		return config.macros.addPasteUpPart.click(ev);
	}
};
//}}}
// // DELIVER INTERNAL PLUGIN STYLES TO PasteUpPluginStyles SHADOW
//{{{
var tid='PasteUpPluginStyles';
config.shadowTiddlers[tid]='/*{{{*/\n'+store.getTiddlerText(tiddler.title+'##css','')+'\n/*}}}*/';;
config.annotations[tid]='CSS definitions used internally by PasteUpPlugin.  Do not modify unless you are sure you know what you are doing!';
store.addNotification(tid,refreshStyles);
//}}}
/***
{{{
!css
.hidden
	{ display:none; }
.pasteUp
	{ border:1px solid transparent; z-index:1; }
.pasteUpBorder
	{ border:1px dotted black !important; }
div[tags~="pasteup"].tiddler div.viewer,
div[tags~="part"].tiddler div.viewer,
div[tiddler="DefaultPage"] div.viewer,
div[tiddler="DefaultPageHeader"] div.viewer,
div[tiddler="DefaultPageFooter"] div.viewer,
div[tiddler="DefaultPart"] div.viewer {
	width:[[PasteUpConfig::Width]];
	height:[[PasteUpConfig::Height]];
	padding:0em;
	border:1px solid;
}
!end
}}}
***/
// // REFRESH DISPLAY WHEN PasteUpConfig IS CHANGED (applies user settings)
//{{{
store.addNotification('PasteUpConfig', function(title){ refreshAll(); });
//}}}
// // DELIVER SHADOW CONTENT FOR DefaultPage (for use with {{{<<newTiddler>>}}})
//{{{
config.shadowTiddlers['DefaultPage']=store.getTiddlerText(tiddler.title+'##defaultpage','');
config.annotations['DefaultPage']='This content is used to create new pasteup pages';
//}}}
/***
{{{
!defaultpage
<<pasteUp DefaultPageHeader x:0px y:0%  w:100% h:10%>>
<<pasteUp DefaultPageFooter x:0px y:90% w:100% h:10%>>
!end
}}}
***/
// // DELIVER SHADOW CONTENT FOR DefaultPart (used by addPasteUpPart)
//{{{
config.shadowTiddlers['DefaultPart']=store.getTiddlerText(tiddler.title+'##defaultpart','');
config.annotations['DefaultPart']='This content is used to create new parts on pasteup pages';
//}}}
/***
{{{
!defaultpart
This is "DefaultPart"
Please click to edit.
!end
}}}
***/
 
|Name|[[PasteUpPluginInfo]]|
|Source|http://www.TiddlyTools.com/#PasteUpPlugin|
|Documentation|http://www.TiddlyTools.com/#PasteUpPluginInfo|
|Version|1.1.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Type|documentation|
|~SeeAlso|EditSectionPlugin PasteUpHelperPlugin|
|Description|documentation for PasteUpPlugin and PasteUpHelperPlugin|
The {{{<<pasteUp>>}}} macro provides enhancements to the {{{<<tiddler>>}}} macro that allow you to ''specify the placement, size and appearance of embedded content'' to create 'free form layouts' using overlapping "paste-up" elements.  You can also ''embed and position paste-up elements within the content of other paste-up elements'', so that adjustments to the position of a containing element affects all the nested elements within it as well (i.e., they move together as a group).

You can use the mouse to ''drag an element to change its position'' (i.e., move the top-left corner), or use ''shift-drag to change its dimensions'' (i.e., move the lower-right corner).  When you release the mouse, changes to the x,y,w,h parameters are automatically updated in the corresponding {{{<<pasteUp>>}}} (or {{{<<tiddler>>}}}) macro (note: this //modifies the tiddler in which the macro occurs//).  You can hand-edit the macro parameters in the tiddler source to customize or further 'fine tune' the layout.

When [[EditSectionPlugin]] is installed, you can ''single-click on an element to display a popup editor'' that permits you to ''directly modify the element's source content'' without having to first locate and open the associated source tiddler.  When [[EditSectionPlugin]] is not present, ''a double-click on an element opens the associated source tiddler in a standard tiddler editor''.

When [[PasteUpHelperPlugin]] is also installed, the default popup editor is enhanced to add extra controls for editing the current size/position (x,y,w,h) of a paste-up element as well as 'helper' controls for selecting from pre-defined, configurable lists of font sizes, styles, and images, along with x,y,w,h values for positioning/sizing the selected image.  The 'helper' then //automatically generates// the TiddlyWiki syntax needed to set the size, position, font, style and image (if any) for a paste-up element.
!!!Usage
<<<
{{{
<<pasteUp TiddlerName class:"classname" noedit noadjust nopopup style:"..." x:... y:... z:... w:... h:... >>
   or
<<tiddler TiddlerName class:"classname" edit adjust nopopup style:"..." x:... y:... z:... w:... h:... >>
}}}
''//(all parameters -- except for ~TiddlerName -- are optional)//''
*''class:"classname"'' (default="")<br>specifies a CSS classname (or combination of space-separated classnames, enclosed in quotes) that will be assigned to the element.
*''style:"..."'' (default="")<br>specifies any valid sequence of one or more CSS "property:value;" pairs (e.g., "border:1px solid black;font-size:300%;") that will be assigned to the element.
*''edit/noedit'' (keyword)<br>enables editing of an embedded {{{<<tiddler>>}}} element.  Note: when using the {{{<<pasteUp>>}}} macro, editing is automatically enabled by default; use ''noedit'' to bypass this handling.
*''adjust/noadjust'' (keyword)<br>enables moving/stretching of an embedded {{{<<tiddler>>}}} element.  Note: when using the {{{<<pasteUp>>}}} macro, moving/stretching is automatically enabled by default; use ''noadjust'' to bypass this handling.
*''nopopup'' (keyword)<br>bypasses single-click popup editing even if [[EditSectionPlugin]] is installed.  When editing is enabled, double-click an element to edit it using a standard tiddler editor.
*''x, y, z, w, h'' (default="auto")<br>specifies the left (x), top (y), z-index "stacking order" (z), width (w), and height (h) of the paste-up element using any valid CSS units of measure (e.g., px, cm, in, em, %, or 'auto').
Notes:
*You can define the position, size and appearance of a paste-up element using any combination of ''class:"..."'', ''style:"..."'', and/or separate ''x, y, z, w, h'' parameters.  Classname-based attributes are applied first, and can be selectively overridden by style-based attributes which, in turn, can be overriden by specific x, y, z, w, and h parameters.  Note: //Classname and style parameter values can contain spaces.  It is a good habit to ''always'' enclose these values within quotes to ensure proper macro handling.//
*{{span{The output format for a part generated by the [[PasteUpHelperPlugin]]-enhanced popup editor is:
{{{
<<pasteUp [[partname::image]] noedit x:0px y:0px w:auto h:auto>>/%
image: [img(100%,auto)[path/file.ext]]
%/{{fontsize classname{
content
}}} 
}}}
* If no image is selected in the popup editor droplist, the image portion of the syntax, up to and including the "{{{%/}}}", is omitted.
* If neither fontsize nor classname is selected, the 'CSS wrapper' around the part content is omitted.
* Note: if you hand-edit the resulting tiddler content, avoid changing any [[PasteUpHelperPlugin]]-generated syntax that may surround your content, as this can prevent the plugin from correctly processing and displaying that content later on.
}}}
<<<
!!!Configuration
>see [[PasteUpConfig]] and related shadow tiddlers: [[DefaultPage]], [[DefaultPart]], [[PasteUpStylesheet]]
>optional installation: [[EditSectionPlugin]] and [[PasteUpHelperPlugin]]
!!!Examples
<<<
Inline, custom class, editable but not adjustable:
>{{{<<tiddler PasteUpPluginInfo##Sample1 "groupbox" edit>>}}}
><<tiddler PasteUpPluginInfo##Sample1 "groupbox" edit>>
Inline (initial position/size), editable and adjustable ("tear-off" to change position/size):
>{{{<<tiddler PasteUpPluginInfo##Sample1 "groupbox" edit adjust>>}}}
><<tiddler PasteUpPluginInfo##Sample1 "groupbox" edit adjust>>
Pasteup (custom position/size/style), editable and adjustable by default:
>{{{<<pasteUp PasteUpPluginInfo##Sample1 style:"border:1px solid blue;color:black;background:white;" x:4in y:-0.5in w:3in h:auto>>}}}
><<pasteUp PasteUpPluginInfo##Sample1 style:"border:1px solid blue;color:black;background:white;" x:4in y:-0.5in w:3in h:auto>>
Refrigerator magnets (custom size/style, not editable/adjustable, with editable/adjustable nested elements)
>{{{<<tiddler PasteUpPluginInfo##Fridge style:"display:block;border:1px solid;color:black;background:#ccc;" w:3in h:4in>>}}}
><<tiddler PasteUpPluginInfo##Fridge style:"display:block;border:1px solid;color:black;background:#ccc;" w:3in h:4in>>
Example section data:
>{{wrapper{
{{{
!Sample1
This content will be embedded ''inline'' using the extended parameters of the {{{<<tiddler>>}}} or {{{<<pasteUp>>}}} macros.
!!!!!!
}}}
{{{
!Fridge
My Refrigerator:
<<pasteUp PasteUpPluginInfo##MagnetA class:groupbox x:113px y:231px w:auto h:auto>>
<<pasteUp PasteUpPluginInfo##MagnetB class:groupbox x:90px y:47px w:auto h:auto>>
<<pasteUp PasteUpPluginInfo##MagnetC class:groupbox x:13px y:109px w:auto h:auto>>
!!!!MagnetA
Pizza Delivery
30 minutes or less
555-1212
!!!!MagnetB
Shopping: bread, milk, eggs
!!!!MagnetC
A1 Auto Body
123 Main Street
Somewhere, CA 91234
"We'll Fix You Up Good!"
!!!!!!
}}}
}}}
<<<
!!!Revisions
<<<
2011.04.27 1.1.1 merge/clone defaultCustomFields for saving on TiddlySpace
2011.03.19 1.1.0 re-factor mousetracking functions for cleaner event handling
2011.02.23 1.0.10 mousetracking: in capture(), invoke release() first (fix for Chrome 'sticky drag' problem?)
2011.02.08 1.0.9 when saving new tiddlers, use config.defaultCustomFields for TiddlySpace compatibility
2011.01.30 1.0.8 in addPart(), retain existing tags when adding part to current tiddler
2011.01.12 1.0.7 in handler(), make sure tiddler element was actually rendered
2011.01.11 1.0.6 corrected hijack of config.macros.tiddler.handler (avoids stepping on other plugins)
2011.01.03 1.0.5 in addPart(), allow parts to be created as sections of tiddlers or just stand-alone tiddlers
2010.12.31 1.0.4 added {{{<<addPasteUpPart label tip>>}}} macro (same as toolbar command)
2010.12.16 1.0.3 added chkPasteUpEditAll (for global editing) and 'snapshot' CSS class to shadow PasteUpStylesheet (for printing)
2010.12.12 1.0.2 corrected mouse capture for DRAG handling
2010.11.27 1.0.1 added shadows: DefaultPage, DefaultPart, PasteUpStylesheet.  Added PasteUpConfig for default pos/size of new parts and images. Added 'nopopup' keyword (bypasses EditSectionPlugin)
2010.11.15 1.0.0 complete re-write and initial release
2010.11.01 0.9.5 helper controls
2010.10.25 0.9.0 mouse handling
2010.07.23 0.8.0 lots of fixes
2010.07.21 0.7.5 alpha prototype (for review - do not distribute)
<<<
/%
|Name|PasteUpToolbar|
|Source|http://www.TiddlyTools.com/#PasteUpToolbar|
|Version|1.2.5|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Type|plugin|
|Description|PasteUp Quickstart command toolbar for use within ViewTemplate|

%/<<tiddler PasteUpCommands##slideshow_toolbar	if:{{config.options.chkSlideshow}}>>/%
%/<<tiddler PasteUpCommands##addpart		if:{{!window.readOnly}}>>/%
%/<<tiddler PasteUpCommands##addpage		if:{{!window.readOnly}}>>/%
%/<<tiddler PasteUpCommands##deletepage		if:{{!window.readOnly}}>>
This package provides a toolbar of interactive 'power tools' that you can use while editing a tiddler to quickly insert TiddlyWiki tiddler links, images, macros, etc. or common formatting sequences directly into tiddler content, as well as perform other functions (such as find/replace, sort, split, convert, etc.) that can be used to modify the current tiddler's source content in a variety of ways.

<<tiddler QuickEditToolbar with: show>>
!!!!!Installation:
<<<
Individual ~QuickEdit buttons are defined in separate tiddlers (e.g., [[QuickEdit_replace]]) that have also been //transcluded// into a single toolbar definition named [[QuickEditToolbar]].  You can edit this definition to add, remove, or rearrange the toolbar buttons to best suit your needs, and then embed the [[QuickEditToolbar]] tiddler into your document's [[EditTemplate]], like this:
{{{
<div macro='tiddler QuickEditToolbar'></div>
}}}
Next, in order to support some of the formatting 'shortcuts' provided by the toolbar, add a reference to the shortcuts CSS class definitions in your [[StyleSheet]]:
{{{
[[StyleSheetShortcuts]]
}}}
By default, the QuickEdit toolbar is hidden until you enable it by using the ''toggleQuickEdit'' command, which you can add to the ~EditToolbar definition in [[ToolbarCommands]]:
{{{
|EditToolbar|... toggleQuickEdit ...|
}}}
You can also toggle the ~QuickEdit toolbar display via a single checkbox option that can be added to [[SideBarOptions]] (or any other desired location):
{{{
<<option chkShowQuickEdit>> show QuickEdit toolbar
}}}
Note: You can 'hard-code' the ''chkShowQuickEdit'' setting, so that the toolbar will be //initially// displayed, by creating a tiddler (e.g., ConfigTweaks), tagged with <<tag systemConfig>>, containing:
{{{
config.options.chkShowQuickEdit=true;
}}}
Alternatively, if you want the toolbar to //always// be displayed, regardless of the option setting, you can add a special keyword, ''show'', to the [[EditTemplate]] syntax, like this:
{{{
<div macro='tiddler QuickEditToolbar with: show'></div>
}}}
<<<
/***
|Name|QuickEditPlugin|
|Source|http://www.TiddlyTools.com/#QuickEditPlugin|
|Documentation|http://www.TiddlyTools.com/#QuickEditPlugin|
|Version|2.4.4|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Support functions for ~QuickEdit package: styles, utility functions, and 'toggleQuickEdit' command|
!!!!!Revisions
<<<
2011.02.14 2.4.4 fix OSX error: use picker.file.path
2009.06.11 2.4.3 added keyup() function to abbreviate listbox handling for CR and ESC
2009.05.07 2.4.2 added processed() function to abbreviate event handler code
2008.09.07 2.4.1 added removeCookie() function for compatibility with [[CookieManagerPlugin]]
2008.05.17 2.4.0 copied code from StickyPopupPlugin to remove dependency
2008.05.12 2.3.0 added "toggleQuickEdit" command handler (replaces inline script command)
2008.01.11 2.2.0 converted from inline script
2007.03.29 1.0.0 initial release (as inline script)
<<<
!!!!!Code
***/
//{{{
version.extensions.QuickEditPlugin= {major: 2, minor: 4, revision: 4, date: new Date(2011,2,14)};

// SET STYLESHEET
setStylesheet("\
.quickEdit a { border:2px outset ButtonFace; padding:0px 3px !important; \
	-moz-border-radius:.5em; -webkit-border-radius:.5em; \
	-moz-appearance:button !important; -webkit-appearance:push-button !important; \
	background-color:ButtonFace; color:ButtonText !important;  \
	line-height:200%; font-weight:normal; } \
.quickEdit a:hover { border: 2px inset ButtonFace; background-color:ButtonFace; }\
", "quickEditStyles");

// REMOVE COOKIE
if (window.removeCookie===undefined) {
	window.removeCookie=function(name) {
		document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
	}
}

// UTILITY FUNCTIONS
config.quickEdit = {
	processed: function(ev) { ev=ev||window.event;
		ev.cancelBubble=true;
		if(ev.stopPropagation) ev.stopPropagation();
		return false;
	},
	keyup: function(ev){ var k=(ev||window.event).keyCode;
		if (k==13) this.onclick();
		if (k==27) Popup.remove();
	},
	getField: function(where) {
		var here=story.findContainingTiddler(where); if (!here) return null;
		var e=story.getTiddlerField(here.getAttribute("tiddler"),"text");
		if (e&&e.getAttribute("edit")=="text") return e;
		return null;
	},
	setSelection: function(where,newtext) {
		var e=this.getField(where); if (!e) return false;
		e.focus(); replaceSelection(e,newtext);
		return false;
	},
	wrapSelection: function(where,before,after) {
		var e=this.getField(where); if (!e) return false;
		e.focus(); replaceSelection(e,before+config.quickEdit.getSelection(e)+after);
		return false;
	},
	getSelection: function(e) {
		var seltext="";
		if (e&&e.setSelectionRange)
			seltext=e.value.substr(e.selectionStart,e.selectionEnd-e.selectionStart);
		else if (document.selection) {
			var range = document.selection.createRange();
			if (range.parentElement()==e) seltext=range.text
		}
		return seltext;
	},
	promptForFilename: function(msg,path,file) {
		if(window.Components) { // moz
			try {
				netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
				var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
				var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
				picker.init(window, msg, nsIFilePicker.modeOpen);
				var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
				thispath.initWithPath(path);
				picker.displayDirectory=thispath;
				picker.defaultExtension='jpg';
				picker.defaultString=file;
				picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterImages);
				if (picker.show()!=nsIFilePicker.returnCancel)
					var result="file:///"+picker.file.path.replace(/\\/g,'/');
			}
			catch(e) { alert('error during local file access: '+e.toString()) }
		}
		else { // IE
			try { // XP only
				var s = new ActiveXObject('UserAccounts.CommonDialog');
				s.Filter='All files|*.*|JPG files|*.jpg|GIF files|*.gif|PNG files|*.png|';
				s.FilterIndex=1; // default to JPG
				s.InitialDir=path;
				s.FileName=file;
				if (s.showOpen()) var result=s.FileName;
			}
			catch(e) { var result=prompt(msg,path+file); } // fallback for non-XP IE
		}
		return result;
	}
}
//}}}

//{{{
if (config.options.chkShowQuickEdit===undefined) config.options.chkShowQuickEdit=false;
config.commands.toggleQuickEdit = {
	hideReadOnly: true,
	getText: function() { return config.options.chkShowQuickEdit?'\u221Aquickedit':'quickedit'; },

	tooltip: 'show QuickEdit toolbar buttons',
	handler: function(event,src,title) {
		var opt='chkShowQuickEdit';
		config.options[opt]=!config.options[opt];
		config.macros.option.propagateOption(opt,"checked", config.options[opt],"input");
		if (config.options[opt]) saveOptionCookie(opt);	else removeCookie(opt);
		src.innerHTML=config.commands.toggleQuickEdit.getText();
		story.forEachTiddler(function(t,e){if (story.isDirty(t)) refreshElements(e);});
		return false;
	}
};
//}}}

// // COPIED FROM [[StickyPopupPlugin]] TO ELIMINATE PLUGIN DEPENDENCY
//{{{
if (config.options.chkStickyPopups==undefined) config.options.chkStickyPopups=false;
Popup.stickyPopup_onDocumentClick = function(ev)
{
	// if click is in a sticky popup, ignore it so popup will remain visible
	var e = ev ? ev : window.event; var target = resolveTarget(e);
	var p=target; while (p) {
		if (hasClass(p,"popup") && (hasClass(p,"sticky")||config.options.chkStickyPopups)) break;
		else p=p.parentNode;
	}
	if (!p) // not in sticky popup (or sticky popups disabled)... use normal click handling
		Popup.onDocumentClick(ev);
	return true;
};
try{removeEvent(document,"click",Popup.onDocumentClick);}catch(e){};
try{addEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
//}}}
/%
|Name|QuickEditToolbar|
|Source|http://www.TiddlyTools.com/#QuickEditToolbar|
|Version|2.4.4|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.2|
|Type|transclusion|
|Requires|QuickEditPlugin|
|Optional|QuickEdit_*|
|Description|format/insert TiddlyWiki content using toolbar buttons|

Usage:
* install [[QuickEditPlugin]] (runtime support functions)

* add the toolbar to [[EditTemplate]]:
	<div macro='tiddler QuickEditToolbar with: show'></div>

* 'show' (optional) forces the toolbar to always be displayed or,
  omit keyword and use <<option chkShowQuickEdit>> setting

* selected QuickEdit buttons can also be added individually to the
  regular tiddler toolbar by adding references directly in [[EditTemplate]]:
	<span class='toolbar' macro='tiddler QuickEdit_...'></span>

* see [[QuickEditPackage]] for additional installation options

%/{{hidden fine center quickEdit{
<<tiddler {{ // show/hide toolbar
	var here=story.findContainingTiddler(place); if (here) var tid=here.getAttribute('tiddler');
	var show='$1'!='$'+'1'||config.options.chkShowQuickEdit||tid=='QuickEditToolbar'; 
	place.style.display=show?'block':'none';
'';}}>>/%

TOOLBAR DEFINITION - add, remove, or re-order items as desired:
= = = = = = = = = =
%/<<tiddler QuickEdit_format>>/%
%/<<tiddler QuickEdit_align>>/%
%/<<tiddler QuickEdit_color>>/%
%/<<tiddler QuickEdit_font>>/%
%/<<tiddler QuickEdit_custom>>/%
%/ &nbsp;/% (SPACER)
%/<<tiddler QuickEdit_replace>>/%
%/<<tiddler QuickEdit_split>>/%
%/<<tiddler QuickEdit_sort>>/%
%/<<tiddler QuickEdit_convert>>/%
%/ &nbsp;/% (SPACER)
%/<<tiddler QuickEdit_link>>/%
%/<<tiddler QuickEdit_insert>>/%
%/<<tiddler QuickEdit_macro>>/%
%/<<tiddler QuickEdit_image>>/%
%/}}}
/%
|Name|QuickEdit_align|
|Source|http://www.TiddlyTools.com/#QuickEdit_align|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - text alignment|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="justér tekst"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('vælg tekstjustering...','');
	s.options[s.length]=new Option('venstre','left');
	s.options[s.length-1].title='{{left{...}}}';
	s.options[s.length]=new Option('centrer','center');
	s.options[s.length-1].title='{{center{...}}}';
	s.options[s.length]=new Option('højre','right');
	s.options[s.length-1].title='{{right{...}}}';
	s.options[s.length]=new Option('ret','justify');
	s.options[s.length-1].title='{{justify{...}}}';
	s.options[s.length]=new Option('flyd til venstre','floatleft');
	s.options[s.length-1].title='{{floatleft{...}}}';
	s.options[s.length]=new Option('flyd til højre','floatright');
	s.options[s.length-1].title='{{floatright{...}}}';
	s.size=s.length;
	s.onclick=function(){ if (!this.value.length) return;
		config.quickEdit.wrapSelection(this.button,'{{'+this.value+'{','}}}');
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s.focus();
	return config.quickEdit.processed(event);"
>justér</a></html>
/%
|Name|QuickEdit_color|
|Source|http://www.TiddlyTools.com/#QuickEdit_color|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - text/background color|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="tekst/baggrundsfarve - @@color:#RGB;background-color:#RGB;...@@"
onclick="var p=Popup.create(this,null,'popup sticky smallform'); if (!p) return false;
 	p.style.padding='2px';
	function hex(d) { return '0123456789ABCDEF'.substr(d,1); }
	var fg=createTiddlyElement(p,'select'); fg.button=this;
	fg.style.width='12em';
	fg.options[0]=new Option('tekstfarve...','');
	fg.options[1]=new Option('\xa0 eller skriv en værdi','_ask');
	fg.options[2]=new Option('\xa0 eller brug standardfarve','');
	for (var r=0;r<16;r+=3) for (var g=0;g<16;g+=3) for (var b=0;b<16;b+=3) {
		var label=hex(r)+hex(g)+hex(b);
		fg.options[fg.length]=new Option(label,'#'+label);
		fg.options[fg.length-1].style.color='#'+label;
	}
	fg.onchange=function(){ var val=this.value;
		if (val=='_ask') { val=prompt('Skriv en CSS farveværdi');
		if (!val||!val.length) return false; }
		this.options[0].value=val; this.options[0].text=val.length?'text: '+val:'text color...';
		var bg=this.nextSibling;
		for (var i=3;i<bg.options.length;i++) bg.options[i].style.color=val;
		var preview=this.nextSibling.nextSibling.nextSibling;
		var t=config.quickEdit.getSelection(config.quickEdit.getField(this.button));
		t=t.replace(/^@@(color\:.+;)?(background-color\:.+;)?/,'').replace(/@@$/,'');
		if (!t.length) t='~AaBbCcDdEeFfGgHhIiJj 1234567890';
		var fg=this.value; if (fg.length) fg='color:'+fg+';';
		var bg=this.nextSibling.value; if (bg.length) bg='background-color:'+bg+';';
		if (fg.length||bg.length) t='@@'+fg+bg+t+'@@';
		removeChildren(preview); wikify(t,preview);
		this.selectedIndex=0; return false;
	};
	var bg=createTiddlyElement(p,'select'); bg.button=this;
	bg.style.width='12em';
	bg.options[0]=new Option('baggrundsfarve...','');
	bg.options[1]=new Option('\xa0 eller skriv en værdi','_ask');
	bg.options[2]=new Option('\xa0 eller brug standardfarve','');
	for (var r=0;r<16;r+=3) for (var g=0;g<16;g+=3) for (var b=0;b<16;b+=3) {
		var label=hex(15-r)+hex(15-g)+hex(15-b);
		bg.options[bg.length]=new Option(label,'#'+label);
		bg.options[bg.length-1].style.backgroundColor='#'+label;
	}
	bg.onchange=function(){ var val=this.value;
		if (val=='_ask') { val=prompt('Skriv en CSS farveværdi');
		if (!val||!val.length) return false; }
		this.options[0].value=val;
		this.options[0].text=val.length?'background: '+val:'baggrundsfarve...';
		var fg=this.previousSibling;
		for (var i=3;i<fg.options.length;i++) fg.options[i].style.backgroundColor=val;
		var preview=this.nextSibling.nextSibling;
		var t=config.quickEdit.getSelection(config.quickEdit.getField(this.button));
		t=t.replace(/^@@(color\:.+;)?(background-color\:.+;)?/,'').replace(/@@$/,'');
		if (!t.length) t='~AaBbCcDdEeFfGgHhIiJj 1234567890';
		var fg=this.previousSibling.value; if (fg.length) fg='color:'+fg+';';
		var bg=this.value; if (bg.length) bg='background-color:'+bg+';';
		if (fg.length||bg.length) t='@@'+fg+bg+t+'@@';
		removeChildren(preview); wikify(t,preview);
		this.selectedIndex=0; return false;
	};
	var b=createTiddlyElement(p,'input',null,null,null,{type:'button'}); b.button=this;
	b.value='ok'; b.style.width='4em';
	b.onclick=function() {
		var fg=this.previousSibling.previousSibling.value; if (fg.length) fg='color:'+fg+';';
		var bg=this.previousSibling.value; if (bg.length) bg='background-color:'+bg+';';
		var t=config.quickEdit.getSelection(config.quickEdit.getField(this.button));
		t=t.replace(/^@@(color\:.+;)?(background-color\:.+;)?/,'').replace(/@@$/,'');
		if (fg.length||bg.length) config.quickEdit.setSelection(this.button,'@@'+fg+bg+t+'@@');
		Popup.remove(); return false;
	};
	var preview=createTiddlyElement(p,'div',null,'viewer'); var s=preview.style;
	s.border='1px solid'; s.margin='2px'; s.width='24em'; s.padding='3px'; s.MozBorderRadius='3px';
	s.overflow='hidden'; s.textAlign='center'; s.whiteSpace='normal';
	var t=config.quickEdit.getSelection(config.quickEdit.getField(this));
	wikify(t.length?t:'~AaBbCcDdEeFfGgHhIiJj 1234567890',preview);
	Popup.show();
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>farve</a></html>
/%
|Name|QuickEdit_convert|
|Source|http://www.TiddlyTools.com/#QuickEdit_convert|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - convert between comma/tab-separated and TW table format|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="kovertér mellem komma/tab-separeret og TW tabelformat"
onclick="var e=config.quickEdit.getField(this);
	if (e) e.focus(); var txt=config.quickEdit.getSelection(e);
	if (txt.indexOf(',')+txt.indexOf('\t')+txt.indexOf('|')==-3) {
		alert('Vælg tekst der indeholder tabulatorer, kommaer, eller TiddlyWiki tabelsyntaks.');
		return false;
	}
	var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('vælg en konverter...','');
	if (txt.indexOf(',')!=-1) {
		s.options[s.length]=new Option('kommaer -> tabel','commasToTable');
		s.options[s.length]=new Option('kommaer -> tabulatorer','commasToTabs');
	}
	if (txt.indexOf('\t')!=-1) {
		s.options[s.length]=new Option('tabulatorer -> tabel','tabsToTable');
		s.options[s.length]=new Option('tabulatorer -> kommaer','tabsToCommas');
	}
	if (txt.indexOf('|')!=-1) {
		s.options[s.length]=new Option('tabel -> tabulatorer','tableToTabs');
		s.options[s.length]=new Option('tabel -> kommaer','tableToCommas');
	}
	s.size=s.length;
	s.onclick=function(){ if (!this.value.length) return;
	        var e=config.quickEdit.getField(this.button); if (!e) return false;
		e.focus(); var txt=config.quickEdit.getSelection(e);
		switch(this.value) {
			case 'tabsToTable':
				txt=txt.replace(/\t/g,'|').replace(/^|$/g,'|');
				txt=txt.replace(/\n/g,'|\n|').replace(/^\|$/g,'');
				break;
			case 'tableToTabs':
				txt=txt.replace(/\t/g,' ').replace(/\|/g,'\t');
				txt=txt.replace(/^\t/g,'').replace(/\t$/g,'');
				txt=txt.replace(/\n\t/g,'\n').replace(/\t\n/g,'\n');
				break;
			case 'commasToTable':
				txt=txt.replace(/,/g,'|').replace(/^|$/g,'|');
				txt=txt.replace(/\n/g,'|\n|').replace(/^\|$/g,''); 
				break;
			case 'tableToCommas':
				txt=txt.replace(/,/g,' ').replace(/\|/g,',');
				txt=txt.replace(/^,/g,'').replace(/,$/g,''); 
				txt=txt.replace(/\n,/g,'\n').replace(/,\n/g,'\n'); 
				break;
			case 'tabsToCommas':
				txt=txt.replace(/\t/g,',');
				break;
			case 'commasToTabs':
				txt=txt.replace(/,/g,'\t');
				break;
		}
		replaceSelection(e,txt);
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s.focus();
	return config.quickEdit.processed(event);"
>konvertér</a></html>
/%
|Name|QuickEdit_custom|
|Source|http://www.TiddlyTools.com/#QuickEdit_custom|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - custom defined formats|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

!help
Påmindelser:

Brugerdefinerede formater gemmes som en "HR-separeret liste" i [[QuickEdit_customList]], hvor den første linie af hvert listeemne er den 'etiket', der vises i rullelisten, efterfulgt af een eller flere linier af wiki indhold der skal sættes ind i tiddlerkilden.

Erstatningsmarkører  kan bruges til dynamisk at indsætte værdier i det formaterede resultat: $1 indsætter tiddler editorens aktuelt markerede tekst. $[[message|default value]] interactively prompts for a value to be inserted. $[[message|$1]] uses the selected text as the default value. $[[message|{{javascript}}]] calculates the default value using javascript code.
!end help

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" title="brugerdefinerede formater"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('vælg et brugerdefineret format...','');
	var items=store.getTiddlerText('QuickEdit_customList','').split('\n----\n');
	for (var i=0; i<items.length; i++) {
		if (!items[i].length) continue; var lines=items[i].split('\n');
		var label=lines.shift(); var val=lines.join('\n');
		s.options[s.length]=new Option(label,val); s.options[s.length-1].title=val;
	}
	s.options[s.length]=new Option('[Redigér brugerdefinerede formater...]','_edit');
	s.options[s.length-1].title='tilføj/skift brugerdefinerede formater...';
	s.size=Math.min(s.length,15);
	s.onclick=function(){ if (!this.value.length) return;
		if (this.value=='_edit') {
			alert(store.getTiddlerText('QuickEdit_custom##help'));
			story.displayTiddler(story.findContainingTiddler(this.button),
				'QuickEdit_customList',DEFAULT_EDIT_TEMPLATE);
		} else {
		        var e=config.quickEdit.getField(this.button); if (!e) return false;
			e.focus(); var txt=config.quickEdit.getSelection(e);
			replaceSelection(e, this.value.replace(/\$\x31/g,txt)
				.replace(/\$\[\[[^\]]+\]\]/g, function(t){
					x=t.substr(3,t.length-5).split('|');
					var msg=x[0]; var def=x[1]||'';
					if (def.startsWith('{{')) {
						try{def=eval(def.substr(2,def.length-4))} catch(ex){showException(ex)}
					}
					return prompt(msg,def)||'';
				})
			);
		}
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s.focus();
	return config.quickEdit.processed(event);"
>brugerdefineret</a></html>
timestamp
$[[enter a date|{{new Date().formatString('DDD, MMM DDth, YYYY hh12:0mm:0ssam')}}]]
----
scrollbox
@@display:block;height:10em;overflow:auto;$1@@@@display:block;text-align:right;^^scroll for more...^^@@
----
nested slider
+++[$1]<<tiddler $1>>===
----
big red
@@font-size:36pt;color:red;$1@@
----
wikilink
[[$1]]
----
ikon
{{span{$1<<setIcon $2.png "" notext>>}}}
----
iframe + menubox
<html><div <span class='menubox' style='float:center;margin:0em'<div align="center"><iframe src="$1" frameborder="0" width="100%" height="800"></iframe></div></html>
----
iframe
<html><div align="center"><iframe src="$1" frameborder="0" width="100%" height="600"></iframe></div></html>
----
Hurtig fET tabel
<<forEachTiddler where 'tiddler.tags.contains("$1")'
sortBy 'tiddler.title'
write 
 '(index < 600)? "|!"+(index+1)+"|[["+tiddler.title+"]] |\n" : ""'
              begin '"|sortable|k\n" 
+"| !antal | !<<tag $1\>\> |h\n"' 
end 'count+" tiddlere tagget med $1\n"' none '"ingen tiddlere tagget med $1 \n"'>>
----
fET TagTilTabs
<<forEachTiddler
    where
       'tiddler.tags.contains("$1")'

    sortBy
       'tiddler.title.toUpperCase()'

    write '" [["+tiddler.title+" ]] \"view ["+tiddler.title+"]\" [["+tiddler.title+"]] "'

        begin '"<<tabs txtMyAutoTab "'

        end '">"+">"'

        none '"//Ingen tiddlere er tagget med \"$1\"//"'
>>
----
Tiddlermakro
<<tiddler $1>>
----
Billede
[img(100%+,auto)[$1]]
----
ShowPopup
<<tiddler ShowPopup with: $1[[Klik]][[Se i popup her]] button>>
----
Ryk ned og gør til overskrift

$1h
/%
|Name|QuickEdit_font|
|Source|http://www.TiddlyTools.com/#QuickEdit_font|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - select font family|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="vælg en fontfamilie CSS attribut - @@font-family:facename;...@@"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('vælg en fontfamilie...','');
	var fonts=store.getTiddlerText('QuickEdit_fontList','').split('\n');
	for (var i=0; i<fonts.length; i++) {
		if (!fonts[i].length) continue;
		s.options[s.length]=new Option(fonts[i],fonts[i]);
		s.options[s.length-1].style.fontFamily=fonts[i];
	}
	s.options[s.length]=new Option('[Redigér listen over fonte...]','_edit');
	s.options[s.length-1].title='skriv fontnavn, et pr linie...';
	s.size=Math.min(s.length,15);
	s.onclick=function(){
		if (this.value=='_edit')
			story.displayTiddler(story.findContainingTiddler(this.button),'QuickEdit_fontList',DEFAULT_EDIT_TEMPLATE);			
		else
			config.quickEdit.wrapSelection(this.button,'@@font-family:\x22'+this.value+'\x22;','@@');
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s.focus();
	return config.quickEdit.processed(event);"
>fonte</a></html>
Arial,helvetica,sans-serif
Arial Black,Gadget,sans-serif
Bookman Old Style,serif
Comic Sans MS,cursive
Courier,monospaced
Courier New,Courier,monospaced
Garamond,serif
Georgia,serif
Impact,Charcoal,sans-serif
Lucida Console,Monaco,monospaced
Lucida Sans Unicode,Lucida Grande,sans-serif
MS Sans Serif,Geneva,sans-serif
MS Serif,New York,sans-serif
Palatino Linotype,Book Antiqua,Palatino,serif
Symbol,sans-serif
Tahoma,Geneva,sans-serif
Times New Roman,Times,serif
Trebuchet MS,Helvetica,sans-serif
Verdana,Geneva,sans-serif
Webdings,sans-serif
Wingdings,Zapf Dingbats,sans-serif 
/%
|Name|QuickEdit_format|
|Source|http://www.TiddlyTools.com/#QuickEdit_format|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - basic text formats, headings, blockquotes, etc.|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="ren tekst (fjern AL formatering)" accesskey="P" 
onclick="var e=config.quickEdit.getField(this); if (e) e.focus(); var txt=config.quickEdit.getSelection(e);
	config.quickEdit.setSelection(e,wikifyPlainText(txt)); return false;"
>&nbsp;~&nbsp;</a></html>/%

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="''fed''" accesskey="F"
onclick="config.quickEdit.wrapSelection(this,'\x27\x27','\x27\x27'); return false;"
>&nbsp;F&nbsp;</a></html>/%

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="//kursiv//" accesskey="K" 
onclick="config.quickEdit.wrapSelection(this,'//','//'); return false;"
>&nbsp;K&nbsp;</a></html>/%

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="__understreg__" accesskey="U" 
onclick="config.quickEdit.wrapSelection(this,'__','__'); return false;"
>&nbsp;U&nbsp;</a></html>/%

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="--gennemstreg--" accesskey="G" 
onclick="config.quickEdit.wrapSelection(this,'--','--'); return false;"
>&nbsp;G&nbsp;</a></html>/%

%/ &nbsp;/%  SPACER

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="formatér tekst"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('vælg tekst format...','');
	s.options[s.length]=new Option('CSS klasse indpakning','{{$1{,}}},Skriv et CSS klassenavn');
	s.options[s.length-1].title='CSS klasse indpakning - {{klassenavn klassenavn etc{...}}}';
	s.options[s.length]=new Option('inline CSS stilarter','@@$1,@@,Skriv CSS (attribut:værdi;attribut:værdi;...;)');
	s.options[s.length-1].title='inline CSS stilarter - @@attr:value;attr:value;...@@';
	s.options[s.length]=new Option('overskrift 1','\n!,\n');
	s.options[s.length-1].title='H1 heading - !';
	s.options[s.length]=new Option('overskrift 2','\n!!,\n');
	s.options[s.length-1].title='H2 heading - !!';
	s.options[s.length]=new Option('overskrift 3','\n!!!,\n');
	s.options[s.length-1].title='H3 heading - !!!';
	s.options[s.length]=new Option('overskrift 4','\n!!!!,\n');
	s.options[s.length-1].title='H4 heading - !!!!';
	s.options[s.length]=new Option('overskrift 5','\n!!!!!,\n');
	s.options[s.length-1].title='H5 heading - !!!!!';
	s.options[s.length]=new Option('blockquote','\n\<\<\<\n,\n\<\<\<\n');
	s.options[s.length-1].title='indskudt blokcitat - \<\<\<';
	s.options[s.length]=new Option('monospaced','{{{,}}}');
	s.options[s.length-1].title='inline monospaced tekst - {{{...}}}';
	s.options[s.length]=new Option('ren tekst','\n{{{\n,\n}}}\n');
	s.options[s.length-1].title='multi-linie monospaced tekst boks - {{{...}}}';
	s.options[s.length]=new Option('superscript','^^,^^');
	s.options[s.length-1].title='^^superscript^^';
	s.options[s.length]=new Option('subscript','~~,~~');
	s.options[s.length-1].title='~~subscript~~';
	s.options[s.length]=new Option('HTML','<html>,<\x2fhtml>');
	s.options[s.length-1].title='HTML syntaks - <html>...<\x2fhtml>';
	s.options[s.length]=new Option('kommentar','/%,%/');
	s.options[s.length-1].title='kommentar (skjult indhold) - /%...%/';
	s.size=s.length;
	s.onclick=function(){ if (!this.value.length) return;
		var parts=this.value.split(',');
		var prefix=parts[0]; var suffix=parts[1]; var ask=parts[2];
		if (ask) {
			var val=prompt(ask); if (!val) { Popup.remove(); return false; }
			prefix=prefix.replace(/\$1/g,val); suffix=suffix.replace(/\$1/g,val);
		}
		config.quickEdit.wrapSelection(this.button,prefix,suffix);
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s.focus();
	return config.quickEdit.processed(event);"
>formatér</a></html>
/%
|Name|QuickEdit_image|
|Source|http://www.TiddlyTools.com/#QuickEdit_image|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - embed an image|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
	title="indsæt et billede (jpg/gif/png) - [img[værktøjstip|URL]] eller [img[værktøjstip|sti/til/fil.filtype]]"
	onclick="var fn=config.quickEdit.promptForFilename(
		'Skriv/vælg en billedfil',getLocalPath(document.location.href),'');
	if (!fn) return false;  /* cancelled by user */
	var h=document.location.href; var p=decodeURIComponent(h.substr(0,h.lastIndexOf('/')+1));
	if (fn.startsWith(p)) fn=fn.substr(p.length); /* use RELATIVE path/filename.ext */
	var tip=prompt('Enter a tooltip for this image',''); if (!tip) tip=''; else tip+='|';
	return config.quickEdit.setSelection(this,'[img['+tip+fn+']]');"
>billede</a></html>
/%
|Name|QuickEdit_insert|
|Source|http://www.TiddlyTools.com/#QuickEdit_insert|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - insert content from another tiddler or external file|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="indsæt indhold fra en anden tiddler eller ekstern fil"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';

	var s2=createTiddlyElement(p,'select'); s2.title='filtrer efter tag';
	s2.options[0]=new Option('filtrer efter tag...','');
	s2.options[s2.length]=new Option('[alle tiddlere]','');
	var tags=store.getTags();
	for (var t=0; t<tags.length; t++) s2.options[s2.length]=new Option(tags[t][0],tags[t][0]);
	s2.onchange=function(){
		var tag=this.value;
		var tids=tag.length?store.reverseLookup('tags',tag,true):store.reverseLookup('tags','excludeLists');
		var list=this.nextSibling.nextSibling;
		while (list.length) list.options[0]=null;
		var prompt='select a tiddler or file...';
		if (tag.length) prompt='vælg en tagget tiddler ['+tids.length+' matches]...';
		list.options[0]=new Option(prompt,'');
		if (!tag.length) list.options[list.length]=new Option('[gennemse...]','_file');
		for (var t=0; t<tids.length; t++) {
			list.options[list.length]=new Option(tids[t].title,tids[t].title);
			list.options[list.length-1].title=tids[t].getSubtitle();
		}
		list.size=Math.min(list.length,10);
		list.selectedIndex=0; list.focus();
		this.style.width=list.offsetWidth+'px';
		if (!tag.length) this.selectedIndex=0;
	};
	createTiddlyElement(p,'br');

	var s=createTiddlyElement(p,'select'); s.button=this;
	s.title='select a tiddler or file';
	s.options[0]=new Option('vælg en tiddler eller fil...','');
	s.options[s.length]=new Option('[gennemse...]','_file');
	var tids=store.reverseLookup('tags','excludeLists');
	for (var t=0; t<tids.length; t++) {
		s.options[s.length]=new Option(tids[t].title,tids[t].title);
		s.options[s.length-1].title=tids[t].getSubtitle();
	}
	s.size=Math.min(s.length,10);
	s.onclick=function(){ if (!this.value.length) return false;
		if (this.value=='_file') {
			var fn=config.quickEdit.promptForFilename(
				'Enter/select a text file',getLocalPath(document.location.href),'');
			if (!fn) return false; /* cancelled by user */
			var txt=loadFile(getLocalPath(fn));
			if (!txt) { alert('Fejl: kan ikke læse indholdet fra \0027'+fn+'\0027'); return; }
		}
		else var txt=store.getTiddlerText(this.value);
		if (!txt) {
			displayMessage(this.value+' ikke fundet');
			this.selectedIndex=0; this.focus();
			return false;
		}
		config.quickEdit.setSelection(this.button,txt);
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s2.style.width=s.offsetWidth+'px';
	s.focus();
	return config.quickEdit.processed(event);"
>indsæt</a></html>
/%
|Name|QuickEdit_link|
|Source|http://www.TiddlyTools.com/#QuickEdit_link|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - link to tiddler or external file|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="add a link to a tiddler or external file - [[link text|TiddlerName]]"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';

	var s2=createTiddlyElement(p,'select'); s2.title='filter by tag';
	s2.options[0]=new Option('filter by tag...','');
	s2.options[s2.length]=new Option('[all tiddlers]','');
	var tags=store.getTags();
	for (var t=0; t<tags.length; t++) s2.options[s2.length]=new Option(tags[t][0],tags[t][0]);
	s2.onchange=function(){
		var tag=this.value;
		var tids=tag.length?store.reverseLookup('tags',tag,true):store.reverseLookup('tags','excludeLists');
		var list=this.nextSibling.nextSibling;
		while (list.length) list.options[0]=null;
		var prompt='select a tiddler or file...';
		if (tag.length) prompt='select a tagged tiddler ['+tids.length+' matches]...';
		list.options[0]=new Option(prompt,'');
		if (!tag.length) list.options[list.length]=new Option('[browse for file...]','_file');
		for (var t=0; t<tids.length; t++) {
			list.options[list.length]=new Option(tids[t].title,tids[t].title);
			list.options[list.length-1].title=tids[t].getSubtitle();
		}
		list.size=Math.min(list.length,10);
		list.selectedIndex=0; list.focus();
		this.style.width=list.offsetWidth+'px';
		if (!tag.length) this.selectedIndex=0;
	};
	createTiddlyElement(p,'br');

	var s=createTiddlyElement(p,'select'); s.button=this;
	s.title='select a tiddler or file';
	s.options[0]=new Option('select a tiddler or file...','');
	s.options[s.length]=new Option('[browse for file...]','_file');
	var tids=store.reverseLookup('tags','excludeLists');
	for (var t=0; t<tids.length; t++) {
		s.options[s.length]=new Option(tids[t].title,tids[t].title);
		s.options[s.length-1].title=tids[t].getSubtitle();
	}
	s.size=Math.min(s.length,10);
	s.onclick=function(){ if (!this.value.length) return false;
		var title=this.value; var txt=title;
		if (title=='_file') {
			title=config.quickEdit.promptForFilename('Select a file',
				getLocalPath(document.location.href),'');
			if (!title) { this.selectedIndex=0; this.focus(); return false; }
			var txt=title.substr(title.lastIndexOf('/')+1);
		}
		var txt=prompt('Enter the text to display for this link',txt);
		if (!txt) { this.selectedIndex=0; this.focus(); return false; }
		config.quickEdit.setSelection(this.button,'[['+txt+'|'+title+']]');
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s2.style.width=s.offsetWidth+'px';
	s.focus();
	return config.quickEdit.processed(event);"
>link</a></html>
/%
|Name|QuickEdit_macro|
|Source|http://www.TiddlyTools.com/#QuickEdit_macro|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - embed a macro with 'guide text'|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

Note:
Optional 'guideText' can be used to add suggested defaults/placeholders for specific macro parameters.
Add guideText to your own plugin-defined macros using:
	config.macros.macroName.guideText='guide text goes here';

%/<<tiddler {{
	/* define guide text for a few common TW core macros */
	config.macros.edit.guideText='fieldname #rows';
	config.macros.view.guideText='fieldname (link,wikified,date) format';
	config.macros.slider.guideText='cookie TiddlerName label tooltip';
	config.macros.option.guideText='(txtCookieName,chkCookieName)';
	config.macros.tiddler.guideText='TiddlerName with: params...';
	''; /* must return blank to suppress output */ }}>>/%

%/<html><hide linebreaks><a href='javascript:;' class='tiddlyLink' tabindex='-1' 
title='tilføj en makro - \<\<makroNavn ...\>\>'
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select a macro...','');
	var macros=[]; for (var m in config.macros) if (config.macros[m].handler) macros.push(m); macros.sort();
	for (var i=0; i<macros.length; i++) { var m=macros[i];
		var help=config.macros[m].guideText; if (!help) help=''; else help=' '+help;
		s.options[s.length]=new Option(m,m+help);
		s.options[s.length-1].title='\<\<'+m+help+'\>\>';
	}
	s.size=Math.min(s.length,15);
	s.onclick=function(){ if (!this.value.length) return;
		config.quickEdit.setSelection(this.button,'\<\<'+this.value+'\>\>');
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s.focus();
	return config.quickEdit.processed(event);"
>makro</a></html>
/%
|Name|QuickEdit_replace|
|Source|http://www.TiddlyTools.com/#QuickEdit_replace|
|Version|2.4.5|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - find/replace selected text with replacement text|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar
!!!Revisions
<<<
2010.12.26 2.4.5 fix use getField(this) to support hijacks by editSectionPlugin
<<<
%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="find/erstat valgt tekst med anden tekst"
onclick="var p=Popup.create(this,null,'popup sticky smallform'); if (!p) return false;
	var e=config.quickEdit.getField(this);
	var s=config.quickEdit.getSelection(e); 
	var t=createTiddlyElement(p,'input'); t.onfocus=function(){this.select()};
	t.value=s.length?s:'skriv måltekst';
	var r=createTiddlyElement(p,'input'); r.onfocus=function(){this.select()};
	r.value='skriv tekst der skal erstattes';
	var b=createTiddlyElement(p,'button',null,null,'?');
	b.style.width='2em';
	b.title='FIND/FIND NÆSTE måltekst';
	b.root=this;
	b.onclick=function(ev) { /* FIND */
		var e=config.quickEdit.getField(this.root);
		var t=this.previousSibling.previousSibling;
		var tv=t.value.replace(/\\t/mg,'\t').unescapeLineBreaks();
		e.focus();
		if (e.setSelectionRange) { /* MOZ */
			var newstart=e.value.indexOf(tv,e.selectionStart+1);
			if (newstart==-1) newstart=e.value.indexOf(tv); /* wrap around */
			if (newstart==-1) { alert('\u0022'+t.value+'\u0022 not found'); t.focus(); return; }
			e.setSelectionRange(newstart,newstart+tv.length);
			var linecount=e.value.split('\n').length;
			var thisline=e.value.substr(0,e.selectionStart).split('\n').length;
			e.scrollTop=Math.floor((thisline-1-e.rows/2)*e.scrollHeight/linecount);
		} else if (document.selection) { /* IE */
			var range=document.selection.createRange();
			if(range.parentElement()==e) {
				range.collapse(false);
				var found=false; try{found=range.findText(v,e.value.length,4)}catch(e){}
				if (found) range.select();
				else { alert('\u0022'+t.value+'\u0022 not found'); t.focus(); }
			}
		}
	};
	b=createTiddlyElement(p,'button',null,null,'=');
	b.style.width='2em';
	b.title='ERSTAT valgt tekst';
	b.root=this;
	b.onclick=function(ev) { /* REPLACE */
		var e=config.quickEdit.getField(this.root);
		var t=this.previousSibling.previousSibling.previousSibling;
		var r=this.previousSibling.previousSibling;
		var rv=r.value.replace(/\\t/mg,'\t').unescapeLineBreaks();
		if (   (e.selectionStart!==undefined && e.selectionEnd==e.selectionStart)
		    || (document.selection && document.selection.createRange().text==''))
			this.previousSibling.click(); /* no selection... do FIND first */
		if (   (e.selectionStart!==undefined && e.selectionEnd==e.selectionStart)
		    || (document.selection && document.selection.createRange().text==''))
			{ t.focus(); return; } /* still no selection... goto target input */
		e.focus(); replaceSelection(e,rv);
	};
	b=createTiddlyElement(p,'button',null,null,'+');
	b.style.width='2em';
	b.title='ERSTAT valgt tekst OG FIND NÆSTE MÅLTEKST';
	b.onclick=function(ev) { /* REPLACE and FIND NEXT */
		this.previousSibling.click();
		this.previousSibling.previousSibling.click();
	};
	b=createTiddlyElement(p,'button',null,null,'!');
	b.style.width='2em';
	b.title='ERSTAT ALLE forekomster af målteksten';
	b.root=this;
	b.onclick=function(ev) { /* REPLACE ALL */
		var e=config.quickEdit.getField(this.root);
		var t=this.previousSibling.previousSibling.previousSibling.previousSibling.previousSibling;
		var r=this.previousSibling.previousSibling.previousSibling.previousSibling;
		var tv=t.value.replace(/\\t/mg,'\t').unescapeLineBreaks();
		var rv=r.value.replace(/\\t/mg,'\t').unescapeLineBreaks();
		if (!tv.length) { alert('Please enter the target text'); t.focus(); return; }
		var m='Dette vil erstatte alle forekomster af:\n\n'+tv+'\n\nwith:\n\n'+rv+'\n\nEr du sikker?';
		if (!confirm(m)) { r.focus(); r.select(); return; }
		e.value=e.value.replace(new RegExp(tv.escapeRegExp(),'gm'),rv);
		e.focus(); e.select(); Popup.remove();
	};
	Popup.show();
	if (!s.length) {t.focus();t.select()} else {r.focus();r.select()}
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>erstat</a></html>
/%
|Name|QuickEdit_sort|
|Source|http://www.TiddlyTools.com/#QuickEdit_sort|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - sort lines of text|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="sortér tekstlinier"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('vælg sorteringsorden...','');
	s.options[s.length]=new Option('stigende','A');
	s.options[s.length-1].title='ascending';
	s.options[s.length]=new Option('faldende','D');
	s.options[s.length-1].title='descending';
	s.size=s.length;
	s.onclick=function(){ if (!this.value.length) return;
		var e=config.quickEdit.getField(this.button); if (!e) return false;
		var lines=config.quickEdit.getSelection(e).split('\n').sort();
		if (this.value=='D') lines=lines.reverse();
		replaceSelection(e,lines.join('\n'));
		e.focus();
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s.focus();
	return config.quickEdit.processed(event);"
>sortér</a></html>
/%
|Name|QuickEdit_split|
|Source|http://www.TiddlyTools.com/#QuickEdit_split|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - move selection to new tiddler and insert link, embedded tiddler, or slider|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

Based on ideas originally developed by YannPerrin
(http://yann.perrin.googlepages.com/twkd.html#easySlicer)

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="flyt det markerede til en ny tiddler og indsæt et link, en indlejret tiddler, eller en slider"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	p.style.whiteSpace='nowrap';
	var i=createTiddlyElement(p,'input');
	i.defaultValue='Skriv titelen på en ny tiddler';
	i.onfocus=function(){this.select()};
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('vælg type...','');
	s.options[0].title='vælg opdelingstype';
	s.options[1]=new Option('link','link');
	s.options[1].title='erstat med [[TiddlerNavn]]';
	s.options[2]=new Option('embed','embed');
	s.options[2].title='erstat med\<\<tiddler TiddlerName\>\>';
	s.options[3]=new Option('slider','slider');
	s.options[3].title='erstat med \<\<slider \u0022\u0022 [[TiddlerNavn]] [[etiket]] [[værktøjstip]]\>\>';
	s.onchange=function(){
		if (s.previousSibling.value==s.previousSibling.defaultValue)
			{ alert('A tiddler title is required'); s.selectedIndex=0; s.previousSibling.focus(); return false; }
		var tid=s.previousSibling.value;
		if (store.tiddlerExists(tid) && !confirm(config.messages.overwriteWarning.format([tid])))
			{ s.previousSibling.focus(); return false; }
		switch(s.value) {
			case 'link':
				var newtxt='[['+tid+']]';
				break;
			case 'embed':
				var newtxt='\<\<tiddler [['+tid+']]\>\>';
				break;
			case 'slider':
				var label=prompt('Skriv en slider-etiket',tid);
				if (!label) { Popup.remove(); return false; }
				var tip=prompt('Skriv et slider værktøjstip',label);
				if (!tip) { Popup.remove(); return false; }
				var newtxt='\<\<slider \u0022\u0022 [['+tid+']] [['+label+']] [['+tip+']]\>\>';
				break;
		}
		var txt=config.quickEdit.getSelection(config.quickEdit.getField(this.button));
		store.saveTiddler(tid,tid,txt,config.options.txtUserName,new Date(),[],{});
		story.displayTiddler(story.findContainingTiddler(this.button),tid);
		config.quickEdit.setSelection(this.button,newtxt);
		Popup.remove(); return false;
	};
	Popup.show();
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>opdel</a></html>
/***
|Name|SaveAsPlugin|
|Source|http://www.TiddlyTools.com/#SaveAsPlugin|
|Documentation|http://www.TiddlyTools.com/#SaveAsPluginInfo|
|Version|2.7.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Save current document to another path/filename|
!!!!!Documentation
<<<
see [[SaveAsPluginInfo]]
<<<
!!!!!Revisions
<<<
2011.02.14 2.7.1 fix OSX error: use picker.file.path
2009.10.13 2.7.0 added 'here' param (saves current tiddler)
2009.08.16 2.6.2 fixed handling for backstage
| Please see [[SaveAsPluginInfo]] for additional revision details |
2006.02.03 1.0.0 Created
<<<
!!!!!Code
***/
//{{{
version.extensions.SaveAsPlugin= {major: 2, minor: 7, revision: 1, date: new Date(2011,2,14)};

config.macros.saveAs = {
	label: 'gem som...',
	labelparam: 'label:',
	prompt: 'Gem dette dokument til en anden fil',
	promptparam: 'prompt:',
	filePrompt: 'Vælg eller skriv en sti/et filnavn',
	targetparam: 'mål:',
	defaultFilename: 'ny.html',
	filenameparam: 'filnavn:',
	currfilekeyword: 'her',
	typeparam: 'type:',
	type_TW: 'tw', type_PS: 'ps', type_TX: 'tx', type_CS: 'cs', type_NF: 'nf', // file type tokens
	type_map: {
		tiddlywiki:'tw', tw:'tw', wiki: 'tw',
		purestore: 'ps', ps:'ps', store:'ps',
		plaintext: 'tx', tx:'tx', text: 'tx',
		comma:     'cs', cs:'cs', csv:  'cs',
		newsfeed:  'nf', nf:'nf', xml:  'nf', rss:'nf'
	},
	limitparam: 'limit:',
	replaceparam: 'replace',
	mergeparam: 'merge',
	quietparam: 'quiet',
	openparam: 'open',
	askParam: 'ask',
	hereParam: 'here',
	askMsg: "Angiv et tag filter (brug * for alle tiddlere, 'none' for et tomt dokument)",
	hereMsg: 'Angiv en tiddlertitel',
	emptyParam: 'none',
	confirmmsg: "Fandt %0 tiddlere der matcher\n\n'%1'\n\nKlik OK for at fortsætte",
	mergeprompt: '%0\nindeholder alleredetiddlerdefinitioner.\n'
		+'\nKlik OK for at tilføje nye/reviderede tiddlere til den aktuelle fils indhold.'
		+'\nKlik fortrydfor at erstatte filens indhold fuldstændig',
	mergestatus: 'Flettede %0 nye/reviderede tiddlere og %1 allerede eksisterende tiddlere',
	okmsg: '%0 tiddlere skrevet til %1',
	failmsg: 'Der opstod en fejl da %1 skulle laves',
	filter: '',
	handler: function(place,macroName,params) {
		if ((params[0]||'').startsWith(this.labelparam))
			var label=params.shift().substr(this.labelparam.length);
		if ((params[0]||'').startsWith(this.promptparam))
			var prompt=params.shift().substr(this.promptparam.length);
		if ((params[0]||'').startsWith(this.targetparam))
			var target=params.shift().substr(this.targetparam.length);
		if ((params[0]||'').startsWith(this.filenameparam))
			var filename=params.shift().substr(this.filenameparam.length);
		if ((params[0]||'').startsWith(this.typeparam))
			var filetype=this.type_map[params.shift().substr(this.typeparam.length).toLowerCase()];
		if ((params[0]||'').startsWith(this.limitparam))
			var limit=params.shift().substr(this.limitparam.length);
		var q=((params[0]||'')==this.quietparam);   if (q) params.shift();
		var o=((params[0]||'')==this.replaceparam); if (o) params.shift();
		var m=((params[0]||'')==this.mergeparam);   if (m) params.shift();
		var a=((params[0]||'')==this.openparam);    if (a) params.shift();
		var btn=createTiddlyButton(place,label||this.label,prompt||this.prompt,
			function(){ config.macros.saveAs.go( this.getAttribute('target'),
				this.getAttribute('filename'), this.getAttribute('filetype'),
				this.getAttribute('filter'), this.getAttribute('limit'),
				this.getAttribute('quiet')=='true',
				this.getAttribute('overwrite')=='true',
				this.getAttribute('merge')=='true',
				this.getAttribute('autoopen')=='true',
				this);
				return false;
			});
		if (target) btn.setAttribute('target',target);
		if (filename) btn.setAttribute('filename',filename);
		btn.setAttribute('filetype',filetype||this.type_TW);
		btn.setAttribute('filter',params.join(' '));
		btn.setAttribute('limit',limit||0);
		btn.setAttribute('quiet',q?'true':'false');
		btn.setAttribute('overwrite',o?'true':'false');
		btn.setAttribute('merge',m?'true':'false');
		btn.setAttribute('autoopen',a?'true':'false');
	},
	go: function(target,filename,filetype,filter,limit,quiet,overwrite,merge,autoopen,here) {
		var cm=config.messages; // abbreviation
		var cms=config.macros.saveAs; // abbreviation
		if (window.location.protocol!='file:') // make sure we are local
			{ displayMessage(cm.notFileUrlError); return; }

		// get tidders, confirm filtered results
		var tids=cms.selectTiddlers(filter,here);
		if (tids===false) return; // cancelled by user
		if (cms.filter!=cms.emptyParam && cms.filter.length && !quiet)
			if (!confirm(cms.confirmmsg.format([tids.length,cms.filter]))) return;

		// get target path/filename
		if (!filetype) filetype=this.type_TW;
		target=target||cms.getTarget(filename,filetype==this.type_TX?'txt':filetype==this.type_CS?'csv':'html');
		if (!target) return; // cancelled by user

		var link='file:///'+target.replace(/\\/g,'/');
		var samefile=link==decodeURIComponent(window.location.href);
		var p=getLocalPath(document.location.href);
		if (samefile) {
			if (config.options.chkSaveBackups)
				{ var t=loadOriginal(p);if(t)saveBackup(p,t); }
			if (config.options.chkGenerateAnRssFeed && saveRss instanceof Function)
				saveRss(p);
		}
		var notes='';
		var total={val:0};
		var out=this.assembleFile(target,filetype,tids,limit||0,notes,quiet,overwrite,merge,total);
		var ok=saveFile(target,out);
		if (ok && autoopen) {
			if (!samefile) window.open(link).focus();
			else { store.setDirty(false); window.location.reload(); }
		}
		if (!quiet || !(ok && autoopen))
			displayMessage((ok?this.okmsg:this.failmsg).format([total.val,target]),link);
	},
	selectTiddlers: function(filter,here) {
		var cms=config.macros.saveAs; // abbreviation
		var tids=[]; cms.filter=filter||'';
		if (filter==cms.emptyParam)
			return tids;
		if (filter==config.macros.saveAs.hereParam) {
			var here=story.findContainingTiddler(here);
			if (here) var tid=here.getAttribute('tiddler');
			else var tid=prompt(config.macros.saveAs.hereMsg,'');
			while (tid && !store.tiddlerExists(tid)) {
				var err='"'+tid+'" not found.\nPlease try again.\n\n';
				var tid=prompt(err+config.macros.saveAs.hereMsg,tid);
			}
			if (!tid) return false;  // cancelled by user
			return [store.getTiddler(tid)];
		}
		if (filter==config.macros.saveAs.askParam) {
			filter=prompt(config.macros.saveAs.askMsg,'');
			if (!filter) return false;  // cancelled by user
			cms.filter=filter=='*'?'':filter;
		}
		if (!filter||!filter.length||filter=='*') tids=store.getTiddlers('title');
		else tids=store.filterTiddlers('[tag['+filter+']]');
		return tids;
	},
	getTarget: function(defName,defExt) {
		var cms=config.macros.saveAs; // abbreviation
		// get new target path/filename
		var newPath=getLocalPath(window.location.href);
		var slashpos=newPath.lastIndexOf('/'); if (slashpos==-1) slashpos=newPath.lastIndexOf('\\'); 
		if (slashpos!=-1) newPath=newPath.substr(0,slashpos+1); // trim filename
		if (!defName||!defName.length) { // use current filename as default
			var p=getLocalPath(window.location.href);
			var s=p.lastIndexOf('/'); if (s==-1) s=p.lastIndexOf('\\'); 
			if (s!=-1) defName=p.substr(s+1);
		}
		var defFilename=(defName||cms.defaultFilename).replace(/.html$/,'.'+defExt);
		var target=cms.askForFilename(cms.filePrompt,newPath,defFilename,defExt);
		if (!target) return; // cancelled by user
		// if specified file does not include a path, assemble fully qualified path and filename
		var slashpos=target.lastIndexOf('/'); if (slashpos==-1) slashpos=target.lastIndexOf('\\');
		if (slashpos==-1) target=target+(defName||cms.defaultFilename).replace(/.html$/,'.'+defExt);
		return target;
	},
	askForFilename: function(msg,path,file,defExt) {
		if(window.Components) { // moz
			try {
				netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
				var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
				var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
				picker.init(window, msg, nsIFilePicker.modeSave);
				var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
				thispath.initWithPath(path);
				picker.displayDirectory=thispath;
				picker.defaultExtension=defExt||'html';
				picker.defaultString=file;
				picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
				if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.path;
			}
			catch(e) { alert('error during local file access: '+e.toString()) }
		}
		else { // IE
			try { // XP/Vista only
				var s = new ActiveXObject('UserAccounts.CommonDialog');
				s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
				s.FilterIndex=(defExt=='txt')?2:3; // default to HTML files;
				s.InitialDir=path;
				s.FileName=file;
				if (s.showOpen()) var result=s.FileName;
			}
			catch(e) { var result=prompt(msg,path+file); } // fallback for non-XP IE
		}
		return result;
	},
	plainTextHeader:
		 'Source:\n\t%0\n'
		+'Title:\n\t%1\n'
		+'Subtitle:\n\t%2\n'
		+'Created:\n\t%3 by %4\n'
		+'Application:\n\tTiddlyWiki %5 / %6 %7\n\n',
	plainTextTiddler:
		'- - - - - - - - - - - - - - -\n'
		+'|     title: %0\n'
		+'|   created: %1\n'
		+'|  modified: %2\n'
		+'| edited by: %3\n'
		+'|      tags: %4\n'
		+'- - - - - - - - - - - - - - -\n'
		+'%5\n',
	plainTextFooter:
		'',
	newsFeedHeader:
		 '<'+'?xml version="1.0"?'+'>\n'
		+'<rss version="2.0">\n'
		+'<channel>\n'
		+'<title>%1</title>\n'
		+'<link>%0</link>\n'
		+'<description>%2</description>\n'
		+'<language>en-us</language>\n'
		+'<copyright>Copyright '+(new Date().getFullYear())+' %4</copyright>\n'
		+'<pubDate>%3</pubDate>\n'
		+'<lastBuildDate>%3</lastBuildDate>\n'
		+'<docs>http://blogs.law.harvard.edu/tech/rss</docs>\n'
		+'<generator>TiddlyWiki %5 / %6 %7</generator>\n',
	newsFeedTiddler:
		'\n%0\n',
	newsFeedFooter:
		'</channel></rss>',
	pureStoreHeader:
		 '<html><body>'
		+'<style type="text/css">'
		+'	#storeArea {display:block;margin:1em;}'
		+'	#storeArea div {padding:0.5em;margin:1em;border:2px solid black;height:10em;overflow:auto;}'
		+'	#pureStoreHeading {width:100%;text-align:left;background-color:#eeeeee;padding:1em;}'
		+'</style>'
		+'<div id="pureStoreHeading">'
		+'	TiddlyWiki "PureStore" export file<br>'
		+'	Source'+': <b>%0</b><br>'
		+'	Title: <b>%1</b><br>'
		+'	Subtitle: <b>%2</b><br>'
		+'	Created: <b>%3</b> by <b>%4</b><br>'
		+'	TiddlyWiki %5 / %6 %7<br>'
		+'	Notes:<hr><pre>%8</pre>'
		+'</div>'
		+'<div id="storeArea">',
	pureStoreTiddler:
		'%0\n%1',
	pureStoreFooter:
		'</div><!--POST-BODY-START-->\n<!--POST-BODY-END--></body></html>',
	assembleFile: function(target,filetype,tids,limit,notes,quiet,overwrite,merge,total) {
		var revised='';
		var now = new Date().toLocaleString();
		var src=convertUnicodeToUTF8(document.location.href);
		var title = convertUnicodeToUTF8(wikifyPlain('SiteTitle').htmlEncode());
		var subtitle = convertUnicodeToUTF8(wikifyPlain('SiteSubtitle').htmlEncode());
		var user = convertUnicodeToUTF8(config.options.txtUserName.htmlEncode());
		var twver = version.major+'.'+version.minor+'.'+version.revision;
		var v=version.extensions.SaveAsPlugin; var pver = v.major+'.'+v.minor+'.'+v.revision;
		var headerargs=[src,title,subtitle,now,user,twver,'SaveAsPlugin',pver,notes];
		switch (filetype) {
			case this.type_TX: // plain text
				var header=this.plainTextHeader.format(headerargs);
				var footer=this.plainTextFooter;
				break;
			case this.type_CS: // comma-separated
				var fields={};
				for (var i=0; i<tids.length; i++) for (var f in tids[i].fields) fields[f]=f;
				var names=['title','created','modified','modifier','tags','text'];
				for (var f in fields) names.push(f);
				var header=names.join(',')+'\n';
				var footer='';
				break;
			case this.type_NF: // news feed (XML)
				headerargs[0]=store.getTiddlerText('SiteUrl','');
				var header=this.newsFeedHeader.format(headerargs);
				var footer=this.newsFeedFooter;
				tids=store.sortTiddlers(tids,'-modified');
				break;
			case this.type_PS: // PureStore (no code)
				var header=this.pureStoreHeader.format(headerargs);
				var footer=this.pureStoreFooter;
				break;
			case this.type_TW: // full TiddlyWiki
			default:
				var currPath=getLocalPath(window.location.href);
				var original=loadFile(currPath);
				if (!original) { alert(config.messages.cantSaveError); return; }
				var posDiv = locateStoreArea(original);
				if (!posDiv) { alert(config.messages.invalidFileError.format([currPath])); return; }
				var header = original.substr(0,posDiv[0]+startSaveArea.length)+'\n';
				var footer = '\n'+original.substr(posDiv[1]);
				break;
		}
		if (parseInt(limit)!=0) tids=tids.slice(0,limit);
		var out=this.getData(target,filetype,tids,quiet,overwrite,merge,fields);
		var revised = header+convertUnicodeToUTF8(out.join('\n'))+footer;
		// if full TW, insert page title and language attr, and reset MARKUP blocks as needed...
		if (filetype==this.type_TW) {
			var newSiteTitle=convertUnicodeToUTF8(getPageTitle()).htmlEncode();
			revised=revised.replaceChunk('<title'+'>','</title'+'>',' ' + newSiteTitle + ' ');
			revised=updateLanguageAttribute(revised);
			var titles=[]; for (var i=0; i<tids.length; i++) titles.push(tids[i].title);
			revised=updateMarkupBlock(revised,'PRE-HEAD',
				titles.contains('MarkupPreHead')? 'MarkupPreHead' :null);
			revised=updateMarkupBlock(revised,'POST-HEAD',
				titles.contains('MarkupPostHead')?'MarkupPostHead':null);
			revised=updateMarkupBlock(revised,'PRE-BODY',
				titles.contains('MarkupPreBody')? 'MarkupPreBody' :null);
			revised=updateMarkupBlock(revised,'POST-SCRIPT',
				titles.contains('MarkupPostBody')?'MarkupPostBody':null);
		}
		total.val=out.length;
		return revised;
	},
	getData: function(target,filetype,tids,quiet,overwrite,merge,fields) {
		// output selected tiddlers and gather list of titles (for use with merge)
		var out=[]; var titles=[];
		var url=store.getTiddlerText('SiteUrl','');
		for (var i=0; i<tids.length; i++) {
			out.push(this.formatItem(store,filetype,tids[i],url,fields));
			titles.push(tids[i].title);
		}
		// if TW or PureStore format, ask to merge with existing tiddlers (if any)
		if (filetype==this.type_TW || filetype==this.type_PS) {
			if (overwrite) return out; // skip merge... forced overwrite
			var txt=loadFile(target);
			if (txt && txt.length) {
				var remoteStore=new TiddlyWiki();
				if (version.major+version.minor*.1+version.revision*.01<2.52) txt=convertUTF8ToUnicode(txt);
				if (remoteStore.importTiddlyWiki(txt) && (merge||confirm(this.mergeprompt.format([target])))) {
					var existing=remoteStore.getTiddlers('title');
					for (var i=0; i<existing.length; i++)
						if (!titles.contains(existing[i].title))
							out.push(this.formatItem(remoteStore,filetype,existing[i],url));
					if (!quiet) displayMessage(this.mergestatus.format([tids.length,out.length-tids.length]));
				}
			}
		}
		return out;
	},
	formatItem: function(s,f,t,u,fields) {
		if (f==this.type_TW)
			var r=s.getSaver().externalizeTiddler(s,t);
		if (f==this.type_PS)
			var r=this.pureStoreTiddler.format([t.title,s.getSaver().externalizeTiddler(s,t)]);
		if (f==this.type_NF)
			var r=this.newsFeedTiddler.format([t.saveToRss(u)]);
		if (f==this.type_TX)
			var r=this.plainTextTiddler.format([t.title, t.created.toLocaleString(), t.modified.toLocaleString(),
				t.modifier, String.encodeTiddlyLinkList(t.tags), t.text]);
		if (f==this.type_CS) {
			function toCSV(t) { return '"'+t.replace(/"/g,'""')+'"'; } // always encode CSV
			var out=[ toCSV(t.title), toCSV(t.created.toLocaleString()), toCSV(t.modified.toLocaleString()),
				toCSV(t.modifier), toCSV(String.encodeTiddlyLinkList(t.tags)), toCSV(t.text) ];
			for (var f in fields) out.push(toCSV(t.fields[f]||''));
			var r=out.join(',');
		}
		return r||'';
	}
};
//}}}
//{{{
// automatically add saveAs to backstage
config.tasks.saveAs = {
	text: 'gemSom',
	tooltip: config.macros.saveAs.prompt,
	action: function(){ clearMessage(); config.macros.saveAs.go(); }
}
config.backstageTasks.splice(config.backstageTasks.indexOf('save')+1,0,'saveAs');
//}}}
/***
|Name|SearchOptionsPlugin|
|Source|http://www.TiddlyTools.com/#SearchOptionsPlugin|
|Documentation|http://www.TiddlyTools.com/#SearchOptionsPluginInfo|
|Version|3.0.10|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|extend core search function with additional user-configurable options|
Adds extra options to core search function including selecting which data items to search, enabling/disabling incremental key-by-key searches, and generating a ''list of matching tiddlers'' instead of immediately displaying all matches.  This plugin also adds syntax for rendering 'search links' within tiddler content to embed one-click searches using pre-defined 'hard-coded' search terms.
!!!!!Documentation
>see [[SearchOptionsPluginInfo]]
!!!!!Configuration
<<<
<<tiddler SearchOptions>>
<<option chkSearchResultsOptions>> Include {{{options...}}} slider in "search again" form
<<<
!!!!!Revisions
<<<
2011.04.08 3.0.10 fixed typo in CSS in formatSearchResults_buttons().  Restore missing options in Configuration section.
|please see [[SearchOptionsPluginInfo]] for additional revision details|
2005.10.18 1.0.0 Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.SearchOptionsPlugin= {major: 3, minor: 0, revision: 10, date: new Date(2011,3,18)};
//}}}
//{{{
var defaults={
	chkSearchTitles:	true,
	chkSearchText:		true,
	chkSearchTags:		true,
	chkSearchFields:	true,
	chkSearchTitlesFirst:	true,
	chkSearchList:		true,
	chkSearchHighlight:	true,
	chkSearchListTiddler:	false,
	chkSearchByDate:	false,
	chkIncrementalSearch:	true,
	chkSearchShadows:	true,
	chkSearchOpenTiddlers:	false,
	chkSearchResultsOptions:true,
	chkSearchExcludeTags:	true,
	txtSearchExcludeTags:	'excludeSearch',
	txtIncrementalSearchDelay:	500,
	txtIncrementalSearchMin:	3
}; for (var id in defaults) if (config.options[id]===undefined)
	config.options[id]=defaults[id];
if (config.macros.search.reportTitle==undefined)
	config.macros.search.reportTitle="SearchResults"; // note: not a cookie!
config.macros.search.label+="\xa0"; // a little bit of space just because it looks better
//}}}
// // searchLink: {{{[search[text to find]] OR [search[text to display|text to find]]}}}
//{{{
config.formatters.push( {
	name: "searchLink",
	match: "\\[search\\[",
	lookaheadRegExp: /\[search\[(.*?)(?:\|(.*?))?\]\]/mg,
	prompt: "search for: '%0'",
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var label=lookaheadMatch[1];
			var text=lookaheadMatch[2]||label;
			var prompt=this.prompt.format([text]);
			var btn=createTiddlyButton(w.output,label,prompt,
				function(){story.search(this.getAttribute("searchText"))},"searchLink");
			btn.setAttribute("searchText",text);
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
});
//}}}
// // incremental search uses option settings instead of hard-coded delay and minimum input values
//{{{
var fn=config.macros.search.onKeyPress;
fn=fn.toString().replace(/500/g, "config.options.txtIncrementalSearchDelay||500");
fn=fn.toString().replace(/> 2/g, ">=(config.options.txtIncrementalSearchMin||3)");
eval("config.macros.search.onKeyPress="+fn);
//}}}
// // REPLACE story.search() for option to "show search results in a list"
//{{{
Story.prototype.search = function(text,useCaseSensitive,useRegExp)
{
	var co=config.options; // abbrev
	var re=new RegExp(useRegExp ? text : text.escapeRegExp(),useCaseSensitive ? "mg" : "img");
	if (config.options.chkSearchHighlight) highlightHack=re;
	var matches = store.search(re,co.chkSearchByDate?"modified":"title","");
	if (co.chkSearchByDate) matches=matches.reverse(); // most recent first
	var q = useRegExp ? "/" : "'";
	clearMessage();
	if (!matches.length) {
		if (co.chkSearchListTiddler) discardSearchResults();
		displayMessage(config.macros.search.failureMsg.format([q+text+q]));
	} else {
		if (co.chkSearchList||co.chkSearchListTiddler) 
			reportSearchResults(text,matches);
		else {
			var titles = []; for(var t=0; t<matches.length; t++) titles.push(matches[t].title);
			this.closeAllTiddlers(); story.displayTiddlers(null,titles);
			displayMessage(config.macros.search.successMsg.format([matches.length, q+text+q]));
		}
	}
	highlightHack = null;
}
//}}}
// // REPLACE store.search() for enhanced searching/sorting options
//{{{
TiddlyWiki.prototype.search = function(searchRegExp,sortField,excludeTag,match)
{
	var co=config.options; // abbrev
	var tids = this.reverseLookup("tags",excludeTag,!!match,sortField);
	var opened=[]; story.forEachTiddler(function(tid,elem){opened.push(tid);});

	// eliminate tiddlers tagged with excluded tags
	if (co.chkSearchExcludeTags&&co.txtSearchExcludeTags.length) {
		var ex=co.txtSearchExcludeTags.readBracketedList();
		var temp=[]; for(var t=tids.length-1; t>=0; t--)
			if (!tids[t].tags.containsAny(ex)) temp.push(tids[t]);
		tids=temp;
	}

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

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

	return results;
}
//}}}
// // HIJACK core {{{<<search>>}}} macro to add "report" and "simple inline" output
//{{{
config.macros.search.SOP_handler=config.macros.search.handler;
config.macros.search.handler = function(place,macroName,params)
{
	// if "report", use SearchOptionsPlugin report generator for inline output
	if (params[1]&&params[1].substr(0,6)=="report") {
		var keyword=params[0];
		var options=params[1].split("=")[1]; // split "report=option+option+..."
		var heading=params[2]?params[2].unescapeLineBreaks():"";
		var matches=store.search(new RegExp(keyword.escapeRegExp(),"img"),"title","excludeSearch");
		if (matches.length) wikify(heading+window.formatSearchResults(keyword,matches,options),place);
	} else if (params[1]) {
		var keyword=params[0];
		var heading=params[1]?params[1].unescapeLineBreaks():"";
		var seperator=params[2]?params[2].unescapeLineBreaks():", ";
		var matches=store.search(new RegExp(keyword.escapeRegExp(),"img"),"title","excludeSearch");
		if (matches.length) {
			var out=[];
			for (var m=0; m<matches.length; m++) out.push("[["+matches[m].title+"]]");
			wikify(heading+out.join(seperator),place);
		}
	} else
		config.macros.search.SOP_handler.apply(this,arguments);
};
//}}}
// // SearchResults panel handling
//{{{
setStylesheet(".searchResults { padding:1em 1em 0 1em; }","searchResults"); // matches std tiddler padding

config.macros.search.createPanel=function(text,matches,body) {

	function getByClass(e,c) { var d=e.getElementsByTagName("div");
		for (var i=0;i<d.length;i++) if (hasClass(d[i],c)) return d[i]; }
	var panel=createTiddlyElement(null,"div","searchPanel","searchPanel");
	this.renderPanel(panel,text,matches,body);
	var oldpanel=document.getElementById("searchPanel");
	if (!oldpanel) { // insert new panel just above tiddlers
		var da=document.getElementById("displayArea");
		da.insertBefore(panel,da.firstChild);
	} else { // if panel exists
		var oldwrap=getByClass(oldpanel,"searchResults");
		var newwrap=getByClass(panel,"searchResults");
		// if no prior content, just insert new content
		if (!oldwrap) oldpanel.insertBefore(newwrap,null);
		else {	// swap search results content but leave containing panel intact
			oldwrap.style.display='block'; // unfold wrapper if needed
			var i=oldwrap.getElementsByTagName("input")[0]; // get input field
			if (i) { var pos=this.getCursorPos(i); i.onblur=null; } // get cursor pos, ignore blur
			oldpanel.replaceChild(newwrap,oldwrap);
			panel=oldpanel; // use existing panel
		} 
	}
	this.showPanel(true,pos);
	return panel;
}

config.macros.search.renderPanel=function(panel,text,matches,body) {

	var wrap=createTiddlyElement(panel,"div",null,"searchResults");
	wrap.onmouseover = function(e){ addClass(this,"selected"); }
	wrap.onmouseout = function(e){ removeClass(this,"selected"); }
	// create toolbar: "åben alle", "fold/foldud", "luk"
	var tb=createTiddlyElement(wrap,"div",null,"toolbar");
	var b=createTiddlyButton(tb, "åben alle", "åben alle matchende tiddlere", function() {
		story.displayTiddlers(null,this.getAttribute("list").readBracketedList()); return false; },"button");
	var list=""; for(var t=0;t<matches.length;t++) list+='[['+matches[t].title+']] ';
	b.setAttribute("list",list);
	var b=createTiddlyButton(tb, "fold", "visning af søgeresultater til/fra", function() {
		config.macros.search.foldPanel(this); return false; },"button");
	var b=createTiddlyButton(tb, "luk", "fortryd søgeresultater",	function() {
		config.macros.search.showPanel(false); return false; },"button");
	createTiddlyText(createTiddlyElement(wrap,"div",null,"title"),"Søg efter: "+text); // title
	wikify(body,createTiddlyElement(wrap,"div",null,"viewer")); // report
	return panel;
}

config.macros.search.showPanel=function(show,pos) {
	var panel=document.getElementById("searchPanel");
	var i=panel.getElementsByTagName("input")[0];
	i.onfocus=show?function(){config.macros.search.stayFocused(true);}:null;
	i.onblur=show?function(){config.macros.search.stayFocused(false);}:null;
	if (show && panel.style.display=="block") { // if shown, grab focus, restore cursor
		if (i&&this.stayFocused()) { i.focus(); this.setCursorPos(i,pos); }
		return;
	}
	if(!config.options.chkAnimate) {
		panel.style.display=show?"block":"none";
		if (!show) { removeChildren(panel); config.macros.search.stayFocused(false); }
	} else {
		var s=new Slider(panel,show,false,show?"none":"children");
		s.callback=function(e,p){e.style.overflow="visible";}
		anim.startAnimating(s);
	}
	return panel;
}

config.macros.search.foldPanel=function(button) {
	var d=document.getElementById("searchPanel").getElementsByTagName("div");
	for (var i=0;i<d.length;i++) if (hasClass(d[i],"viewer")) var v=d[i]; if (!v) return;
	var show=v.style.display=="none";
	if(!config.options.chkAnimate)
		v.style.display=show?"block":"none";
	else {
		var s=new Slider(v,show,false,"none");
		s.callback=function(e,p){e.style.overflow="visible";}
		anim.startAnimating(s);
	}
	button.innerHTML=show?"fold":"unfold";
	return false;
}

config.macros.search.stayFocused=function(keep) { // TRUE/FALSE=set value, no args=get value
	if (keep===undefined) return this.keepReportInFocus;
	this.keepReportInFocus=keep;
	return keep
}	

config.macros.search.getCursorPos=function(i) {
	var s=0; var e=0; if (!i) return { start:s, end:e };
	try {
		if (i.setSelectionRange) // FF
			{ s=i.selectionStart; e=i.selectionEnd; }
		if (document.selection && document.selection.createRange) { // IE
			var r=document.selection.createRange().duplicate();
			var len=r.text.length; s=0-r.moveStart('character',-100000); e=s+len;
		}
	}catch(e){};
	return { start:s, end:e };
}
config.macros.search.setCursorPos=function(i,pos) {
	if (!i||!pos) return; var s=pos.start; var e=pos.end;
	if (i.setSelectionRange) //FF
		i.setSelectionRange(s,e);
	if (i.createTextRange) // IE
		{ var r=i.createTextRange(); r.collapse(true); r.moveStart("character",s); r.select(); }
}
//}}}
// // SearchResults report generation
// note: these functions are defined globally, so they can be more easily redefined to customize report formats//
//{{{
if (!window.reportSearchResults) window.reportSearchResults=function(text,matches)
{
	var cms=config.macros.search; // abbrev
	var body=window.formatSearchResults(text,matches);
	if (!config.options.chkSearchListTiddler) // show #searchResults panel
		window.scrollTo(0,ensureVisible(cms.createPanel(text,matches,body)));
	else { // write [[SearchResults]] tiddler
		var title=cms.reportTitle;
		var who=config.options.txtUserName;
		var when=new Date();
		var tags="excludeLists excludeSearch temporary";
		var tid=store.getTiddler(title); if (!tid) tid=new Tiddler();
		tid.set(title,body,who,when,tags);
		store.addTiddler(tid);
		story.closeTiddler(title);
		story.displayTiddler(null,title);
	}
}

if (!window.formatSearchResults) window.formatSearchResults=function(text,matches,opt)
{
	var body='';
	var title=config.macros.search.reportTitle
	var q = config.options.chkRegExpSearch ? "/" : "'";
	if (!opt) var opt="all";
	var parts=opt.split("+");
	for (var i=0; i<parts.length; i++) { var p=parts[i].toLowerCase();
		if (p=="again"||p=="all")   body+=window.formatSearchResults_again(text,matches);
		if (p=="summary"||p=="all") body+=window.formatSearchResults_summary(text,matches);
		if (p=="list"||p=="all")    body+=window.formatSearchResults_list(text,matches);
		if (p=="buttons"||p=="all") body+=window.formatSearchResults_buttons(text,matches);
	}
	return body;
}

if (!window.formatSearchResults_again) window.formatSearchResults_again=function(text,matches)
{
	var title=config.macros.search.reportTitle
	var body='';
	// search again
	body+='{{span{<<search "'+text.replace(/"/g,'&#x22;')+'">> /%\n';
	body+='%/<html><input type="button" value="søg igen"';
	body+=' onclick="var t=this.parentNode.parentNode.getElementsByTagName(\'input\')[0];';
	body+=' config.macros.search.doSearch(t); return false;">';
	if (!config.options.chkSearchResultsOptions) // omit "options..."
		body+='</html>';
	else {
		body+=' <a href="javascript:;" onclick="';
		body+=' var e=this.parentNode.nextSibling;';
		body+=' var show=e.style.display!=\'block\';';
		body+=' if(!config.options.chkAnimate) e.style.display=show?\'block\':\'none\';';
		body+=' else anim.startAnimating(new Slider(e,show,false,\'none\'));';
		body+=' return false;">options...</a>';
		body+='</html>@@display:none;border-left:1px dotted;margin-left:1em;padding:0;padding-left:.5em;font-size:90%;/%\n';
		body+='	%/<<tiddler SearchOptions>>@@';
	};
	body+='}}}\n\n';
	return body;
}

if (!window.formatSearchResults_summary) window.formatSearchResults_summary=function(text,matches)
{
	// summary: nn tiddlers found matching '...', options used
	var body='';
	var co=config.options; // abbrev
	var title=config.macros.search.reportTitle
	var q = co.chkRegExpSearch ? "/" : "'";
	body+="''"+config.macros.search.successMsg.format([matches.length,q+"{{{"+text+"}}}"+q])+"''\n";
	var opts=[];
	if (co.chkSearchTitles) opts.push("titles");
	if (co.chkSearchText) opts.push("text");
	if (co.chkSearchTags) opts.push("tags");
	if (co.chkSearchFields) opts.push("fields");
	if (co.chkSearchShadows) opts.push("shadows");
	if (co.chkSearchOpenTiddlers) body+="^^//search limited to displayed tiddlers only//^^\n";
	body+="~~&nbsp; searched in "+opts.join(" + ")+"~~\n";
	body+=(co.chkCaseSensitiveSearch||co.chkRegExpSearch?"^^&nbsp; using ":"")
		+(co.chkCaseSensitiveSearch?"case-sensitive ":"")
		+(co.chkRegExpSearch?"pattern ":"")
		+(co.chkCaseSensitiveSearch||co.chkRegExpSearch?"matching^^\n":"");
	return body;
}

if (!window.formatSearchResults_list) window.formatSearchResults_list=function(text,matches)
{
	// bullet list of links to matching tiddlers
	var body='';
	var co=config.options; // abbrev
	var pattern=co.chkRegExpSearch?text:text.escapeRegExp();
	var sensitive=co.chkCaseSensitiveSearch?"mg":"img";
	var link='{{tiddlyLinkExisting{<html><nowiki><a href="javascript:;" onclick="'
		+'if(config.options.chkSearchHighlight)'
		+'	highlightHack=new RegExp(\x27'+pattern+'\x27.escapeRegExp(),\x27'+sensitive+'\x27);'
		+'story.displayTiddler(null,\x27%0\x27);'
		+'highlightHack = null; return false;'
		+'" title="%2">%1</a></html>}}}';
	for(var t=0;t<matches.length;t++) {
		body+="* ";
		if (co.chkSearchByDate)
			body+=matches[t].modified.formatString('YYYY.0MM.0DD 0hh:0mm')+" ";
		var title=matches[t].title;
		var fixup=title.replace(/'/g,"\\x27").replace(/"/g,"\\x22");
		var tid=store.getTiddler(title);
		var tip=tid?tid.getSubtitle():''; tip=tip.replace(/"/g,"&quot;");
		body+=link.format([fixup,title,tip])+'\n';
	}
	return body;
}

if (!window.formatSearchResults_buttons) window.formatSearchResults_buttons=function(text,matches)
{
	// embed buttons only if writing SearchResults to tiddler
	if (!config.options.chkSearchListTiddler) return "";
	// "open all" button
	var title=config.macros.search.reportTitle;
	var body="";
	body+="@@display:block;<html><input type=\"button\" href=\"javascript:;\" "
		+"onclick=\"story.displayTiddlers(null,[";
	for(var t=0;t<matches.length;t++)
		body+="'"+matches[t].title.replace(/\'/mg,"\\'")+"'"+((t<matches.length-1)?", ":"");
	body+="],1);\" accesskey=\"O\" value=\"open all matching tiddlers\"></html> ";
	// "discard SearchResults" button
	body+="<html><input type=\"button\" href=\"javascript:;\" "
		+"onclick=\"discardSearchResults()\" value=\"discard "+title+"\"></html>";
	body+="@@\n";
	return body;
}

if (!window.discardSearchResults) window.discardSearchResults=function()
{
	// remove the tiddler
	story.closeTiddler(config.macros.search.reportTitle);
	store.deleteTiddler(config.macros.search.reportTitle);
	store.notify(config.macros.search.reportTitle,true);
}
//}}}
// // DELIVER [[SearchOptions]] shadow payload
//{{{
config.shadowTiddlers.SearchOptions = store.getTiddlerText('SearchOptionsPlugin##panel','');
config.annotations.SearchOptions    = 'created by SearchOptionsPlugin';
//}}}
/***
//{{{
!panel
search in:
  {{nowrap{<<option chkSearchTitles>>titles <<option chkSearchText>>text <<option chkSearchTags>>tags}}} /%
%/{{nowrap{<<option chkSearchFields>>fields <<option chkSearchShadows>>shadows}}}
----
  {{nowrap{<<option chkCaseSensitiveSearch>>case-sensitive}}} /%
%/{{nowrap{<<option chkRegExpSearch>>match text patterns}}}
  {{nowrap{<<option chkIncrementalSearch>>key-by-key search:}}} /%
	%/{{threechar smallform nowrap{<<option txtIncrementalSearchMin>> or more characters}}} /%
	%/{{threechar smallform nowrap{<<option txtIncrementalSearchDelay>> msec delay}}}<hr>
  {{nowrap{<<option chkSearchList>>show results in a list &nbsp; &nbsp;}}} /%
%/{{nowrap{<<option chkSearchListTiddler>>save list in ''[[SearchResults]]''}}}
  {{nowrap{<<option chkSearchTitlesFirst>>show title matches first}}} /%
%/{{nowrap{<<option chkSearchByDate>>sort results by date}}} /%
%/{{nowrap{<<option chkSearchHighlight>>highlight matching text}}}
----
{{nowrap{<<option chkSearchOpenTiddlers>>search open tiddlers only}}}
{{nowrap{<<option chkSearchExcludeTags>>exclude tiddlers tagged with:}}}
{{editor{<<option txtSearchExcludeTags>>}}}
!end
//}}}
***/
 
@@display:block;margin-left:.5em;gå til@@<<gotoTiddler>><<search>><<closeAll>><<permaview>><<newTiddler>><<saveChanges>><<saveAs>> [[TspotControls]]<<slider chkSliderOptionsPanel OptionsPanel "muligheder »" "Tilpas TiddlyWikis avancerede muligheder">>
<<tiddler SideBarTabs##tabs>>/%
<<slider chkSliderSideBarTabs SideBarTabs##tabs "index »" "view lists of document contents">>

!tabs
<<tabs txtMainTab
	"pasteup" "side layouts og dele" SideBarTabs##pages
	"tidslinie" "alle tiddlere, efter dato" TabTimeline
	"titler" "alle tiddlere, efter titel" TabAll
	"flere" "flere" SideBarTabs##more
>>
!out
 ($1)
!pages
~PasteUp sider <<tiddler SideBarTabs##out with: {{store.getTaggedTiddlers('pasteup').length||'ingen';}}>>:{{borderleft{
<<list filter [tag[pasteup]]>>}}}~PasteUp dele<<tiddler SideBarTabs##out with: {{store.getTaggedTiddlers('part').length||'ingen';}}>>:
{{borderleft{
<<list filter [tag[part]]>>}}}
!more
<<tabs txtMoreTab
	"tags" "alle tiddlere, efter tag" TabTags
	"skyggede" "system tiddlere" TabMoreShadowed
>>
!end
%/
/***
|Name|SinglePageModePlugin|
|Source|http://www.TiddlyTools.com/#SinglePageModePlugin|
|Documentation|http://www.TiddlyTools.com/#SinglePageModePluginInfo|
|Version|2.9.7|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Show tiddlers one at a time with automatic permalink, or always open tiddlers at top/bottom of page.|
This plugin allows you to configure TiddlyWiki to navigate more like a traditional multipage web site with only one tiddler displayed at a time.
!!!!!Documentation
>see [[SinglePageModePluginInfo]]
!!!!!Configuration
<<<
<<option chkSinglePageMode>> Display one tiddler at a time
><<option chkSinglePagePermalink>> Automatically permalink current tiddler
><<option chkSinglePageKeepFoldedTiddlers>> Don't close tiddlers that are folded
><<option chkSinglePageKeepEditedTiddlers>> Don't close tiddlers that are being edited
<<option chkTopOfPageMode>> Open tiddlers at the top of the page
<<option chkBottomOfPageMode>> Open tiddlers at the bottom of the page
<<option chkSinglePageAutoScroll>> Automatically scroll tiddler into view (if needed)

Notes:
* The "display one tiddler at a time" option can also be //temporarily// set/reset by including a 'paramifier' in the document URL: {{{#SPM:true}}} or {{{#SPM:false}}}.
* If more than one display mode is selected, 'one at a time' display takes precedence over both 'top' and 'bottom' settings, and if 'one at a time' setting is not used, 'top of page' takes precedence over 'bottom of page'.
* When using Apple's Safari browser, automatically setting the permalink causes an error and is disabled.
<<<
!!!!!Revisions
<<<
2010.11.30 2.9.7 use story.getTiddler()
2008.10.17 2.9.6 changed chkSinglePageAutoScroll default to false
| Please see [[SinglePageModePluginInfo]] for previous revision details |
2005.08.15 1.0.0 Initial Release.  Support for BACK/FORWARD buttons adapted from code developed by Clint Checketts.
<<<
!!!!!Code
***/
//{{{
version.extensions.SinglePageModePlugin= {major: 2, minor: 9, revision: 7, date: new Date(2010,11,30)};
//}}}
//{{{
config.paramifiers.SPM = { onstart: function(v) {
	config.options.chkSinglePageMode=eval(v);
	if (config.options.chkSinglePageMode && config.options.chkSinglePagePermalink && !config.browser.isSafari) {
		config.lastURL = window.location.hash;
		if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
	}
} };
//}}}
//{{{
if (config.options.chkSinglePageMode==undefined)
	config.options.chkSinglePageMode=false;
if (config.options.chkSinglePagePermalink==undefined)
	config.options.chkSinglePagePermalink=true;
if (config.options.chkSinglePageKeepFoldedTiddlers==undefined)
	config.options.chkSinglePageKeepFoldedTiddlers=false;
if (config.options.chkSinglePageKeepEditedTiddlers==undefined)
	config.options.chkSinglePageKeepEditedTiddlers=false;
if (config.options.chkTopOfPageMode==undefined)
	config.options.chkTopOfPageMode=false;
if (config.options.chkBottomOfPageMode==undefined)
	config.options.chkBottomOfPageMode=false;
if (config.options.chkSinglePageAutoScroll==undefined)
	config.options.chkSinglePageAutoScroll=false;
//}}}
//{{{
config.SPMTimer = 0;
config.lastURL = window.location.hash;
function checkLastURL()
{
	if (!config.options.chkSinglePageMode)
		{ window.clearInterval(config.SPMTimer); config.SPMTimer=0; return; }
	if (config.lastURL == window.location.hash) return; // no change in hash
	var tids=decodeURIComponent(window.location.hash.substr(1)).readBracketedList();
	if (tids.length==1) // permalink (single tiddler in URL)
		story.displayTiddler(null,tids[0]);
	else { // restore permaview or default view
		config.lastURL = window.location.hash;
		if (!tids.length) tids=store.getTiddlerText("DefaultTiddlers").readBracketedList();
		story.closeAllTiddlers();
		story.displayTiddlers(null,tids);
	}
}


if (Story.prototype.SPM_coreDisplayTiddler==undefined)
	Story.prototype.SPM_coreDisplayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler,template,animate,slowly)
{
	var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
	var tiddlerElem=story.getTiddler(title); // ==null unless tiddler is already displayed
	var opt=config.options;
	var single=opt.chkSinglePageMode && !startingUp;
	var top=opt.chkTopOfPageMode && !startingUp;
	var bottom=opt.chkBottomOfPageMode && !startingUp;
	if (single) {
		story.forEachTiddler(function(tid,elem) {
			// skip current tiddler and, optionally, tiddlers that are folded.
			if (	tid==title
				|| (opt.chkSinglePageKeepFoldedTiddlers && elem.getAttribute("folded")=="true"))
				return;
			// if a tiddler is being edited, ask before closing
			if (elem.getAttribute("dirty")=="true") {
				if (opt.chkSinglePageKeepEditedTiddlers) return;
				// if tiddler to be displayed is already shown, then leave active tiddler editor as is
				// (occurs when switching between view and edit modes)
				if (tiddlerElem) return;
				// otherwise, ask for permission
				var msg="'"+tid+"' is currently being edited.\n\n";
				msg+="Press OK to save and close this tiddler\nor press Cancel to leave it opened";
				if (!confirm(msg)) return; else story.saveTiddler(tid);
			}
			story.closeTiddler(tid);
		});
	}
	else if (top)
		arguments[0]=null;
	else if (bottom)
		arguments[0]="bottom";
	if (single && opt.chkSinglePagePermalink && !config.browser.isSafari) {
		window.location.hash = encodeURIComponent(String.encodeTiddlyLink(title));
		config.lastURL = window.location.hash;
		document.title = wikifyPlain("SiteTitle") + " - " + title;
		if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
	}
	if (tiddlerElem && tiddlerElem.getAttribute("dirty")=="true") { // editing... move tiddler without re-rendering
		var isTopTiddler=(tiddlerElem.previousSibling==null);
		if (!isTopTiddler && (single || top))
			tiddlerElem.parentNode.insertBefore(tiddlerElem,tiddlerElem.parentNode.firstChild);
		else if (bottom)
			tiddlerElem.parentNode.insertBefore(tiddlerElem,null);
		else this.SPM_coreDisplayTiddler.apply(this,arguments); // let CORE render tiddler
	} else
		this.SPM_coreDisplayTiddler.apply(this,arguments); // let CORE render tiddler
	var tiddlerElem=story.getTiddler(title);
	if (tiddlerElem&&opt.chkSinglePageAutoScroll) {
		// scroll to top of page or top of tiddler
		var isTopTiddler=(tiddlerElem.previousSibling==null);
		var yPos=isTopTiddler?0:ensureVisible(tiddlerElem);
		// if animating, defer scroll until after animation completes
		var delay=opt.chkAnimate?config.animDuration+10:0;
		setTimeout("window.scrollTo(0,"+yPos+")",delay); 
	}
}

if (Story.prototype.SPM_coreDisplayTiddlers==undefined)
	Story.prototype.SPM_coreDisplayTiddlers=Story.prototype.displayTiddlers;
Story.prototype.displayTiddlers = function() {
	// suspend single/top/bottom modes when showing multiple tiddlers
	var opt=config.options;
	var saveSPM=opt.chkSinglePageMode; opt.chkSinglePageMode=false;
	var saveTPM=opt.chkTopOfPageMode; opt.chkTopOfPageMode=false;
	var saveBPM=opt.chkBottomOfPageMode; opt.chkBottomOfPageMode=false;
	this.SPM_coreDisplayTiddlers.apply(this,arguments);
	opt.chkBottomOfPageMode=saveBPM;
	opt.chkTopOfPageMode=saveTPM;
	opt.chkSinglePageMode=saveSPM;
}
//}}}
{{fine{
<<tiddler Version>>}}}
pasteup
<<emptyTrash>>
<<storyViewer
	{{store.getTiddlerText('PasteUpConfig::SlideshowList')}}
	list allbuttons
	prompt:{{store.getTiddlerText('PasteUpConfig::SlideshowPrompt')}}>>/%
%/<<storyViewer
	{{store.getTiddlerText('PasteUpConfig::SlideshowList')}}
	timer:{{store.getTiddlerText('PasteUpConfig::SlideshowTimer')}}>>
/***
|Name|SnapshotPlugin|
|Source|http://www.TiddlyTools.com/#SnapshotPlugin|
|Documentation|http://www.TiddlyTools.com/#SnapshotPluginInfo|
|Version|1.4.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|save or print HTML+CSS image of rendered document content|
This plugin provides a macro as well as tiddler toolbar commands to create a file or browser window containing the //rendered// CSS-and-HTML that is currently being displayed for selected elements of the current document.
!!!!!Documentation
>see [[SnapshotPluginInfo]]
!!!!!Configuration
<<<
<<option chkSnapshotHTMLOnly>> output HTML only (omit CSS)
<<<
!!!!!Revisions
<<<
2011.02.14 1.4.3 fix OSX error: use picker.file.path
2011.01.03 1.4.2 added snapshotSaveViewer toolbar command
2010.12.15 1.4.1 added 'snapshot' class to wrapper
|please see [[SnapshotPluginInfo]] for additional revision details|
2008.04.21 1.0.0 initial release - derived from [[NewDocumentPlugin]] with many improvements...
<<<
!!!!!Code
***/
//{{{
version.extensions.SnapshotPlugin= {major: 1, minor: 4, revision: 3, date: new Date(2011,2,14)};

if (config.options.chkSnapshotHTMLOnly===undefined)
	config.options.chkSnapshotHTMLOnly=false;

config.macros.snapshot = {
	snapLabel: "save a snapshot",
	printLabel: "print a snapshot",
	snapPrompt: "save an HTML image",
	printPrompt: "print an HTML image",
	hereID: "here",
	viewerID: "viewer",
	storyID: "story",
	allID: "all",
	askID: "ask",
	askTiddlerID: "askTiddler",
	askDOMID: "askDOM",
	askMsg: "select an element...",
	hereItem: "tiddler: '%0'",
	viewerItem: "tiddler: '%0' (content only)",
	storyItem: "story column (one file)",
	storyFilesItem: "story column (multiple files)",
	allItem: "entire document",
	tiddlerItem: "select a tiddler...",
	IDItem: "select a DOM element by ID...",
	HTMLItem: "[%0] output HTML only (omit CSS)",
	fileMsg: "select or enter a target path/filename",
	defaultFilename: "snapshot.html",
	okmsg: "snapshot written to %0",
	failmsg: "An error occurred while creating %0",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var printing=params[0]&&params[0]=="print"; if (printing) params.shift();
		params = paramString.parseParams("anon",null,true,false,false);
		var id=getParam(params,"id","here");
		var label=getParam(params,"label",printing?this.printLabel:this.snapLabel);
		var prompt=getParam(params,"prompt",printing?this.printPrompt:this.snapPrompt);
		var btn=createTiddlyButton(place,label,prompt, function(ev){
			this.setAttribute("snapID",this.getAttribute("startID"));
			config.macros.snapshot.go(this,ev)
		});
		btn.setAttribute("startID",id);
		btn.setAttribute("snapID",id);
		btn.setAttribute("printing",printing?"true":"false");
		btn.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
	},
	go: function(here,ev) {
		var cms=config.macros.snapshot; // abbreviation
		var id=here.getAttribute("snapID");
		var printing=here.getAttribute("printing")=="true";
		var HTMLOnly=here.getAttribute("HTMLOnly")=="true";

		if (id==cms.askID||id==cms.askTiddlerID||id==cms.askDOMID) {
			cms.askForID(here,ev);
		} else if (id==cms.storyID) {
			story.forEachTiddler(function(t,e) {
				var out=cms.getsnap(e,e.id,printing,HTMLOnly);
				if (printing) cms.printsnap(out);
				else cms.savesnap(out,e.getAttribute('tiddler')+'.html');
			});
		} else {
			if (id==cms.allID) id="contentWrapper";
			var snapElem=document.getElementById(id);
			if (id==cms.hereID || id==cms.viewerID)
				var snapElem=story.findContainingTiddler(here);
			if (snapElem && hasClass(snapElem,"tiddler") && (id==cms.viewerID || HTMLOnly)) {
				// find viewer class element within tiddler element
				var nodes=snapElem.getElementsByTagName("*");
				for (var i=0; i<nodes.length; i++)
					if (hasClass(nodes[i],"viewer")) { snapElem=nodes[i]; break; }
			}
			if (!snapElem) // not in a tiddler or no viewer element or unknown ID
				{ e.cancelBubble=true; if(e.stopPropagation)e.stopPropagation(); return(false); }
			// write or print snapshot
			var out=cms.getsnap(snapElem,id,printing,HTMLOnly);
			if (printing) cms.printsnap(out); else cms.savesnap(out);
		}
		return false;
	},
	askForID: function(here,ev) {
		var ev = ev ? ev : window.event; 
		var cms=config.macros.snapshot; // abbreviation
		var id=here.getAttribute("snapID");
		var indent='\xa0\xa0\xa0\xa0';
		var p=Popup.create(here); if (!p) return false; p.className+=' sticky smallform';
		var s=createTiddlyElement(p,'select'); s.button=here;
		if (id==cms.askID) {
			s.options[s.length]=new Option(cms.askMsg,cms.askID);
			var tid=story.findContainingTiddler(here);
			if(tid) { 
				var title=tid.getAttribute("tiddler");
				if (here.getAttribute("HTMLOnly")!="true")
					s.options[s.length]=new Option(indent+cms.hereItem.format([title]),cms.hereID);
				s.options[s.length]=new Option(indent+cms.viewerItem.format([title]),cms.viewerID);
			}
			s.options[s.length]=new Option(indent+cms.tiddlerItem,cms.askTiddlerID);
			s.options[s.length]=new Option(indent+cms.IDItem,cms.askDOMID);
			s.options[s.length]=new Option(indent+cms.storyItem,"tiddlerDisplay");
			s.options[s.length]=new Option(indent+cms.storyFilesItem,cms.storyID);
			s.options[s.length]=new Option(indent+cms.allItem,"contentWrapper");
		}
		if (id==cms.askDOMID) {
			s.options[s.length]=new Option(cms.IDItem,cms.askDOMID);
			var elems=document.getElementsByTagName("*");
			var ids=[];
			for (var i=0;i<elems.length;i++)
				if (elems[i].id.length && elems[i].className!="animationContainer")
					ids.push(elems[i].id);
			ids.sort();
			for (var i=0;i<ids.length;i++) s.options[s.length]=new Option(indent+ids[i],ids[i]);
		}
		if (id==cms.askTiddlerID) {
			s.options[s.length]=new Option(cms.tiddlerItem,cms.askTiddlerID);
			var elems=document.getElementsByTagName("div");
			var ids=[];
			for (var i=0;i<elems.length;i++) { var id=elems[i].id;
				if (id.length && id.substr(0,story.idPrefix.length)==story.idPrefix && id!="tiddlerDisplay")
					ids.push(id);
			}
			ids.sort();
			for (var i=0;i<ids.length;i++) s.options[s.length]=new Option(indent+ids[i].substr(story.idPrefix.length),ids[i]);
		}
		s.options[s.length]=new Option(cms.HTMLItem.format([here.getAttribute("HTMLOnly")=="true"?"\u221a":"_"]),cms.HTMLItem);
		s.onchange=function(ev){
			var ev = ev ? ev : window.event; 
			var cms=config.macros.snapshot; // abbreviation
			var here=this.button;
			if (this.value==cms.HTMLItem) {
				config.options.chkSnapshotHTMLOnly=!config.options.chkSnapshotHTMLOnly;
				here.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
				config.macros.option.propagateOption("chkSnapshotHTMLOnly","checked",
					config.options.chkSnapshotHTMLOnly,"input");
			} else
				here.setAttribute("snapID",this.value);
			config.macros.snapshot.go(here,ev);
			return false;
		};
		Popup.show();
		ev.cancelBubble=true;
		if(ev.stopPropagation)ev.stopPropagation();
		return false;
	},
	getpath: function() {
		// get current path
		var path=getLocalPath(window.location.href);
		var slashpos=path.lastIndexOf("/");
		if (slashpos==-1) slashpos=path.lastIndexOf("\\"); 
		if (slashpos!=-1) path=path.substr(0,slashpos+1); // trim filename
		return path;
	},
	getsnap: function(snapElem,id,printing,HTMLOnly) {
		var cms=config.macros.snapshot; // abbreviation
		var out='<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" />';
		if (printing)
			out+='<base href="file:///'+cms.getpath().replace(/\\/g,'/')+'"></base>\n';
		if (!HTMLOnly) {
			var styles=document.getElementsByTagName('style');
			var fmt='<style>\n/* stylesheet=%0 */\n%1\n\n</style>\n';
			for(var i=0; i < styles.length; i++)
				out+=fmt.format([styles[i].getAttribute('id'),styles[i].innerHTML]);
		}
		out+='</head>\n';

		var elems=snapElem.getElementsByTagName('input');
		for (var i=0; i<elems.length; i++) { var e=elems[i];
			if (e.type=='text')		e.defaultValue=e.value;
			if (e.type=='checkbox')	 	e.defaultChecked=e.checked;
			if (e.type=='radiobutton')	e.defaultChecked=e.checked;
		}
		var elems=snapElem.getElementsByTagName('textarea');
		for (var i=0; i<elems.length; i++)	elems[i].defaultValue=elems[i].value;

		var fmt='<body>\n\n<div class="snapshot %0">%1</div>\n\n</body>\n';
		out+=fmt.format([(id==cms.viewerID?'tiddler viewer':''),snapElem.innerHTML]);

		return '<html>\n'+out+'</html>';
	},
	printsnap: function(out) {
		var win=window.open("","_blank","");
		win.document.open();
		win.document.writeln(out);
		win.document.close();
		win.focus(); // bring to front
		win.print(); // trigger print dialog
	},
	savesnap: function(out,target) {
		var cms=config.macros.snapshot; // abbreviation
		// make sure we are local
		if (window.location.protocol!="file:")
			{ alert(config.messages.notFileUrlError); return; }
		var target=target||cms.askForFilename(cms.fileMsg,cms.getpath(),cms.defaultFilename);
		if (!target) return; // cancelled by user
		// if specified file does not include a path, assemble fully qualified path and filename
		var slashpos=target.lastIndexOf("/"); if (slashpos==-1) slashpos=target.lastIndexOf("\\");
		if (slashpos==-1) {
			var h=document.location.href;
			var cwd=getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf('/')+1)));
			target=cwd+target;
		}
		var link="file:///"+target.replace(/\\/g,'/'); // link for message text
		var ok=saveFile(target,convertUnicodeToUTF8(out));
		var msg=ok?cms.okmsg.format([target]):cms.failmsg.format([target]);
		displayMessage(msg,link);
	},
	askForFilename: function(msg,path,file) {
		if(window.Components) { // moz
			try {
				netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
				var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
				var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
				picker.init(window, msg, nsIFilePicker.modeSave);
				var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
				thispath.initWithPath(path);
				picker.displayDirectory=thispath;
				picker.defaultExtension='html';
				picker.defaultString=file;
				picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
				if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.path;
			}
			catch(e) { alert('error during local file access: '+e.toString()) }
		}
		else { // IE
			try { // XP/Vista only
				var s = new ActiveXObject('UserAccounts.CommonDialog');
				s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
				s.FilterIndex=3; // default to HTML files;
				s.InitialDir=path;
				s.FileName=file;
				if (s.showOpen()) var result=s.FileName;
			}
			catch(e) { var result=prompt(msg,path+file); } // fallback for non-XP IE
		}
		return result;
	}
};
//}}}

// // TOOLBAR DEFINITIONS
//{{{
config.commands.snapshotSave = {
	text: "snap",
	tooltip: config.macros.snapshot.snapPrompt,
	handler: function(ev,src,title) {
		src.setAttribute("snapID","ask");
		src.setAttribute("printing","false");
		src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
		config.macros.snapshot.go(src,ev);
		return false;
	}
};
config.commands.snapshotSaveViewer = {
	text: "snap",
	tooltip: config.macros.snapshot.snapPrompt,
	handler: function(ev,src,title) {
		src.setAttribute("snapID","viewer");
		src.setAttribute("printing","false");
		src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
		config.macros.snapshot.go(src,ev);
		return false;
	}
};
config.commands.snapshotPrint = {
	text: "print",
	tooltip: config.macros.snapshot.printPrompt,
	handler: function(ev,src,title) {
		src.setAttribute("snapID","ask");
		src.setAttribute("printing","true");
		src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
		config.macros.snapshot.go(src,ev);
		return false;
	}
};
config.commands.snapshotPrintViewer = {
	text: "print",
	tooltip: config.macros.snapshot.printPrompt,
	handler: function(ev,src,title) {
		src.setAttribute("snapID","viewer");
		src.setAttribute("printing","true");
		src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
		config.macros.snapshot.go(src,ev);
		return false;
	}
};
//}}}

// // COPIED FROM [[StickyPopupPlugin]] TO ELIMINATE PLUGIN DEPENDENCY
//{{{
if (config.options.chkStickyPopups==undefined) config.options.chkStickyPopups=false;
Popup.stickyPopup_onDocumentClick = function(ev)
{
	// if click is in a sticky popup, ignore it so popup will remain visible
	var e = ev ? ev : window.event; var target = resolveTarget(e);
	var p=target; while (p) {
		if (hasClass(p,"popup") && (hasClass(p,"sticky")||config.options.chkStickyPopups)) break;
		else p=p.parentNode;
	}
	if (!p) // not in sticky popup (or sticky popups disabled)... use normal click handling
		Popup.onDocumentClick(ev);
	return true;
};
try{removeEvent(document,"click",Popup.onDocumentClick);}catch(e){};
try{addEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
//}}}
//{{{
/***
Adjustments to system and plugins for PasteUp QuickStart document
NOTE: only change these if you know what you are doing!
***/
config.macros.startupSettings={init:function(){ // process AFTER all plugins are loaded
	var co=config.options;	// abbrev
	// readOnly=true;		// TW CORE - UN-COMMENT TO FORCE READ-ONLY ON STARTUP
	co.chkSinglePageMode=co.chkSinglePageMode||readOnly; 		// SinglePageModePlugin
	co.chkSinglePagePermalink=false;				// SinglePageModePlugin
	co.chkShowRightSidebar=false;					// ToggleRightSidebar
	co.chkPasteUpHelper=true;					// PasteUpHelperPlugin
	co.chkSlideshow=false;						// StoryMenu/ViewTemplate
	co.chkShowQuickEdit=true;					// QuickEditPackage
	config.formatterHelpers.imageSize={ tip: '', dragtip: '' };	// ImageSizePlugin
	config.commands.addPasteUpPart.text='tilføj en del...';		// PasteUpPlugin
	config.commands.snapshotSaveViewer.text='eksportér';				// SnapshotPlugin
	config.commands.snapshotSaveViewer.tooltip='Eksportér denne tiddler som HTML';	// SnapshotPlugin
	config.commands.snapshotPrintViewer.text='print';				// SnapshotPlugin
	config.commands.snapshotPrintViewer.tooltip='Print denne tiddler';		// SnapshotPlugin
	config.macros.saveAs.label='gem som';		// SaveAsPlugin
	config.macros.storyViewer.started=false;	// StoryViewerPlugin
}}
//}}}
{{medium center{
{{floatleft left{
	<<tiddler StoryMenu##contents>><<tiddler StoryMenu##pages>>
}}}{{floatright right{
	<<tiddler StoryMenu##toggleEdit>><<tiddler StoryMenu##toggleSidebar>>
}}}{{button{[[hjælp|Instruktioner]]}}}{{bordertop{
	<<tiddler StoryMenu##printall>><<tiddler StoryMenu##slideshow>>/%
	%/<<tiddler StoryMenu##newpage>><<tiddler StoryMenu##setup>>}}}/%
	%/{{smallform fine{
		<<unsavedChanges panel>>}}}/%
%/}}}{{hidden{

!contents
<html><nowiki><a href='javascript:;' class='button' title='gå tilbage til MainMenu' onclick='
	story.closeAllTiddlers(); restart();
'>&#x25C4;indhold</a></html>
!end

!toggleEdit
<html><nowiki><span class='button' title="slå redigering af dette dokument til/fra" onclick="
	if (window.readOnly) {
		this.innerHTML=this.savedHTML;
		this.savedHTML=null;
	} else {
		var chk='<input type=\x22checkbox\x22 checked style=\x22margin:0;padding:0;\x22>';
		this.savedHTML=this.innerHTML;
		this.innerHTML=chk+this.innerHTML;
	}
	window.readOnly=!window.readOnly;
	config.macros.option.propagateOption('chkHttpReadOnly','checked',window.readOnly,'input');
	config.macros.option.propagateOption('chkSinglePageMode','checked',window.readOnly,'input');
	window.showBackstage=!window.readOnly; if(showBackstage && !backstage.area) backstage.init();
	backstage.button.style.display=showBackstage?'block':'none'; backstage.hide();
	story.switchTheme(config.options.txtTheme); store.notifyAll(); story.refreshAllTiddlers(true);
	return false;
">redigér</span></html><<tiddler {{
	var e=place.lastChild.getElementsByTagName('span')[0];
	if (!window.readOnly && e.innerHTML.indexOf('checkbox')==-1) {
		var chk='<input type=\x22checkbox\x22 checked style=\x22margin:0;padding:0;\x22>';
		e.savedHTML=e.innerHTML;
		e.innerHTML=chk+e.innerHTML;
	}
'';}}>>
!end

!toggleSidebar
<<tiddler ToggleRightSidebar with: "sidepanel&#x25BA;" "vis/skjul sidepanelets funktioner" "button">>
!end

!pages
<<tag pasteup "sider">>
!end

!slideshow
<html><nowiki><span class='button' title="start/stop automatisk slideshow" onclick="
	if (this.savedHTML) {
		this.innerHTML=this.savedHTML;
		this.savedHTML=null;
		config.macros.option.propagateOption('chkSlideshow','checked',false,'input');
		config.macros.storyViewer.started=false;
		story.refreshAllTiddlers(true);
	} else {
		var chk='<input type=\x22checkbox\x22 checked style=\x22margin:0;padding:0;\x22>';
		this.savedHTML=this.innerHTML;
		this.innerHTML=chk+this.innerHTML;
		var storyname=store.getTiddlerText('PasteUpConfig::SlideshowList');
		var list=config.macros.storyViewer.getStory(storyname);
		if (!list.length) list.push('DefaultPage');
		config.macros.option.propagateOption('chkSlideshow','checked',true,'input');
		config.macros.storyViewer.started=true;
		story.closeAllTiddlers();
		story.displayTiddler(null,list[0]);
	}
	return false;
">slideshow</span></html>
!end

!printall
<html><nowiki><span class='button' title="print alle sider" onclick="
	var storyname=store.getTiddlerText('PasteUpConfig::SlideshowList');
	var list=config.macros.storyViewer.getStory(storyname);
	if (!list.length) list.push('DefaultPage');
	story.closeAllTiddlers();
	story.displayTiddlers(null,list);
	window.print();
	return false;
">print alle</span></html>
!end

!newpage
<<newTiddler
	label:'tilføj en side'
	prompt:'opret en ny pasteup side'
	title:'NySide'
	text:{{store.getTiddlerText('DefaultPage','')}}
	tag:pasteup>>
!end

!setup
<<tiddler {{if (readOnly) place.style.display='none';'';}}>>/%
%/<<slider closed StoryMenu##setupbox opsætning
	"tilpas PasteUp indstillinger for dette dokument">>
!setupbox
|background:white; <<tiddler PasteUpConfig##setupmenu>> |
!end

}}}
/***
|Name|[[StoryViewerPlugin]]|
|Source|http://www.TiddlyTools.com/#StoryViewerPlugin|
|Documentation|http://www.TiddlyTools.com/#StoryViewerPluginInfo|
|Version|1.4.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|view a set of tiddlers using a droplist, "first/previous/next/last" links, or timed slideshow|
The {{{<<storyViewer>>}}} macro allows you to quickly ''display //and// navigate between a set of tiddlers'', using a droplist of titles and/or individual "first/previous/next/last" buttons/text links.  It also provides a "slideshow" feature that permits you to ''present one tiddler at a time with a countdown timer to automatically advance to the next tiddler'' after a specified number of seconds.
!!!!!Documentation
> see [[StoryViewerPluginInfo]]
!!!!!Revisions
<<<
2011.03.11 1.4.0 added 'sort:fieldname' parameter
2011.01.24 1.3.4 in droplist onchange handler, don't clear slideshow 'started' flag (allows slideshow to continue after manual navigation)
|please see [[StoryViewerPluginInfo]] for additional revision details|
2007.10.23 1.0.0 Initial release, split {{{<<storyViewer>>}}} macro definition from [[StorySaverPlugin]] to allow separate installation of story saving vs. story viewing features.
<<<
!!!!!Code
***/
//{{{
version.extensions.StoryViewerPlugin= {major: 1, minor: 4, revision: 0, date: new Date(2011,3,11)};

config.macros.storyViewer = {
	tag:			"story",
	storynotfoundmsg:	"'%0' is an empty/unrecognized story",
	firstcmd:		"first",
	firstbutton:		"<<",
	firstmsg:		"first: '%0'",
	nextcmd:		"next",
	nextbutton:		">",
	nextmsg:		"next: '%0'",
	previouscmd:		"previous",
	previousbutton:		"<",
	prevmsg:		"previous: '%0'",
	lastcmd:		"last",
	lastbutton:		">>",
	lastmsg:		"last: '%0'",
	refreshmsg:		"redisplay '%0'",
	refreshmsg:		"",
	autostart:		false,
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {

		var parsed=paramString.parseParams('anon',null,true,false,false);
		var here=story.findContainingTiddler(place);
		if (here) var tid=here.getAttribute("tiddler");
		var storyname="";
		var p=params.shift();
		var keywords=['first','previous','here','next','last','list','links','timer','sort'];
		if (!p || keywords.indexOf(p.split(':')[0])!=-1) {
			// find story from current tiddler name
			if (!tid) return; // not in a tiddler... do nothing!
			var stories=store.getTaggedTiddlers(this.tag);
			if (!stories) return;
			for (var s=0; s<stories.length; s++) {
				if (!stories[s].linksUpdated) stories[s].changed();
				var tids=stories[s].links.slice(0);
				if (tids.contains(tid)) { storyname=stories[s].title; break; }
			}
			if (!storyname.length) return; // current tiddler is not part of a saved story
		}
		else { storyname=p; p=params.shift(); } // user-specified story name

		var sortby=getParam(parsed,'sort','title');
		var tids=this.getStory(storyname,sortby); // get tiddler list

		var target=null;
		switch (p?p.split(':')[0]:'') {
			case 'first':
				target=tids[0];
				break;
			case 'previous':
				var i=tids.indexOf(tid);
				if (i!=-1) var target=tids[Math.max(i-1,0)];
				break;
			case 'here':
				if (tid) target=tid;
				break;
			case 'next':
				var i=tids.indexOf(tid);
				if (i!=-1) var target=tids[Math.min(i+1,tids.length-1)];
				break;
			case 'last':
				target=tids[tids.length-1];
				break;
			case 'links':
				this.renderAllLinks(place,storyname);
				break;
			case 'timer':
				var delay=parseInt(getParam(parsed,'timer',15))*1000; // msecs between slides
				var autostart=params[0]=='autostart'; if (autostart) params.shift();
				var action=params[0]; // null/close/fold
				this.renderTimer(place,tids,tid,delay,autostart,action);
				break;
			case 'list':
			default:
				var prompt=getParam(parsed,'prompt',storyname+'...');
				var nobuttons=params.contains("nobuttons");
				var allbuttons=params.contains("allbuttons");
				var onlybuttons=params.contains("onlybuttons");
				this.renderList(place,tids,tid,storyname,prompt,nobuttons,allbuttons,onlybuttons);
				break;
		}
		var label=getParam(parsed,'label',params[0]||target);
		if (target) this.renderLink(place,tid,target,label);
	},
	getStory: function(storyname,sortby) { // READ TIDDLER LIST
		var tids=[];
		var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
		var tagged=store.sortTiddlers(fn.apply(store,[storyname]),sortby||'title');
		if (tagged.length) // if storyname is a tag, get tagged tiddlers rather than links
			for (var t=0; t<tagged.length; t++) tids.push(tagged[t].title);
		else {
			var t=store.getTiddler(storyname);
			if (t && !t.linksUpdated) t.changed();
			var tids=t?t.links.slice(0):[];
		}
		return tids;
	},
	renderLink: function(place,tid,target,label) {
		// override default labelling with specified text (if any)
		if (tid==target) { // self-referential links turn into 'refresh links'
			var btn=createTiddlyButton(place,null,this.refreshmsg.format([tid]), function() {
				var here=story.findContainingTiddler(place).getAttribute("tiddler");
				story.refreshTiddler(here,null,true);
			});
			wikify(label,btn); 
		}
		else // create link
			wikify(label,createTiddlyLink(place,target,false));
	},
	renderAllLinks: function(place,storyname) {
		var out="{{floatleft{";
		out+="<<storyViewer [["+storyname+"]] first first>> &nbsp;";
		out+="<<storyViewer [["+storyname+"]] previous previous>> &nbsp;";
		out+="}}}";
		out+="{{floatright{";
		out+="&nbsp; <<storyViewer [["+storyname+"]] next next>>";
		out+="&nbsp; <<storyViewer [["+storyname+"]] last last>>";
		out+="}}}";
		out+="{{center{<<storyViewer [["+storyname+"]] here>>}}}";
		wikify(out,place);
	},
	renderList: function(place,tids,tid,storyname,prompt,nobuttons,allbuttons,onlybuttons) {
		var h="";
		h+='<form style="display:inline">';
		if ((!nobuttons||onlybuttons) && allbuttons) {
			h+='<input type="button" value="'+this.firstbutton+'" ';
			h+='	style="padding:0" title="'+(tids[0]?this.firstmsg.format([tids[0]]):'')+'"';
			h+=' onclick="if (this.form.list.length<2) return; ';
			h+='	this.form.list.selectedIndex=1; this.form.list.onchange();">';
		}
		if (!nobuttons||onlybuttons) {
			h+='<input type="button" value="'+this.previousbutton+'" style="padding:0 0.3em"';
			h+=' onclick="if (this.form.list.length<2) return; ';
			h+=' 	var i=this.form.list.selectedIndex-1; if (i<1) i=1; ';
			h+='	this.form.list.selectedIndex=i; this.form.list.onchange();"';
			h+=' onmouseover="if (this.form.list.length<2) return; ';
			h+=' 	var i=this.form.list.selectedIndex-1; if (i<1) i=1; ';
			h+='	var v=this.form.list.options[i].value; if (!v.length) return; ';
			h+='	this.title=config.macros.storyViewer.prevmsg.format([v]);">';
		}
		h+='<select size="1" name="list"';
		if (onlybuttons) h+=' style="display:none;"';
		h+=' onchange="if (this.value) story.displayTiddler(this,this.value);">';
		h+='<option value="">'+prompt+'</option>';
		for (i=0; i<tids.length; i++) {
			h+='<option '+
				(tids[i]==tid?'selected ':'')+
				'value="'+tids[i]+'">\xa0\xa0'+tids[i]+'</option>';
		}
		h+='</select>';
		if (!nobuttons||onlybuttons) {
			h+='<input type="button" value="'+this.nextbutton+'" style="padding:0 0.3em"';
			h+=' onclick="var i=this.form.list.selectedIndex+1; ';
			h+='	if (i>this.form.list.options.length-1) i=this.form.list.options.length-1; ';
			h+='	this.form.list.selectedIndex=i; this.form.list.onchange();"';
			h+=' onmouseover="var i=this.form.list.selectedIndex+1; ';
			h+='	if (i>this.form.list.options.length-1) i=this.form.list.options.length-1; ';
			h+='	var v=this.form.list.options[i].value; if (!v.length) return;';
			h+='	this.title=config.macros.storyViewer.nextmsg.format([v]);">';
		}
		if ((!nobuttons||onlybuttons) && allbuttons) {
			h+='<input type="button" value="'+this.lastbutton+'" ';
			h+='	style="padding:0" title="'+(tids[tids.length-1]?this.lastmsg.format([tids[tids.length-1]]):'')+'"';
			h+=' onclick="this.form.list.selectedIndex=this.form.list.options.length-1; this.form.list.onchange();">';
		}
		h+='</form>';
		createTiddlyElement(place,"span").innerHTML=h;
	},
	renderTimer: function(place,tids,tid,delay,autostart,action) {
		var now=new Date().getTime(); // msec
		var target=createTiddlyElement(null,'input',now+Math.random()); // unique ID
		target.setAttribute('type','button'); target.style.padding='0';
		place.appendChild(target);
		target.tid		=tids[Math.min(tids.indexOf(tid)+1,tids.length-1)]||''; // next tiddler
		target.action		=action;
		target.formatTimer	=this.formatTimer;
		target.start		=this.startTimer;
		target.stop		=this.stopTimer;
		target.onmouseover	=this.pauseTimer;
		target.onmouseout	=this.resumeTimer;
		target.tick		=this.timerTick;
		target.onclick		=this.timerClick;
		target.next		=this.timerNext;
		target.start(delay,autostart);
	},
	formatTimer: function(t) {
		return '0:'+String.zeroPad(Math.floor(t/1000),2);
	},
	startTimer: function(delay,start) {
		var co=config.options; // abbrev
		start=config.macros.storyViewer.started=start||config.macros.storyViewer.started;
		var now=new Date().getTime(); // msec
		this.started=start;
		this.delay=delay;
		this.paused=start?0:delay;
		this.stopTime=now+delay; // msec
		this.title='CLICK='+(start?'reset':'start')+" slideshow timer... next: '"+this.tid+"'";
		this.style.cursor='pointer';
		this.value=this.formatTimer(delay);
		if (start) {
			var code="var e=document.getElementById('"+this.id+"'); if(e)e.tick()";
			this.timer=setTimeout(code,500);
		}
		return false;
	},
	stopTimer: function() {
		this.timer=clearTimeout(this.timer);
		this.started=config.macros.storyViewer.started=false;
		this.paused=0;
		this.title="CLICK=start slideshow timer... next: '"+this.tid+"'";
		this.value=this.formatTimer(this.delay);
		return false;
	},
	pauseTimer: function() {
		if (!this.started) return;
		var now=new Date().getTime(); // msec
		this.paused=Math.max(this.stopTime-now,0);
		this.stopTime=now+this.paused;
		return false;
	},
	resumeTimer: function() {
		if (!this.started || !this.paused) return;
		var now=new Date().getTime(); // msec
		this.stopTime=now+this.paused;
		this.paused=0;
		return false;
	},
	timerTick: function() {
		var now=new Date().getTime(); // msec
		if (!this.started)
			this.stopTime=now+this.delay;
		else if (this.paused) {
			this.stopTime=now+this.paused;
			this.title="[PAUSED] MOUSEOUT=resume, CLICK=reset... next: '"+this.tid+"'";
		}
		var remaining=this.stopTime-now;
		if (remaining>0) {
			if (this.started && !this.paused) this.value=this.formatTimer(remaining);
			var code="var e=document.getElementById('"+this.id+"'); if(e)e.tick()";
			this.timer=setTimeout(code,500);
		} else {
			this.stop();
			this.next();
		}
		return false;
	},
	timerClick: function() {
		return this.started?this.stop():this.start(this.delay,true);
	},
	timerNext: function() { // OPEN NEXT TIDDLER
		var here=story.findContainingTiddler(this);
		config.macros.storyViewer.started=true; // next slide autostarts to continue slideshow
		if (this.tid) story.displayTiddler(here,this.tid);
		config.macros.storyViewer.started=false;
		if (!here) return false;
		var t=here.getAttribute('tiddler');
		if (this.action=='close') story.closeTiddler(t);
		if (this.action=='fold' && config.commands.collapseTiddler) // see CollapseTiddlerPlugin
			config.commands.collapseTiddler.handler(null,here,t);
		return false;
	}
}
//}}}
//{{{
config.paramifiers.story = {
	onstart: function(v) {
		var t=store.getTiddler(v); if (t) t.changed();
		var list=t?t.links:store.getTiddlerText(v,"").parseParams("open",null,false);
		story.displayTiddlers(null,list);
	}
};
//}}}
/***
|Name|StoryViewerPluginInfo|
|Source|http://www.TiddlyTools.com/#StoryViewerPlugin|
|Documentation|http://www.TiddlyTools.com/#StoryViewerPluginInfo|
|Version|1.4.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for StoryViewerPlugin|
The {{{<<storyViewer>>}}} macro allows you to quickly ''display //and// navigate between a set of tiddlers'', using a droplist of titles and/or individual "first/previous/next/last" buttons/text links.  It also provides a "slideshow" feature that permits you to ''present one tiddler at a time with a countdown timer to automatically advance to the next tiddler'' after a specified number of seconds.
!!!!!Usage
<<<
{{{
<<storyViewer storyname|tagvalue list buttonoption prompt:... sort:...>>
<<storyViewer storyname|tagvalue first|previous|here|next|last sort:...>>
<<storyViewer storyname|tagvalue links sort:fieldname>>
<<storyViewer storyname|tagvalue timer:nnn autostart close|fold sort:...>>
}}}
where:
* ''storyname'' or ''tagvalue''<br>specifies a set of tiddler titles, defined either by matching a tag value, or by creating a tiddler, tagged with <<tag story>>, containing a space-separated list of titles.  //Note: You can use the {{{<<saveStory>>}}} macro (see [[StorySaverPlugin]]) to automatically create stories using the titles of the tiddlers that are currently being viewed.//  If you omit the storyname/tagname parameter, the plugin will attempt to identify a suitable story by locating the current tiddler title within a saved story tiddler.  The story view controls are not displayed unless the current tiddler title is explicitly found in at least one saved story.
** Note: if [[MatchTagsPlugin]] is installed, you can use a compound //boolean tag expression//, enclosed within doubled square brackets.  This allows you to generate sets of stories based on complex combinations of tags, rather than matching just one tag value.  [[MatchTagsPlugin]] also allows you to use a //wildcard// expression, ".*" (without quotes), that will match all tiddlers, regardless of their tag value(s).
* ''list''<br>displays a droplist of tiddlers for the specified story, with previous/next pushbuttons on either side of the list.  You can also specify which buttons will appear when using a droplist:
** ''allbuttons''<br>displays buttons for first/last as well as previous/next.
** ''nobuttons''<br>displays the droplist without any buttons
** ''onlybuttons''<br>hides the droplist and shows just the buttons
* ''prompt:...'' (default={{{"storyname..."}}})<br>specifies non-selectable label text to use as the first item in the droplist.
* ''sort:fieldname'' //(optional)//<br>when a ''tagvalue'' is used to select tiddlers, you can specify a tiddler fieldname that can be used to sort the resulting list of tiddlers, with an optional "-" prefix to indicate descending vs. ascending ordering, e.g, "sort:-modified" will generate a list of tiddlers in reverse date order (newest tiddler first).
* ''first'' or ''previous'' or ''here'' or ''next'' or ''last''<br>displays an individual link to the indicated tiddler within the story. The next/previous links are automatically calculated relative to the current tiddler.  ''here'' displays the current tiddler title.
* ''links''<br>displays the set of first, previous, here, next and last links with just one convenient macro invocation, allowing you to quickly and easily embed story navigation links into any tiddler content.
* ''timer:nnn''<br>displays an automatic countdown 'slideshow' timer, where ''nnn'' is the number of seconds between slides.  Click on the timer to start the countdown.  The countdown is paused when hovering over the timer.  Click a //running// timer to immediately advance to the next tiddler in the story.  Optional slideshow parameters:
** ''autostart''<br>automatically starts the countdown without an initial click.
** ''close'' or ''fold''<br>close or fold (see [[CollapseTiddlerPlugin]]) the current tiddler when the next tiddler in the story is opened. The default is to simply display the next tiddler following the current one.
<<<
!!!!!Examples
<<<
{{smallform{
{{{
<<storyViewer MenuDefinitions list nobuttons>>
}}}
><<storyViewer MenuDefinitions list nobuttons>> //uses "saved story" tiddler//
{{{
<<storyViewer pluginInfo>>
}}}
><<storyViewer pluginInfo>>
{{{
<<storyViewer pluginInfo list allbuttons prompt:"TiddlyTools menu definitions...">>
}}}
><<storyViewer pluginInfo list allbuttons prompt:"TiddlyTools menu definitions...">>
{{{
<<storyViewer pluginInfo first>>
<<storyViewer pluginInfo previous>>
<<storyViewer pluginInfo next>>
<<storyViewer pluginInfo last>>
}}}
><<storyViewer pluginInfo first>>
><<storyViewer pluginInfo previous>>
><<storyViewer pluginInfo next>>
><<storyViewer pluginInfo last>>
{{{
<<storyViewer pluginInfo previous label:"back">>
<<storyViewer pluginInfo next label:"forward">>
}}}
><<storyViewer pluginInfo previous label:"back">>
><<storyViewer pluginInfo next label:"forward">>
{{{
<<storyViewer pluginInfo links>>
}}}
><<storyViewer pluginInfo links>>
{{{
<<storyViewer pluginInfo timer:20 fold>>
}}}
><<storyViewer pluginInfo timer:20 fold>>
{{{
<<storyViewer ".*" prompt:"timeline..." sort:-modified>>
}}}
><<storyViewer ".*" prompt:"timeline..." sort:-modified>>
}}}
<<<
!!!!!Revisions
<<<
2011.03.11 1.4.0 added 'sort:fieldname' parameter
2011.01.24 1.3.4 in droplist onchange handler, don't clear slideshow 'started' flag (allows slideshow to continue after manual navigation)
2011.01.12 1.3.3 added config.macros.storyViewer.started (controls 'autostart' for automatic presentation of multiple pages)
2011.01.11 1.3.2 use pushbutton instead of text to display slideshow timer
2011.01.11 1.3.1 code and documentation cleanup
2011.01.10 1.3.0 added slideshow (params= timer:nnn, autostart, close/fold).  Added custom prompt for droplist (param= prompt:"text"). Added support for [[MatchTagsPlugin]]
2008.06.05 1.2.0 added custom story paramifier to extract story titles from tiddler links instead of using parseParams.  Permits use of links from any tiddler as a story, even if it contains wiki-syntax formatting in addition to list of tiddler titles
2008.03.10 *.*.* plugin size reduction: documentation moved to [[StoryViewerPluginInfo]]
2007.12.31 1.1.0 instead of readBracketedList(), use internal tiddler.links[] to retrieve story list from tiddler content.  Allows more flexible formatting of story tiddler content.
2007.12.04 *.*.* update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.23 1.0.0 Initial release, split {{{<<storyViewer>>}}} macro definition from [[StorySaverPlugin]] to allow separate installation of story saving vs. story viewing features.
<<<
/***
!!!Included styles
***/
/*{{{*/
[[StyleSheetShortcuts]]		/* convenient classes for formatting content */
[[StyleSheetAdjustments]]	/* common adjustments to TiddlyWiki core elements */
/*}}}*/
/***
!!!~PasteUp ~QuickStart Document styles (do not modify)
***/
/*{{{*/
body
		{ background:#ddf; }
.viewer
		{ background:#eef; }
#mainMenu,.tagged, .subtitle
		{ display:none !important; }
#displayArea
		{ margin-left:1em; !important; }
.menubuttons ul
		{ margin:0;padding:0; } 
.menubuttons li {
 	list-style:none;
	line-height:2em; width:100%;
	display:block; background:#999;
	border:1px solid black;
	-moz-border-radius:.3em;
	-webkit-border-radius:.3em;
	margin:0 .5em 1px 0;
	text-align:center;
	vertical-align:center;
	font-size:200%;
}
.menubuttons li:hover
		{ background:#ccc; }
.viewer, .editor
		{ min-width:[[PasteUpConfig::Width]]; }
div.snapshot.tiddler.viewer {
	width:[[PasteUpConfig::Width]] !important;
	height:[[PasteUpConfig::Height]] !important;
	padding:0em !important;
	border:0px !important;
}
#tiddlerMainMenu .viewer
		{ min-width:0; }
div[tags~="pasteup"].tiddler div.viewer,
div[tags~="part"].tiddler div.viewer {
	width:[[PasteUpConfig::Width]];
	height:[[PasteUpConfig::Height]];
	padding:0em;
	border:1px solid;
	background:#eef;
}
.popup .viewer
	{ width:auto !important; }
.pasteupcmd { display:none; }
div[tags~="pasteup"].tiddler .pasteupcmd,
div[tags~="part"].tiddler .pasteupcmd,
#tiddlerDefaultPage .pasteupcmd,
#tiddlerDefaultPart .pasteupcmd
	{ display:inline; }

@media print {
.header, .title, .subtitle, .toolbar, .pasteupcmd,
#mainMenu, #sidebar, #messageArea, #backstageButton, #backstageArea, #storyMenu
	{ display:none !important; }
.tiddler
	{ page-break-after:always; }
.tiddler .viewer
	{ border:0px !important; background: transparent !important; }
}

/*}}}*/
/*{{{*/
/* ADJUSTMENTS TO STANDARD ELEMENTS */
.headerShadow, .headerForeground
	{ padding-top:1em; white-space:nowrap; }
#mainMenu
	{ text-align:left; width:14em; padding:0.5em; }
#mainMenu table, #mainMenu table td 
	{ border:1px solid #999; border-collapse:collapse; padding:.3em; }
#displayArea
	{ margin-left:16em; margin-right:15em; }
#messageArea
	{	white-space:nowrap;
		-moz-border-radius:.5em;
		-webkit-border-radius:.5em;
	}

.messageToolbar .button
	{ font-size:80%; }
.toolbar
	{ float:right; white-space:nowrap; }
.selected .toolbar a
	{ color:black; }
.popup
	{ max-height:40em; overflow:auto; -moz-border-radius:.5em; -webkit-border-radius:.5em; padding:.5em; }
.popup li
	{ white-space:nowrap; line-height:100%; }
.viewer
	{ border:1px solid gray; -moz-border-radius:.5em; -webkit-border-radius:.5em; padding:.5em; }
.tiddler .subtitle
	{ display:inline; }
.tagged
	{ border:1px solid #999; -moz-border-radius:3px; -webkit-border-radius:3px; }
.tagged
	{ opacity:.7; }
.selected .tagged
	{ opacity:1; }
.button, .tiddler .button, #sidebarTabs .button
	{ margin:0px; padding: 0px .3em; border:1px solid transparent;
		-moz-border-radius:3px; -webkit-border-radius:3px; }
.button:hover
	{ border:1px solid #999; }
#sidebarTabs .button
	{ margin:0px 0.2em; padding:0.2em 0.3em; border:1px solid transparent;
		-moz-border-radius:3px; -webkit-border-radius:3px; display:block; }
#sidebarTabs .button:hover
	{ border:1px solid #999; }
.editor textarea
	{ font-family:monospace; }
.tab
	{	padding-bottom:1px;
		-moz-border-radius-topleft:.5em;
		-moz-border-radius-topright:.5em;
		-webkit-border-top-left-radius:.5em;
		-webkit-border-top-right-radius:.5em;
	}
.tabContents
	{ -moz-border-radius:.5em; -webkit-border-radius:.5em; }
.tabContents, .tabSelected
	{ background-color:#eef; }
.tabUnselected
	{ background-color:#79d; }
/*}}}*/
/***
|Name|StyleSheetShortcuts|
|Source|http://www.TiddlyTools.com/#StyleSheetShortcuts|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|CSS|
|Description|'convenience' classes for common formatting, alignment, boxes, tables, etc.|

These 'style tweaks' can be easily included in other stylesheet tiddler so they can share a baseline look-and-feel that can then be customized to create a wide variety of 'flavors'.
***/
/*{{{*/

/* text alignments */
.left
	{ display:block;text-align:left; }
.center
	{ display:block;text-align:center; }
.center table
	{ margin:auto !important; }
.right	
	{ display:block;text-align:right; }
.justify
	{ display:block;text-align:justify; }
.indent
	{ display:block;margin:0;padding:0;border:0;margin-left:2em; }
.floatleft
	{ float:left; }
.floatright
	{ float:right; }
.valignTop, .valignTop table, .valignTop tbody, .valignTop th, .valignTop tr, .valignTop td
	{ vertical-align:top; }
.valignBottom, .valignBottom table, .valignBottom tbody, .valignBottom th, .valignBottom tr, .valignBottom td
	{ vertical-align:bottom; }
.clear
	{ clear:both; }
.wrap
	{ white-space:normal; }
.nowrap
	{ white-space:nowrap; }
.hidden
	{ display:none; }
.show
	{ display:inline !important; }
.span
	{ display:span; }
.block
	{ display:block; }
.relative
	{ position:relative; }
.absolute
	{ position:absolute; }

/* font sizes */
.big
	{ font-size:14pt;line-height:120% }
.medium
	{ font-size:12pt;line-height:120% }
.normal
	{ font-size:9pt;line-height:120% }
.small
	{ font-size:8pt;line-height:120% }
.fine
	{ font-size:7pt;line-height:120% }
.tiny
	{ font-size:6pt;line-height:120% }
.larger
	{ font-size:120%; }
.smaller
	{ font-size:80%; }

/* font styles */
.bold
	{ font-weight:bold; }
.italic
	{ font-style:italic; }
.underline
	{ text-decoration:underline; }

/* plain list items (no bullets or indent) */
.nobullets li { list-style-type: none; margin-left:-2em; }

/* vertical tabsets - courtesy of Tobias Beer */
.vTabs .tabset {float:left;display:block;padding:0px;margin-top:.5em;min-width:20%;}
.vTabs .tabset .tab {display:block;text-align:right;padding:2px 3px 2px 7px; margin:0 1px 1px 0;}
.vTabs .tabContents {margin-left:20%;max-width:80%;padding:5px;}
.vTabs .tabContents .tabContents {border:none; background:transparent;}

/* multi-column tiddler content (not supported in Internet Explorer) */
.twocolumns { display:block;
	-moz-column-count:2; -moz-column-gap:1em; -moz-column-width:50%; /* FireFox */
	-webkit-column-count:2; -webkit-column-gap:1em; -webkit-column-width:50%; /* Safari */
	column-count:2; column-gap:1em; column-width:50%; /* Opera */
}
.threecolumns { display:block;
	-moz-column-count:3; -moz-column-gap:1em; -moz-column-width:33%; /* FireFox */
	-webkit-column-count:3; -webkit-column-gap:1em; -webkit-column-width:33%; /* Safari */
	column-count:3; column-gap:1em; column-width:33%; /* Opera */
}
.fourcolumns { display:block;
	-moz-column-count:4; -moz-column-gap:1em; -moz-column-width:25%; /* FireFox */
	-webkit-column-count:4; -webkit-column-gap:1em; -webkit-column-width:25%; /* Safari */
	column-count:4; column-gap:1em; column-width:25%; /* Opera */
}

/* page breaks */
.breakbefore { page-break-before:always; }
.breakafter { page-break-before:always; } 

/* show/hide browser-specific content for InternetExplorer vs. non-IE ("moz") browsers */
*[class="ieOnly"]
	{ display:none; } /* hide in moz (uses CSS selector) */
* html .mozOnly, *:first-child+html .mozOnly
	{ display: none; } /* hide in IE (uses IE6/IE7 CSS hacks) */

/* borderless tables */
.borderless, .borderless table, .borderless td, .borderless tr, .borderless th, .borderless tbody
	{ border:0 !important; margin:0 !important; padding:0 !important; }
.widetable, .widetable table
	{ width:100%; }

/* thumbnail images (fixed-sized scaled images) */
.thumbnail img { height:5em !important; }

/* stretchable images (auto-size to fit tiddler) */
.stretch img { width:95%; }

/* grouped content */
.outline
	{ display:block; padding:1em; -moz-border-radius:1em;-webkit-border-radius:1em; border:1px solid; }
.menubox
	{ display:block; padding:1em; -moz-border-radius:1em;-webkit-border-radius:1em; border:1px solid; background:#fff; color:#000; }
.menubox .button, .menubox .tiddlyLinkExisting, .menubox .tiddlyLinkNonExisting
	{ color:#009 !important; }
.groupbox
	{ display:block; padding:1em; -moz-border-radius:1em;-webkit-border-radius:1em; border:1px solid; background:#ffe; color:#000; }
.groupbox a, .groupbox .button, .groupbox .tiddlyLinkExisting, .groupbox .tiddlyLinkNonExisting
	{ color:#009 !important; }
.groupbox code
	{ color:#333 !important; }
.borderleft
	{ margin:0;padding:0;border:0;margin-left:1em; border-left:1px dotted; padding-left:.5em; }
.borderright
	{ margin:0;padding:0;border:0;margin-right:1em; border-right:1px dotted; padding-right:.5em; }
.borderbottom
	{ margin:0;padding:1px 0;border:0;border-bottom:1px dotted; margin-bottom:1px; padding-bottom:1px; }
.bordertop
	{ margin:0;padding:0;border:0;border-top:1px dotted; margin-top:1px; padding-top:1px; }

/* scrolled content */
.scrollbars { overflow:auto; }
.height10em { height:10em; }
.height15em { height:15em; }
.height20em { height:20em; }
.height25em { height:25em; }
.height30em { height:30em; }
.height35em { height:35em; }
.height40em { height:40em; }

/* compact form */
.smallform
	{ white-space:nowrap; }
.smallform input, .smallform textarea, .smallform button, .smallform checkbox, .smallform radio, .smallform select
	{ font-size:8pt; }

/* stretchable edit fields and textareas (auto-size to fit tiddler) */
.stretch input { width:99%; }
.stretch textarea { width:99%; }

/* compact input fields (limited to a few characters for entering percentages and other small values) */
.onechar input   { width:1em; }
.twochar input   { width:2em; }
.threechar input { width:3em; }
.fourchar input  { width:4em; }
.fivechar input  { width:5em; }

/* text colors */
.white { color:#fff !important }
.gray  { color:#999 !important }
.black { color:#000 !important }
.red   { color:#f66 !important }
.green { color:#0c0 !important }
.blue  { color:#99f !important }

/* rollover highlighting */
.mouseover 
	{color:[[ColorPalette::TertiaryLight]] !important;}
.mouseover a
	{color:[[ColorPalette::TertiaryLight]] !important;}
.selected .mouseover
	{color:[[ColorPalette::Foreground]] !important;}
.selected .mouseover .button, .selected .mouseover a
	{color:[[ColorPalette::PrimaryDark]] !important;}

/* rollover zoom text */
.zoomover
	{ font-size:80% !important; }
.selected .zoomover
	{ font-size:100% !important; }

/* [[ColorPalette]] text colors */
.Background	{ color:[[ColorPalette::Background]];	 }
.Foreground	{ color:[[ColorPalette::Foreground]];	 }
.PrimaryPale	{ color:[[ColorPalette::PrimaryPale]];	 }
.PrimaryLight	{ color:[[ColorPalette::PrimaryLight]];	 }
.PrimaryMid	{ color:[[ColorPalette::PrimaryMid]];	 }
.PrimaryDark	{ color:[[ColorPalette::PrimaryDark]];	 }
.SecondaryPale	{ color:[[ColorPalette::SecondaryPale]]; }
.SecondaryLight	{ color:[[ColorPalette::SecondaryLight]];}
.SecondaryMid	{ color:[[ColorPalette::SecondaryMid]];	 }
.SecondaryDark	{ color:[[ColorPalette::SecondaryDark]]; }
.TertiaryPale	{ color:[[ColorPalette::TertiaryPale]];	 }
.TertiaryLight	{ color:[[ColorPalette::TertiaryLight]]; }
.TertiaryMid	{ color:[[ColorPalette::TertiaryMid]];	 }
.TertiaryDark	{ color:[[ColorPalette::TertiaryDark]];	 }
.Error		{ color:[[ColorPalette::Error]];	 }

/* [[ColorPalette]] background colors */
.BGBackground	  { background-color:[[ColorPalette::Background]];	}
.BGForeground	  { background-color:[[ColorPalette::Foreground]];	}
.BGPrimaryPale	  { background-color:[[ColorPalette::PrimaryPale]];	}
.BGPrimaryLight	  { background-color:[[ColorPalette::PrimaryLight]];	}
.BGPrimaryMid	  { background-color:[[ColorPalette::PrimaryMid]];	}
.BGPrimaryDark	  { background-color:[[ColorPalette::PrimaryDark]];	}
.BGSecondaryPale  { background-color:[[ColorPalette::SecondaryPale]]; 	}
.BGSecondaryLight { background-color:[[ColorPalette::SecondaryLight]];	}
.BGSecondaryMid	  { background-color:[[ColorPalette::SecondaryMid]];	}
.BGSecondaryDark  { background-color:[[ColorPalette::SecondaryDark]]; 	}
.BGTertiaryPale	  { background-color:[[ColorPalette::TertiaryPale]];	}
.BGTertiaryLight  { background-color:[[ColorPalette::TertiaryLight]]; 	}
.BGTertiaryMid	  { background-color:[[ColorPalette::TertiaryMid]];	}
.BGTertiaryDark	  { background-color:[[ColorPalette::TertiaryDark]];	}
.BGError	  { background-color:[[ColorPalette::Error]];	 	}
/*}}}*/
/***
|Name|TextAreaPlugin|
|Source|http://www.TiddlyTools.com/#TextAreaPlugin|
|Documentation|http://www.TiddlyTools.com/#TextAreaPluginInfo|
|Version|2.2.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Adds Find/Again keyboard search, autosize, and 'stretch bar' resize for textarea controls|
!!!!!Documentation
>see [[TextAreaPluginInfo]]
!!!!!Configuration
<<<
<<option chkTextAreaExtensions>> use control-f (find), control-g (find again) inside text area
<<option chkDisableAutoSelect>> place cursor at start of textarea instead of pre-selecting content
<<option chkResizeEditor>> modify shadow EditTemplate to add resizeable text area (and autosize command)
<<<
!!!!!Revisions
<<<
2009.04.08 [2.2.1] added autosizeEditor macro to enable automatic autosizing without using toolbar command
2009.04.06 [2.2.0] added resizeListbox macro definition and adjusted dragbar width calculation.
|please see [[TextAreaPluginInfo]] for additional revision details|
2006.01.22 [1.0.0] Moved from temporary "System Tweaks" tiddler into 'real' TextAreaPlugin tiddler.
<<<
!!!!!Code
***/
//{{{
version.extensions.TextAreaPlugin= {major: 2, minor: 2, revision: 1, date: new Date(2009,4,8)};

if (config.options.chkTextAreaExtensions===undefined) config.options.chkTextAreaExtensions=true;
if (config.options.chkDisableAutoSelect===undefined) config.options.chkDisableAutoSelect=true;
if (config.options.chkResizeEditor===undefined) config.options.chkResizeEditor=true;

// automatically tweak shadow EditTemplate to add "autosizeEditor" toolbar command
if (config.options.chkResizeEditor)
	config.shadowTiddlers.EditTemplate=config.shadowTiddlers.EditTemplate.replace(/deleteTiddler/,"deleteTiddler autosizeEditor");
// automatically tweak shadow EditTemplate to add "resizeEditor" macro
if (config.options.chkResizeEditor)
	config.shadowTiddlers.EditTemplate+="<span macro='resizeEditor'></span>";

// Put focus in a specified tiddler field
Story.prototype.TextAreaExtensions_focusTiddler=Story.prototype.focusTiddler;
Story.prototype.focusTiddler = function(title,field)
{
	this.TextAreaExtensions_focusTiddler.apply(this,arguments); // first call core
	var e = this.getTiddlerField(title,field);
	if (e && config.options.chkDisableAutoSelect) {
		if (e.setSelectionRange) // FF
			e.setSelectionRange(0,0);
		else if (e.createTextRange) // IE
			{ var r=e.createTextRange(); r.collapse(true); r.select(); }
	}
	if (e && config.options.chkTextAreaExtensions) addKeyDownHandlers(e);
}
//}}}

//{{{
function addKeyDownHandlers(e)
{
	// exit if not textarea or element doesn't allow selections
	if (e.tagName.toLowerCase()!="textarea"||!e.setSelectionRange||e.initialized) return;

	// utility function: exits keydown handler and prevents browser from processing the keystroke
	var processed=function(ev) {
		ev.cancelBubble=true; // IE4+
		try{event.keyCode=0;}catch(e){}; // IE5
		if (window.event) ev.returnValue=false; // IE6
		if (ev.preventDefault) ev.preventDefault(); // moz/opera/konqueror
		if (ev.stopPropagation) ev.stopPropagation(); // all
		return false;
	}
	// capture keydown in edit field
	e.saved_onkeydown=e.onkeydown; // save current keydown handler (if any)
	e.onkeydown=function(ev) { if (!ev) var ev=window.event;
		var key=ev.keyCode;
		if (!key) {
			var char=event.which?event.which:event.charCode;
			if (char==102) key=70;
			if (char==103) key=71;
		}
		// process CTRL-F (find matching text) or CTRL-G (find next match)
		if (ev.ctrlKey && (key==70||key==71)) {

			// prompt for text to find
			var defFind=e.findText?e.findText:e.value.substring(e.selectionStart,e.selectionEnd);
			if (key==70||!e.findText||!e.findText.length) // ctrl-f or no saved search text
				{ var f=prompt("find:", defFind); e.focus(); if (f) e.findText=f; }
			if (!e.findText||!e.findText.length) return processed(ev); //  if no search text, exit

			// do case-insensitive match with 'wraparound'...  if not found, alert and exit 
			var newstart=e.value.toLowerCase().indexOf(e.findText.toLowerCase(),e.selectionStart+1);
			if (newstart==-1) newstart=e.value.toLowerCase().indexOf(e.findText.toLowerCase());
			if (newstart==-1) { alert("'"+e.findText+"' not found"); e.focus(); return processed(ev); }

			// set new selection, scroll it into view, and report line position in status bar
			e.setSelectionRange(newstart,newstart+e.findText.length);
			var linecount=e.value.split('\n').length;
			var thisline=e.value.substr(0,e.selectionStart).split('\n').length;
			e.scrollTop=Math.floor((thisline-1-e.rows/2)*e.scrollHeight/linecount);
			window.status="line: "+thisline+"/"+linecount;
			return processed(ev);
		}
		if (e.saved_onkeydown) // call previous keydown handler (if any)
			e.saved_onkeydown(ev);
	}
	e.initialized=true;
}
//}}}

// // 'autosize' toolbar command
//{{{
config.commands.autosizeEditor = {
	text: 'autosize',
	tooltip: 'automatically adjust the editor height to fit the contents',
	text_alt: '\u221Aautosize',
	hideReadOnly: false,
	handler: function(event,src,title) {
		var here=story.findContainingTiddler(src); if (!here) return;
		var ta=here.getElementsByTagName('textarea'); if (!ta) return;
		for (i=0;i<ta.length;i++) {
			// only autosize textareas actually used to edit tiddler fields
			if (ta[i].getAttribute("edit")==undefined) continue;
			ta[i].button=src;
			if (!ta[i].maxed)
				config.commands.autosizeEditor.on(ta[i]);
			else
				config.commands.autosizeEditor.off(ta[i],true);
		}
		return false;
	},
	on: function(e) {
		if (e.maxed) return; // already autosizing!
		if (e.savedheight==undefined)
			e.savedheight=e.style.height;
		if (e.savedkeyup==undefined) {
			e.savedkeyup=e.onkeyup;
			e.onkeyup=function(ev) {
				if (!ev) var ev=window.event; var e=resolveTarget(ev);
				e.style.height=e.scrollHeight+'px';
				if (e.savedkeyup) e.savedkeyup();
			}
		}
		// IE reports error: "not implemented" for onkeypress
		if (!config.browser.isIE && e.savedkeypress==undefined) {
			e.savedkeypress=e.onkeypress;
			e.onkeypress=function(ev) {
				if (!ev) var ev=window.event; var e=resolveTarget(ev);
				if (ev.keyCode==33) { // PGUP
					if (window.scrollByPages) window.scrollByPages(-1);
					return false;
				}
				if (ev.keyCode==34) { // PGDN
					if (window.scrollByPages) window.scrollByPages(1);
					return false;
				}
				if (e.savedkeypress) e.savedkeypress();
			}
		}
		e.style.height=e.scrollHeight+'px';
		if (e.button) e.button.innerHTML=config.commands.autosizeEditor.text_alt;
		e.maxed=true;
	},
	off: function(e,resetHeight) {
		if (resetHeight) e.style.height=e.savedheight;
		e.onkeyup=e.savedkeyup;
		// IE reports error: "not implemented" for onkeypress
		if (!config.browser.isIE) e.onkeypress=e.savedkeypress;
		if (e.button) e.button.innerHTML=config.commands.autosizeEditor.text;
		e.maxed=false;
	}
};

config.macros.autosizeEditor={
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var here=story.findContainingTiddler(place); if (!here) return;
		var ta=here.getElementsByTagName('textarea'); if (!ta) return;
		for (i=0;i<ta.length;i++) {
			// only autosize textareas actually used to edit tiddler fields
			if (ta[i].getAttribute("edit")==undefined) continue;
			config.commands.autosizeEditor.on(ta[i]);
		}
		return false;
	}
}
//}}}

// // grab-and-stretch handle
//{{{
config.macros.resizeEditor = { // add stretch bar to editor textarea
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var here=story.findContainingTiddler(place); if (!here) return;
		var ta=here.getElementsByTagName('textarea');
		if (ta) for (i=0;i<ta.length;i++) {
			// only resize tiddler editor textareas
			if (ta[i].getAttribute("edit")==undefined) continue;
			new window.TextAreaResizer(ta[i]);
		}
	}
}

config.macros.resizeTiddler = { // add stretch bar to tiddler viewer element
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var here=story.findContainingTiddler(place); if (!here) return;
		var elems=here.getElementsByTagName('div');
		if (elems) for (i=0;i<elems.length;i++) if (hasClass(elems[i],'viewer')) break;
		if (i<elems.length) new window.TextAreaResizer(elems[i]);
	}
}

config.macros.resizeFrame = { // add stretch bar to iframes
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var here=story.findContainingTiddler(place); if (!here) return;
		var fr=here.getElementsByTagName('iframe');
		if (fr) for (i=0;i<fr.length;i++) new window.TextAreaResizer(fr[i]);
	}
}

config.macros.resizeListbox = { // add stretch bar to listbox controls
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var here=story.findContainingTiddler(place); if (!here) here=place;
		var fr=here.getElementsByTagName('select');
		if (fr) for (i=0;i<fr.length;i++) new window.TextAreaResizer(fr[i]);
	}
}

// TextAreaResizer script by Jason Johnston (jj@lojjic.net)
// Created August 2003.  Use freely, but give me credit.
// adds a handle below textareas that the user can drag with the mouse to resize the textarea.
// MODIFIED by ELS for use with TW

window.TextAreaResizer = function(elt) {
	this.element = elt;
	this.create();
}
window.TextAreaResizer.prototype = {
	create : function() {
		var elt = this.element;
		var thisRef = this;
		var h = this.handle = document.createElement("div");
		h.style.height = "3px"; // was 4px... looked too fat!
		h.style.overflow = "hidden"; // ELS: force IE to trim height to < 1em
		var adjust=elt.nodeName=='textarea'?4:0;  // 4 pixels for textarea border edge
//		h.style.width=(elt.offsetWidth-adjust)+"px";
		h.style.width="auto";
		h.style.backgroundColor = "#999"; // ELS: standard mid-tone (dark) gray
		h.style.cursor = "s-resize";
		h.title = "Drag to resize text box";
		h.onmousedown=function(evt){thisRef.dragStart(evt)};
		elt.parentNode.insertBefore(h, elt.nextSibling);
	},
	dragStart : function(evt) {
		if (!evt) var evt=window.event;
		this.dragStop(evt); // ELS: stop any current drag processing first
		var thisRef = this;
		this.dragStartY = evt.clientY;
		this.dragStartH = this.element.offsetHeight;
		document.savedmousemove=document.onmousemove;
		document.onmousemove=this.dragMoveHdlr=function(evt){thisRef.dragMove(evt)};
		document.savedmouseup=document.onmouseup;
		document.onmouseup=this.dragStopHdlr=function(evt){thisRef.dragStop(evt)};
	},
	dragMove : function(evt) {
		if (!evt) var evt=window.event;
		// ELS: make sure height is at least 10px
		var h=this.dragStartH+evt.clientY-this.dragStartY;
		if (h<10) h=10; this.element.style.height=h+"px";
		// ELS: match handle to textarea width (which may have changed due to document scrollbars)
//		var adjust=this.element.nodeName.toLowerCase()=='textarea'?4:0; // 4 pixels for textarea
//		this.handle.style.width=(this.element.offsetWidth-adjust)+"px";
		// ELS: when manually resizing, disable autoresizing (without restoring saved height)
		if (this.element.maxed!=undefined && this.element.maxed)
			config.commands.autosizeEditor.off(this.element,false);
	},
	dragStop : function(evt) {
		if (!evt) var evt=window.event;
		document.onmousemove=(document.savedmousemove!=undefined)?document.savedmousemove:null;
		document.onmousemove=(document.savedmouseup!=undefined)?document.savedmouseup:null;
	},
	destroy : function() {
		var elt = this.element;
		elt.parentNode.removeChild(this.handle);
		elt.style.height = "";
	}
};
//}}}
/%
!info
|Name|ToggleRightSidebar|
|Source|http://www.TiddlyTools.com/#ToggleRightSidebar|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|show/hide right sidebar (SideBarOptions)|
Usage
<<<
{{{
<<tiddler ToggleRightSidebar>>
<<tiddler ToggleRightSidebar with: label tooltip class>>
}}}
Try it: <<tiddler ToggleRightSidebar##show
	with: {{config.options.chkShowRightSidebar?'►':'◄'}}>>
<<<
Configuration:
<<<
copy/paste the following settings into a tiddler tagged with <<tag systemConfig>> and then modify the values to suit your preferences:
{{{
config.options.chkShowRightSidebar=true;
config.options.txtToggleRightSideBarLabelShow="◄";
config.options.txtToggleRightSideBarLabelHide="►";
}}}
<<<
!end
!show
<<tiddler {{
	var co=config.options;
	if (co.chkShowRightSidebar===undefined) co.chkShowRightSidebar=true;
	var sb=document.getElementById('sidebar');
	var da=document.getElementById('displayArea');
	if (sb) {
		sb.style.display=co.chkShowRightSidebar?'block':'none';
		da.style.marginRight=co.chkShowRightSidebar?'':'1em';
	}
'';}}>><html><nowiki><a href='javascript:;' title="$2" class="$3"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	var co=config.options;
	var opt='chkShowRightSidebar';
	var show=co[opt]=!co[opt];
	var sb=document.getElementById('sidebar');
	var da=document.getElementById('displayArea');
	if (sb) {
		sb.style.display=show?'block':'none';
		da.style.marginRight=show?'':'1em';
	}
	saveOptionCookie(opt);
	var labelShow=co.txtToggleRightSideBarLabelShow||'&#x25C4;';
	var labelHide=co.txtToggleRightSideBarLabelHide||'&#x25BA;';
	if (this.innerHTML==labelShow||this.innerHTML==labelHide) 
		this.innerHTML=show?labelHide:labelShow;
	this.title=(show?'hide':'show')+' right sidebar';
	var sm=document.getElementById('storyMenu');
	if (sm) config.refreshers.content(sm);
	return false;
">$1</a></html>
!end
%/<<tiddler {{
	var src='ToggleRightSidebar';
	src+(tiddler&&tiddler.title==src?'##info':'##show');
}} with: {{
	var co=config.options;
	var labelShow=co.txtToggleRightSideBarLabelShow||'&#x25C4;';
	var labelHide=co.txtToggleRightSideBarLabelHide||'&#x25BA;';
	'$1'!='$'+'1'?'$1':(co.chkShowRightSidebar?labelHide:labelShow);
}} {{
	var tip=(config.options.chkShowRightSidebar?'hide':'show')+' right sidebar';
	'$2'!='$'+'2'?'$2':tip;
}}{{
	'$3'!='$'+'3'?'$3':'';
}}>>
|~ViewToolbar|closeTiddler editTiddler snapshotPrintViewer snapshotSaveViewer permalink |
|~EditToolbar|+saveTiddler -cancelTiddler deleteTiddler|
/***
|Name:|TrashPlugin_da|
|Version:|1.2.0|
|Source:|http://www.TiddlyTools.com/#TrashPlugin|
|Author:|Eric Shulman|
|Translator|Måns Mårtensson|
|OriginalSource:|http://ido-xp.tiddlyspot.com/#TrashPlugin|
|OriginalAuthor:|Ido Magal (idoXatXidomagalXdotXcom)|
|License:|[[BSD open source license]]|
|CoreVersion:|2.1.0|
|Description|add 'Trash' tag to tiddlers instead of deleting them|
!!!!!Documentation
<<<
When TrashPlugin is installed and you click on the 'delete' command in the tiddler toolbar, rather than directly removing the tiddler from the system, it will be tagged with the following tags:
{{{
Trash excludeLists excludeMissing excludeSearch systemConfigDisable
}}}
As a result, although the tiddler still exists within the document, it is ''hidden from view and will not be searched or invoked as a plugin.''
*{{block{
To view a list of all tiddlers tagged with {{{Trash}}}, simply open the [[Trash]] tiddler (aka, the "trash can").}}}
*{{block{
To reclaim a tiddler from the [[Trash]], click on a title in the trash can to open that tiddler.  Then, edit it to remove the Trash tag (as well as the other tags noted above).}}}
*{{block{
To empty the trash can (i.e. actually //delete// the tiddlers), click on the ''//"empty trash"//'' button that appears in the [[Trash]] tiddler.  You can also add this button to your [[SideBarOptions]] or any other desired location by using the following macro:
{{{
<<emptyTrash>>
}}}
}}}
*{{block{
To ''bypass the trash can'' and use the normal delete handling (with the usual confirmation messages, if chkConfirmDelete is enabled), hold CTRL while clicking 'delete'}}}
*{{block{
To ''bypass both the trash can //and// the confirmation message'' and //immediately delete// the tiddler without any further interaction, hold CTRL+SHIFT while clicking 'delete'}}}
<<<
!!!!!Revisions
<<<
2009.05.20 [1.2.0] documentation rewrite and code cleanup/reduction
2009.05.12 [1.1.0.5] refactored code to add entry point: {{{config.commands.deleteTiddler.sendToTrash(title)}}}
2008.11.14 [1.1.0.4] added SHIFT-CLICK = bypass trash and delete immediately WITHOUT CONFIRMATION
2008.10.14 [1.1.0.3] return FALSE from emptyTrash() handler (fixes IE page transition error)
2008.05.18 [1.1.0.2] when creating the Trash tiddler, pass an empty tags array [] instead of a null value, so other plugins (e.g., InstantTimestampPlugin) won't fail
2006.12.21 [1.1.0.1] only call setDirty() when actually removing tiddlers from trash
2006.12.12 [1.1.0.0] added movedMsg (feedback when tiddler is tagged as Trash).   Make sure tiddler actually exists before tagging it with 'Trash'.  Fetch correct tiddler before checking for 'systemConfig' tag
2006.12.11 [1.0.3.1] Don't create Trash tiddler until needed. Remove Trash tiddler when no trash remains. Don't tag Trash tiddler with 'TrashPlugin'. Moved all user-visible strings to variables so they can be translated by 'lingo' plugins. Use displayMessage() instead of alert()
2006.12.11 [1.0.3] Fixed broken reference to core deleteTiddler. Now storing reference to core deleteTiddler in emptyTrash macro. Reduced deleteTiddler hijacking to only the handler.
2006.12.11 [1.0.2] EmptyTrash now uses removeTiddler instead of deleteTiddler. Supports trashing systemConfig tiddlers (adds systemConfigDisable tag).
2006.12.10 [1.0.1] Replaced TW version with proper Core reference. Now properly hijacking deleteTiddler command.
2006.12.10 [1.0.0] First draft.
<<<
!!!!!Code
***/
//{{{
version.extensions.TrashPlugin= {major: 1, minor: 2, revision: 0, date: new Date(2009,5,20)};
//}}}
//{{{
config.macros.emptyTrash = {
	tag: 'Skrald',
	movedMsg: "'%0' er blevet tagget med %1",
	label: 'Tøm skrald',
	tooltip: 'Slet alle tiddlere tagget med %0',
	tooltipOlder: 'Slet tiddlere der er tagget med %0 som er ældre end %1 dage gamle',
	emptyMsg: 'Skraldespanden er tom',
	noneToDeleteMsg: 'Der er ingen tiddlere i skraldespanden, som er ældre end %0 dage gamle',
	confirmMsg: "De følgende tiddlere vil blive slettede:\n\n'%0'\n\nOK at fortsætte?",
	deletedMsg: "Slettede '%0'",
	handler: function ( place,macroName,params,wikifier,paramString,tiddler ) {
		var namedParams = (paramString.parseParams(daysOld))[0];
		var daysOld = namedParams['daysOld'] ? namedParams['daysOld'][0] : 0; // default
		var buttonTitle = namedParams['title'] ? namedParams['title'][0] : this.label;
		var buttonTip=this.tooltip.format([this.tag])
		if (daysOld) buttonTip=this.tooltipOlder.format([this.tag,daysOld])
		var b=createTiddlyButton(place,buttonTitle,buttonTip,this.emptyTrash);
		b.setAttribute('daysOld',daysOld);
	},
	emptyTrash: function() {
		var cme=config.macros.emptyTrash; // abbrev
		var daysOld=this.getAttribute('daysOld');
		var compareDate=new Date(); compareDate.setDate(compareDate.getDate()-daysOld);
		var collected=[];
		store.forEachTiddler(function(title,tiddler) {
			if (tiddler.isTagged(cme.tag) && tiddler.modified<compareDate)
				collected.push(title);
		});
		if (!collected.length)
			displayMessage(daysOld ? cme.noneToDeleteMsg.format([daysOld]) : cme.emptyMsg);
		else if (confirm(cme.confirmMsg.format([collected.join("', '")]))) {
			for (var i=0;i<collected.length;i++) {
				store.removeTiddler(collected[i]);
				store.setDirty(true);
				displayMessage(cme.deletedMsg.format([collected[i]]));
			}
		}
		if (!store.getTaggedTiddlers(cme.tag).length) // remove Trash if empty
			{ story.closeTiddler(cme.tag,true,false); store.removeTiddler(cme.tag); }
		else
			story.refreshTiddler(cme.tag,false,true); // refresh Trash if visible
		return false;
	}
}
//}}}
// // hijack delete command
//{{{
config.commands.deleteTiddler.orig_handler=config.commands.deleteTiddler.handler;
config.commands.deleteTiddler.handler=function(event,src,title) {
	// BYPASS TRASH: CTRL=normal delete, CTRL+SHIFT=without confirmation
	if (event.ctrlKey) {
		if (event.shiftKey) { var temp=config.options.chkConfirmDelete; config.options.chkConfirmDelete=false; }
		config.commands.deleteTiddler.orig_handler.apply(this,arguments);
		if (event.shiftKey) config.options.chkConfirmDelete=temp;
		story.refreshTiddler(config.macros.emptyTrash.tag,false,true);
		return false;
	}
	config.commands.deleteTiddler.sendToTrash(title);
	return false;
};

config.commands.deleteTiddler.sendToTrash = function(title) {
	var cme=config.macros.emptyTrash; // abbrev
	if (!store.tiddlerExists(title)) return; // make sure tiddler actually exists
	if (!store.tiddlerExists(cme.tag)) // make sure Trash tiddler exists
		store.saveTiddler(cme.tag,cme.tag,'<<emptyTrash>>','TrashPlugin',new Date(),[],{});
	store.setTiddlerTag(title,1,cme.tag);
	store.setTiddlerTag(title,1,'excludeLists');
	store.setTiddlerTag(title,1,'excludeMissing');
	store.setTiddlerTag(title,1,'excludeSearch');
	if (store.getTiddler(title).isTagged('systemConfig'))
		store.setTiddlerTag(title,1,'systemConfigDisable');
	story.closeTiddler(title,true);
	if(config.options.chkAutoSave) saveChanges();
	displayMessage(cme.movedMsg.format([title,cme.tag]));
	story.refreshTiddler(cme.tag,false,true);
};
//}}}
/***
Description: Contains the stuff you need to use Tiddlyspot
Note, you also need UploadPlugin, PasswordOptionPlugin and LoadRemoteFileThroughProxy
from http://tiddlywiki.bidix.info for a complete working Tiddlyspot site.
***/
//{{{

// edit this if you are migrating sites or retrofitting an existing TW
config.tiddlyspotSiteId = 'pasteup-da';

// make it so you can by default see edit controls via http
config.options.chkHttpReadOnly = false;
window.readOnly = false; // make sure of it (for tw 2.2)
window.showBackstage = true; // show backstage too

// disable autosave in d3
if (window.location.protocol != "file:")
	config.options.chkGTDLazyAutoSave = false;

// tweak shadow tiddlers to add upload button, password entry box etc
with (config.shadowTiddlers) {
	SiteUrl = 'http://'+config.tiddlyspotSiteId+'.tiddlyspot.com';
	SideBarOptions = SideBarOptions.replace(/(<<saveChanges>>)/,"$1<<tiddler TspotSidebar>>");
	OptionsPanel = OptionsPanel.replace(/^/,"<<tiddler TspotOptions>>");
	DefaultTiddlers = DefaultTiddlers.replace(/^/,"[[WelcomeToTiddlyspot]] ");
	MainMenu = MainMenu.replace(/^/,"[[WelcomeToTiddlyspot]] ");
}

// create some shadow tiddler content
merge(config.shadowTiddlers,{

'TspotOptions':[
 "tiddlyspot password:",
 "<<option pasUploadPassword>>",
 ""
].join("\n"),

'TspotControls':[
 "| tiddlyspot password:|<<option pasUploadPassword>>|",
 "| site management:|<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . .  " + config.tiddlyspotSiteId + ">>//(requires tiddlyspot password)//<br>[[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]], [[download (go offline)|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download]]|",
 "| links:|[[tiddlyspot.com|http://tiddlyspot.com/]], [[FAQs|http://faq.tiddlyspot.com/]], [[blog|http://tiddlyspot.blogspot.com/]], email [[support|mailto:support@tiddlyspot.com]] & [[feedback|mailto:feedback@tiddlyspot.com]], [[donate|http://tiddlyspot.com/?page=donate]]|"
].join("\n"),

'WelcomeToTiddlyspot':[
 "This document is a ~TiddlyWiki from tiddlyspot.com.  A ~TiddlyWiki is an electronic notebook that is great for managing todo lists, personal information, and all sorts of things.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //What now?// &nbsp;&nbsp;@@ Before you can save any changes, you need to enter your password in the form below.  Then configure privacy and other site settings at your [[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]] (your control panel username is //" + config.tiddlyspotSiteId + "//).",
 "<<tiddler TspotControls>>",
 "See also GettingStarted.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Working online// &nbsp;&nbsp;@@ You can edit this ~TiddlyWiki right now, and save your changes using the \"save to web\" button in the column on the right.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Working offline// &nbsp;&nbsp;@@ A fully functioning copy of this ~TiddlyWiki can be saved onto your hard drive or USB stick.  You can make changes and save them locally without being connected to the Internet.  When you're ready to sync up again, just click \"upload\" and your ~TiddlyWiki will be saved back to tiddlyspot.com.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Help!// &nbsp;&nbsp;@@ Find out more about ~TiddlyWiki at [[TiddlyWiki.com|http://tiddlywiki.com]].  Also visit [[TiddlyWiki.org|http://tiddlywiki.org]] for documentation on learning and using ~TiddlyWiki. New users are especially welcome on the [[TiddlyWiki mailing list|http://groups.google.com/group/TiddlyWiki]], which is an excellent place to ask questions and get help.  If you have a tiddlyspot related problem email [[tiddlyspot support|mailto:support@tiddlyspot.com]].",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Enjoy :)// &nbsp;&nbsp;@@ We hope you like using your tiddlyspot.com site.  Please email [[feedback@tiddlyspot.com|mailto:feedback@tiddlyspot.com]] with any comments or suggestions."
].join("\n"),

'TspotSidebar':[
 "<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . .  " + config.tiddlyspotSiteId + ">><html><a href='http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download' class='button'>download</a></html>"
].join("\n")

});
//}}}
/***
|Name|UndoPlugin|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#UndoPlugin|
|Documentation|http://www.TiddlyTools.com/#UndoPlugin|
|Version|0.2.1|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|undo/redo changes to tiddlers|
|Status|Experimental - DO NOT DISTRIBUTE|
This plugin records changes to tiddlers edited during the session, allowing you to quickly revert to previous revisions of a tiddler, even after pressing 'done'.
!!!!!Documentation
<<<
TBD
<<<
!!!!!Configuration
<<<
<<option chkEnableUndo>> enable undo handling
<<<
!!!!!Revisions
<<<
2011.09.11 0.2.1 in setmsg(), make sure undo stack is not empty.  In go(), make sure index is >0.  added disabledmsg with option checkbox.  In render(), use wikify() to display static menu content (noundomsg/disabledmsg)
2011.09.07 0.2.0 refactored click handler and added toolbar command wrapper
2011.05.15 0.1.1 edits to message text
2011.05.02 0.1.0 started
<<<
!!!!!Code
***/
//{{{
version.extensions.UndoPlugin= {major: 0, minor: 2, revision: 1, date: new Date(2011,9,11)};

if (config.options.chkEnableUndo===undefined) config.options.chkEnableUndo=true;

config.macros.undo =  {
	label: 'undo',
	prompt: 'undo changes',
        tip: 'undo changes to "%0"',
	multimsg: 'Undo %0 tiddler changes.  Are you sure?',
	revertedmsg: '"%0" - previous content restored',
	renamedmsg: '"%0" - renamed to "%1"',
	deletedmsg: '"%0" - removed',
	shadowmsg: '"%0" - default (shadow) content restored',
	noundomsg: 'nothing to undo',
	disabledmsg: 'undo is disabled\n----\n<<option chkEnableUndo>>enable undo',
	undoheading: 'undo tiddler changes:',
	dateformat: 'YYYY.0MM.0DD 0hh:0mm:0ss',
	popupformat: '%1 %0<div style="font-size:80%"><i>action: </i><b>%2</b></div>',
	changes: [], // the list of previous tiddler changes
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var p=paramString.parseParams('name',null,true,false,true);
		var label=getParam(p,'label',this.label);
		var prompt=getParam(p,'prompt',this.prompt);
		createTiddlyButton(place,label,prompt,this.click);
	},
	click: function(ev){
		var p=Popup.create(this); if (!p) return false;
		config.macros.undo.render(p);
		Popup.show();
		ev=ev||window.event; ev.cancelBubble=true;
		if(ev.stopPropagation) ev.stopPropagation();
		return false;
	},
	render: function(p) {
		var cmu=config.macros.undo; // abbrev
		if (!config.options.chkEnableUndo) wikify(cmu.disabledmsg,p);
		else if (!cmu.changes.length) wikify(cmu.noundomsg,p);
		else {
			createTiddlyText(p, cmu.undoheading);
			for (var i=cmu.changes.length-1; i>=0; i--) { var c=cmu.changes[i]; var t=c.tiddler;
				var b=createTiddlyButton(createTiddlyElement(p,'li'),
					c.title, cmu.tip.format([c.title]),
					function(ev){return config.macros.undo.go(this.getAttribute('i'));});
				b.innerHTML=cmu.popupformat.format(
					[c.title,c.when.formatString(cmu.dateformat),c.msg]);
				b.setAttribute('i',i);
			}
		}
	},
	add: function(title,tiddler,action,msg){
		this.changes.push({
			title:title,
			tiddler:merge({},tiddler),
			action: action, // create, rename, change, delete
			when: new Date(),
			who: config.options.txtUserName,
			msg: msg
		});
	},
	setmsg: function(msg) {
		if (this.changes.length) this.changes[this.changes.length-1].msg=msg;
	},
	reset: function(i){
		while (this.changes.length) this.changes.pop();
	},
	go: function(i){
		var co=config.options; // abbrev
		var steps=this.changes.length-i; if (steps<0) return false;
		if (steps>1 && !confirm(this.multimsg.format([steps]))) return false;
		var temp=co.chkEnableUndo; co.chkEnableUndo=false; // SUSPEND undo
		var msgs=[];
		for (var j=this.changes.length; j>i; j--) {
			var c=this.changes.pop();
			if (c.action=='create') {
				store.removeTiddler(c.title);
				m=store.isShadowTiddler(c.title)?this.shadowmsg:this.deletedmsg;
				msgs.push(m.format([c.title]));
			} else {
				var t=c.tiddler;
				var revert=store.getTiddlerText(c.title)!=t.text;
				var rename=c.title!=t.title
				store.saveTiddler(t.title,t.title,t.text,
					t.modifier,t.modified,t.tags,t.fields);
				if (rename) { // RENAME: re-render with previous name
					var tidelem=story.getTiddler(c.title);
					if (tidelem) { // if displayed, re-render with previous name
						story.displayTiddler(tidelem,t.title);
						story.closeTiddler(c.title);
					}
					store.removeTiddler(c.title);
					msgs.push(this.renamedmsg.format([c.title,t.title]));
				}
				if (revert) msgs.push(this.revertedmsg.format([t.title]));
			}
		}
		co.chkEnableUndo=temp; // RESUME undo
		while (msgs.length) displayMessage(msgs.shift());
		autoSaveChanges();
		return false;
	}
};
//}}}
// // TOOLBAR COMMAND: undo
//{{{
config.commands.undoChanges = {
	text: 'undo',
	hideReadOnly: true,
	tooltip: 'undo individual document changes since the last save',
	handler: function(ev,src,title) { return config.macros.undo.click.call(src,ev); }
};
//}}}
// // HIJACKS - update changes when a tiddler is saved or deleted
//{{{
if (store.undo_saveTiddler==undefined) store.undo_saveTiddler=store.saveTiddler;
store.saveTiddler = function(title,newTitle,text) {
	var tiddler=store.getTiddler(title);
	if (config.options.chkEnableUndo) {
		var msgs=[];
		if (!tiddler) {
			var action='create';
			msgs.push('remove "'+newTitle+'"');
			if (store.isShadowTiddler(newTitle))
				msgs.push('use default (shadow) content');
		} else {
			var action=title!=newTitle?'rename':'change';
			if (action=='rename') {
				msgs.push('rename to "'+title+'"');
			}
			if (store.getTiddlerText(title)!=text || !msgs.length)
				msgs.push('restore previous content');
		}
		config.macros.undo.add(newTitle,tiddler,action,msgs.join(', '));
	}
	this.undo_saveTiddler.apply(this,arguments);
}
if (store.undo_removeTiddler==undefined) store.undo_removeTiddler=store.removeTiddler;
store.removeTiddler = function(title) {
	var tiddler=store.getTiddler(title);
	if (tiddler && config.options.chkEnableUndo) {
		var action='delete';
		var msg='restore deleted tiddler';
		config.macros.undo.add(title,tiddler,action,msg);
	}
	this.undo_removeTiddler.apply(this,arguments);
}
//}}}
/***
|Name|UnsavedChangesPlugin|
|Source|http://www.TiddlyTools.com/#UnsavedChangesPlugin|
|Version|3.3.5|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|show droplist of tiddlers that have changed since the last time the document was saved|
Display a list of tiddlers that have been changed since the last time the document was saved.  The list includes all new/modified tiddlers as well as those changed with "minor edits" enabled and any tiddlers that you import during the session, regardless of their modification date.
!!!!!Usage
<<<
{{{
<<unsavedChanges panel>> or <<unsavedChanges>>
}}}
{{indent{
the ''panel'' keyword displays a 'control panel' interface containing a droplist of unsaved tiddlers and a 'goto' button, along with a command link to 'save changes'.  Depending upon what other plugins are installed, several additional elements will also be displayed: When [[NestedSlidersPlugin]] is installed, the entire control panel is contained within a ''SLIDER''.  When [[LoadTiddlersPlugin]] is installed, a ''REVERT'' button is added.  When [[SaveAsPlugin]] is installed, a ''SAVE AS'' link is added.  When [[UploadPlugin]] is installed, an ''UPLOAD'' (or ''save to web'') link is added.  When [[TrashPlugin]] is installed and there are tiddlers tagged with<<tag Trash>>, an ''EMPTY TRASH'' link is added.
}}}
{{{
<<unsavedChanges list separator>>
}}}
{{indent{
the ''list'' keyword displays a simple space-separated list of unsaved tiddlers without any other command links.  You can specify an optional ''separator'' value that can be used in place of the default space character.  For example, you can specify {{{"<br>"}}} as the separator in order to display each link, one per line.
}}}
{{{
<<unsavedChanges command label tip>>
}}}
{{indent{
the ''command'' keyword displays a single 'command link' that, when clicked, displays a ~TiddlyWiki popup containing the list of unsaved tiddlers, the 'save changes' command and, depending upon what other plugins are installed, additional commands for 'save as', 'upload', and 'empty trash' (similar to the panel display described above).

You can specify optional ''label'' and ''tip'' parameters in the macro to customize the command link text and tooltip.  The default label for the command link is: "There %1 %0 unsaved tiddler%2...", where:
* %0 is automatically replaced with the number of unsaved changes
* %1 is either "is" (if changes=1) or "are" (if changes>1)
* %2 is either blank (if changes=1) or "s" (if changes>1)
resulting in the text: //"There is 1 unsaved tiddler...", "There are 2 unsaved tiddlers...", etc.//
}}}
<<<
!!!!!Examples
<<<
^^//note: the following examples will not display any output unless you have already created/modified tiddlers in the current document.//^^
{{{<<unsavedChanges>>}}}
<<unsavedChanges>>
----
{{{<<unsavedChanges command>>}}}
<<unsavedChanges command>>
----
{{{<<unsavedChanges list>>}}}
<<unsavedChanges list>>
----
{{{<<unsavedChanges list "<br>">>}}}
<<unsavedChanges list "<br>">>
<<<
!!!!!Revisions
<<<
2011.04.29 3.3.5 in panel(), use custom label (if provided).  Also, removed "small" style from panel commands so surrounding CSS font size will be used.
2010.12.05 3.3.4 display 'save as...' command even if readOnly
2009.03.02 3.3.3 fix handling for titles that contain HTML special chars (lt,gt,quot,amp)
2008.09.02 3.3.2 cleanup popup list output generation and added timestamps/sizes to popup display
2008.08.23 3.3.1 added optional custom 'label' and 'tip' params to 'command' mode and defined default values for mode, label, tip, and separator as object properties for I18N/L10N-readiness.
2008.08.21 3.3.0 complete re-write of rendering and refresh processing to support multiple instances and automatic self-refresh (no longer depends upon core refresh notifications)
2008.08.21 3.2.0 added 'command' option for link+popup as alternative to 'control panel' interface
2008.04.22 3.1.2 use SaveAsPlugin instead of obsolete NewDocumentPlugin to add "save as" link
2007.12.22 3.1.1 hijack removeTiddler() instead of low-level deleteTiddler() to correct tracking and refresh handling issues.  in saveTiddler(), check for 'tiddler rename' (title!=newtitle) and adjust list accordingly.
2007.12.21 3.1.0 added support for {{{<<unsavedChanges list separator>>}}} usage to unsaved tiddlers as a simple list of links, embedded in tiddler content (e.g., [[MainMenu]])
2007.12.20 3.0.0 rewrite to track ALL changed tiddlers, including imports and minor edits, regardless of saved modification dates.  Also, rewrote display logic to directly refresh macro output instead of triggering a page refresh.  The entire process is MUCH more efficient now.
2007.08.02 2.0.0 converted from inline script
2007.01.01 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.UnsavedChangesPlugin= {major: 3, minor: 3, revision: 5, date: new Date(2011,4,29)};

config.macros.unsavedChanges = {
	changed: [], // list of currently unsaved tiddler titles
	defMode: "panel",
	defSep: " ",
	defLabel: "Der er %0 ugemt%2 tiddler%2",
	defTip: "se en liste over ugemte tiddler ændringer",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var wrapper=createTiddlyElement(place,"span",null,"ugemteÆndringer");
		wrapper.setAttribute("mode",params[0]||this.defMode);
		wrapper.setAttribute("sep",params[1]||this.defSep); // for 'list' mode
		wrapper.setAttribute("label",params[1]||this.defLabel); // for 'command' mode
		wrapper.setAttribute("tip",params[2]||this.defTip); // for 'command' mode
		this.render(wrapper);
	},
	render: function(wrapper) {
		removeChildren(wrapper); // make sure its empty
		if (!this.changed.length) return; // no changes = no output
		switch (wrapper.getAttribute("mode")) {
			case "command": this.command(wrapper); break;
			case "list": this.list(wrapper); break;
			case "panel": default: this.panel(wrapper); break;
		}
	},
	refresh: function() {
		var wrappers=document.getElementsByTagName("span");
		for (var w=0; w<wrappers.length; w++)
			if (hasClass(wrappers[w],"unsavedChanges"))
				this.render(wrappers[w]);
	},
	list: function(place) { // show simple list of unsaved tiddlers
		wikify("[["+this.changed.join("]]"+place.getAttribute("sep")+"[[")+"]]",place);
	},
	command: function(place) { // show command link with popup list
		var c=this.changed.length;
		var txt=place.getAttribute("label").format([c,c==1?'er':'er',c==1?'':'e']);
		var tip=place.getAttribute("tip");
		var action=function(ev) { if (!ev) var ev=window.event;
			var p=Popup.create(this); if (!p) return false;
			var d=createTiddlyElement(p,"div");
			d.style.whiteSpace="normal"; d.style.width="auto"; d.style.padding="2px";
			// gather pretty links for changed tiddlers
			var list=[]; var item=" &nbsp;[[%1 - %0 (%2 bytes)|%0]]&nbsp; ";
			for (var i=config.macros.unsavedChanges.changed.length-1; i>=0; i--) {
				var tid=store.getTiddler(config.macros.unsavedChanges.changed[i]);
				if (!tid) continue;
				var when=tid.modified.formatString('YYYY.0MM.0DD 0hh:0mm:0ss');
				list.push(item.format([tid.title,when,tid.text.length]));
			}
			wikify("@@white-space:nowrap;"+list.join("<br>")+"@@",d);
			var t="\n----\n";
			t+="@@white-space:nowrap;display:block;text-align:center; &nbsp;";
			if (!readOnly) {
				t+="<<saveChanges>>";
				t+=config.macros.saveAs?" | <<saveAs>>":"";
				t+=config.macros.upload?" | <<upload>>":"";
				t+=(config.macros.emptyTrash&&store.getTaggedTiddlers("Skrald").length)?" | <<emptyTrash>>":"";
			} else {
				t+=config.macros.saveAs?"<<saveAs>>":"";
			}
			t+="&nbsp; @@";
			wikify(t,d);
			Popup.show();
			ev.cancelBubble=true; if(ev.stopPropagation)ev.stopPropagation();
			return(false);
		}
		createTiddlyButton(place,txt,tip,action,"button");
	},
	panel: function(place) { // show composite droplist+buttons+commands
		// gather changed tiddlers (in reverse order by date - most recent first)
		var tids=[]; for (var i=this.changed.length-1; i>=0; i--)
			{ var t=store.getTiddler(this.changed[i]); if (t) tids.push(t); }
		tids.sort(function(a,b){return a.modified<b.modified?-1:(a.modified==b.modified?0:1);});
		// generate droplist items
 		var list=[]; var item='<option value="%0">%1 - %0 (%2 bytes)</option>';
		for (var i=tids.length-1; i>=0; i--) {
			var when=tids[i].modified.formatString('YYYY.0MM.0DD 0hh:0mm:0ss');
			list.push(item.format([tids[i].title.htmlEncode(),when,tids[i].text.length]));
		}
		// display droplist, buttons, and command links
		var out=''; var c=this.changed.length;
		var NSP=config.formatters.findByField("name","nestedSliders");
		var summary=place.getAttribute("label").format([c,c==1?'er':'er',c==1?'':'e']);
		out+=NSP?'+++(unsaved)['+summary+'|'+this.defTip+']...':(summary+"\n");
		out+='<html><form style="display:inline"><!--\
			--><select size="1" name="list" \
				title="select a tiddler to view" \
				onchange="var v=this.value; if (v.length) story.displayTiddler(null,v);"><!--\
			-->'+list.join('')+'<!--\
			--></select><!--\
			--><input type="button" value="gå til" onclick="this.form.list.onchange();">';
		if (config.macros.loadTiddlers)  {
			out+='<input type="button" value="gendan" \
				title="importér den sidst gemte version af denne tiddler" \
				onclick="var v=this.form.list.value; if (!v.length) return; \
					var t=\'<\'+\'<loadTiddlers [[tiddler:\'+v+\']] \'; \
					t+=document.location.href; \
					t+=\' confirm force noreport>\'+\'>\'; \
					var e=document.getElementById(\'executeRevert\'); \
					if (e) e.parentNode.removeChild(e); \
					e=document.createElement(\'span\'); \
					e.id=\'executeRevert\'; \
					wikify(t,e);">';
		}
		out+='</form></html>';
		out+='\n{{nowrap{';
		if (!readOnly) {
			out+="<<saveChanges>>";
			out+=config.macros.saveAs?" | <<saveAs>>":"";
			out+=config.macros.upload?" | <<upload>>":"";
			out+=(config.macros.emptyTrash&&store.getTaggedTiddlers("Skrald").length)?" | <<emptyTrash>>":"";
		} else {
			out+=config.macros.saveAs?"<<saveAs>>":"";
		}
		out+='}}}';
		out+=NSP?'===':'';
		wikify(out,place);
	}
};

// hijack store.saveTiddler() to track changes to tiddlers
if (store.showUnsaved_saveTiddler==undefined) {
	store.showUnsaved_saveTiddler=store.saveTiddler;
	store.saveTiddler=function(title,newtitle) {
		if (title!=newtitle) {
			var i=config.macros.unsavedChanges.changed.indexOf(title);
			if (i!=-1) config.macros.unsavedChanges.changed.splice(i,1); // remove old from list
		} 
		var i=config.macros.unsavedChanges.changed.indexOf(newtitle);
		if (i!=-1) config.macros.unsavedChanges.changed.splice(i,1); // remove new title from list
		config.macros.unsavedChanges.changed.push(newtitle); // add new title to END of list
		var t=this.showUnsaved_saveTiddler.apply(this,arguments);
		if (!this.notificationLevel) config.macros.unsavedChanges.refresh();
		return t;
	}
}

// hijack store.removeTiddler() to track changes to tiddlers
if (store.showUnsaved_removeTiddler==undefined) {
	store.showUnsaved_removeTiddler=store.removeTiddler;
	store.removeTiddler=function(title) {
		var i=config.macros.unsavedChanges.changed.indexOf(title);
		if (i!=-1) config.macros.unsavedChanges.changed.splice(i,1); // remove from list
		this.showUnsaved_removeTiddler.apply(this,arguments);
		if (!this.notificationLevel) config.macros.unsavedChanges.refresh();
	}
}

// hijack store.setDirty() function to reset change list after file save
// note: do NOT hijack the prototype function.  This hijack should only be applied to
// the main 'store' instance only (i.e., don't refresh when loading temporary store
// as part of ImportTiddlers processing)
if (store.showUnsaved_setDirty==undefined) {
	store.showUnsaved_setDirty=store.setDirty;
	store.setDirty = function(flag) {
		var refresh=this.isDirty() && !flag; // 'dirty' to 'clean', force a refresh...
		this.showUnsaved_setDirty.apply(this,arguments); // but change the flag first.
		if (refresh) {
			config.macros.unsavedChanges.changed=[]; // clear changed list
			config.macros.unsavedChanges.refresh();
		}
	}
}
//}}}
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 29/06/2011 07:33:12 | DitNavn | [[/|http://pasteup-da.tiddlyspot.com/]] | [[store.cgi|http://pasteup-da.tiddlyspot.com/store.cgi]] | . | [[index.html | http://pasteup-da.tiddlyspot.com/index.html]] | . |
| 29/06/2011 16:57:54 | DitNavn | [[/|http://pasteup-da.tiddlyspot.com/]] | [[store.cgi|http://pasteup-da.tiddlyspot.com/store.cgi]] | . | [[index.html | http://pasteup-da.tiddlyspot.com/index.html]] | . |
| 29/06/2011 16:59:00 | DitNavn | [[/|http://pasteup-da.tiddlyspot.com/]] | [[store.cgi|http://pasteup-da.tiddlyspot.com/store.cgi]] | . | [[index.html | http://pasteup-da.tiddlyspot.com/index.html]] | . |
| 29/06/2011 19:47:16 | DitNavn | [[/|http://pasteup-da.tiddlyspot.com/]] | [[store.cgi|http://pasteup-da.tiddlyspot.com/store.cgi]] | . | [[index.html | http://pasteup-da.tiddlyspot.com/index.html]] | . |
| 09/10/2011 09:08:49 | DitNavn | [[/|http://pasteup-da.tiddlyspot.com/]] | [[store.cgi|http://pasteup-da.tiddlyspot.com/store.cgi]] | . | [[index.html | http://pasteup-da.tiddlyspot.com/index.html]] | . |
| 09/10/2011 09:13:40 | DitNavn | [[/|http://pasteup-da.tiddlyspot.com/]] | [[store.cgi|http://pasteup-da.tiddlyspot.com/store.cgi]] | . | [[index.html | http://pasteup-da.tiddlyspot.com/index.html]] | . |
| 02/11/2011 00:02:07 | DitNavn | [[/|http://pasteup-da.tiddlyspot.com/]] | [[store.cgi|http://pasteup-da.tiddlyspot.com/store.cgi]] | . | [[index.html | http://pasteup-da.tiddlyspot.com/index.html]] | . |
| 26/11/2011 21:21:28 | DitNavn | [[/|http://pasteup-da.tiddlyspot.com/]] | [[store.cgi|http://pasteup-da.tiddlyspot.com/store.cgi]] | . | [[index.html | http://pasteup-da.tiddlyspot.com/index.html]] | . |
| 26/11/2011 21:25:21 | DitNavn | [[pasteup-da.html|file:///C:/Documents%20and%20Settings/mama/Skrivebord/pasteup-da.html]] | [[store.cgi|http://pasteup-da.tiddlyspot.com/store.cgi]] | . | [[index.html | http://pasteup-da.tiddlyspot.com/index.html]] | . |
| 20/03/2012 19:49:34 | DitNavn | [[/|http://pasteup-da.tiddlyspot.com/]] | [[store.cgi|http://pasteup-da.tiddlyspot.com/store.cgi]] | . | [[index.html | http://pasteup-da.tiddlyspot.com/index.html]] | . |
/***
|''Name:''|UploadPlugin|
|''Description:''|Save to web a TiddlyWiki|
|''Version:''|4.1.3|
|''Date:''|Feb 24, 2008|
|''Source:''|http://tiddlywiki.bidix.info/#UploadPlugin|
|''Documentation:''|http://tiddlywiki.bidix.info/#UploadPluginDoc|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
|''Requires:''|PasswordOptionPlugin|
***/
//{{{
version.extensions.UploadPlugin = {
	major: 4, minor: 1, revision: 3,
	date: new Date("Feb 24, 2008"),
	source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0'
};

//
// Environment
//

if (!window.bidix) window.bidix = {}; // bidix namespace
bidix.debugMode = false;	// true to activate both in Plugin and UploadService
	
//
// Upload Macro
//

config.macros.upload = {
// default values
	defaultBackupDir: '',	//no backup
	defaultStoreScript: "store.php",
	defaultToFilename: "index.html",
	defaultUploadDir: ".",
	authenticateUser: true	// UploadService Authenticate User
};
	
config.macros.upload.label = {
	promptOption: "Save and Upload this TiddlyWiki with UploadOptions",
	promptParamMacro: "Save and Upload this TiddlyWiki in %0",
	saveLabel: "save to web", 
	saveToDisk: "save to disk",
	uploadLabel: "upload"	
};

config.macros.upload.messages = {
	noStoreUrl: "No store URL in parmeters or options",
	usernameOrPasswordMissing: "Username or password missing"
};

config.macros.upload.handler = function(place,macroName,params) {
	if (readOnly)
		return;
	var label;
	if (document.location.toString().substr(0,4) == "http") 
		label = this.label.saveLabel;
	else
		label = this.label.uploadLabel;
	var prompt;
	if (params[0]) {
		prompt = this.label.promptParamMacro.toString().format([this.destFile(params[0], 
			(params[1] ? params[1]:bidix.basename(window.location.toString())), params[3])]);
	} else {
		prompt = this.label.promptOption;
	}
	createTiddlyButton(place, label, prompt, function() {config.macros.upload.action(params);}, null, null, this.accessKey);
};

config.macros.upload.action = function(params)
{
		// for missing macro parameter set value from options
		if (!params) params = {};
		var storeUrl = params[0] ? params[0] : config.options.txtUploadStoreUrl;
		var toFilename = params[1] ? params[1] : config.options.txtUploadFilename;
		var backupDir = params[2] ? params[2] : config.options.txtUploadBackupDir;
		var uploadDir = params[3] ? params[3] : config.options.txtUploadDir;
		var username = params[4] ? params[4] : config.options.txtUploadUserName;
		var password = config.options.pasUploadPassword; // for security reason no password as macro parameter	
		// for still missing parameter set default value
		if ((!storeUrl) && (document.location.toString().substr(0,4) == "http")) 
			storeUrl = bidix.dirname(document.location.toString())+'/'+config.macros.upload.defaultStoreScript;
		if (storeUrl.substr(0,4) != "http")
			storeUrl = bidix.dirname(document.location.toString()) +'/'+ storeUrl;
		if (!toFilename)
			toFilename = bidix.basename(window.location.toString());
		if (!toFilename)
			toFilename = config.macros.upload.defaultToFilename;
		if (!uploadDir)
			uploadDir = config.macros.upload.defaultUploadDir;
		if (!backupDir)
			backupDir = config.macros.upload.defaultBackupDir;
		// report error if still missing
		if (!storeUrl) {
			alert(config.macros.upload.messages.noStoreUrl);
			clearMessage();
			return false;
		}
		if (config.macros.upload.authenticateUser && (!username || !password)) {
			alert(config.macros.upload.messages.usernameOrPasswordMissing);
			clearMessage();
			return false;
		}
		bidix.upload.uploadChanges(false,null,storeUrl, toFilename, uploadDir, backupDir, username, password); 
		return false; 
};

config.macros.upload.destFile = function(storeUrl, toFilename, uploadDir) 
{
	if (!storeUrl)
		return null;
		var dest = bidix.dirname(storeUrl);
		if (uploadDir && uploadDir != '.')
			dest = dest + '/' + uploadDir;
		dest = dest + '/' + toFilename;
	return dest;
};

//
// uploadOptions Macro
//

config.macros.uploadOptions = {
	handler: function(place,macroName,params) {
		var wizard = new Wizard();
		wizard.createWizard(place,this.wizardTitle);
		wizard.addStep(this.step1Title,this.step1Html);
		var markList = wizard.getElement("markList");
		var listWrapper = document.createElement("div");
		markList.parentNode.insertBefore(listWrapper,markList);
		wizard.setValue("listWrapper",listWrapper);
		this.refreshOptions(listWrapper,false);
		var uploadCaption;
		if (document.location.toString().substr(0,4) == "http") 
			uploadCaption = config.macros.upload.label.saveLabel;
		else
			uploadCaption = config.macros.upload.label.uploadLabel;
		
		wizard.setButtons([
				{caption: uploadCaption, tooltip: config.macros.upload.label.promptOption, 
					onClick: config.macros.upload.action},
				{caption: this.cancelButton, tooltip: this.cancelButtonPrompt, onClick: this.onCancel}
				
			]);
	},
	options: [
		"txtUploadUserName",
		"pasUploadPassword",
		"txtUploadStoreUrl",
		"txtUploadDir",
		"txtUploadFilename",
		"txtUploadBackupDir",
		"chkUploadLog",
		"txtUploadLogMaxLine"		
	],
	refreshOptions: function(listWrapper) {
		var opts = [];
		for(i=0; i<this.options.length; i++) {
			var opt = {};
			opts.push();
			opt.option = "";
			n = this.options[i];
			opt.name = n;
			opt.lowlight = !config.optionsDesc[n];
			opt.description = opt.lowlight ? this.unknownDescription : config.optionsDesc[n];
			opts.push(opt);
		}
		var listview = ListView.create(listWrapper,opts,this.listViewTemplate);
		for(n=0; n<opts.length; n++) {
			var type = opts[n].name.substr(0,3);
			var h = config.macros.option.types[type];
			if (h && h.create) {
				h.create(opts[n].colElements['option'],type,opts[n].name,opts[n].name,"no");
			}
		}
		
	},
	onCancel: function(e)
	{
		backstage.switchTab(null);
		return false;
	},
	
	wizardTitle: "Upload with options",
	step1Title: "These options are saved in cookies in your browser",
	step1Html: "<input type='hidden' name='markList'></input><br>",
	cancelButton: "Cancel",
	cancelButtonPrompt: "Cancel prompt",
	listViewTemplate: {
		columns: [
			{name: 'Description', field: 'description', title: "Description", type: 'WikiText'},
			{name: 'Option', field: 'option', title: "Option", type: 'String'},
			{name: 'Name', field: 'name', title: "Name", type: 'String'}
			],
		rowClasses: [
			{className: 'lowlight', field: 'lowlight'} 
			]}
};

//
// upload functions
//

if (!bidix.upload) bidix.upload = {};

if (!bidix.upload.messages) bidix.upload.messages = {
	//from saving
	invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki",
	backupSaved: "Backup saved",
	backupFailed: "Failed to upload backup file",
	rssSaved: "RSS feed uploaded",
	rssFailed: "Failed to upload RSS feed file",
	emptySaved: "Empty template uploaded",
	emptyFailed: "Failed to upload empty template file",
	mainSaved: "Main TiddlyWiki file uploaded",
	mainFailed: "Failed to upload main TiddlyWiki file. Your changes have not been saved",
	//specific upload
	loadOriginalHttpPostError: "Can't get original file",
	aboutToSaveOnHttpPost: 'About to upload on %0 ...',
	storePhpNotFound: "The store script '%0' was not found."
};

bidix.upload.uploadChanges = function(onlyIfDirty,tiddlers,storeUrl,toFilename,uploadDir,backupDir,username,password)
{
	var callback = function(status,uploadParams,original,url,xhr) {
		if (!status) {
			displayMessage(bidix.upload.messages.loadOriginalHttpPostError);
			return;
		}
		if (bidix.debugMode) 
			alert(original.substr(0,500)+"\n...");
		// Locate the storeArea div's 
		var posDiv = locateStoreArea(original);
		if((posDiv[0] == -1) || (posDiv[1] == -1)) {
			alert(config.messages.invalidFileError.format([localPath]));
			return;
		}
		bidix.upload.uploadRss(uploadParams,original,posDiv);
	};
	
	if(onlyIfDirty && !store.isDirty())
		return;
	clearMessage();
	// save on localdisk ?
	if (document.location.toString().substr(0,4) == "file") {
		var path = document.location.toString();
		var localPath = getLocalPath(path);
		saveChanges();
	}
	// get original
	var uploadParams = new Array(storeUrl,toFilename,uploadDir,backupDir,username,password);
	var originalPath = document.location.toString();
	// If url is a directory : add index.html
	if (originalPath.charAt(originalPath.length-1) == "/")
		originalPath = originalPath + "index.html";
	var dest = config.macros.upload.destFile(storeUrl,toFilename,uploadDir);
	var log = new bidix.UploadLog();
	log.startUpload(storeUrl, dest, uploadDir,  backupDir);
	displayMessage(bidix.upload.messages.aboutToSaveOnHttpPost.format([dest]));
	if (bidix.debugMode) 
		alert("about to execute Http - GET on "+originalPath);
	var r = doHttp("GET",originalPath,null,null,username,password,callback,uploadParams,null);
	if (typeof r == "string")
		displayMessage(r);
	return r;
};

bidix.upload.uploadRss = function(uploadParams,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		if(status) {
			var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
			displayMessage(bidix.upload.messages.rssSaved,bidix.dirname(url)+'/'+destfile);
			bidix.upload.uploadMain(params[0],params[1],params[2]);
		} else {
			displayMessage(bidix.upload.messages.rssFailed);			
		}
	};
	// do uploadRss
	if(config.options.chkGenerateAnRssFeed) {
		var rssPath = uploadParams[1].substr(0,uploadParams[1].lastIndexOf(".")) + ".xml";
		var rssUploadParams = new Array(uploadParams[0],rssPath,uploadParams[2],'',uploadParams[4],uploadParams[5]);
		var rssString = generateRss();
		// no UnicodeToUTF8 conversion needed when location is "file" !!!
		if (document.location.toString().substr(0,4) != "file")
			rssString = convertUnicodeToUTF8(rssString);	
		bidix.upload.httpUpload(rssUploadParams,rssString,callback,Array(uploadParams,original,posDiv));
	} else {
		bidix.upload.uploadMain(uploadParams,original,posDiv);
	}
};

bidix.upload.uploadMain = function(uploadParams,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		var log = new bidix.UploadLog();
		if(status) {
			// if backupDir specified
			if ((params[3]) && (responseText.indexOf("backupfile:") > -1))  {
				var backupfile = responseText.substring(responseText.indexOf("backupfile:")+11,responseText.indexOf("\n", responseText.indexOf("backupfile:")));
				displayMessage(bidix.upload.messages.backupSaved,bidix.dirname(url)+'/'+backupfile);
			}
			var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
			displayMessage(bidix.upload.messages.mainSaved,bidix.dirname(url)+'/'+destfile);
			store.setDirty(false);
			log.endUpload("ok");
		} else {
			alert(bidix.upload.messages.mainFailed);
			displayMessage(bidix.upload.messages.mainFailed);
			log.endUpload("failed");			
		}
	};
	// do uploadMain
	var revised = bidix.upload.updateOriginal(original,posDiv);
	bidix.upload.httpUpload(uploadParams,revised,callback,uploadParams);
};

bidix.upload.httpUpload = function(uploadParams,data,callback,params)
{
	var localCallback = function(status,params,responseText,url,xhr) {
		url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
		if (xhr.status == 404)
			alert(bidix.upload.messages.storePhpNotFound.format([url]));
		if ((bidix.debugMode) || (responseText.indexOf("Debug mode") >= 0 )) {
			alert(responseText);
			if (responseText.indexOf("Debug mode") >= 0 )
				responseText = responseText.substring(responseText.indexOf("\n\n")+2);
		} else if (responseText.charAt(0) != '0') 
			alert(responseText);
		if (responseText.charAt(0) != '0')
			status = null;
		callback(status,params,responseText,url,xhr);
	};
	// do httpUpload
	var boundary = "---------------------------"+"AaB03x";	
	var uploadFormName = "UploadPlugin";
	// compose headers data
	var sheader = "";
	sheader += "--" + boundary + "\r\nContent-disposition: form-data; name=\"";
	sheader += uploadFormName +"\"\r\n\r\n";
	sheader += "backupDir="+uploadParams[3] +
				";user=" + uploadParams[4] +
				";password=" + uploadParams[5] +
				";uploaddir=" + uploadParams[2];
	if (bidix.debugMode)
		sheader += ";debug=1";
	sheader += ";;\r\n"; 
	sheader += "\r\n" + "--" + boundary + "\r\n";
	sheader += "Content-disposition: form-data; name=\"userfile\"; filename=\""+uploadParams[1]+"\"\r\n";
	sheader += "Content-Type: text/html;charset=UTF-8" + "\r\n";
	sheader += "Content-Length: " + data.length + "\r\n\r\n";
	// compose trailer data
	var strailer = new String();
	strailer = "\r\n--" + boundary + "--\r\n";
	data = sheader + data + strailer;
	if (bidix.debugMode) alert("about to execute Http - POST on "+uploadParams[0]+"\n with \n"+data.substr(0,500)+ " ... ");
	var r = doHttp("POST",uploadParams[0],data,"multipart/form-data; ;charset=UTF-8; boundary="+boundary,uploadParams[4],uploadParams[5],localCallback,params,null);
	if (typeof r == "string")
		displayMessage(r);
	return r;
};

// same as Saving's updateOriginal but without convertUnicodeToUTF8 calls
bidix.upload.updateOriginal = function(original, posDiv)
{
	if (!posDiv)
		posDiv = locateStoreArea(original);
	if((posDiv[0] == -1) || (posDiv[1] == -1)) {
		alert(config.messages.invalidFileError.format([localPath]));
		return;
	}
	var revised = original.substr(0,posDiv[0] + startSaveArea.length) + "\n" +
				store.allTiddlersAsHtml() + "\n" +
				original.substr(posDiv[1]);
	var newSiteTitle = getPageTitle().htmlEncode();
	revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
	revised = updateMarkupBlock(revised,"PRE-HEAD","MarkupPreHead");
	revised = updateMarkupBlock(revised,"POST-HEAD","MarkupPostHead");
	revised = updateMarkupBlock(revised,"PRE-BODY","MarkupPreBody");
	revised = updateMarkupBlock(revised,"POST-SCRIPT","MarkupPostBody");
	return revised;
};

//
// UploadLog
// 
// config.options.chkUploadLog :
//		false : no logging
//		true : logging
// config.options.txtUploadLogMaxLine :
//		-1 : no limit
//      0 :  no Log lines but UploadLog is still in place
//		n :  the last n lines are only kept
//		NaN : no limit (-1)

bidix.UploadLog = function() {
	if (!config.options.chkUploadLog) 
		return; // this.tiddler = null
	this.tiddler = store.getTiddler("UploadLog");
	if (!this.tiddler) {
		this.tiddler = new Tiddler();
		this.tiddler.title = "UploadLog";
		this.tiddler.text = "| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |";
		this.tiddler.created = new Date();
		this.tiddler.modifier = config.options.txtUserName;
		this.tiddler.modified = new Date();
		store.addTiddler(this.tiddler);
	}
	return this;
};

bidix.UploadLog.prototype.addText = function(text) {
	if (!this.tiddler)
		return;
	// retrieve maxLine when we need it
	var maxLine = parseInt(config.options.txtUploadLogMaxLine,10);
	if (isNaN(maxLine))
		maxLine = -1;
	// add text
	if (maxLine != 0) 
		this.tiddler.text = this.tiddler.text + text;
	// Trunck to maxLine
	if (maxLine >= 0) {
		var textArray = this.tiddler.text.split('\n');
		if (textArray.length > maxLine + 1)
			textArray.splice(1,textArray.length-1-maxLine);
			this.tiddler.text = textArray.join('\n');		
	}
	// update tiddler fields
	this.tiddler.modifier = config.options.txtUserName;
	this.tiddler.modified = new Date();
	store.addTiddler(this.tiddler);
	// refresh and notifiy for immediate update
	story.refreshTiddler(this.tiddler.title);
	store.notify(this.tiddler.title, true);
};

bidix.UploadLog.prototype.startUpload = function(storeUrl, toFilename, uploadDir,  backupDir) {
	if (!this.tiddler)
		return;
	var now = new Date();
	var text = "\n| ";
	var filename = bidix.basename(document.location.toString());
	if (!filename) filename = '/';
	text += now.formatString("0DD/0MM/YYYY 0hh:0mm:0ss") +" | ";
	text += config.options.txtUserName + " | ";
	text += "[["+filename+"|"+location + "]] |";
	text += " [[" + bidix.basename(storeUrl) + "|" + storeUrl + "]] | ";
	text += uploadDir + " | ";
	text += "[[" + bidix.basename(toFilename) + " | " +toFilename + "]] | ";
	text += backupDir + " |";
	this.addText(text);
};

bidix.UploadLog.prototype.endUpload = function(status) {
	if (!this.tiddler)
		return;
	this.addText(" "+status+" |");
};

//
// Utilities
// 

bidix.checkPlugin = function(plugin, major, minor, revision) {
	var ext = version.extensions[plugin];
	if (!
		(ext  && 
			((ext.major > major) || 
			((ext.major == major) && (ext.minor > minor))  ||
			((ext.major == major) && (ext.minor == minor) && (ext.revision >= revision))))) {
			// write error in PluginManager
			if (pluginInfo)
				pluginInfo.log.push("Requires " + plugin + " " + major + "." + minor + "." + revision);
			eval(plugin); // generate an error : "Error: ReferenceError: xxxx is not defined"
	}
};

bidix.dirname = function(filePath) {
	if (!filePath) 
		return;
	var lastpos;
	if ((lastpos = filePath.lastIndexOf("/")) != -1) {
		return filePath.substring(0, lastpos);
	} else {
		return filePath.substring(0, filePath.lastIndexOf("\\"));
	}
};

bidix.basename = function(filePath) {
	if (!filePath) 
		return;
	var lastpos;
	if ((lastpos = filePath.lastIndexOf("#")) != -1) 
		filePath = filePath.substring(0, lastpos);
	if ((lastpos = filePath.lastIndexOf("/")) != -1) {
		return filePath.substring(lastpos + 1);
	} else
		return filePath.substring(filePath.lastIndexOf("\\")+1);
};

bidix.initOption = function(name,value) {
	if (!config.options[name])
		config.options[name] = value;
};

//
// Initializations
//

// require PasswordOptionPlugin 1.0.1 or better
bidix.checkPlugin("PasswordOptionPlugin", 1, 0, 1);

// styleSheet
setStylesheet('.txtUploadStoreUrl, .txtUploadBackupDir, .txtUploadDir {width: 22em;}',"uploadPluginStyles");

//optionsDesc
merge(config.optionsDesc,{
	txtUploadStoreUrl: "Url of the UploadService script (default: store.php)",
	txtUploadFilename: "Filename of the uploaded file (default: in index.html)",
	txtUploadDir: "Relative Directory where to store the file (default: . (downloadService directory))",
	txtUploadBackupDir: "Relative Directory where to backup the file. If empty no backup. (default: ''(empty))",
	txtUploadUserName: "Upload Username",
	pasUploadPassword: "Upload Password",
	chkUploadLog: "do Logging in UploadLog (default: true)",
	txtUploadLogMaxLine: "Maximum of lines in UploadLog (default: 10)"
});

// Options Initializations
bidix.initOption('txtUploadStoreUrl','');
bidix.initOption('txtUploadFilename','');
bidix.initOption('txtUploadDir','');
bidix.initOption('txtUploadBackupDir','');
bidix.initOption('txtUploadUserName','');
bidix.initOption('pasUploadPassword','');
bidix.initOption('chkUploadLog',true);
bidix.initOption('txtUploadLogMaxLine','10');


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


//}}}

~TiddlyWiki v<<version>> with PasteUpPackage v1.1.5 2011.01.12
Dette er en demo[[Video]]
<html><embed src="http://blip.tv/play/gtQ9go7gPgI" type="application/x-shockwave-flash" width="98%" height="92%" allowscriptaccess="always" allowfullscreen="true"></embed></html>
<!--{{{-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'>
	<span class='title'><!--force toolbar height to match title height--></span>
</span>
<span class='title' macro='view title'></span>
<span class='pasteupcmd smallform'
	macro='tiddler SlideshowToolbar if:{{config.options.chkSlideshow}}'></span>
<span class='pasteupcmd medium' macro='toolbar addPasteUpPart'></span>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->