Tags:
create new tag
, view all tags
moveable.html - TiddlyWiki v2.4.1 plus MoveablePanelPackage a TiddlyTools QuickStart™ document. All rights retained.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

----
Also see AdvancedOptions
<<importTiddlers>>
/***
|Name|CoreTweaks444|
|Source|http://www.TiddlyTools.com/#CoreTweaks|
|Version|n/a|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.2.0|
|Type|plugin|
|Requires||
|Overrides|various|
|Description|a small collection of overrides to TW core functions   |
This tiddler contains changes TW core functions to provide minor changes in standard features or behavior.  It is hoped that some of these tweaks may someday be added into the TW core, so that these adjustments will be available without needing these add-on definitions.
>''Note: the changes contained in this tiddler are generally applicable for version 2.4.1 of TiddlyWiki. Please view [[CoreTweaksArchive]] for tweaks that may be used with earlier versions of TiddlyWiki.''
----
***/
// // {{block{
/***
!!!444 'tiddler' and 'place' - global variables for use in computed macro parameters
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/444 - OPEN
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.
***/
//{{{
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);
}
//}}}
// // }}}}}}
|           !panelname|   !x |   !y |   !w |   !h |   !z | !folded |h
|               header|   150|    10|  auto|  auto|      |         |
|           StyleSheet|   125|   350|   650|  auto|     2|    √    |
|         EditTemplate|   100|   375|   675|  auto|     3|    √    |
|         ViewTemplate|    75|   400|   700|  auto|     4|    √    |
|         PageTemplate|    50|   425|   725|  auto|     5|    √    |
|        CoreTweaks444|   125|   225|   650|  auto|     6|    √    |
|     DragScrollPlugin|   100|   250|   675|  auto|     7|    √    |
|   PanelManagerPlugin|    75|   275|   700|  auto|     8|    √    |
|  MoveablePanelPlugin|    50|   300|   725|  auto|     9|    √    |
|           DefaultMap|   250|   190|   525|  auto|    10|    √    |
| MoveablePanelPackage|    25|   150|   750|  auto|    11|         |
|                 tabs|   -50|   285|      |      |    12|         |
|              options|   -30|    30|      |      |    13|         |
MoveablePanelPackage
MoveablePanelPlugin
PanelManagerPlugin
DragScrollPlugin
CoreTweaks444

PageTemplate
ViewTemplate
EditTemplate
StyleSheet
DefaultMap
/***
|Name|[[DragScrollPlugin]]|
|Source|http://www.TiddlyTools.com/#DragScrollPlugin|
|Documentation|http://www.TiddlyTools.com/#DragScrollPlugin|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|use SHIFT-DRAG to scroll the browser window|
DragScrollPlugin allows you to use your mouse to scroll the browser window by grabbing anywhere on the background of the document while holding the SHIFT key.
!!!!!Documentation
<<<
Whenever your page contains extra-wide content that does not 'wrap' onto extra lines, in can result in both horizontal and vertical scrollbars.  Unfortunately, using each scrollbar separately to navigate across the page can become very tedious and makes it more difficult to interact with your content in a flexible and effective manner.

''Drag-scrolling allows you to move in both the horizontal and vertical direction at the same time, simply by holding SHIFT while clicking and dragging the mouse across the page.''
<<<
!!!!!Configuration
<<<
<<option chkDragScroll>> enable //drag-scrolling//
<<<
!!!!!Revisions
<<<
2008.12.01 [1.0.0] Initial public release
<<<
!!!!!Code
***/
//{{{
version.extensions.DragScrollPlugin= {major: 1, minor: 0, revision: 0, date: new Date(2008,12,01)};

if (!config.dragscroll) { // only once
	config.dragscroll={
		// use to end event handling for processed events
		processed: function(ev) {
			var ev=ev||window.event;
			if (ev) { ev.cancelBubble=true; if (ev.stopPropagation) ev.stopPropagation(); }
			return false;
		},
		// MOUSE DOWN - SET CURSOR, SAVE SCROLL DATA
		savedMouseDown: document.onmousedown,
		mousedown: function(ev) {
			var ev=ev||window.event; var target=resolveTarget(ev); var d=config.dragscroll;
			var scroll=ev.shiftKey&&config.options.chkDragScroll;
			var skip=['input','option','textarea'].contains(target.nodeName.toLowerCase());
			if (!scroll||skip) { // handle event normally
				if (d.savedMouseDown!=undefined) return d.savedMouseDown.apply(target,arguments);
				else return;
			}
			d.mX=!config.browser.isIE?ev.pageX:ev.clientX; d.sX=findScrollX();
			d.mY=!config.browser.isIE?ev.pageY:ev.clientY; d.sY=findScrollY();
			d.scrolling=true; document.body.style.cursor='move';
			return config.dragscroll.processed(ev);
		},
		// MOUSE MOVE - UPDATE SCROLL DATA AND SCROLL THE WINDOW 
		savedMouseMove: document.onmousemove,
		mousemove: function(ev) {
			var ev=ev||window.event; var target=resolveTarget(ev); var d=config.dragscroll;
			if (!d.scrolling || !ev.shiftKey) { // NOT SCROLLING
				if (d.savedMouseMove!=undefined) return d.savedMouseMove.apply(target,arguments);
				else return;
			}
			// set scroll pos based on diff between new and old (x,y)
			var mx=!config.browser.isIE?ev.pageX:ev.clientX;
			var my=!config.browser.isIE?ev.pageY:ev.clientY;
			var sx=!config.browser.isIE?findScrollX():d.sX;
			var sy=!config.browser.isIE?findScrollY():d.sY;
			window.scrollTo(sx-mx+d.mX,sy-my+d.mY);
			return config.dragscroll.processed(ev);
		},
		// MOUSEUP - CLEAR THE DRAG DATA, RESET THE CURSOR
		savedMouseUp: document.onmouseup,
		mouseup: function(ev) {
			var ev=ev||window.event; var target=resolveTarget(ev); var d=config.dragscroll;
			var wasScrolling=d.scrolling; d.scrolling=false; document.body.style.cursor='auto';
			if (d.savedMouseUp!=undefined) return d.savedMouseUp.apply(target,arguments);
			if (wasScrolling) return config.dragscroll.processed(ev);
			return;
		}
	}
	// DEFAULT SETTING (ENABLED)
	if (config.options.chkDragScroll===undefined) config.options.chkDragScroll=true;
	// HIJACK MOUSE HANDLERS
	document.onmousedown=config.dragscroll.mousedown;
	document.onmousemove=config.dragscroll.mousemove;
	document.onmouseup  =config.dragscroll.mouseup;
}
//}}}
<!--{{{-->
<div class='moveablePanel'>
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='viewer'>
	<div class='editor' macro='edit title'></div>
	<div macro='annotations'></div>
	<div class='editor' macro='edit text'></div>
	<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
</div>
<div macro='resizeEditor'></div>
<div macro='moveablePanel name:{{story.findContainingTiddler(place).getAttribute("tiddler")}} undocked fold hover height:auto'></div>
</div>
<!--}}}-->
/***
|Name|GotoPlugin|
|Source|http://www.TiddlyTools.com/#GotoPlugin|
|Documentation|http://www.TiddlyTools.com/#GotoPluginInfo|
|Version|1.7.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|view any tiddler by entering it's title - displays list of possible matches|
''View a tiddler by typing its title and pressing //enter//.''  As you type, a list of possible matches is displayed.  You can scroll-and-click (or use arrows+enter) to select/view a tiddler, or press //escape// to close the listbox to resume typing.  When the listbox is ''//not//'' being displayed, press //escape// to clear the current text input and start over.
!!!!!Documentation
>see [[GotoPluginInfo]]
!!!!!Revisions
<<<
2008.12.15 [1.7.1] up arrow from input field now moves to end of droplist (search for input).  Also, shift+enter cam now be used to quickly invoke search for text.
|please see [[GotoPluginInfo]] for additional revision details|
2006.05.05 [0.0.0] started
<<<
!!!!!Code
***/
//{{{
version.extensions.GotoPlugin= {major: 1, minor: 7, revision: 1, date: new Date(2008,12,15)};

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

config.macros.gotoTiddler= { 
	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 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(/%instyle%/g,instyle);
		html=html.replace(/%liststyle%/g,liststyle);
		html=html.replace(/%filter%/g,filter);
		if (config.browser.isIE) html=this.IEtableFixup.format([html]);
		createTiddlyElement(place,"span").innerHTML=html;
	},

	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... DOWN=select from list, ENTER=open/create tiddler, SHIFT-ENTER=search for text"\
			onclick="this.form.list.style.display=\'none\';"\
			onfocus="this.select(); this.setAttribute(\'accesskey\',\'G\');"\
			%keyevent%="return config.macros.gotoTiddler.inputEscKeyHandler(event,this,this.form.list);"\
			onkeyup="return config.macros.gotoTiddler.inputKeyHandler(event,this,%quiet%,%search%);">\
		<select name=list style="%liststyle%;display:none;position:absolute"\
			onchange="if (!this.selectedIndex) this.selectedIndex=1;"\
			onblur="this.style.display=\'none\';"\
			%keyevent%="return config.macros.gotoTiddler.selectKeyHandler(event,this,this.form.gotoTiddler);"\
			onclick="return config.macros.gotoTiddler.processItem(this.value,this.form.gotoTiddler,this);">\
		</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(val,filter) {
		if (!this.items.length || val.length<2) { // starting new search, refresh cached list of tiddlers/shadows/tags
			this.items=new Array();
			if (filter.length) {
				var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
				var tiddlers=store.sortTiddlers(fn.apply(store,[filter]),'title');
			} else 
				var tiddlers=store.getTiddlers("title","excludeLists");
			for(var t=0; t<tiddlers.length; t++) this.items.push(tiddlers[t].title);
			if (!filter.length) {
				for (var t in config.shadowTiddlers) this.items.pushUnique(t);
				var tags=store.getTags();
				for(var t=0; t<tags.length; t++) this.items.pushUnique(tags[t][0]);
			}
		}
		var found = [];
		var match=val.toLowerCase();
		for(var i=0; i<this.items.length; i++)
			if (this.items[i].toLowerCase().indexOf(match)!=-1) found.push(this.items[i]);
		return found;
	},
	items: [], // cached list of tiddlers/shadows/tags

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

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

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

	inputKeyHandler:
	function(event,here,quiet,search) {
		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 list
		if (!here.value.length && !(key==40 || key==13))
			{ list.style.display="none"; return this.keyProcessed(event); }
		// make sure list is shown (unless quiet option)
		list.style.display=!quiet?"block":"none";
		// non-blank input... enter=show/create tiddler, SHIFT-enter=search for text
		if (key==13) return this.processItem(event.shiftKey?'*':here.value,here,list);
		// up or down key... shows and moves to list...
		if (key==38 || key==40) { list.style.display="block"; list.focus(); }
		// if list is showing, fill it with found results...
		if (list.style.display!="none") {
			var indent='\xa0\xa0\xa0';
			var found = this.getItems(here.value,filter.value); // 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([here.value]),"*",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;
		}
		return true; // key bubbles up
	},

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

	processItem:
	function(title,here,list) {
		if (!title.length) return;
		list.style.display='none';
		if (title=="*")	{ story.search(here.value); return false; } // do full-text search
		here.value=title;
		story.displayTiddler(null,title); // show selected tiddler
		return false;
	}
}
//}}}
[[PanelViewer]]
[[PanelTable]]
<<moveablePanel load:DefaultMap>>
<<moveablePanel maps label:[[load map...]]>>
<!--{{{-->
<!--
|Name|MoveableEditTemplate|
|Source|http://www.TiddlyTools.com/#MoveableEditTemplate|
|Version||
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|template|
|Requires|MoveablePanelPlugin, EditTemplate, TaggedTemplateTweak|
|Overrides||
|Description|add moveablePanel macro to tiddlers tagged with 'moveable'|
-->
<div class='moveablePanel'>
	[[EditTemplate]]
	<div macro='moveablePanel name:{{tiddler?tiddler.title:""}} height:auto'></div>
</div>
<!--}}}-->
<html><style>
#tiddlerMoveablePanelPackage .tagged { display:none; }
#tiddlerMoveablePanelPackage .viewer .content { max-height:999999em; height:auto; overflow:visible; }
</style></html>@@font-size:150%;''"free-range" tiddlers with room to roam...''@@
<<<
@@font-size:90%;line-height:120%;text-align:justify;display:block;<<tiddler QuickStartBadge with: moveable.html>>[[MoveablePanelPlugin]] turns tiddlers and other document content into  '''moveable panels' that can be dragged with the mouse to  //undock// them from their default //anchor points// and reposition them to almost any location on the page -- even far off screen!''  Using moveable panels, your document content can now be spread out over a wide (actually, //infinite//) area, both horizontally and vertically, allowing you to ''quickly create a complete 'web desktop' with different groupings of moveable tiddlers and menus''... all within a single TiddlyWiki document!

No matter where you place the panels, the document extents will ''automatically grow (or shrink) as needed to contain all moveable panels''.  Unfortunately, ''you can only scroll in one direction at a time when using the browser window's separate horizontal and vertical scrollbars'', making navigation between far-flung panels extremely tedious and awkward.  To address this, [[DragScrollPlugin]] allows you to ''scroll the browser window in both the horizontal and vertical directions at the same time, simply by holding down the SHIFT key while dragging the mouse across the page'' until the desired content is scrolled into view.

Of course, once you can move things around, you will want them to //stay there//.  By itself, [[MoveablePanelPlugin]] has no memory and all panels are rendered at their original, docked anchor points each time the document is loaded into the browser.  [[PanelManagerPlugin]] adds the ability to automatically ''track and record each panel's current position and size in a //panel map//, using simple wiki-formatted tables stored in tiddlers''.  The current panel map is also automatically stored as a browser-cookie, so that ''wherever you place a panel, it stays there until you move it again'', even in between document sessions.

[[PanelManagerPlugin]] also adds a popup menu with lots of functions for managing individual moveable panels (e.g., 'bring to front', 'jump to panel', 'dock/undock', etc.) plus a ''powerful, graphical panel map viewer and interactive page navigator'' that allows you to load, save, edit and view //named// panel maps stored in your document.  You can also scroll directly to any panel or other selected page location, anywhere on the page, by using the 'jump to panel' command or ''//compass navigation tool//'' from the Panel Manager popup menu.

You can access the Panel Manager popup map viewer at any time from the <<moveablePanel menu label:[[Panel Manager button (&#x2261;)]]>> that is added to the upper right corner of each undocked panel.  You can also ''open the popup menu from //anywhere// on the page simply by using ALT+CLICK on the //background// of the page'' (i.e., not on a link or other //active// element that could respond to the click!).  This permits access to the Panel Manager commands, even when there are no moveable panels visible on the screen.
@@
<<<
/***
|Name|[[MoveablePanelPlugin]]|
|Source|http://www.TiddlyTools.com/#MoveablePanelPlugin|
|Documentation|http://www.TiddlyTools.com/#MoveablePanelPluginInfo|
|Version|3.0.3|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|move/size any tiddler or page element|
Use the mouse to move/resize any specific tiddler content, page element, or [[floating slider panel|NestedSlidersPlugin]].
!!!!!Documentation
>see [[MoveablePanelPluginInfo]]
!!!!!Configuration
<<<
<<option chkMoveablePanelShowStatus>> show position/size while moving/resizing a panel
<<option chkMoveablePanelShowManager>> automatically add Panel Manager button to undocked panels (see [[PanelManagerPlugin]])
<<<
!!!!!Revisions
<<<
2008.12.24 [3.0.3] added ESC key handling to cancel panel move/size (restores previous panel state)
|please see [[MoveablePanelPluginInfo]] for additional revision details|
2006.03.04 [1.0.0] Initial public release
<<<
!!!!!Code
***/
//{{{
version.extensions.MoveablePanelPlugin= {major: 3, minor: 0, revision: 3, date: new Date(2008,12,24)};
if (config.macros.moveablePanel===undefined) config.macros.moveablePanel={};
//}}}
// // translate
//{{{
// TRANSLATORS: copy this section to MoveablePanelPluginLingoXX (where 'XX' is a language/country code)
if (config.macros.moveablePanel===undefined) config.macros.moveablePanel={};
merge(config.macros.moveablePanel,{

	foldLabel:	'\u2212', // minus
	foldTip:	'FOLD=reduce panel size',
	unfoldLabel:	'+',
	unfoldTip:	'UNFOLD=restore panel size',
	hoverLabel:	'^',
	hoverTip:	'HOVER=keep panel in view when scrolling',
	scrollLabel:	'\u2248', // asymp
	scrollTip:	'SCROLL=allow panel to move with page',
	closeLabel:	'X',
	closeTip:	'CLOSE=hide this panel',
	dockLabel:	'\u221A', // radic
	dockTip:	'DOCK=reset size/position',

	noPid:		'unnamed panel',

	statusMsg:	'%0: pos=(%1,%2)%3 size=(%4,%5) z=%6',
	hoveredMsg:	'[hovering]',
	dockedTip:	'%0: docked',
	scrollMsg:	'%0: pos=(%1,%2)',
	msgDuration:	3000,

	moveTip:	'%0DRAG EDGE=move',
	sizeTip:	'(SHIFT=resize)',
	sizeWidthTip:	'(SHIFT=resize width)',
	sizeHeightTip:	'(SHIFT=resize height)',
	clickTip:	  'CLICK=bring to front, SHIFT-CLICK=send to back',
	dblclickdockTip:  'DOUBLE-CLICK=dock',
	dblclickunfoldTip:'DOUBLE-CLICK=unfold',

	foldParam:	'fold',
	hoverParam:	'hover',
	nocloseParam:	'noclose',
	nodockParam:	'nodock',
	undockedParam:	'undocked',

	jumpParam:	'jump',
	dockParam:	'dock',
	moveParam:	'move',
	labelParam:	'label',
	promptParam:	'prompt',

	allParam:	'all',
	nameParam:	'name',
	topParam:	'top',
	leftParam:	'left',
	widthParam:	'width',
	heightParam:	'height',

	managerParam:	'manager'
});
//}}}
// // global functions (general utilities)
//{{{
// if removeCookie() function is not defined by TW core, define it here (for <TW2.5)
if (window.removeCookie===undefined) {
	window.removeCookie=function(name) {
		document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
	}
}
if (window.copyObject===undefined) {
	window.copyObject=function(src)	{
		for (var i in src) this[i]=typeof src[i]!='object'?src[i]:new copyObject(src[i]);
	}
}
if (window.compareObjects===undefined) {
	window.compareObjects=function(a,b) {
		if (a===b) return true;
		if (a==undefined||b==undefined) return false;
		for (var i in a) if (typeof a[i]!='object'?a[i]!==b[i]:!compareObjects(a[i],b[i])) return false;
		return true;
	}
}
if (window.isEmptyObject===undefined) {
	window.isEmptyObject=function(src) { for (var i in src) return false; return true; }
}

// cross-browser metrics
window.findMouseX=function(ev)
	{ if (!ev) return 0; return !config.browser.isIE?ev.pageX:(ev.clientX+findScrollX()); }
window.findMouseY=function(ev)
	{ if (!ev) return 0; return !config.browser.isIE?ev.pageY:(ev.clientY+findScrollY()); }
//}}}
// // macro
//{{{
merge(config.macros.moveablePanel,{
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {

		// ALTERNATIVE OUTPUT: Panel Manager macro extensions...
		if (this.manager && this.manager.handler(place,macroName,params,wikifier,paramString,tiddler))
			return; // processed by PanelManager

		// UNPACK KEYWORD PARAMS
		var showfold	 =params.contains(this.foldParam);
		var showhover	 =params.contains(this.hoverParam);
		var showclose	 =!params.contains(this.nocloseParam);
		var showdock	 =!params.contains(this.nodockParam);
		var showmanager  =params.contains(this.managerParam);
		var startundocked=params.contains(this.undockedParam);
		var jump	 =params.contains(this.jumpParam);
		var dock	 =params.contains(this.dockParam);
		var move	 =params.contains(this.moveParam);
		var all		 =params.contains(this.allParam);

		// UNPACK VALUE PARAMS
		params=paramString.parseParams('anon',null,true,false,false);
		var label =getParam(params,this.labelParam,null);
		var prompt=getParam(params,this.promptParam,null);
		var name  =getParam(params,this.nameParam,null);
		var top   =getParam(params,this.topParam,null);
		var left  =getParam(params,this.leftParam,null);
		var width =getParam(params,this.widthParam,null);
		var height=getParam(params,this.heightParam,null);

		// COMMANDS: JUMP, MOVE, DOCK
		if (jump||move||dock) {
			if (!label||!label.length) {
				var p=this.findPanel(name);
				if (jump) { if (p) this.scrollToPanel(p,true); else window.scrollTo(left,top); }
				if (move) { this.movePanel(p,left,top,true,true); }
				if (dock) { if (all) this.forAllPanels(this.dockPanel); else if (p) this.dockPanel(p); }
				return;
			}
			var tip=(jump?this.jumpParam:move?this.moveParam:dock?this.dockParam:'')+': '+name;
			var b=createTiddlyButton(place,label,prompt||tip, function(ev) {
				var cmm=config.macros.moveablePanel; var p=cmm.findPanel(this.name);
				if (this.jump) { if (p) cmm.scrollToPanel(p,true); else window.scrollTo(this.left,this.top); }
				if (this.move) { if (p) cmm.movePanel(p,this.left,this.top,true,true); }
				if (this.dock) { if (p) cmm.dockPanel(p); else if (this.all) cmm.forAllPanels(cmm.dockPanel); }
				return cmm.processed(ev)
			},'button');
			b.jump=jump; b.move=move; b.dock=dock;
			b.name=name; b.all=all;   b.left=left; b.top=top;
			return;
		}

		// PANEL SETUP
		var p=this.getPanel(place);
		this.cachePanel(p);
		addClass(p,'moveablePanel');
		p.pid=name;
		p.showmanager=showmanager;
		p.fixedheight=height||undefined;
		p.fixedwidth=width||undefined;
		this.addPanelButtons(p,showfold,showhover,showclose,showdock,showmanager);
		this.addMouseHandlers(p);
		if (startundocked) {
			this.undockPanel(p);
			if (!startingUp) { this.bringPanelToFront(p); this.scrollToPanel(p); }
		}
		if (this.manager) { this.manager.applyMap(p); this.manager.trackMap(p); }
		this.notify(p);
	},
//}}}
// // notifications
//{{{
	quiet: 0, // flag to suspend/resume notifications
	notify: function(p) { // notify others of panel changes
		if (this.quiet) return;
		if (this.manager) this.manager.notify(p); // pass notices to manager (updates viewers)
	},
//}}}
// // general panel utilities
//{{{
	getPanel: function(place) { // find containing panel or floating slider (use current element as fallback)
		var p=place;
		while (p && !(hasClass(p,'moveablePanel')||hasClass(p,'floatingPanel'))) p=p.parentNode;
		return p||place;
	},
	getAllPanels: function(zSort) { // find 'moveablePanel' elements (optionally sort by zIndex)
		var panels=[];
		var sortByZindex=function(a,b){
			var v1=parseInt(a.style.zIndex); if (isNaN(v1)) v1=0;
			var v2=parseInt(b.style.zIndex); if (isNaN(v2)) v2=0;
			return(v1==v2)?0:(v1>v2?1:-1);
		}
		// if native browser fn is defined, use it (*much* more efficient!)
		if (document.getElementsByClassName) { 
			var elems=document.getElementsByClassName('moveablePanel');
			for (var i=0; i<elems.length; i++) panels.push(elems[i]);
			return zSort?panels.sort(sortByZindex):panels;
		}
		// otherwise, find all DIVs and SPANs with the right class
		// NOTE: IE requires use of Enumerator() to iterate over elements, or it FREEZES UP COMPLETELY!!
		var isIE=config.browser.isIE;
		var elems=document.getElementsByTagName('DIV');
		for (var i=isIE?new Enumerator(elems):0; isIE?!i.atEnd():(i<elems.length); isIE?i.moveNext():i++) {
			var panel=isIE?i.item():elems[i];
			if (hasClass(panel,'moveablePanel')) panels.push(panel);
		}
		var elems=document.getElementsByTagName('SPAN');
		for (var i=isIE?new Enumerator(elems):0; isIE?!i.atEnd():(i<elems.length); isIE?i.moveNext():i++) {
			var panel=isIE?i.item():elems[i];
			if (hasClass(panel,'moveablePanel')) panels.push(panel);
		}
		return zSort?panels.sort(sortByZindex):panels;
	},
	findPanel: function(pid) { // find a named panel
		var p=this.getAllPanels();
		for (var i=0; i<p.length; i++) { if (pid && p[i].pid==pid) return p[i]; }
		return undefined;
	},
	forAllPanels: function(callback) { // invoke a function on each panel
		var panels=this.getAllPanels();
		this.quiet++;
		for (var i=0; i<panels.length; i++) callback.apply(this,[panels[i]]);
		this.quiet--;
		this.notify('all');
	},
	cachePanel: function(p) { // save original styles and handlers
		if (!p.saved) p.saved={ 
			x:p.style.left||'', y:p.style.top||'', w:p.style.width||'', h:p.style.height||'',
			z:p.style.zIndex||'', pos:p.style.position||'', title: p.title,
			mouseover:p.onmouseover, mouseout:p.onmouseout,
			mousedown:p.onmousedown, mousemove:p.onmousemove, dblclick:p.ondblclick
		};
	},
	restorePanel: function(p) { // restore original styles
		if (!p.saved) return;
		p.style.left=p.saved.x; p.style.top=p.saved.y; p.style.width=p.saved.w; p.style.height=p.saved.h;
		p.style.zIndex=p.saved.z; p.style.position=p.saved.pos; p.title=p.saved.title;
		removeClass(p,'folded'); removeClass(p,'hover'); removeClass(p,'undocked');
	},
//}}}
// // panel metrics
//{{{
	getPanelOffset: function(p) { // adjustment for child elements inside relative/floatingPanel containers
		var r=new Object(); r.x=0; r.y=0; if (!p) return r;
		var pp=p.parentNode; while (pp && !(pp.style&&pp.style.position=='relative')) pp=pp.parentNode;
		if (pp) { r.x+=findPosX(pp); r.y+=findPosY(pp); }
		var pp=p.parentNode; while (pp && !hasClass(pp,'floatingPanel')) pp=pp.parentNode;
		if (pp) { r.x+=findPosX(pp); r.y+=findPosY(pp); }
		return r;
	},
	// PROBLEM: the offsetWidth/offsetHeight do not seem to account for padding or borders
	// WORKAROUND: subtract padding and border (in px) from width and height
	// ISSUE: I still don't understand why this is needed...
	// TBD: get padding/border values from p.style and convert to px
	// NOTE: 10.6667 seems to be about 1em...
	getPanelEdgeWidth:
	  	function(p) { return 10.6667; },
	getPanelEdgeHeight:
		function(p) { return 10.6667; },
	getPanelHeight:
		function(p) { var pad=10.6667; var border=1; return p.offsetHeight-(pad*2+border*2); },
	getPanelWidth:
		function(p) { var pad=10.6667; var border=1; return p.offsetWidth -(pad*2+border*2); },
//}}}
// // panel stacking (zIndex)
//{{{
	isStackable: function(p) { // zIndex is only effective with absolute or fixed elements
		return (['absolute','fixed'].contains(p.style.position)&&!hasClass(p,'popup'));
	},
	normalizeStack: function(panels) { // set zIndex to correspond to stack order
		for (var i=0; i<panels.length; i++) {var z=panels[i].style.zIndex;
			if (z==0||z=='auto') continue; // if not stacking (e.g., 'auto', '', or null)
			if (z<10000 || z>10000) continue; // use large values for "always in front/back"
			if (z!=i+2) panels[i].style.zIndex=i+2;
			if (this.manager) this.manager.trackMap(panels[i]);
		}
		return panels;
	},
	bringPanelToFront: function(p) { if (!p) return;
		if (!this.isStackable(p)) return; // can't be stacked
		var panels=this.getAllPanels(true);
// WFFL - normalizing every time works, but takes too long
//		if (p.style.zIndex>panels.length+2) return; // stay in front
//		this.normalizeStack(panels);
//		p.style.zIndex=panels.length+2;
// WFFL - for now, just bump up the max (ignore z>10000) and normalize much less often
		if (p.style.zIndex>1000) this.normalizeStack(panels);
		var zMax=0; if (panels.length) {
			var i=panels.length-1; zMax=parseInt(panels[i].style.zIndex);
			while (zMax>10000 && i>=0) zMax=parseInt(panels[--i].style.zIndex);
			if (p==panels[i]) return; // already in front
			if (isNaN(zMax)) zMax=0;
		}
		p.style.zIndex=zMax+1;
		this.notify(p);
	},
	sendPanelToBack: function(p) { if (!p) return;
		if (!this.isStackable(p)) return; // can't be stacked
		var panels=this.getAllPanels(true);
// WFFL - normalizing every time works, but takes too long
//		if (p.style.zIndex<2) return; // stay in back
//		this.normalizeStack(panels);
//		p.style.zIndex=1;
// WFFL - for now, just bump down the min (ignore z<10000) and normalize much less often
		if (p.style.zIndex<1000) this.normalizeStack(panels);
		var zMin=0; if (panels.length) {
			var i=0; zMin=parseInt(panels[i].style.zIndex);
			while (zMin<10000 && i<panels.length-1) zMin=parseInt(panels[++i].style.zIndex);
			if (p==panels[i]) return; // already in back
			if (isNaN(zMin)) zMin=0;
		}
		p.style.zIndex=zMin-1;
		this.notify(p);
	},
	returnPanelToStack: function(p) { if (!p) return;
		p.style.zIndex=p.saved?p.saved.zIndex:'';
		this.notify(p);
	},
//}}}
// // panel scrolling 
//{{{
	noScrollX: 0, // flags to disable TW built-in scrolling behavior
	noScrollY: 0, // set by hijacks, cleared by ensurePanelVisible(), below
	// scroll view to show panel along nearest edge of window or centered (optional)
	scrollToPanel: function(p,center) { if (!p) return;
		if (hasClass(p,'popup')) return; // popup=let core scrolling handle it
		if (hasClass(p,'hover')) return; // hover=always in view=don't scroll
		var scrollSize=findWindowWidth()-document.body.offsetWidth; // width of scrollbar
		var sx=findScrollX();	var ww=findWindowWidth()-scrollSize;
		var sy=findScrollY();	var wh=findWindowHeight()-scrollSize;
		var px=findPosX(p);	var pw=p.offsetWidth;
		var py=findPosY(p);	var ph=p.offsetHeight;
		var nx=sx; var ny=sy; // assume no scrolling is needed
		// if BR is not in view, scroll to show BR
		if (px+pw>sx+ww) nx=px+pw-ww;
		if (py+ph>sy+wh) ny=py+ph-wh;
		// if TL not in view or too big... scroll to show TL
		if (px<nx || px>nx+ww || px+pw>nx+ww) nx=px;
		if (py<ny || py>ny+wh || py+ph>ny+wh) ny=py;
		// optionally, center in view (if panel fits)
		if (center && pw<ww) nx-=(ww-pw)/2;
		if (center && ph<wh) ny-=(wh-ph)/2;
		if (nx!=sx||ny!=sy) { // if we need to scroll...
			window.scrollTo(nx,ny);
			if (config.options.chkMoveablePanelShowStatus && !startingUp) {
				var id=hasClass(p,'tiddler')?p.getAttribute('tiddler'):p.pid;
				this.timedMessage(this.scrollMsg.format([id||this.noPid,px,py]),this.msgDuration);
			}
			this.notify(p);
		}
	},
	// bring to front and scroll into view (with optional ASYNC)
	ensurePanelVisible: function(p,delay) { if (!p) return;
		if (delay && !startingUp) { // wait for core animation to complete...
			if (hasClass(p,'tiddler'))
				p=config.macros.moveablePanel.findPanel(p.getAttribute('tiddler'))||p;
			if (!p.id) p.id=new Date().getTime()+Math.random(); // unique ID
			var code='config.macros.moveablePanel.ensurePanelVisible(document.getElementById("%0"));';
			setTimeout(code.format([p.id]),delay);
			return;
		}
		// unblock scrolling and bring the panel into view
		if (this.noScrollX) this.noScrollX--; if (this.noScrollY) this.noScrollY--;
		if (hasClass(p,'popup')) return; // leave popups alone!
		this.bringPanelToFront(p);
		if (this.noScrollX+this.noScrollY==0 && !startingUp) // no scroll during document startup
			this.scrollToPanel(p);
	},
//}}}
// // panel status
//{{{
	formatPanelStatus: function(p) {
		var s=p.style; var msg=this.statusMsg.format([p.pid||this.noPid,
			s.left,s.top,hasClass(p,'hover')?this.hoveredMsg:'',s.width,s.height,s.zIndex]);
		return msg.replace(/(\.[0-9]+)|px/g,''); // remove decimals and 'px'
	},
	showPanelStatus: function(p,show) { // display panel info in titlebar while moving/sizing
		if (!config.options.chkMoveablePanelShowStatus) return;
		if (show) document.title=this.formatPanelStatus(p)
		else refreshPageTitle();
	},
	timedMessage: function(msg,duration) {
		document.title=msg; setTimeout('refreshPageTitle()',duration);
	},
	getPanelTooltip: function(p) {
		return hasClass(p,'undocked')?this.formatPanelStatus(p):this.dockedTip.format([p.pid||this.noPid]);
	},
//}}}
// // panel actions
//{{{
	undockPanel: function(p,front) { // undocked with default pos/size
		if (hasClass(p,'undocked')) return; // already undocked
		// get size BEFORE undocking
		p.style.width=p.fixedwidth  ||(this.getPanelWidth(p)+'px');
		p.style.height=p.fixedheight||(this.getPanelHeight(p)+'px');
		addClass(p,'undocked');	if (!this.isStackable(p)) p.style.position='absolute'; // UNDOCK it
		// set position AFTER undocking
		var offset=this.getPanelOffset(p);
		p.style.left=findPosX(p)-offset.x+'px'; p.style.top=findPosY(p)-offset.y+'px';
		if (front) this.bringPanelToFront(p);
		this.notify(p);
	},
	dockPanel: function(p) { // reset to docked pos/size
		if (!hasClass(p,'undocked')) return; // already docked
		this.restorePanel(p); // reset panel
		// FOR FLOATING SLIDERS: trigger slider adjustment handler (if any)
		if (hasClass(p,'floatingPanel') && window.adjustSliderPos)
			window.adjustSliderPos(p.parentNode,p.button,p);
		this.quiet++; if (this.manager) this.manager.trackMap(p); this.quiet--;
		this.notify(p)
	},
	closePanel: function(p) { // dock panel, then close (for tiddlers and floating sliders)
		var t=story.findContainingTiddler(p);
		var isTiddler=t&&this.findPanel(t.getAttribute('tiddler'));
		var isFloating=hasClass(p,'floatingPanel');
		if (!isTiddler) // when closing TIDDLERS, leave them undocked (keeps size/pos)
			this.dockPanel(p);
		// FOR FLOATING SLIDERS: set focus and do a fake click on slider button
		if (isFloating) { p.button.focus(); onClickNestedSlider({target:p.button}); }
		// FOR TIDDLERS: call story.closeTiddler()
		if (isTiddler) { story.closeTiddler(t.getAttribute('tiddler')); }
	},
	movePanel: function(p,x,y,show,centered) { if (!p) return;
		this.quiet++;
		this.undockPanel(p);
		// adjust for child elements inside relative/floatingPanel containers
		var offset=this.getPanelOffset(p);
		p.style.left=x-offset.x+'px'; p.style.top=y-offset.y+'px';
		if (show) { this.bringPanelToFront(p); this.scrollToPanel(p,centered); }
		this.quiet--;
		this.showPanelStatus(p,true);
		if (this.manager) this.manager.trackMap(p);
	},
	foldPanel: function(p) { // toggle panel height
		if (hasClass(p,'folded')) removeClass(p,'folded'); else addClass(p,'folded');
		if (this.manager) this.manager.trackMap(p);
		this.notify(p);
	},
	hoverPanel: function(p) { // toggle fixed position
		if (hasClass(p,'hover')) {
			removeClass(p,'hover');
			var offset=this.getPanelOffset(p);
			p.style.left=p.offsetLeft+findScrollX()-offset.x+'px';
			p.style.top=p.offsetTop+findScrollY()-offset.y+'px';
		} else {
			var offset=this.getPanelOffset(p);
			var ww=findWindowWidth(); var wh=findWindowHeight();
			p.style.left=(p.offsetLeft-findScrollX()+offset.x)%ww+'px';
			p.style.top =(p.offsetTop -findScrollY()+offset.y)%wh+'px';
			addClass(p,'hover'); 
		}
		if (this.manager) this.manager.trackMap(p);
		this.notify(p);
	},
	resetPanel: function(p) { // reset to session starting pos/size
		if (this.manager) this.manager.resetPanel(p); else this.dockPanel(p);
	},
//}}}
// // menu buttons
//{{{
	processed: function(ev) { var ev=ev||window.event; // use to end event handling for menus and mouse actions
		if (ev) { ev.cancelBubble=true; if (ev.stopPropagation) ev.stopPropagation(); } return false;
	},
	addPanelButtons: function(p,showfold,showhover,showclose,showdock,showmanager) {
		if (p.menu) return; // only once per panel
		function cmd(menu,label,tip,callback,show,arg) {
			var fn=function(ev){return this.callback.apply(config.macros.moveablePanel,[this,ev,this.arg]);}
			var b=createTiddlyButton(menu,label,tip,fn,'moveablePanelButton');
			b.style.display=show?'inline':'none'; b.callback=callback; b.arg=arg;
			return b;
		}
		var m=createTiddlyElement(p,'div',null,'moveablePanelMenu');
		p.showfold=showfold;
		p.foldbutton= cmd(m,this.foldLabel,this.foldTip,this.foldHandler,showfold);
		p.unfoldbutton= cmd(m,this.unfoldLabel,this.unfoldTip,this.foldHandler,false);
		p.showhover=showhover;
		p.hoverbutton=cmd(m,this.hoverLabel,this.hoverTip,this.hoverHandler,showhover);
		p.scrollbutton=cmd(m,this.scrollLabel,this.scrollTip,this.hoverHandler,false);
		p.showdock=showdock;
		p.dockbutton= cmd(m,this.dockLabel,this.dockTip,this.dockHandler,showdock);
		p.showclose=showclose;
		p.closebutton=cmd(m,this.closeLabel,this.closeTip,this.closeHandler,showclose);
		p.showmanager=showmanager;
		if (this.manager) p.managerbutton=cmd(m,this.manager.buttonLabel,this.manager.buttonTip,
			this.manager.popup,showmanager,p.pid);
		p.menu=m;
	},
	togglePanelButtons: function(p,show) { if (!p||!p.menu) return;
		var undocked=hasClass(p,'undocked');
		var floating=hasClass(p,'floatingPanel');
		var hover=hasClass(p,'hover');
		var folded=hasClass(p,'folded');
		var t=story.findContainingTiddler(p);
		var tiddler=t&&this.findPanel(t.getAttribute('tiddler'));
		var show=show&&(undocked||floating);
		p.menu.style.display=show?'inline':'none';
		if (p.showfold)  p.foldbutton.style.display  =!folded?'inline':'none';
		if (p.showfold)  p.unfoldbutton.style.display= folded?'inline':'none';
		if (p.showhover) p.hoverbutton.style.display =!hover?'inline':'none';
		if (p.showhover) p.scrollbutton.style.display= hover?'inline':'none';
		if (p.showdock)  p.dockbutton.style.display =undocked?'inline':'none';
		if (p.showclose) p.closebutton.style.display=floating||(tiddler&&undocked)?'inline':'none';
		if (p.managerbutton) { // see [[PanelManagerPlugin]]
			var show=p.showmanager||config.options.chkMoveablePanelShowManager;
			p.managerbutton.style.display=show?'inline':'none';
		}
	},
	foldHandler: function(place,ev){ var p=this.getPanel(place);
		this.foldPanel(p); this.togglePanelButtons(p,true); return this.processed(ev); },
	hoverHandler: function(place,ev){ var p=this.getPanel(place);
		this.hoverPanel(p); this.togglePanelButtons(p,true); return this.processed(ev); },
	dockHandler: function(place,ev){ var p=this.getPanel(place);
		this.dockPanel(p); this.togglePanelButtons(p,true); return this.processed(ev); },
	closeHandler: function(place,ev){ var p=this.getPanel(place);
		this.closePanel(p); this.togglePanelButtons(p,true); return this.processed(ev); },
//}}}
// // mouse handlers
//{{{
	addMouseHandlers: function(p) {
		if (p.handlers) return true; // only add handlers ONCE
		p.onmouseover=function(ev) { var ev=ev||window.event;
			var r=config.macros.moveablePanel.mouseover(this,ev);
			return r&&this.saved.mouseover?this.saved.mouseover.apply(this,arguments):true;
		};
		p.onmouseout=function(ev) { var ev=ev||window.event;
			var r=config.macros.moveablePanel.mouseout(this,ev);
			return r&&this.saved.mouseout?this.saved.mouseout.apply(this,arguments):true;
		};
		p.onmousemove=function(ev) { var ev=ev||window.event;
			var r=config.macros.moveablePanel.mousemove(this,ev);
			return r&&this.saved.mousemove?this.saved.mousemove.apply(this,arguments):true;
		};
		p.ondblclick=function(ev) { var ev=ev||window.event;
			var r=config.macros.moveablePanel.dblclick(this,ev);
			return r&&this.saved.dblclick?this.saved.dblclick.apply(this,arguments):r;
		};
		p.onmousedown=function(ev) { var ev=ev||window.event;
			var r=config.macros.moveablePanel.mousedown(this,ev);
			return r&&this.saved.mousedown?this.saved.mousedown.apply(this,arguments):r;
		};
		p.handlers=true;
	},
	isEdge: function(p,ev) { // near 'edge' of panel (or child element)?
		var ev=ev||window.event; var target=resolveTarget(ev);
		if (!p) return false;
		// ignore form input fields
		if (['input','select','option','textarea'].contains(target.nodeName.toLowerCase())) return false;
		var left=findPosX(p); var top=findPosY(p);
		var width=p.offsetWidth; var height=p.offsetHeight;
		var x=findMouseX(ev); var y=findMouseY(ev);
		if (hasClass(p,'hover')) { x-=findScrollX(); y-=findScrollY(); } // window-relative panel
		if (x<left||y<top||x>=left+width||y>=top+height) { // outside of panel
			if (p==target || p!=this.getPanel(target)) return false;
			return this.isEdge(target,ev); // check target child element
		}
		var edgeW=this.getPanelEdgeWidth(p); var edgeH=this.getPanelEdgeHeight(p);
		var isT=(y-top<edgeH); var isL=(x-left<edgeW);
		var isB=(top+height-y<edgeH); var isR=(left+width-x<edgeW);
		return isT||isL||isB||isR;
	},
	// temporary element during move/size keeps document from shrinking 
	addGhost: function(p) {
		var g=document.getElementById('moveablePanelGhost');
		if (!g) g=createTiddlyElement(document.body,'div','moveablePanelGhost','moveablePanelGhost');
		var border=1; // note: must match CSS for 'moveablePanelGhost' WFFL-HACK
		g.style.left=findPosX(p)+'px';
		g.style.top=findPosY(p)+'px';
		g.style.width=((p.offsetWidth-border*2)||0)+'px';
		g.style.height=((p.offsetHeight-border*2)||0)+'px';
	},
	clearGhost: function() {
		var e=document.getElementById('moveablePanelGhost');
		if (e) e.parentNode.removeChild(e);
	},
	// MOUSEOVER=SHOW MENU
	mouseover: function(place,ev) { var ev=ev||window.event;
		var p=this.getPanel(place);
		addClass(p,'selected'); // shows toolbar-classed items
		this.togglePanelButtons(p,true);
		return true;
	},
	// MOUSEOUT=HIDE MENU
	mouseout: function(place,ev) { var ev=ev||window.event;
		var p=this.getPanel(place);
		removeClass(p,'selected'); // hides toolbar-classed items
		this.togglePanelButtons(p,false);
		return true;
	},
	// MOUSEMOVE=SHOW MENU AND SET CURSOR/TIP
	mousemove: function(place,ev) { var ev=ev||window.event;
		var p=this.getPanel(place);
		p.style.cursor='auto'; p.title=p.saved?p.saved.title:'';
		if (!this.isEdge(p,ev)) return true;
		var fw=p.fixedwidth;  if (fw==null) fw=undefined;
		var fh=p.fixedheight; if (fh==null) fh=undefined;

		p.title=this.moveTip.format([p.pid?p.pid+': ':'']);
		if (fw===undefined&&fh===undefined) p.title+=' '+this.sizeTip;
		else if  (fw===undefined) p.title+=' '+this.sizeWidthTip;
		else if  (fh===undefined) p.title+=' '+this.sizeHeightTip;
		if (hasClass(p,'undocked')) {
			p.title+=', '+this.clickTip+', ';
			p.title+=hasClass(p,'folded')?this.dblclickunfoldTip:this.dblclickdockTip;
		}
		p.style.cursor='move';
		if (ev.shiftKey&&!(fw&&fh)) { // set resizing cursor (if not fixed width/height)
			var left=findPosX(p); var top=findPosY(p);
			var width=p.offsetWidth; var height=p.offsetHeight;
			var x=findMouseX(ev); var y=findMouseY(ev);
			if (hasClass(p,'hover')) { x-=findScrollX(); y-=findScrollY(); } // window-relative panel
			var edgeW=this.getPanelEdgeWidth(p); var edgeH=this.getPanelEdgeHeight(p);
			var isT=(y-top<edgeH); var isL=(x-left<edgeW);
			var isB=(top+height-y<edgeH); var isR=(left+width-x<edgeW);
			p.style.cursor=(fh===undefined?(isT?'n':(isB?'s':'')):'')
				+(fw===undefined?(isL?'w':(isR?'e':'')):'')+'-resize';
		}
		return true;
	},
	// DOUBLE-CLICK=DOCK OR UNFOLD
	dblclick: function(place,ev) { var ev=ev||window.event;
		var p=this.getPanel(place);
		if (!this.isEdge(p,ev)) return true;
		// if folded... unfold, otherwise... undock
		if (hasClass(p,'folded')) this.foldPanel(p); else this.dockPanel(p);
		this.togglePanelButtons(p,false);
		return this.processed(ev);
	},
	// MOUSEDOWN=START MOVE/SIZE, CLICK=BRING TO FRONT, SHIFT-CLICK=SEND TO BACK
	mousedown: function(place,ev) { var ev=ev||window.event;
		var p=this.getPanel(place);

		// CLICK ALWAYS BRINGS TO FRONT
		this.quiet++;
		this.bringPanelToFront(p);
		if (this.manager) this.manager.trackMap(p);
		this.quiet--;
		if (!this.isEdge(p,ev)) return true;

		// start capturing mouse events and set mouse/key handlers
		var target=p; // if 'capture' not supported, track in panel only
		if (document.body.setCapture) // IE
			{ document.body.setCapture(); var target=document.body; }
		if (window.captureEvents) // moz
			{ window.captureEvents(Event.MouseMove|Event.MouseUp,true); var target=window; }
 		if (target.onmousemove!=undefined) target.saved_mousemove=target.onmousemove;
		target.onmousemove=this.dragmove;
		if (target.onmouseup!=undefined) target.saved_mouseup=target.onmouseup;
		target.onmouseup=this.dragstop;
 		if (target.onkeydown!=undefined) target.saved_keydown=target.onkeydown;
		target.onkeydown=this.dragkey;

		// calculate and save drag data in target element
		var x=findMouseX(ev); var left=findPosX(p); var width =p.offsetWidth;
		var y=findMouseY(ev); var top =findPosY(p); var height=p.offsetHeight;
		var sizing=ev.shiftKey;
		var edgeW=this.getPanelEdgeWidth(p); var edgeH=this.getPanelEdgeHeight(p);
		var isT=(y-top<edgeH); var isL=(x-left<edgeW);
		var isB=(top+height-y<edgeH); var isR=(left+width-x<edgeW);
		var d=new Object();
		d.panel=p; d.left=left; d.top=top;
		d.width=this.getPanelWidth(p); d.height=this.getPanelHeight(p);
		d.sizing=sizing; d.edgeW=edgeW; d.edgeH=edgeH;
		d.isT=isT; d.isL=isL; d.isB=isB; d.isR=isR; d.offset=this.getPanelOffset(p);
		d.saved={ x:p.style.left, y:p.style.top, w:p.style.width, h:p.style.height,
			z:p.style.zIndex, pos:p.style.position, classname:p.className };
		target.data=d;
		this.addGhost(p); // keep document from shrinking during move/size
		return this.processed(ev);
	},
	// MOUSEMOVE (during drag)=move/size panel
	dragmove: function(ev){ var ev=ev||window.event; var cmm=config.macros.moveablePanel;
		var d=this.data; var p=d.panel;
		if (!p) { this.onmousemove=this.saved_mousemove?this.saved_mousemove:null; return; }

		cmm.quiet++; // save all notifications until the end...

		// ensure panel is undocked and scrolled into view, THEN get starting mouse and scroll positions
		if (!hasClass(p,'undocked'))
			{ cmm.undockPanel(p,true); if (this.manager) this.manager.trackMap(p); }
		if (d.x===undefined) // first move event only
			{ cmm.scrollToPanel(p); d.x=findMouseX(ev); d.y=findMouseY(ev); }

		// get current mouse pos
		var newX=findMouseX(ev); var newY=findMouseY(ev);

		// calculate new TLWH (start with current panel pos/size)
		var startX=d.x; var startY=d.y; var offsetX=d.offset.x; var offsetY=d.offset.y;
		var L=d.left; var T=d.top; var W=d.width; var H=d.height;
		var newL=L; var newT=T; var newW=p.fixedwidth||W; var newH=p.fixedheight||H;
		if (d.sizing) { // resize panel
			var minW=d.edgeW*2; var minH=d.edgeH*2; // stay bigger than edge areas
			if (hasClass(p,'folded')) this.fold(p.foldButton,ev); // un-fold first!
			if (d.isT) newH=H-newY+startY+1;
			if (d.isB) newH=H+newY-startY+1;
			if (d.isL) newW=W-newX+startX+1;
			if (d.isR) newW=W+newX-startX+1;
			if (d.isT) newT=T-offsetY+newY-startY+1; else newT=T-offsetY; 
			if (d.isL) newL=L-offsetX+newX-startX+1; else newL=L-offsetX; 
			if ((d.isL||d.isR)&&!p.fixedwidth)  newW=(newW>minW?newW:minW);
			if ((d.isT||d.isB)&&!p.fixedheight) newH=(newH>minH?newH:minH);
		} else { // move panel
			newL=L-offsetX+newX-startX+1;
			newT=T-offsetY+newY-startY+1;
		}
		if (hasClass(p,'hover')) { // hover=stay on first screen
			var ww=findWindowWidth(); var wh=findWindowHeight();
			newL+=offsetX; newT+=offsetY; // hover=no relative offset (window-relative)
			// WFFL lower right is off... a bit too far (perhaps scrollwidth?)
			if (newL+newW>ww) newL=ww-newW; if (newT+newH>wh) newT=wh-newH; // limit lower right
			if (newL<0) newL=0; if (newT<0) newT=0; // limit upper left
		} else { // normal floating panel=limit upper left (stay on page)
			if (newL+offsetX<0) newL=0-offsetX; if (newT+offsetY<0) newT=0-offsetY;
		}

		// move the panel and scroll into view as needed
		p.style.left=newL.toString()+'px';
		p.style.top=newT.toString()+'px';
		if (d.sizing) p.style.width=newW.toString()+'px';
		if (d.sizing) p.style.height=newH.toString()+'px';
		cmm.scrollToPanel(p);

		// report new position and notify panel manager... done!
		cmm.quiet--; cmm.showPanelStatus(p,true); cmm.notify(p);
		return cmm.processed(ev);
	},
	dragkey: function(ev){ var ev=ev||window.event;
		var d=this.data; var p=d.panel;
		if (ev.keyCode==27) { // ESC=CANCEL... restore panel to previous pos/size
			p.style.left =d.saved.x; p.style.top   =d.saved.y;
			p.style.width=d.saved.w; p.style.height=d.saved.h;
			p.style.zIndex=d.saved.z;
			p.style.position=d.saved.pos;
			p.className=d.saved.classname;
			return this.onmouseup(ev);
		}
		if (this.saved_keydown) return this.saved_keydown(ev);
	},
	// MOUSEUP: END MOVE/SIZE, SHIFT-CLICK=SEND TO BACK
	dragstop: function(ev){ var ev=ev||window.event; var cmm=config.macros.moveablePanel;
		var newX=findMouseX(ev); var newY=findMouseY(ev);
		if (this.releaseCapture) this.releaseCapture(); // IE
		if (this.releaseEvents) this.releaseEvents(Event.MouseMove|Event.MouseUp); // moz
		this.onmousemove=this.saved_mousemove?this.saved_mousemove:null;
		this.onmouseup=this.saved_mouseup?this.saved_mouseup:null;
		this.onkeydown=this.saved_keydown?this.saved_keydown:null;
		var d=this.data; var p=d.panel;
		if (ev.shiftKey && d.x==newX && d.y==newY && cmm.isEdge(p,ev))
			cmm.sendPanelToBack(p); // SHIFT-CLICK *EDGE*
		cmm.togglePanelButtons(p,true);
		cmm.quiet++; if (cmm.manager) cmm.manager.trackMap(p); cmm.quiet--;
		cmm.clearGhost(); // allow document to adjust extents (if needed)
		cmm.showPanelStatus(p,false); cmm.timedMessage(cmm.formatPanelStatus(p),cmm.msgDuration);
		return cmm.processed(ev);
	},
//}}}
// // CSS definitions
//{{{
	css: '/*{{{*/\n'
		+'.moveablePanelMenu\n'
			+'\t{ display:none; position:absolute; right:.5em; top:-1em; }\n'
		+'.undocked .selected.moveablePanelMenu\n'
			+'\t{ display:inline; }\n'
		+'.floatingPanel .selected .moveablePanelMenu\n'
			+'\t{ display:inline; }\n'
		+'.hover\n'
			+'\t{ position:fixed !important; }\n'
		+'.folded\n'
			+'\t{ height:1.5em !important; overflow:hidden !important; }\n'
		+'.tiddler .folded\n'
			+'\t{ height:2em !important; }\n'
		+'.folded  .moveablePanelMenu\n'
			+'\t{ top:.5em; }	/* buttons fit in folded panel */\n'
		+'.tiddler .moveablePanelMenu\n'
			+'\t{ top:.2em; }	/* buttons fit in tiddler title */\n'
		+'.undocked .toolbar\n'
			+'\t{ padding-right:7.5em; }	/* make room for buttons next to toolbar */\n'
		+'.floatingPanel .moveablePanelMenu\n'
			+'\t{ right:1em;top:1em; } /* buttons fit in floating panel */\n'
		+'.moveablePanelButton\n {'
			+'\tbackground:#ccc !important; color:#000 !important;\n'
			+'\tborder:1px solid #666; padding:0 .25em; margin:0px 1px;\n'
			+'}\n'
		+'.moveablePanelButton:hover\n'
			+'\t{ background:#fff !important; color:#000 !important; }\n'
		+'.popup\n'
			+'\t{ z-index:9999999 !important; } /* popups MUST always be on top!  */\n'
		+'.moveablePanelGhost\n'
			+'\t{ position:absolute; border:1px dotted #999; }\n'
		+'/*}}}*/'
});
//}}}
// // load time initialization
//{{{
// defaults for options
if (config.options.txtMoveablePanelMapName===undefined)
	config.options.txtMoveablePanelMapName='DefaultMap';
if (config.options.chkMoveablePanelShowStatus===undefined)
	config.options.chkMoveablePanelShowStatus=true;
if (config.options.chkMoveablePanelShowManager===undefined)
	config.options.chkMoveablePanelShowManager=true;

// set up shadow stylesheet, then load styles (might be customized)
config.shadowTiddlers.MoveablePanelStyles=config.macros.moveablePanel.css;
var css=store.getRecursiveTiddlerText('MoveablePanelStyles',config.macros.moveablePanel.css,10);
setStylesheet(css,'moveablePanelStyles');
//}}}
// // hijacks
//{{{
// adjust popup placement to account for the current horizontal scrollbar
// offset (if any), so that popups will appear in the correct location, even
// when their 'root' element is scrolled far from the page origin.
var fn=Popup.place; fn=fn.toString(); if (fn.indexOf('findScrollX')==-1) { // only once
	fn=fn.replace(/winWidth\s*-\s*scrollWidth\s*-\s*1/,
		'findScrollX() + winWidth - scrollWidth - 1');
	fn=fn.replace(/winWidth\s*-\s*popupWidth\s*-\s*scrollWidth\s*-\s*1/,
		'findScrollX() + winWidth - popupWidth - scrollWidth - 1');
	eval('Popup.place='+fn);
}
//}}}
//{{{
// window.scrollTo() is used throughout the core (and plugins) to scroll to a *vertical*
// position as computed by ensureVisible(), in order to bring a tiddler into view.
// Unfortunately, the *horizontal* scroll position is almost always hard-coded to 0
// (i.e. a return to the left edge of the page).  Normally, this is not a problem,
// since a page is rarely scrolled horizontally.  However, when there are moveable
// panels, they can appear far from the left edge, so always scrolling to the left
// edge is very disruptive.  In addition, unwanted scrolling can occur as a side
// effect when displaying or refreshing a tiddler (e.g., switching between
// view/edit templates).  These hijacks adds control flags ('noScrollX' and 'noscrollY')
// that can be used to temporarily disable scrolling within the document.
if (window.scrollTo_moveablePanel==undefined) { // only once
window.scrollTo_moveablePanel=window.scrollTo;
	window.scrollTo=function(x,y) {
		var cmm=config.macros.moveablePanel;
		if (cmm.noScrollX&&cmm.noScrollY) return;
		x=cmm.noScrollX?findScrollX():x;
		y=cmm.noScrollY?findScrollY():y;
		window.scrollTo_moveablePanel(x,y);
	}
}
// ensureVisible() is used to calculate the y-offset of a tiddler, just before scrolling
// This tweak sets up an ASYNC timer to invoke the 'bring to front/scroll into view'
// function for 'tiddler' and 'popup' classes.  This allows the function
// to be triggered *after* core scrolling occurs, so the fixups are not
// stomped on by the core's normal scroll handling
if (window.ensureVisible_moveablePanel==undefined) { // only once
	window.ensureVisible_moveablePanel=window.ensureVisible;
	window.ensureVisible=function(e) {
		var ny=ensureVisible_moveablePanel.apply(this,arguments); // get core value

		// fixup height to account for horizontal scrollbar (if present)
		var atBottom=findPosY(e)+e.offsetHeight>=findScrollY()+findWindowHeight();
		var hasHScroll=document.documentElement.scrollWidth>findWindowWidth();
		var hScrollSize=findWindowWidth()-document.body.offsetWidth;
		if (atBottom && hasHScroll) ny+=hScrollSize;

		// defer scrolling for tiddlers and popups (except during startup)
		if (!startingUp && (hasClass(e,'tiddler')||hasClass(e,'popup'))) {
			var cmm=config.macros.moveablePanel;
			cmm.noScrollX++; if (hasClass(e,'tiddler')) cmm.noScrollY++;
			var delay=config.options.chkAnimate?config.animDuration+50:50;
			cmm.ensurePanelVisible(e,delay); // ASYNC SCROLL
		}
		return ny;
	}
}

// story.refreshTiddler()
if (Story.prototype.refreshTiddler_moveablePanel==undefined) { // only once
	Story.prototype.refreshTiddler_moveablePanel=Story.prototype.refreshTiddler;
	Story.prototype.refreshTiddler=function() {
		var cmm=config.macros.moveablePanel;
		cmm.noScrollX++; cmm.noScrollY++; // DON'T SCROLL AT ALL
		var r=this.refreshTiddler_moveablePanel.apply(this,arguments);
		cmm.noScrollX--; cmm.noScrollY--;
		return r;

	}
}
// story.displayTiddler()
if (Story.prototype.displayTiddler_moveablePanel==undefined) { // only once
	Story.prototype.displayTiddler_moveablePanel=Story.prototype.displayTiddler;
	Story.prototype.displayTiddler=function(srcElement,tiddler) {
		var cmm=config.macros.moveablePanel;
//WFFL		cmm.noScrollX++; cmm.noScrollY++;
		var r=this.displayTiddler_moveablePanel.apply(this,arguments);
		var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
		var panel=cmm.findPanel(title); // if moveable... unfold panel (but not during startup)
		if (panel&&hasClass(panel,'folded')&&!startingUp) cmm.foldPanel(panel);
		var delay=config.options.chkAnimate?config.animDuration+50:50;
		cmm.ensurePanelVisible(this.getTiddler(title),delay); // ASYNC SCROLL
		return r;

	}
}
//}}}
//{{{
// Zoomer() displays an animated bounding box when showing a tiddler.  But this box 'zooms' to the tiddler's 'anchor point', not the current panel position, which can cause a 'scroll blink'.  This hijack redirects the zoomer's target directly to the undocked panel (if any)
if (window.Zoomer_moveablePanel==undefined) { // only once
	window.Zoomer_moveablePanel=window.Zoomer;
	window.Zoomer=function(text,startElement,targetElement,unused) {
		if (hasClass(targetElement,'tiddler')) {
			var tid=targetElement.getAttribute('tiddler');
			arguments[2]=config.macros.moveablePanel.findPanel(tid)||targetElement;			
		}
		return window.Zoomer_moveablePanel.apply(this,arguments);
	}
}
//}}}
/***
|Name|MoveablePanelPluginInfo|
|Source|http://www.TiddlyTools.com/#MoveablePanelPlugin|
|Documentation|http://www.TiddlyTools.com/#MoveablePanelPluginInfo|
|Version|3.0.3|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|documentation for MoveablePanelPlugin|
Adds move/resize mouse handling plus fold/unfold, hover/scroll, and close/dock buttons to any rendered tiddler content, page element, or [[floating slider panel|NestedSlidersPlugin]].
!!!!!Usage
<<<
Please see [[MoveablePanelPackage]] for a general overview of features as well as information about other plugins and tiddlers associated with installation and use of moveable panels.
{{{
<<moveablePanel>>
<<moveablePanel undocked fold hover noclose nodock manager name:... width:... height:...>>

<<moveablePanel move label:... prompt:... name:... top:... left:...>>

<<moveablePanel jump label:... prompt:... name:... >>
<<moveablePanel jump label:... prompt:... top:... left:... >>

<<moveablePanel dock label:... prompt:... name:... >>
<<moveablePanel dock label:... prompt:... all>>
}}}
Without any parameters, the {{{<<moveablePanel>>}}} simply adds the 'moveable panel' mouse handling and button commands to a containing element that has been marekd with a CSS class of 'moveablePanel' (e.g., """{{moveablePanel{...}}}""") or 'floatingPanel' (created by [[NestedSlidersPlugin]]) .  If no containing 'moveablePanel' or 'floatingPanel' element is located, the panel handlers are added directly to the element in which the macro is contained.

__Optional macro parameters are:__
*''undocked''<br>by default, a moveable panel is rendered inline ('docked'), and only floats in front of other content ('undocked') after the user has moved it from it's 'anchor point'.  The ''undocked'' keyword indicates that the panel should be be immediately 'undocked' and brought to the front of the 'stack' of undocked panels as soon as it is rendered.
*''fold''<br>adds the fold/unfold (-/+) button
*''hover''<br>adds the hover/scroll (^/=) button
*''noclose''<br>supresses the close (X) button
*''nodock''<br>supresses the dock (&radic;) button
*''manager''<br>forces the Panel Manger button to always appear in the panel, regardless of the option setting (see below)
*''name:...''<br>specifies a unique identifier for the panel, to be used by the ''menu'', ''move'', ''jump'', or ''dock'' functions described below, as well as by the (optional) [[PanelManagerPlugin]] to create //panel maps// that track and record the size and position of named panels, so that they can remain where you put them, even in between browser sessions.
*''width:...''<br>specifies a fixed-width for the panel (using CSS dimensions).  This prevents horizontal resizing.
*''height:...''<br>specifies a fixed-height for the panel (using CSS dimensions).  This prevents vertical resizing.

In addition to adding panel handlers to a containing element, the macro can also be used to invoke several panel-specific actions, either immediately, or by clicking on an embedded command link:
*''dock''<br>returns a named panel to it's original anchor point.
*''jump''<br>scrolls the window to view a named panel or go to the specified (top,left) location on the page.  To dock all panels at once, the ''all'' keyword can be used instead of specifying a ''name:...'' parameter.
*''move''<br>moves the named panel to the specified (top,left) location on the page.
Note: when using ''dock'', ''jump'', or ''move'', if the ''label:...'' parameter is omitted, the action is performed immediately upon rendering the macro.  Otherwise, a command link is created using the specified ''label:...'' and (optional) ''prompt:...'' values.

__Mouse handling:__
When the mouse is just inside the edges of a moveable panel, the cursor will change to 'crossed-arrows'.  Grab (click-hold) the panel anywhere in the edge area and then drag the mouse to reposition it.  To resize the panel, hold the ''shift'' key before grabbing the panel: the cursor will change to a 'double-arrow' resizing symbol.  Drag a side edge of the panel to stretch horizontally or vertically, or drag a corner of the panel to stretch in both dimensions at once.  Double-clicking the edge of a panel resets it to its original 'docked' size and location.  Clicking (anywhere) in a moveable panel brings it to the top of the 'zIndex' stack (if overlapping with other panels).  Shift-click (along an edge) sends the panel to the back.

__Panel buttons:__
When the mouse is anywhere over a panel (not just near the edge), a special 'panel menu' appears in the ''upper right corner'' of the panel, with the following command buttons:
* &minus;/+ (fold/unfold): ''fold'' temporarily reduces the panel height to just one line.  ''unfold'' restores the panel height.
*^/= (hover/scroll): ''hover'' causes the panel to remain in view (i.e., 'fixed position') even when scrolling the rest of the page content.  ''scroll'' allows the panel to revert to scrolling with the page content (the usual behavior)
*X (close): ''close'' hides a panel from the page display.  If you have moved/resized a panel, closing it restores its default position and size.
*&radic; (dock): When a moveable panel has actually been moved from its default position, the ''close'' command is replaced with ''dock'', which restores the tiddler to its default //non-floating// location on the page.
*&#x2261; (manager): If [[PanelManagerPlugin]] is installed, this button provides instant access to the entire Panel Manager popup menu and interactive, graphical panel map viewer.

__Adding panel handlers to all tiddlers__
You can apply {{{<<moveablePanel ...>>}}} to //all// tiddlers by customizing the [[ViewTemplate]] definition to wrap the entire tiddler layout within a span that invokes the macro.  To uniquely name each moveable tiddler panel (i.e., so its position/size will be remembered by the Panel Manager), you can use a 'computed parameter' to dynamically assign the tiddler's title as the value of the 'name:...' parameter, like this:
{{{
<div class='moveablePanel'>
	... rest of tiddler layout template (i.e., everything from the normal ViewTemplate)
	<div macro='moveablePanel name:{{tiddler?tiddler.title:""}} height:auto'></div>
</div>
}}}
//Note: reference to 'tiddler.title' in this way requires installation of TiddlyTools'// [[CoreTweaks##444]] or use of TW2.5 (not yet available)
<<<
!!!!!Configuration
<<<
<<option chkMoveablePanelShowManager>> automatically add<<moveablePanel menu label:[[Panel Manager Popup Menu]]>>in undocked panels
{{{<<option chkMoveablePanelShowManager>>}}}
<<option chkMoveablePanelShowStatus>> show position/size while moving/resizing a panel
{{{<<option chkMoveablePanelShowStatus>>}}}
<<<
!!!!!Revisions
<<<
2008.12.24 [3.0.3] added ESC key handling to cancel panel move/size (restores previous panel state)
2008.12.20 [3.0.2] addGhost()/clearGhost(): shows panel outline during move/size (prevents document from shrinking until move/size is done)
2008.12.15 [3.0.1] handling for 'hovered' elements: adjust for fixed vs. absolute (no relative offsets, no scroll offsets), translate movement to top-left screen, restrict movement within screen bounds
2008.12.10 [3.0.0] total rewrite: extensive code refactoring and improved event handling for cross-browser compatibility, manage zIndex 'stacking' of panels, added shadow tiddler for customizable CSS, named panels, macro commands for embedding jump, dock, or move command links, complete I18N/L10N-readiness, {{{ensureVisible()}}} 'fixups' for horizontal scrolling, and hooks for optional [[PanelManagerPlugin]] (panel map 'memory' and interactive graphical viewers)
2008.11.17 [2.6.0] added optional 'height:...' and 'width:...' macro params for fixed size dimensions (use 'height:auto' for moveable tiddlers).  Added CSS for moveablePanelMenu and moveablePanelButton styles (for easier customization)
2008.11.16 [2.5.2] small fixes to mouseover/isEdge() handling.  some code cleanup as well
2008.11.15 [2.5.1] changed stored panel data format to be compatible with Project Cecily map format (space-separated, strip decimals and 'px').  Also, moved slider-specific adjustPanel() logic into [[NestedSlidersPlugin]].
2008.11.12 [2.5.0] more major code changes (lots of event handling fixes and code refactoring)
2008.11.09 [2.4.0] major re-write to fix mouse event handling issues and isEdge() logic for nested moveable panels
2008.11.06 [2.3.0] added CLICK/SHIFT-CLICK for 'move to top / return to stack' panel zIndex handling
2008.11.03 [2.2.0] automatically store/recall position/size of named panels using a cookie and/or tiddler
2008.09.11 [2.1.2] corrected caching of transient attribute (use =='true' to convert string to boolean)
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.30 [2.1.0] added 'noedges' option for alternative 'grab handles' (top=move, bottom-right=resize)
2007.12.17 [2.0.0] code reduction and feature cleanup: in getPanel(), removed handling for returning a tiddler element.  Instead, when the macro is not in a floating panel, it will make it's containing element moveable.  Removed 'maximize' functionality (which was badly broken), and replaced it with 'double-click=DOCK' (resets size/position without hiding panel). Changed 'float/close' menu style to use absolute positioned elements instead of using 'float:right' so panels don't suddenly stretch when the menu items are displayed.  Also, throughout code, replaced direct comparison for className=='floatingPanel' with hasClass() test function.  This allows additional classes to be used with moveable floating panels to apply custom CSS styles.
2007.06.10 [1.3.7] in handler(), mouse event handlers now use apply() to correctly invoke any previous mouse handler functions.  This allows *moveable tiddlers* to still process the TW standard handlers for mouseover/out that toggle the 'selected' class used to highlight the toolbar items when the mouse is over a tiddler.  Also, when setting up a moveable 'floatingPanel', clear the existing 'snap panel back to button location' mouseover/out event handlers (defined by NestedSlidersPlugin when the panels are created).  This extends the fix from v1.3.5 (see below). 
2007.06.08 [1.3.6] in getPanel(), remove unneeded check for 'moveable' tag.  Also, added support for 'noclose' macro param, and updated documentation accordingly.
2007.06.02 [1.3.5] in handler(), if floating panel has a corresponding button element (i.e., a NestedSlider), then remove onmouseover handler from that button element, to prevent automatic 'snap to original location' behavior.  This allows *moveable* floating panels to maintain their placement when they have been manually re-positioned.  This change is made for compatibility with [[NestedSlidersPlugin]] use of onmouseover (see entry for version 2.0.4)
2006.10.17 [1.3.4] when moving panel, adjust position for relative containing DIV
2006.05.25 [1.3.3] in closePanel(), use p.button.onclick() so that normal processing (updating slider button tooltip, access key, etc.) is performed
2006.05.11 [1.3.2] doc update
2006.05.11 [1.3.1] re-define all functions within moveablePanel object (eliminate global window.* function definitions (and some 'leaky closures' in IE)
2006.05.11 [1.3.0] converted from inline javascript to true plugin
2006.05.09 [1.2.3] in closePanel(), set focus to sliderpanel button (if any)
2006.05.02 [1.2.2] in MoveOrSizePanel(), calculate adjustments for top and left when inside nested floating panels
2006.04.06 [1.2.1] in getPanel(), allow redefinition or bypass of 'moveable' tag (changed from hard-coded 'tearoff')
2006.03.29 [1.2.0] in getPanel(), require 'tearoff' tag to enable floating tiddlers
2006.03.13 [1.1.0] added handling for floating tiddlers and conditional menu display
2006.03.06 [1.0.2] set move or resize cursor during mousetracking
2006.03.05 [1.0.1] use 'window' vs 'document.body' so mousetracking in FF doesn't drop the panel when moving too quickly
2006.03.04 [1.0.0] Initial public release
<<<
/***
This stylesheet contains CSS definitions for extra styling of tiddlers (and other standard page content) for use with MoveablePanelPlugin
***/
/*{{{*/
/* UNDOCKED STYLES */
.tiddler
	{ margin:0 !important; padding:0 !important; overflow:visible !important;
}
.undocked .header {
	border:1px solid; -moz-border-radius:.5em; -webkit-border-radius:.5em;
}
.undocked #sidebarOptions { 
	width:auto; border:1px solid; padding:1em; margin:0; background:#fff;
	-moz-border-radius:1em; -webkit-border-radius:1em;
}
.undocked #sidebarTabs { 
	width:auto; border:1px solid; padding:1.0em; background:#fff;
	-moz-border-radius:1em; -webkit-border-radius:1em;
}
.undocked #sidebarTabs .tabContents
	{ width:17em; max-height:30em; overflow:auto; }
.undocked #sidebarTabs .tabContents .tabContents
	{ width:16em; max-height:24em; overflow:auto; }

/* TIDDLER 'TITLEBAR' */
.title {
	font-size:120%;
	line-height:150%;
	background-color:#ace;
	color:[[ColorPalette::Background]];
	border:1px solid [[ColorPalette::Foreground]]; border-bottom:0;
	-moz-border-radius:1em 1em 0 0;
	-webkit-border-bottom-left-radius:0;
	-webkit-border-bottom-right-radius:0;
	-webkit-border-top-left-radius: .7em;
	-webkit-border-top-right-radius: .7em;
	padding-left:.5em;
}
.selected .title {
	background-color:#def;
	color:[[ColorPalette::Foreground]];
}
.subtitle { display:none; }

/* TIDDLER TOOLBAR */
.tiddler .folded
	{ height:2em !important; }
.tiddler .folded .title
	{ -moz-border-radius:1em; -webkit-border-radius:1em; border:1px solid #000; }
.tiddler .moveablePanelMenu
	{ top:.4em !important }	/* shift buttons to fit in titlebar */
.undocked .toolbar
	{ padding-right:8em !important; } /* make room for buttons next to toolbar */
.toolbar
	{ float:right; visibility:hidden; margin-top:.5em; margin-right:.5em; }
.toolbar .button
	{ padding:0px .5em; }
.selected .toolbar 
	{ visibility:visible; }
.selected .toolbar .button {
	background:#fff; color:black; border:1px solid black; margin:0 1px;
	-moz-border-radius:.5em; -webkit-border-radius:.5em; }
.selected .toolbar .button:hover
	{ background:#ace; }

/* TIDDLER BODY */
.viewer {
	border:1px solid; padding:1em; background:#fff;
	-moz-border-radius:0 0 1em 1em;
	-webkit-border-bottom-left-radius:1em;
	-webkit-border-bottom-right-radius:1em;
	-webkit-border-top-left-radius:0;
	-webkit-border-top-right-radius:0;
}
.viewer .content
	{ max-height:35em; overflow:auto; } /* limit tiddler height */

/* ADJUST 'TAGGED' DISPLAY FOR UNDOCKED TIDDLERS */
.undocked .tagged
	{ position:absolute; right:2.5em; }
.selected .undocked .tagged
	{ opacity:0.1 !important; filter:'alpha(opacity:10)' !important; }
.selected .undocked .tagged:hover
	{ opacity:1 !important; filter:'alpha(opacity:100)' !important; }

/* DOTTED FOCUS AROUND CURRENT TIDDLER */
.moveablePanel
	{ margin:1px; }
.selected .moveablePanel
	{ margin:0px; border:1px dotted;
	-moz-border-radius:1.1em; -webkit-border-radius:1.1em; }

/* ELIMINATE SCROLLBARS (and TAGS) IN PanelViewer */
#tiddlerPanelViewer .viewer .content
	{ max-height:999999em; }
#tiddlerPanelViewer .panelManagerMapViewer
	{ margin-right:1em; }
#tiddlerPanelViewer .tagged
	{ display:none; }

/*}}}*/
<!--{{{-->
<!--
|Name|MoveableViewTemplate|
|Source|http://www.TiddlyTools.com/#MoveableViewTemplate|
|Version||
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|template|
|Requires|MoveablePanelPlugin, ViewTemplate, TaggedTemplateTweak|
|Overrides||
|Description|add moveablePanel macro to tiddlers tagged with 'moveable'|
-->
<div class='moveablePanel'>
	[[ViewTemplate]]
	<div macro='moveablePanel name:{{tiddler?tiddler.title:""}} height:auto'></div>
</div>
<!--}}}-->
<!--{{{-->
<div macro='moveablePanel name:header'>
	<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>
<div id='mainMenu' class='moveablePanel'>
	<div refresh='content' tiddler='MainMenu'></div>
	<div macro='moveablePanel name:mainmenu width:auto height:auto'></div>
</div>
<div id='sidebar'>
	<span  style='position:relative'>
	<div macro='moveablePanel name:options width:16em height:auto'>
		<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
	</div>
	<div macro='moveablePanel name:tabs width:16em height:auto'>
		<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
	</div>
	</span>
</div>
<div id='displayArea'>
	<div id='messageArea'></div>
	<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
/***
|Name|[[PanelManagerPlugin]]|
|Source|http://www.TiddlyTools.com/#PanelManagerPlugin|
|Documentation|http://www.TiddlyTools.com/#PanelManagerPlugin|
|Version|1.0.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|MoveablePanelPlugin|
|Overrides||
|Description|Add-on for [[MoveablePanelPlugin]]: Panel Manager Menu, Control Panel, and Map Viewer |
Track position/size of moveable panels using named //panel maps//.  Interactive graphical map viewer provides "bird's eye" view of entire document for quick navigation between panels and management of panel layouts.
!!!//''PLEASE NOTE: this is an experimental addition to MoveablePanelPlugin.  It is currently a __BETA release for testing and review purposes only__, and is subject to change without notice or regard for backward-compatibility with this or other versions of this plugin.  Do not rely on this release for production-ready purposes!''//
!!!!!Documentation
<<<
see [[PanelManagerPluginInfo]] (pending)
{{{
<<moveablePanel menu label:... prompt:...>>
<<moveablePanel menu label:... prompt:... name:...>>
<<moveablePanel maps label:... prompt:...>>
<<moveablePanel load label:... prompt:... name:...>>
<<moveablePanel viewer size:... >>
<<moveablePanel table>>
<<moveablePanel commands>>
}}}
*''menu''<br>instead of adding the mouse handling to the containing panel, the macro will render just the Panel Manager menu button.  This allows you to embed the button anywhere in your document (e.g., in the main menu or sidebar) to provide a fixed location for always accessing the current panel layout.  When ''menu'' is specified, you can use ''label:...'' and ''prompt:...'' to override the default button text (&#x2261;) and tooltip to suit your purposes.  If you provide a ''name:...'' parameter along with ''menu'', then only the section of the Panel Manager menu that applies to that named panel will be included in the resulting menu (to control a single, specific panel).
*''maps''<br>embeds a popup list of all panel maps stored in the document, permitting you to quickly switch between panel maps just by selecting a map form the popup list.
*''load''<br>embeds a command link that loads the panel map specified by the ''name:...'' parameter.
*''viewer''<br>embeds a graphical, interactive panel map viewer and page navigator in your tiddler content.  You can specify the maximum width and height of the embedded viewer using the ''size:...'' parameter with CSS units of measure (e.g., px, em, cm, in, %).  If the size is not specified, the default is for the viewer to fit the element in which it rendered (i.e., using the 'auto' or '100%' CSS value).  The ''viewer'' display is updated //live// as panels are docked/undocked, moved, size, folded, etc.
*''table''<br>embeds a panel map data table viewer in your tiddler content.  This table shows the x, y, w, h, and z, values associated with each panel stored in the current map.  As with the ''viewer'', the ''table'' data is automatically updated when panels are changed.
*''commands''<br>embeds the panel map management commands (i.e., ''new'', ''load'', ''edit'', ''save'', and ''view table...'').

// more documentation pending... //
<<<
!!!!!Open issues
<<<
Known problems:
* IE: Popups appear as a vertical line when X > window width (i.e., the core assumes left side of page)... maybe a CSS clipping issue?
* IE: 'zoomed in' mapsize calculation is way off.  These equations need to be re-examined for all browsers.
Additional features (for later):
* Track hover/docked states (in addition to x,y,w,h,z,folded)
* Drag outline in map to scroll page
* Option to normalize z-range when saving maps
<<<
!!!!!Configuration
<<<
<<option chkPanelManagerUseCookies>> remember panel maps between sessions (enables cookies)
<<option chkMoveablePanelShowStatus>> show position/size while moving/resizing a panel
<<option chkMoveablePanelShowManager>> add Panel Manager button to all undocked panels
<<option chkPanelManagerAutoMap>> automatically show map viewer as soon as popup menu is opened
<<option chkPanelManagerMapFullPage>> show full page (zoom out) in map viewer (no scrollbars)
Popup map viewer display size (maximum width and height): {{fourchar{<<option txtPanelManagerPopupMapSize>>}}}
^^//(use CSS dimensions, leave blank or use 'auto' to fit to container)//^^
<<<
!!!!!Examples
<<<
popup menu:
>{{{<<moveablePanel menu label:panels>>}}}
><<moveablePanel menu label:panels>>
map viewer control panel
>{{{<<moveablePanel commands>>}}}
><<moveablePanel commands>>
map viewer display
>{{{<<moveablePanel viewer size:400px>>}}}
>{{groupbox floatleft center{<<moveablePanel viewer size:400px>>}}}{{clear block{}}}
<<<
!!!!!Revisions
<<<
2008.12.15 [1.0.1] handling for 'hovered' elements: adjust for fixed vs. absolute (no relative offsets, no scroll offsets), translate movements to top-left screen, restrict movements within screen bounds
2008.11.26 [1.0.0] initial release - use with [[MoveablePanelPlugin]] v3.0.0 or above
|please see [[MoveablePanelPluginInfo]] for additional information|
<<<
!!!!!Code
***/
//{{{
version.extensions.PanelManagerPlugin= {major: 1, minor: 0, revision: 1, date: new Date(2008,12,15)};
//}}}
// // defaults for options
//{{{
if (config.options.txtMoveablePanelMapName===undefined)
	config.options.txtMoveablePanelMapName='DefaultMap';
if (config.options.chkMoveablePanelShowStatus===undefined)
	config.options.chkMoveablePanelShowStatus=true;
if (config.options.chkMoveablePanelShowManager===undefined)
	config.options.chkMoveablePanelShowManager=true;
if (config.options.chkPanelManagerAutoMap===undefined)
	config.options.chkPanelManagerAutoMap=true;
if (config.options.chkPanelManagerMapFullPage===undefined)
	config.options.chkPanelManagerMapFullPage=true;
if (config.options.txtPanelManagerPopupMapSize===undefined)
	config.options.txtPanelManagerPopupMapSize='auto';
if (config.options.chkPanelManagerUseCookies===undefined)
	config.options.chkPanelManagerUseCookies=true;
//}}}
// // shadow tiddlers (for displaying interfaces inside sliders, tabs, etc)
//{{{
config.shadowTiddlers.PanelViewer='<<moveablePanel viewer>>';
config.shadowTiddlers.PanelTable='<<moveablePanel table>>';
config.shadowTiddlers.PanelCommands='<<moveablePanel commands>>';
//}}}
// // translate
//{{{
// TRANSLATORS: copy this section to PanelManagerPluginLingoXX
if (config.macros.moveablePanel===undefined) config.macros.moveablePanel={};
if (config.macros.moveablePanel.manager===undefined) config.macros.moveablePanel.manager={};
merge(config.macros.moveablePanel.manager,{

	buttonLabel:	'\u2261', // equiv
	buttonTip:	'Panel Manager',

	panelCmd:	"panel: '%0'\xa0",
	jumpToPanelCmd:	'jump to panel',
	jumpToPanelTip:	"bring '%0' into view",
	frontCmd:	'bring to front',
	frontTip:	"bring '%0' to front of stack",
	backCmd:	'send to back',
	backTip:	"send '%0' to back of stack",
	stackCmd:	'return to stack',
	stackTip:	"return '%0' to it's default stack order (zIndex)",
	moveCmd:	'move panel',
	moveTip:	"move '%0' to another location on the page",
	foldCmd:	'fold panel',
	foldTip:	"reduce the height of '%0'",
	unfoldCmd:	'unfold panel',
	unfoldTip:	"restore the height of '%0'",
	hoverCmd:	'hover panel',
	hoverTip:	"keep '%0' in view when scrolling",
	scrollCmd:	'scroll panel',
	scrollTip:	"allow '%0' to move with page",
	dockCmd:	'dock panel',
	dockTip:	"attach '%0' to it's default anchor point",
	undockCmd:	'undock panel',
	undockTip:	"detach '%0' from it's default anchor point",
	closeCmd:	'close panel',
	closeTip:	"hide/close '%0'",
	openCmd:	'open panel',
	openTip:	"show/open '%0'",
	resetCmd:	'reset panel',
	resetTip:	"return '%0' to it's starting size/position for this session",

	tiddlerCmd:	"tiddler: '%0'",
	tiddlerDirtyMsg:"'%0' is currently being edited. Unsaved changes will be discarded.",

	selectPanelCmd:	'panels...',
	selectPanelTip:	'select and navigate to other panels',
	selectPanelMsg:	'select a panel:',

	selectMapCmd:	'maps...',
	selectMapTip:	'Select a stored panel layout',
	selectMapMsg:	'select a map:',

	viewMapCmd:	"map: '%0'\xa0",
	viewMapTip:	'view, load, edit and save panel layouts',
	viewMapHeader:	"__//current map:// %0 %1__\n",
	viewMapEmpty:	'| there are currently no //undocked// panels |>|>|>|>|>|',
	viewMapUnsaved:	'(unsaved)',
	newMapCmd:	'new',
	newMapTip:	"Dock all panels and start a new map",
	newMapPrompt:	'Create a new panel map:',
	newMapName:	'NewMap',
	newMapErr:	"A panel map named '%0' already exists.  Unsaved changes in '%0' will be discarded.",
	loadMapCmd:	'load',
	loadThisMapTip:	"Apply the panel layout from '%0'",
	switchMapMsg:	"Now using panel map: '%0'",
	editMapCmd:	"edit",
	editMapTip:	'Edit the stored panel layout',
	saveMapCmd:	'save',
	saveMapTip:	'Save the current panel layout',
	saveMapPrompt:	'Save the current panel map to a tiddler:',
	saveMapMsg:	"Panel layout saved to '%0'",
	unsavedMapErr:	"Unsaved changes to the current panel map, '%0', will be discarded.",

	optionsCmd:	'options...',
	optionsTip:	'set MoveablePanel options',
	useCookiesCmd:	'remember panel maps between sessions\xa0',
	useCookiesTip:	'remember panel maps between sessions (uses cookies)',
	showManagerCmd:	'add PanelManager button to all panels\xa0',
	showManagerTip:	'add PanelManager button to all panels',
	autoMapCmd:	'show map viewer when popup menu is opened\xa0',
	autoMapTip:	'show map viewer when popup menu is opened',
	showStatusCmd:	'show panel info while moving/sizing\xa0',
	showStatusTip:	'show panel info while moving/sizing',
	mapFullPageCmd:	'zoom out (fullpage)',
	mapFullPageTip:	'view the entire panel map scaled to fit\xa0',
	mapScrollPageCmd:'zoom in (scroll)',
	mapScrollPageTip:'view a portion of the panel map with scrolling',
	mapSizeCmd:	'viewer size:\xa0',
	mapSizeTip:	'set the map viewer display (use CSS measurements: px, em, in, cm, %)',

	dockAllCmd:	'dock all panels',
	dockAllTip:	'Return all panels to their default anchor points',
	resetAllCmd:	'reset all panels',
	resetAllTip:	'Reset all panels to their starting size/position for this session',

	noPid:		'unnamed panel',
	noPanels:	'\xa0no active panels\xa0',
	notAPanel:	"\xa0has not been displayed yet\xa0",
	noMaps:		'\xa0no saved maps\xa0',
	thisPanel:	'this panel',
	notMoveableMsg:	"'%0' is not a moveable panel",
	viewerMapStatsMsg:
		 "| document size:&nbsp;|''%0 x %1'' |\n"
		+"| window size:&nbsp;|''%2 x %3'' |\n"
		+"| window view:&nbsp;|''(%4-%5) x (%6-%7)'' |\n",
	viewerTableCmd:	'show table...',
	viewerTableTip:	'show/hide current map data table',
	viewerBackgroundTip:'click for display options...',
	refreshMapCmd:	'refresh viewer',
	refreshMapTip:	'redraw map viewer display image',

	viewerMapTip:	'click to scroll...',
	XYJumpCmd:	'scroll window to:',
	XYJumpTip:	'scroll to %0(%1,%2)',
	XYMoveCmd:	"move '%0' to:",
	XYMoveTip:	'move panel to %0(%1,%2)',
	jumpHereCmd:	'scroll here (%0,%1)\xa0',
	moveHereCmd:	'move here (%0,%1)\xa0',
	compassJumpCmd:	'or, scroll to:',
	compassMoveCmd:	'or, move to:',
	centerJumpCmd:	'center on panel',
	centerJumpTip:	'view panel in center of window ',
	centerMoveCmd:	'center in view',
	centerMoveTip:	'center of current window view ',
	compassTL:	'\u25E4', compassT: '\u25B2', compassTR: '\u25E5',
	compassL:	'\u25C4', compassC: '\u25CA', compassR:  '\u25BA',
	compassBL:	'\u25E3', compassB: '\u25BC', compassBR: '\u25E2',
	compassTLTip:	'top left corner of page ',
   	compassTTip:	'top edge of page ',
	compassTRTip:	'top right corner of page ',
	compassLTip:	'left edge of page ',
	compassCTip:	'center of page ',
	compassRTip:	'right edge of page ',
	compassBLTip:	'bottom left corner of page ',
	compassBTip:	'bottom edge of page ',
	compassBRTip:	'bottom right corner of page ',

	mapTags:	['panelmap'], // default tags - 1st tag used to find panelmaps - can be customized
	mapTag:		'panelmap', // fallback default - DO NOT CHANGE
	mapHeader:	'| %0!panelname|   !x |   !y |   !w |   !h |   !z | !fold | !hover |h', // CHANGE HEADINGS ONLY
	mapFormat:	'| %0| %1| %2| %3| %4| %5|   %6   |    %7   |', // DO NOT CHANGE
	checkmark:	'\u221A', // DO NOT CHANGE

	// DO NOT TRANSLATE PARAMETERS (BREAKS PORTABILITY OF CONTENT ACROSS DOCUMENTS)
	nameParam:	'name',
	menuParam:	'menu',
	mapsParam:	'maps',
	labelParam:	'label',
	promptParam:	'prompt',
	commandsParam:	'commands',
	viewerParam:	'viewer',
	tableParam:	'table',
	sizeParam:	'size',
	loadParam:	'load'
});
//}}}
// // general utilities (global)
//{{{
// if removeCookie() function is not defined by TW core, define it here (for <TW2.5)
if (window.removeCookie===undefined) {
	window.removeCookie=function(name) {
		document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
	}
}
if (window.copyObject===undefined) {
	window.copyObject=function(src)	{
		for (var i in src) this[i]=typeof src[i]!='object'?src[i]:new copyObject(src[i]);
	}
}
if (window.compareObjects===undefined) {
	window.compareObjects=function(a,b) {
		if (a===b) return true;
		if (a==undefined||b==undefined) return false;
		for (var i in a) if (typeof a[i]!='object'?a[i]!==b[i]:!compareObjects(a[i],b[i])) return false;
		return true;
	}
}
if (window.isEmptyObject===undefined) {
	window.isEmptyObject=function(src) { for (var i in src) return false; return true; }
}

// cross-browser metrics
window.findMouseX=function(ev)
	{ if (!ev) return 0; return !config.browser.isIE?ev.pageX:(ev.clientX+findScrollX()); }
window.findMouseY=function(ev)
	{ if (!ev) return 0; return !config.browser.isIE?ev.pageY:(ev.clientY+findScrollY()); }
// NOTE: WEBKIT uses document.width/height, MOZ uses the 'documentElement.scrollWidth/Height'
window.findDocumentWidth=function()
	{ var dw=document.documentElement.scrollWidth; if (document.width>dw) dw=document.width; return dw; }
window.findDocumentHeight=function()
	{ var dh=document.documentElement.scrollHeight; if (document.height>dh) dh=document.height; return dh; }

// abbreviations for adding menu elements
window.addLI=function(place)
	{return createTiddlyElement(place,'li');};
window.addBR=function(place)
	{return createTiddlyElement(place,'br');};
window.addHR=function(place)
	{return createTiddlyElement(createTiddlyElement(place,'li',null,'listBreak'),'div');};
window.addSEP=function(place)
	{return createTiddlyText(place,'\xa0|\xa0');};
window.addTXT=function(place,txt)
	{return createTiddlyText(addLI(place),txt)};
window.addBTN=function(place,label,tip,fn)
	{return createTiddlyButton(place,label,tip,fn,'button')};
window.addCMD=function(place,label,tip,fn)
	{return createTiddlyButton(addLI(place),label,tip,fn,'button')};
window.addPOP=function(place,className)
	{return Popup.create(place,null,'popup '+className)};
window.addCHK=function(place,label,tip,opt,hidechk) { // option checkbox AND text toggle config.options[chk...]
	if (!hidechk) config.macros.option.genericCreate(place,'chk',opt,null,'no');
	var b=addBTN(place,label,tip,function(ev){
		var ev=ev||window.event; var cmm=config.macros.moveablePanel;
		config.options[this.opt]=!config.options[this.opt];
		config.macros.option.propagateOption(this.opt,'checked',config.options[this.opt],'input');
		saveOptionCookie(this.opt); cmm.manager.notify('option:'+this.opt);
		Popup.remove(Popup.find(this)); return cmm.processed(ev);
	}); b.opt=opt; b.innerHTML=label;
};

// open popup at current mouse position
Popup.showHere=function(place,ev) {
	var x=findMouseX(ev)-findPosX(place);
	var y=findMouseY(ev)-findPosY(place);
	Popup.show('top','left',{x:x,y:y});
}
//}}}
// // macro
//{{{
if (config.macros.moveablePanel===undefined) config.macros.moveablePanel={};
if (config.macros.moveablePanel.manager===undefined) config.macros.moveablePanel.manager={};
merge(config.macros.moveablePanel.manager,{
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {

		var showmenu	=params.contains(this.menuParam);
		var showcommands=params.contains(this.commandsParam);
		var showtable	=params.contains(this.tableParam);
		var showviewer	=params.contains(this.viewerParam);
		var showmaps	=params.contains(this.mapsParam);

		params=paramString.parseParams('anon',null,true,false,false);
		var load	=getParam(params,this.loadParam,null);
		var name	=getParam(params,this.nameParam,null);
		var label	=getParam(params,this.labelParam,null);
		var prompt	=getParam(params,this.promptParam,null);
		var size	=getParam(params,this.sizeParam,null);

		if (load) addBTN(place,label||load,prompt||this.loadThisMapTip.format([load]),function(ev){
			config.macros.moveablePanel.manager.loadMap(this.map,ev)}).map=load;
		if (showmenu) 	  this.menu(place,name,label||this.buttonLabel,prompt||this.buttonTip);
		if (showcommands) this.viewer_commands(createTiddlyElement(place,'div'));
		if (showtable)	  this.viewer_table(createTiddlyElement(place,'div'));
		if (showviewer)	  this.viewer_map(createTiddlyElement(place,'div'),false,size);
		if (showmaps)	  this.menu_loadMap(place,label||this.selectMapCmd,prompt||this.selectMapTip,'bottom','left');

		return load||showmenu||showcommands||showtable||showviewer||showmaps; // handled==TRUE
	},
//}}}
// // notifications
//{{{
	notify: function(p) { // p=panel that was changed (or a text message if refresh/reload event)
		if (config.macros.moveablePanel.quiet) return;
		// for now, just a general refresh of all currently display viewers
		this.refreshAllViewers(p);
	},
//}}}
// // panel maps
//{{{
	map: undefined,
	startingMap: undefined,
	trackMap: function(p) {
		if (!p||!p.pid||!p.pid.length) return;
		this.readMap(config.options.txtMoveablePanelMapName);
		var re=/(\.[0-9]*px)|px/g; // removes decimals and 'px' from CSS
		if (!hasClass(p,'undocked'))
			delete this.map[p.pid];
		else this.map[p.pid]={ pid:p.pid, 
			x:p.style.left.replace(re,''),  y:p.style.top.replace(re,''),
			w:p.style.width.replace(re,''),	h:p.style.height.replace(re,''),
			z:p.style.zIndex, folded:hasClass(p,'folded'), hover:hasClass(p,'hover')  };
		this.setMapCookie(config.options.txtMoveablePanelMapName);
		this.notify(p);
	},
	applyMap: function(p) {
		var cmm=config.macros.moveablePanel;
		if (!p||!p.pid||!p.pid.length) return;
		this.readMap(config.options.txtMoveablePanelMapName);
		var d=this.map[p.pid]; if (!d) return; // panel is not mapped... do nothing
		if (!cmm.isStackable(p)) p.style.position='absolute';
		addClass(p,'undocked');
		if (d.folded) addClass(p,'folded'); else removeClass(p,'folded');
		if (d.hover)  addClass(p,'hover');  else removeClass(p,'hover');
		function addPX(v) { return v&&v.length?v+(!isNaN(v)?'px':''):''; }
		p.style.left  =addPX(d.x); p.style.top   =addPX(d.y);
		p.style.width =addPX(d.w); p.style.height=addPX(d.h);
		p.style.zIndex=d.z&&d.z.length?d.z:'';
		this.notify(p);
	},
	formatMap: function(includeHeading) {
		var cmm=config.macros.moveablePanel;
		function pad(t,maxlen) {
			var spaces='                                                  '; // 50 spaces
			return t.toString().length>=maxlen?'':spaces.substr(0,maxlen-t.toString().length);
		}
		var panels=cmm.getAllPanels(true); // sorted by zIndex
		var maxlen=0; for (var i=0; i<panels.length; i++)
			if (panels[i].pid && panels[i].pid.length>maxlen) maxlen=panels[i].pid.length;
		var panelHeader=this.mapHeader.split('|')[1].trim().format(['']);
		if (maxlen<panelHeader.length) maxlen=panelHeader.length;
		var out=[]; 
		if (includeHeading) out.push(this.mapHeader.format([pad(panelHeader,maxlen)]));
		for (var i=0; i<panels.length; i++) {
			var pid=panels[i].pid; var d=this.map[pid]; if (!d) continue;
			out.push(this.mapFormat.format([pad(pid,maxlen)+pid,
				pad(d.x,5)+d.x, pad(d.y,5)+d.y,	pad(d.w,5)+d.w, pad(d.h,5)+d.h,
				pad(d.z,5)+d.z, d.folded?this.checkmark:' ', d.hover?this.checkmark:' ' ]));
		}
		return out.join('\n');
	},
	setMapCookie: function(map) {
		if (!config.options.chkPanelManagerUseCookies) return;
		var opt='txt'+map;
		config.options[opt]=this.formatMap();
		if (config.options[opt].length) saveOptionCookie(opt); else removeCookie(opt);
	},
	readMap: function(map,force) { // get map from tiddler+cookie (cookie takes precedence)
		if (this.map && !force) return; // CACHED or LOAD ON DEMAND
		delete this.map; this.map=new Object();
		var t=store.getTiddlerText(map);
		if (config.options.chkPanelManagerUseCookies) var c=config.options['txt'+map];
		var m=(t||'')+(t&&c?'\n':'')+(c||'');
		if (!m||!m.length) return false; // NO MAP
		var items=m.split('\n');
		for (var i=0; i<items.length; i++) {
			// skip non-data table rows (|h, |c, or |k syntax)
			if (items[i].substr(items[i].length-1,1)!='|') continue;
			var d=items[i].split('|');
			for (var j=0;j<d.length;j++) d[j]=d[j]?d[j].trim():'';
			if (d[1]&&d[1].length) { 
				var m=this.map[d[1]]=new Object();
				m.pid=d[1]; m.x=d[2]; m.y=d[3]; m.w=d[4]; m.h=d[5]; m.z=d[6];
				m.folded=(d[7]&&d[7].length>0); m.hover=(d[8]&&d[8].length>0);
			}
		}
		if (!force) this.startingMap=new copyObject(this.map); // DEEP COPY TO CACHE
	},
	writeMap: function(map) {
		this.readMap(map);
		var t=store.getTiddler(map);
		var who=t&&config.options.chkForceMinorUpdate?t.modifier:config.options.txtUserName;
		var when=t&&config.options.chkForceMinorUpdate?t.modified:new Date();
		var tags=t?t.tags:this.mapTags; tags.pushUnique(this.mapTags[0]||this.mapTag);
		var fields=t?t.fields:{};
		store.saveTiddler(map,map,this.formatMap(true),who,when,tags,fields);
		story.refreshTiddler(map,null,true);
	},
	newMap: function(ev) { // clear map and docked all panels
		var cmm=config.macros.moveablePanel;
		var map=config.options.txtMoveablePanelMapName;
		var newname=prompt(this.newMapPrompt,this.newMapName);
		while (newname && newname.trim().length && newname!=map && newname!=this.newMapName
			&& (config.options['txt'+newname]||store.tiddlerExists(newname)) ) {
			if (confirm(this.newMapErr.format([newname]))) break;  // CANCELLED
			newname=prompt(this.newMapPrompt,newname);
		}
		if (!newname || !newname.trim().length) return true; // CANCELLED
		if (this.isMapChanged(map)&&!confirm(this.unsavedMapErr.format([map]))) return true;
		delete this.map; this.map=new Object();
		config.options['txt'+newname]=''; removeCookie('txt'+newname); // flush new map cookie (if any)
		var panels=cmm.getAllPanels();
		cmm.quiet++; for (var i=0; i<panels.length; i++) cmm.restorePanel(panels[i]); cmm.quiet--;
		config.options.txtMoveablePanelMapName=newname;
		saveOptionCookie('txtMoveablePanelMapName');
		this.notify('new map');
		return cmm.processed(ev);
	},
	loadMap: function(map,ev) { // *adds* entries to existing map data
		var cmm=config.macros.moveablePanel;
		var currmap=config.options.txtMoveablePanelMapName;
		if (this.isMapChanged(currmap)&&!confirm(this.unsavedMapErr.format([currmap]))) return true;
		config.options['txt'+map]=''; removeCookie('txt'+map);
		this.readMap(map,true);	// FORCE RELOAD
		cmm.quiet++;
		var panels=cmm.getAllPanels();
		for (var i=0; i<panels.length; i++) {
			if (hasClass(panels[i],'undocked')) cmm.restorePanel(panels[i]);
			this.applyMap(panels[i]);
		}
		cmm.quiet--;
		config.options.txtMoveablePanelMapName=map;
		saveOptionCookie('txtMoveablePanelMapName')
		this.setMapCookie(map);
		this.notify('load map');
		return cmm.processed(ev);
	},
	saveMap: function(map,ev) {
		var cmm=config.macros.moveablePanel;
		var map=prompt(this.saveMapPrompt,map);
		while (map && map.trim().length && store.tiddlerExists(map)) {
			var msg=story.isDirty(map)?this.tiddlerDirtyMsg:config.messages.overwriteWarning;
			if (confirm(msg.format([map]))) break;  // CANCELLED
			map=prompt(this.saveMapPrompt,map);
		}
		if (!map || !map.trim().length) return true; // CANCELLED
		if (story.isDirty(map)) { story.closeTiddler(map); story.displayTiddler(null,map); }
		this.writeMap(map);
		displayMessage(this.saveMapMsg.format([map]));
		config.options.txtMoveablePanelMapName=map; saveOptionCookie('txtMoveablePanelMapName');
		return cmm.processed(ev);
	},
	isPanelMapped: function(pid) { // is panel ID in the map?
		return this.map && this.map[pid];
	},
	isPanelChanged: function(p) { // compare current and starting map values
		var now=this.map?this.map[p.pid]:undefined;
		var then=this.startingMap?this.startingMap[p.pid]:undefined;
		if (!now&&!then) return false;
		if (!now&&then || now&&!then) return true;
		return (now.x!=then.x || now.y!=then.y || now.w!=then.w || now.h!=then.h || now.z!=then.z);
	},
	resetPanel: function(p) { // restore panel from starting map (if any)
		var cmm=config.macros.moveablePanel;
		if (!this.startingMap || !this.startingMap[p.pid]) { cmm.dockPanel(p); return; }
		cmm.quiet++;
		if (hasClass(p,'folded')) cmm.foldPanel(p);  // un-fold
		if (hasClass(p,'hover')) cmm.hoverPanel(p);  // un-hover
		this.map[p.pid]=new copyObject(this.startingMap[p.pid]);
		this.setMapCookie(config.options.txtMoveablePanelMapName);
		cmm.quiet--;
		this.applyMap(p);
	},
	isMapChanged: function(map) { // compare with saved map or starting map
		var currMap=this.formatMap(true);
		var savedMap=store.getTiddlerText(map);
		if (isEmptyObject(this.map)&&(!savedMap||(map==this.newMapName))) return false;
		return savedMap?currMap!=savedMap:!compareObjects(this.map,this.startingMap);
	},
//}}}
// // menu button and popup
//{{{
	menu: function(place,name,label,prompt) {
		if (name) { // show only the submenu for the named panel
			var b=addBTN(place,label,prompt,function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				var popup=addPOP(this,'panelManagerPopup'); if (!popup) return false;
				var docX=findMouseX(ev)+findScrollX(); var docY=findMouseY(ev)+findScrollY();
				cmm.manager.menu_panel(popup,cmm.findPanel(this.pid),this.pid,Popup.find(this)+1,docX,docY);
				Popup.show(); return cmm.processed(ev);
			}); b.innerHTML=label; b.pid=name;
		} else { // show entire manager menu
			var b=addBTN(place,label,prompt,function(ev){
				return config.macros.moveablePanel.manager.popup(this,ev,null,true);
			}); b.innerHTML=label;
		}
	},
	popup: function(place,ev,pid,nopanel) {
		var ev=ev||window.event; var cmm=config.macros.moveablePanel; var mgr=cmm.manager;
		var popup=addPOP(place,'sticky panelManagerPopup'); if (!popup) return cmm.processed(ev);
		popup.onclick=function(ev) { var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			var lvl=Popup.find(this); if (lvl<Popup.stack.length-1) // toggle child popups
				{ Popup.remove(lvl+1); return cmm.processed(ev); }
		}
		var panel=cmm.findPanel(pid)||cmm.getPanel(place);
		var showPanelMenu=hasClass(panel,'moveablePanel')&&!nopanel;
		mgr.menu_map(popup,config.options.chkPanelManagerAutoMap);
		if (showPanelMenu) { // FOR THIS PANEL
			var b=addCMD(popup,mgr.panelCmd.format([pid]),cmm.getPanelTooltip(panel),function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				var popup=addPOP(this,'panelManagerPopup'); if (!popup) return false;
				var docX=findMouseX(ev)+findScrollX(); var docY=findMouseY(ev)+findScrollY();
				cmm.manager.menu_panel(popup,panel,this.panel.pid,Popup.find(this)+1,docX,docY);
				Popup.show('top','right'); return cmm.processed(ev);
			}); b.panel=panel;
		}
		addHR(popup);
		mgr.menu_forAll(popup);
		addHR(popup);
		mgr.menu_selectMap(popup);
		mgr.menu_selectPanel(popup);
		mgr.menu_options(popup);
		addHR(popup);
		addTXT(popup,mgr.XYJumpCmd);
		mgr.menu_compass(popup,showPanelMenu?panel:null,findMouseX(ev),findMouseY(ev)); // scroll
		Popup.showHere(place,ev)
		return cmm.processed(ev);
	},
//}}}
// // manager menu
//{{{
	menu_panel: function(place,p,pid,remove,x,y) {
		var cmm=config.macros.moveablePanel;
		// commands FOR ONE PANEL
		// p=panel, pid=requested panel ID, remove=popup level to close afterwards
		if (!p){addTXT(place,this.panelCmd.format([pid]));addTXT(place,this.notAPanel.format([pid]));return;}
		function cmd(place,label,tip,callback,p,arg) { // buttons invoke 'callback(p,arg)'
			var b=addCMD(place,label,tip,function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				this.callback.apply(cmm,[this.panel,this.arg]);
				cmm.manager.trackMap(this.panel);
				cmm.manager.refreshAllViewers();
				Popup.remove(this.remove);
				return cmm.processed(ev);
			}); b.panel=p; b.callback=callback; b.arg=arg; b.remove=remove;
		}
		var pid=p.pid||this.thisPanel;
		var u=hasClass(p,'undocked');
		var f=hasClass(p,'floatingPanel');
		var folded=hasClass(p,'folded');
		var hover=hasClass(p,'hover');
		var v=p.style.display!='none'; 
		var here=story.findContainingTiddler(p);
		var t=here&&cmm.findPanel(here.getAttribute('tiddler'));
		cmd(place,this.jumpToPanelCmd,this.jumpToPanelTip.format([pid]),cmm.ensurePanelVisible, p);
		if (u) cmd(place,this.frontCmd,this.frontTip.format([pid]),cmm.bringPanelToFront, p);
		if (u) cmd(place,this.backCmd, this.backTip.format( [pid]),cmm.sendPanelToBack,   p);
		if (u) cmd(place,this.stackCmd,this.stackTip.format([pid]),cmm.returnPanelToStack,p);
		if (p.showfold && (u||f)) {
			if (!folded) cmd(place,this.foldCmd,  this.foldTip.format(  [pid]),cmm.foldPanel, p);
			if ( folded) cmd(place,this.unfoldCmd,this.unfoldTip.format([pid]),cmm.foldPanel, p);
		}
		if (p.showhover && (u||f)) {
			if (!hover) cmd(place,this.hoverCmd, this.hoverTip.format( [pid]),cmm.hoverPanel,p);
			if ( hover) cmd(place,this.scrollCmd,this.scrollTip.format([pid]),cmm.hoverPanel,p);
		}
		if (cmm.manager.isPanelChanged(p))
			cmd(place,this.resetCmd,this.resetTip.format([pid]),cmm.resetPanel,p);
		if (t)		cmd(place,this.closeCmd,this.closeTip.format([pid]),cmm.closePanel,p);
		if (f&&v)	cmd(place,this.closeCmd,this.closeTip.format([pid]),cmm.closePanel,p);
		if (f&&!v)	cmd(place,this.openCmd, this.openTip.format( [pid]),cmm.closePanel,p);
		if (u)  cmd(place,this.dockCmd,  this.dockTip.format(  [pid]),cmm.dockPanel,  p);
		if (!u) cmd(place,this.undockCmd,this.undockTip.format([pid]),cmm.undockPanel,p,true);
		if (u||f) { // move panel
			addHR(place); addTXT(place,this.XYMoveCmd.format([pid]));
			this.menu_compass(place,p,x,y,true); // move
		}
	},
	menu_compass: function(place,p,x,y,move) { // scroll page or move panel using 'compass' buttons
		function cmd(place,label,tip,isTD,p,x,y,move) {
			var b=createTiddlyButton(isTD?createTiddlyElement(place,'TD'):addLI(place),label,tip,function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				if (this.move && this.p) cmm.movePanel(this.p,this.x,this.y,true,true);
				else window.scrollTo(this.x,this.y);
				cmm.manager.refreshAllViewers(); Popup.remove(Popup.find(this)); return cmm.processed(ev);
			},isTD?'panelManagerPopupCompassButton':'button'); b.p=p; b.x=x; b.y=y; b.move=move;
		}
		var ww=findWindowWidth();  var dw=findDocumentWidth();  var sx=findScrollX();
		var wh=findWindowHeight(); var dh=findDocumentHeight(); var sy=findScrollY();
		var cx=Math.floor(dw/2); var cy=Math.floor(dh/2);
		var nx=sx; var ny=sy; // assume scrolling
		move=move&&p; // only if a valid panel
		var tip=move?this.XYMoveTip:this.XYJumpTip;
		if (p) { // if panel, calc window center position for center on panel / center in view
			var px=p.offsetLeft; var py=p.offsetTop; var pw=p.offsetWidth; var ph=p.offsetHeight;
			if (move) { // adjust document width/centering to account for panel width/height
				dw-=pw+2; cx-=pw/2; var nx=px;
				dh-=ph+2; cy-=ph/2; var ny=py;
				var wcx=Math.floor(sx+ww/2-pw/2);
				var wcy=Math.floor(sy+wh/2-ph/2);
			} else {
				var offset=config.macros.moveablePanel.getPanelOffset(p); // adjust for relative elements
				var wcx=Math.max(Math.floor(px+offset.x-ww/2+pw/2),0);
				var wcy=Math.max(Math.floor(py+offset.y-wh/2+ph/2),0);
			}
		}
		var indent='\xa0\xa0';
		// PANEL
		if (p) {
			var label=move?this.centerMoveCmd:this.centerJumpCmd;
			var prompt=tip.format([move?this.centerMoveTip:this.centerJumpTip,wcx,wcy]);
			cmd(place,indent+label,prompt,false,p,wcx,wcy,move);
		}
		// HERE
		var label=move?this.moveHereCmd:this.jumpHereCmd;
		cmd(place,indent+label.format([x,y]),tip.format(['',x,y]),false,p,x,y,move);
		addTXT(place,indent+(move?this.compassMoveCmd:this.compassJumpCmd));
		// COMPASS
		var tbl=createTiddlyElement(place,'table',null,'panelManagerPopupCompass');
		var tbody=createTiddlyElement(tbl,'tbody');
		var tr=createTiddlyElement(tbody,'tr');
		cmd(tr,this.compassTL,tip.format([this.compassTLTip, 0,0]),true,p, 0,0,move);
		cmd(tr,this.compassT, tip.format([this.compassTTip ,nx,0]),true,p,nx,0,move);
		cmd(tr,this.compassTR,tip.format([this.compassTRTip,dw,0]),true,p,dw,0,move);
		var tr=createTiddlyElement(tbody,'tr');
		cmd(tr,this.compassL, tip.format([this.compassLTip, 0,ny]),true,p, 0,ny,move);
		cmd(tr,this.compassC, tip.format([this.compassCTip,cx,cy]),true,p,cx,cy,move);
		cmd(tr,this.compassR, tip.format([this.compassRTip,dw,ny]),true,p,dw,ny,move);
		var tr=createTiddlyElement(tbody,'tr');
		cmd(tr,this.compassBL,tip.format([this.compassBLTip, 0,dh]),true,p, 0,dh,move);
		cmd(tr,this.compassB, tip.format([this.compassBTip ,nx,dh]),true,p,nx,dh,move);
		cmd(tr,this.compassBR,tip.format([this.compassBRTip,dw,dh]),true,p,dw,dh,move);
	},
	menu_map: function(place,autoclick) {
		var map=config.options.txtMoveablePanelMapName;
		var b=addCMD(place,this.viewMapCmd.format([map]),this.viewMapTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			var popup=addPOP(this,'sticky panelManagerMapPopup'); if (!popup) return false;
			cmm.manager.viewer_commands(popup);
			addHR(popup);
			cmm.manager.viewer_map(popup);
			popup.onclick=function(ev) {
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				var lvl=Popup.find(this); if (lvl<Popup.stack.length-1) // toggle child popup
					{ Popup.remove(lvl+1); return cmm.processed(ev); }
				var popup=addPOP(this,'sticky panelManagerPopup'); if(!popup)return false;
				cmm.manager.menu_mapBackground(popup);
				Popup.showHere(this,ev); return cmm.processed(ev);
			}
			popup.title=cmm.manager.viewerBackgroundTip;
			Popup.show('top','right');
			return cmm.processed(ev);
		});
		// autoclick on initial mouseover
		if (autoclick) b.onmouseover=function(ev) { this.onmouseover=null; return this.onclick.apply(this,arguments); };
	},
	menu_forAll: function(place) {
		var cmm=config.macros.moveablePanel;
		// commands FOR ALL PANELS
		function cmd(label,tip,callback) {
			var b=addCMD(place,label,tip,function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				if (!confirm(this.title+'?')) return false;
				var panels=cmm.forAllPanels(this.callback);
				cmm.manager.refreshAllViewers();
				Popup.remove(Popup.find(this)); return cmm.processed(ev);
			}); b.callback=callback;
		};
		cmd(this.resetAllCmd,this.resetAllTip,cmm.resetPanel);
		cmd(this.dockAllCmd,this.dockAllTip,cmm.dockPanel);
	},
	menu_selectPanel: function(place){
		// LIST OF PANELS with PANEL SUBMENUS
		addCMD(place,this.selectPanelCmd,this.selectPanelTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			var popup=addPOP(this,'panelManagerPopup'); if (!popup) return false;
			var panels=cmm.getAllPanels();
			addTXT(popup,panels.length?cmm.manager.selectPanelMsg:cmm.manager.noPanels);
			for (var i=0; i<panels.length; i++) { var p=panels[i];
				var b=addCMD(popup,p.pid||cmm.manager.noPid,cmm.getPanelTooltip(p),function(ev){
					var ev=ev||window.event; var cmm=config.macros.moveablePanel;
					var popup=addPOP(this,'panelManagerPopup');
					if(!popup)return false;
					var docX=findMouseX(ev)+findScrollX(); var docY=findMouseY(ev)+findScrollY();
					cmm.manager.menu_panel(popup,this.p,
						this.p.pid||cmm.manager.thisPanel,Popup.find(this)+1,docX,docY);
					Popup.show('top','right'); return cmm.processed(ev);
				}); b.p=p; b.onmouseover=b.onclick; // ALWAYS autoclick on mouseover
			}
			Popup.show('top','right'); return cmm.processed(ev);
		});
	},
	menu_selectMap: function(place){
		// same as LOAD COMMAND IN VIEWER (with different label/tip and popup alignment)
		this.menu_loadMap(addLI(place),this.selectMapCmd,this.selectMapTip,'top','right');
	},
	menu_options: function(place) {
		var on='<input type="checkbox" checked>'; var off='<input type="checkbox">';
		addCMD(place,this.optionsCmd,this.optionsTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel; var mgr=cmm.manager;
			var popup=addPOP(this,'sticky panelManagerPopup'); if (!popup) return false;
			addCHK(popup,mgr.useCookiesCmd,mgr.useCookiesTip,'chkPanelManagerUseCookies');
			addBR(popup);
			addCHK(popup,mgr.showManagerCmd,mgr.showManagerTip,'chkMoveablePanelShowManager');
			addBR(popup);
			addCHK(popup,mgr.autoMapCmd,mgr.autoMapTip,'chkPanelManagerAutoMap');
			addBR(popup);
			addCHK(popup,mgr.showStatusCmd,mgr.showStatusTip,'chkMoveablePanelShowStatus');
			Popup.show('top','right'); return cmm.processed(ev);
		});
	},
//}}}
// // panel map viewers
//{{{
	// MAP MANAGEMENT COMMANDS
	viewer_commands: function(place,refresh) {
		if (refresh) removeChildren(place);
		else place=createTiddlyElement(place,'div',null,'panelManagerMapCommands');
		var map=config.options.txtMoveablePanelMapName;
		var unsaved=this.isMapChanged(map)?this.viewMapUnsaved:'';
		wikify(this.viewMapHeader.format([map,unsaved]),place);
				this.command_newMap(place);
		addSEP(place); 	this.menu_loadMap(place,this.loadMapCmd,this.selectMapTip);
		addSEP(place); 	this.command_editMap(place);
		addSEP(place); 	this.command_saveMap(place);
		addSEP(place); 	this.command_viewerTable(place);
	},
//}}}
//{{{
	// TABLE VIEW - ALL MAP ENTRIES
	viewer_table: function(place,refresh) {
		var cmm=config.macros.moveablePanel;
		if (refresh) removeChildren(place);
		else place=createTiddlyElement(place,"div",null,"panelManagerMapTable");
		place.onclick=function(ev){ var cmm=config.macros.moveablePanel;
			var lvl=Popup.find(this); if (lvl!=-1) Popup.remove(lvl+1);
			cmm.manager.refreshAllViewers(); return cmm.processed(ev); }
		var link='[[%0]]'; var cmd='<<moveablePanel %2 %3:[[%0]] %4:[[%0]] %5:[[%1]]>>';
		cmd=cmd.format(['%0','%1',this.menuParam,this.nameParam,this.labelParam,this.promptParam]);
		var sortByZ=function(a,b){ var v1=parseInt(a.z); var v2=parseInt(b.z); return(v1==v2)?0:(v1>v2?1:-1); }
		var map=[]; for (var pid in this.map) map.push(this.map[pid]); map=map.sort(sortByZ);
		var rows=[]; for (var i=0; i<map.length; i++) { var m=map[i];
			var isPanel=cmm.findPanel(m.pid);
			var isTiddler=store.tiddlerExists(m.pid)||store.isShadowTiddler(m.pid);
			var fmt=isPanel?cmd:(isTiddler?link:cmd);
			var lbl=fmt.format([m.pid,this.panelCmd.format([m.pid])]);
			rows.push(this.mapFormat.format([lbl,m.x,m.y,m.w,m.h,m.z,
				m.folded?this.checkmark:' ', m.hover?this.checkmark:' ']));
		}
		var table=this.mapHeader.format([''])+'\n'+rows.join('\n')+(!rows.length?this.viewMapEmpty:'');
		wikify(table,place);
	},
//}}}
//{{{
	// GRAPHICAL VIEWER - ACTIVE PANELS AND TIDDLERS
	mapXtoDocX: function(e,ev,scale,scroller) { // convert mouse click in map panel to equivalent document location
		var mouseX=findMouseX(ev);
		var mapX=findPosX(e.parentNode)-scroller.scrollLeft;
		var docX=Math.floor((mouseX-mapX)/scale)-Math.floor((mouseX-mapX)*scale);
		return docX;
	},
	mapYtoDocY: function(e,ev,scale,scroller) { // convert mouse click in map panel to equivalent document location
		var mouseY=findMouseY(ev);
		var mapY=findPosY(e.parentNode)-scroller.scrollTop;
		var docY=Math.floor((mouseY-mapY)/scale)-Math.floor((mouseY-mapY)*scale);
		return docY;
	},
	viewer_map: function(place,refresh,mapSize){
		var cmm=config.macros.moveablePanel;
		if (!refresh) {
			place=createTiddlyElement(place,'div',null,'panelManagerMapViewer');
			place.mapSize=mapSize; // save for use with refresh
		} else {
			var mapSize=place.mapSize; // refresh... use saved map size
			removeChildren(place); // NOTE: ASSUMES CONTAINER HAS NO OTHER CONTENT
		}

		// METRICS
		var dw=findDocumentWidth();  var ww=findWindowWidth();  if (dw<ww) dw=ww; var sx=findScrollX();
		var dh=findDocumentHeight(); var wh=findWindowHeight(); if (dh<wh) dh=wh; var sy=findScrollY();

		// SET MAP MAXSIZE
		var wrapper=createTiddlyElement(place,'div');
		if (Popup.find(place)!=-1) mapSize=config.options.txtPanelManagerPopupMapSize; // IF POPUP
		wrapper.style.width=mapSize||''; mapSize=wrapper.offsetWidth; // APPLY CSS THEN GET PIXELS

		// SET SCROLLING/SCALING
		var scroll=!config.options.chkPanelManagerMapFullPage;
		// default to fit entire page in viewer
		if (dw>dh) { var w=mapSize; var h=dh/dw*mapSize; var scale=w/dw; }
		else 	   { var h=mapSize; var w=dw/dh*mapSize; var scale=h/dh; }
		if (scroll) { // set smaller dimension to fixed value, scroll the other
			wrapper.style.width=mapSize+'px'; wrapper.style.height=wh/ww*mapSize+'px';  
			wrapper.style.overflow='auto'; // make it's contents scrollable
			var scrollsize=findWindowWidth()-document.body.offsetWidth+2;
			if (dw<=ww&&dh<=wh) { // smaller than window... enlarge to fit width
				w=mapSize; h=dh/dw*w; scale=w/dw;
				wrapper.style.overflow='visible'; // no scrollbars
			} else if (dw>dh) { // wide... add hScroll
				h=wh/ww*mapSize; w=dw/dh*h; scale=h/dh;
				wrapper.style.height=h+scrollsize+'px';  
			} else { // tall... add vScroll
				w=mapSize-scrollsize; h=dh/dw*w; scale=w/dw;
			}
		}

		// CREATE DOCUMENT BACKGROUND
		var doc=createTiddlyElement(wrapper,'div',null,'map');
		doc.style.width=w+'px'; doc.style.height=h+'px';
		doc.onclick=function(ev){ // BACKGROUND POPUP: SCROLL+OPTIONS
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			var lvl=Popup.find(this); if (lvl<Popup.stack.length-1) // toggle child popup
				{ Popup.remove(lvl+1); return cmm.processed(ev); }
			var popup=addPOP(this,'sticky panelManagerPopup'); if(!popup)return false;
			var dx=cmm.manager.mapXtoDocX(this,ev,scale,this.parentNode);
			var dy=cmm.manager.mapYtoDocY(this,ev,scale,this.parentNode);
			addTXT(popup,cmm.manager.XYJumpCmd); cmm.manager.menu_compass(popup,null,dx,dy);
			addHR(popup); cmm.manager.menu_mapBackground(popup);
			Popup.showHere(this,ev); return cmm.processed(ev);
		};
		doc.scale=scale; doc.title=this.viewerMapTip; doc.style.cursor='crosshair';

		// SHOW VIEWPORT (CURRENT WINDOW POS)
		var currview=createTiddlyElement(doc,'div');
		var s=currview.style; s.border='1px dotted'; s.position='absolute';
		s.left=sx*scale+'px'; s.top=sy*scale+'px'; s.width=(ww-2)*scale+'px'; s.height=(wh-2)*scale+'px';

		// GET ALL PANELS AND FIND BASELINE Z FOR RENDERING MAP ON TOP OF POPUPS/PANELS
		var panels=cmm.getAllPanels(); var allPids=[]; var minZ=0; var viewerZ=0;
		for (var i=0; i<panels.length; i++) { var p=panels[i]; allPids.push(p.pid); 
			if (p.style.zIndex<minZ) minZ=p.style.zIndex;
		}
		if (Popup.find(place)!=-1) viewerZ=Popup.stack[Popup.find(place)].popup.style.zIndex;
		else if (cmm.getPanel(place)) viewerZ=cmm.getPanel(place).style.zIndex;
		var baseZ=viewerZ-minZ+1;

		// DRAW PANEL BOXES
		for (var i=0; i<panels.length; i++) {
			var p=panels[i];
			var d=cmm.manager.viewer_mapbox_draw(doc,p,scale,baseZ);
			d.title=cmm.getPanelTooltip(p);
		}

		// DRAW TIDDLER BOXES
		story.forEachTiddler(function(t,e){
			if (allPids.contains(t)) return; // TIDDLER IS ALSO MOVEABLE PANEL... SKIP IT
			var d=cmm.manager.viewer_mapbox_draw(doc,e,scale,baseZ);
			d.tid=t; var tiddler=store.getTiddler(t);
 			d.title=tiddler?tiddler.getSubtitle():config.macros.moveablePanel.manager.tiddlerCmd.format([t]);
		});

		// SHOW DOC/WINDOW SIZE/VIEWPORT
		var span=createTiddlyElement(place,'span',null,'panelManagerMapStats');
		var msg=this.viewerMapStatsMsg.format([dw,dh,ww,wh,sx,sx+ww,sy,sy+wh]);
		wikify(msg,span);

		// SET MAP SCROLLPOS TO MATCH PAGE SCROLLPOS
		// NOTE: must be done *after* all content has been rendered or scrollbar will jump to zero
		if (scroll) { wrapper.scrollTop=sy*scale; wrapper.scrollLeft=sx*scale; }

	},
	// draw one map box with borders, mouseover shading and drag handling for moving
	viewer_mapbox_draw: function(doc,p,scale,baseZ) {
		var x=findPosX(p); var w=p.offsetWidth; var y=findPosY(p); var h=p.offsetHeight;
		if (hasClass(p,'hover')) { x+=findScrollX(); y+=findScrollY(); } // hover=always in view
		var db=createTiddlyElement(doc,'div',null,'panelManagerViewerMapBox');
		db.panel=p; 		db.scale=scale; 	var s=db.style;
		s.border="1px solid";	s.position='absolute';	s.cursor='crosshair';	s.zIndex=baseZ+p.style.zIndex;
		s.top=y*scale+'px';	s.left=x*scale+'px'; 	s.width=w*scale+'px';	s.height=h*scale+'px';
		s.background='#eee';	s.opacity='0.6';	s.filter='alpha(opacity:60)';
		db.onmouseover=function(ev)
			{ var s=this.style; s.background='#999';s.opacity='1';s.filter='alpha(opacity:100)'; }
		db.onmouseout=function(ev)
			{ var s=this.style; s.background='#eee';s.opacity='0.5';s.filter='alpha(opacity:50)'; }
		db.onmousedown=this.viewer_mapbox_dragstart;
		db.onclick=this.viewer_mapbox_popup;
		return db;
	},
	viewer_mapbox_dragstart: function(ev) { var ev=ev||window.event; var cmm=config.macros.moveablePanel;
		// capture mouse events and set drag handlers on target (body, window, or this panel)
		var target=this; // fallback to this panel if 'capture' not supported
		if (document.body.setCapture) // IE
			{ document.body.setCapture(); var target=document.body; }
		if (window.captureEvents) // moz
			{ window.captureEvents(Event.MouseMove|Event.MouseUp,true); var target=window; }
		// save drag data in target element
		if (!target.dragData) target.dragData=new Object();
		var d=target.dragData;
		d.box=this; d.scale=this.scale;	d.map=this.parentNode; d.scroller=this.parentNode.parentNode;
		d.startX=findMouseX(ev); d.startScrollX=d.scroller.scrollLeft; d.grabX=findMouseX(ev)-findPosX(this);
		d.startY=findMouseY(ev); d.startScrollY=d.scroller.scrollTop;  d.grabY=findMouseY(ev)-findPosY(this);
		d.offset=cmm.getPanelOffset(d.box.panel);
		d.dragging=true; this.style.cursor='move';
		d.savedonmousemove=target.onmousemove;
		target.onmousemove=cmm.manager.viewer_mapbox_dragmove;
		d.savedonmouseup=target.onmouseup;
		target.onmouseup=cmm.manager.viewer_mapbox_dragstop;
		cmm.addGhost(d.box.panel); // keep document from shrinking during move/size
		cmm.noScrollX++; cmm.noScrollY++; // prevent document from scrolling during move/size
		return cmm.processed(ev);
	},
	viewer_mapbox_dragmove: function(ev) { var ev=ev||window.event; var cmm=config.macros.moveablePanel;
		var d=this.dragData; if (!d || !d.dragging) return; // NOT DRAGGING
		if (!hasClass(d.box.panel,'moveablePanel')) { // NOT MOVEABLE
			clearMessage();
			displayMessage(cmm.manager.notMoveableMsg.format([d.box.panel.pid||d.box.tid]));
			return this.onmouseup(ev);
		}
		cmm.quiet++; cmm.undockPanel(d.box.panel,true); cmm.quiet--; // GET READY TO MOVE
		var mouseX=!config.browser.isIE?ev.pageX:ev.clientX;
		var mouseY=!config.browser.isIE?ev.pageY:ev.clientY;
		var mapX=findPosX(d.map)+d.startScrollX; var mapW=d.map.offsetWidth;
		var mapY=findPosY(d.map)+d.startScrollY; var mapH=d.map.offsetHeight;
		var scrollX=d.scroller.scrollLeft;	 var scrollW=d.scroller.offsetWidth;
		var scrollY=d.scroller.scrollTop;	 var scrollH=d.scroller.offsetHeight;
		var boxW=d.box.offsetWidth;		 var boxH=d.box.offsetHeight;
		var boxX=findMouseX(ev)-mapX-d.grabX+scrollX;
		var boxY=findMouseY(ev)-mapY-d.grabY+scrollY;
		if (boxX<0) boxX=0; if (boxY<0) boxY=0; // limit upper left=stay on page
		if (hasClass(d.box.panel,'hover')) { // hover=limit bottom right (stay in screen)
			if (boxX+boxW>scrollW) boxX=scrollW-boxW; if (boxY+boxH>scrollH) boxY=scrollH-boxH;
			if (boxX<scrollX) boxX=scrollX; if (boxY<scrollY) boxY=scrollY;
		}
		var docX=Math.floor(boxX/d.scale)-d.offset.x;
		var docY=Math.floor(boxY/d.scale)-d.offset.y;
		if (hasClass(d.box.panel,'hover')) { // window-relative placement
			var ww=findWindowWidth();  var sx=findScrollX();
			var wh=findWindowHeight(); var sy=findScrollY();
			docX-=sx-d.offset.x; docY-=sy-d.offset.y;
			if (docX+d.box.panel.offsetWidth >ww) docX=ww-d.box.panel.offsetWidth;
			if (docY+d.box.panel.offsetHeight>wh) docY=wh-d.box.panel.offsetHeight;
			if (docX<0) docX=0; if (docY<0) docY=0;
		}
		// update box AND panel positions
		d.box.style.left=boxX+'px';	d.box.panel.style.left=docX+'px';
		d.box.style.top =boxY+'px';	d.box.panel.style.top =docY+'px';
		// resize map/scroll viewer as needed
		if (boxX<scrollX) d.scroller.scrollLeft=boxX;
		if (boxX+boxW>scrollX+scrollW || boxX+boxW>d.map.offsetWidth) {
			d.map.style.width=Math.max(boxX+boxW,mapW)+'px';
			d.scroller.scrollLeft=boxX+boxW-scrollW;
		}
		if (boxY<scrollY) d.scroller.scrollTop=boxY;
		if (boxY+boxH>scrollY+scrollH || boxY+boxH>d.map.offsetHeight) {
			d.map.style.height=Math.max(boxY+boxH,mapH)+'px';
			d.scroller.scrollTop=boxY+boxH-scrollH;
		}
		cmm.showPanelStatus(d.box.panel,true);
		return cmm.processed(ev);
	},
	viewer_mapbox_dragstop: function(ev) { var ev=ev||window.event; var cmm=config.macros.moveablePanel;
		var d=this.dragData; if (!d || !d.dragging) return; // NOT DRAGGING
		if (this.releaseCapture) this.releaseCapture(); // IE
		if (this.releaseEvents) this.releaseEvents(Event.MouseMove|Event.MouseUp); // moz
		this.onmousemove=d.savedonmousemove; this.onmouseup=d.savedonmouseup;
		cmm.noScrollX--; cmm.noScrollY--; // allow document to scroll
		cmm.clearGhost(); // allow document to adjust extents (if needed)
		var moved=findMouseX(ev)!=d.startX || findMouseY(ev)!=d.startY;
		if (moved) { cmm.manager.trackMap(d.box.panel); cmm.manager.refreshAllViewers(); }
		d.dragging=false; d.box.style.cursor='pointer';
		cmm.showPanelStatus(d.box.panel,false);
		cmm.timedMessage(cmm.formatPanelStatus(d.box.panel),cmm.msgDuration);
		// HACK: ignore next click to prevent webkit from closing popup after dragging
		d.box.ignoreClick=moved&&config.browser.isSafari;
		return cmm.processed(ev);
	},
	viewer_mapbox_popup: function(ev) {
		var ev=ev||window.event; var cmm=config.macros.moveablePanel; var mgr=cmm.manager;
		if (this.ignoreClick) { this.ignoreClick=false; return cmm.processed(ev); } // HACK
		var lvl=Popup.find(this); if (lvl<Popup.stack.length-1) // toggle child popup
			{ Popup.remove(lvl+1); return cmm.processed(ev); }
		var popup=addPOP(this,'sticky panelManagerPopup'); if (!popup) return false;
		var dx=cmm.manager.mapXtoDocX(this,ev,this.scale,this.parentNode.parentNode);
		var dy=cmm.manager.mapYtoDocY(this,ev,this.scale,this.parentNode.parentNode);
		if (this.tid)	cmm.manager.menu_mapTiddler(popup,this.tid,this.panel,dx,dy);
		else		cmm.manager.menu_mapPanel(popup,this.panel,dx,dy);
		Popup.showHere(this,ev); return cmm.processed(ev);
	},

//}}}
//{{{
	refreshAllViewers: function(){
		var elems=document.getElementsByTagName("DIV");
		for (var i=0; i<elems.length; i++) {
			if (hasClass(elems[i],'panelManagerMapViewer'))   this.viewer_map(elems[i],true);
			if (hasClass(elems[i],'panelManagerMapTable'))	  this.viewer_table(elems[i],true);
			if (hasClass(elems[i],'panelManagerMapCommands')) this.viewer_commands(elems[i],true);
		}
	},
//}}}
// // map viewer commands
//{{{
	menu_mapBackground: function(place) {
		var centered=createTiddlyElement(place,'div'); centered.style.textAlign='center';
		if (Popup.find(place)>0) { // POPUP VIEWER PERMITS RESIZING
			addBTN(centered,'\xa0'+this.mapSizeCmd,this.refreshMapTip,function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				cmm.manager.refreshAllViewers();
				Popup.remove(Popup.find(this));	return cmm.processed(ev);
			});
			wikify('{{panelManagerMapPopupEdit{<<option txtPanelManagerPopupMapSize>>}}}\xa0',centered);
		}
		var opt='chkPanelManagerMapFullPage'; // toggle label...
		var label=config.options[opt]?this.mapScrollPageCmd:this.mapFullPageCmd;
		var tip=config.options[opt]?this.mapScrollPageTip:this.mapFullPageTip;
		addCHK(addLI(centered),label,tip,opt,true);
		addHR(centered); addCMD(centered,this.refreshMapCmd,this.refreshMapTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			cmm.manager.refreshAllViewers();
			Popup.remove(Popup.find(this));	return cmm.processed(ev);
		});
	},
	menu_mapPanel: function(place,panel,docX,docY) {
		var cmm=config.macros.moveablePanel;
		var b=addCMD(place,this.panelCmd.format([panel.pid]),cmm.getPanelTooltip(panel),function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			var popup=addPOP(this,'panelManagerPopup'); if (!popup) return false;
			cmm.manager.menu_panel(popup,panel,this.panel.pid||this.thisPanel,Popup.find(this)+1,docX,docY);
			Popup.show('top','right'); return cmm.processed(ev);
		}); b.panel=panel;
		// autoclick on initial mouseover
		b.onmouseover=function(ev) { this.onmouseover=null; return this.onclick.apply(this,arguments); };
		addHR(place); addTXT(place,this.XYJumpCmd); this.menu_compass(place,panel,docX,docY);
		addHR(place); this.menu_mapBackground(place);
	},
	menu_mapTiddler: function(place,tid,tiddlerElem,docX,docY) {
		var cmm=config.macros.moveablePanel;
		var b=addCMD(place,this.tiddlerCmd.format([tid]),'',function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel; var mgr=cmm.manager;
			var popup=addPOP(this,'panelManagerPopup'); if (!popup) return false;
			var b=addCMD(popup,mgr.jumpToPanelCmd,mgr.jumpToPanelTip.format([tid]),function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				cmm.scrollToPanel(this.tiddlerElem,true); cmm.manager.refreshAllViewers();
				Popup.remove(Popup.find(this)); return cmm.processed(ev);
			}); b.tid=this.tid; b.tiddlerElem=this.tiddlerElem;
			var b=addCMD(popup,mgr.closeCmd,mgr.closeTip.format([tid]),function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				var OK=!story.isDirty(this.tid)||confirm(cmm.manager.tiddlerDirtyMsg.format([this.tid]));
				if (OK) { story.closeTiddler(this.tid); cmm.manager.refreshAllViewers(); }
				Popup.remove(Popup.find(this)); return cmm.processed(ev);
			}); b.tid=this.tid;
			Popup.show('top','right'); return cmm.processed(ev);
		}); b.tid=tid; b.tiddlerElem=tiddlerElem;
		// autoclick on initial mouseover
		b.onmouseover=function(ev) { this.onmouseover=null; return this.onclick.apply(this,arguments); };
		addHR(place); addTXT(place,this.XYJumpCmd); this.menu_compass(place,tiddlerElem,docX,docY);
		addHR(place); this.menu_mapBackground(place);
	},
	command_newMap: function(place){
		addBTN(place,this.newMapCmd,this.newMapTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			if (!cmm.manager.newMap(ev)) cmm.manager.refreshAllViewers();
			return cmm.processed(ev);
		});
	},
	menu_loadMap: function(place,label,tip,valign,halign){
		addBTN(place,label,tip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			var popup=addPOP(this,'panelManagerPopup'); if (!popup) return false;
			var tids=store.getTaggedTiddlers(cmm.manager.mapTags[0]||cmm.manager.mapTag);
			addTXT(popup,tids.length?cmm.manager.selectMapMsg:cmm.manager.noMaps);
			for (var t=0;t<tids.length;t++) { var title=tids[t].title;
				var b=addCMD(popup,title,cmm.manager.loadThisMapTip.format([title]),function(ev){
					var ev=ev||window.event; var cmm=config.macros.moveablePanel;
					if (!cmm.manager.loadMap(this.map,ev)) { 
						cmm.manager.refreshAllViewers();
						displayMessage(cmm.manager.switchMapMsg.format([this.map]));
					}
					Popup.remove(Popup.find(this)); return cmm.processed(ev);
				}); b.map=title;
			}
			if (valign||halign) Popup.show(valign,halign); else Popup.showHere(this,ev);
			return cmm.processed(ev);
		});
	},
	command_editMap: function(place){
		var map=config.options.txtMoveablePanelMapName;
		addBTN(place,this.editMapCmd.format([map]),this.editMapTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			if (!store.tiddlerExists(this.map)&&cmm.manager.saveMap(this.map,ev)) return cmm.processed(ev);
			cmm.manager.refreshAllViewers();
			story.displayTiddler(null,this.map,DEFAULT_EDIT_TEMPLATE);
			return cmm.processed(ev);
		}).map=map;
	},
	command_saveMap: function(place){
		addBTN(place,this.saveMapCmd,this.saveMapTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			if (!cmm.manager.saveMap(this.map,ev)) cmm.manager.refreshAllViewers();
			return cmm.processed(ev);
		}).map=config.options.txtMoveablePanelMapName;
	},
	command_viewerTable: function(place){
		addBTN(place,this.viewerTableCmd,this.viewerTableTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			var popup=addPOP(this.parentNode,'panelManagerPopup'); if (!popup) return false;
			cmm.manager.viewer_table(popup);
			Popup.showHere(place,ev); return cmm.processed(ev);
		});
	},
//}}}
// // CSS definitions
//{{{
	css: '/*{{{*/\n'
		+'.panelManagerPopup\n'
			+'\t{ white-space:nowrap; }\n'
		+'.panelManagerPopup input\n'
			+'\t{ text-align:center; font-size:90%; }\n'
		+'.panelManagerPopupCompass {\n'
			+'\tbackground:#999; margin:1em;\n'
			+'\t-moz-border-radius:.5em; -webkit-border-radius:.5em;\n'
			+'}\n'
		+'.panelManagerPopupCompass td {\n'
			+'\tfont-size:2em; width:1.5em; height:1.5em; text-align:center; vertical-align;center;\n'
			+'\tbackground:#eee !important; color:#000 !important;\n'
			+'\tborder:1px solid #666; padding:0; margin:0;\n'
			+'\t-moz-border-radius:2px; -webkit-border-radius:2px;\n'
			+'}\n'
		+'.panelManagerPopupCompass td:hover\n'
			+'\t{ background:#fff !important; color:#000 !important; }\n'
		+'.panelManagerPopupCompassButton:hover\n'
			+'\t{ background:transparent !important; color:#000; }\n'
		+'.panelManagerMapPopup\n'
			+'\t{ text-align:center; white-space:nowrap; }\n'
		+'.panelManagerMapPopupEdit input\n'
			+'\t{ width:5em; margin-top:.2em; }\n'
		+'.panelManagerMapViewer .map {\n'
			+'\tposition:relative; overflow:hidden;\n'
			+'\tcolor:#000; background-color:#fff;\n'
			+'\tmargin:0; border:1px solid;\n'
			+'\t-moz-border-radius:3px; -webkit-border-radius:3px;\n'
			+'}\n'
		+'.panelManagerViewerMapBox\n'
			+'\t{ border:1px solid; -moz-border-radius:2px; -webkit-border-radius:2px; }\n'
		+'.panelManagerMapStats\n'
			+'\t{ font-size:80%; }\n'
		+'.panelManagerMapStats .twtable, .panelManagerMapStats .twtable tr, .panelManagerMapStats .twtable td\n'
			+'\t{ padding:0; margin:0; border:0; }\n'
		+'.panelManagerMapStats .twtable\n'
			+'\t{ width:100%; }\n'
		+'.panelManagerMapStats .twtable td\n'
			+'\t{ width:50%; }\n'
		+'/*}}}*/'
});
//}}}
// // CSS initialization (during startup)
//{{{
// set up shadow stylesheet, then load styles so customized CSS (if any) will be applied
config.shadowTiddlers.PanelManagerStyles=config.macros.moveablePanel.manager.css;
var css=store.getRecursiveTiddlerText('PanelManagerStyles',config.macros.moveablePanel.manager.css,10);
setStylesheet(css,'panelManagerStyles');
//}}}
// // hijack: sticky popups (allows interaction inside popup)
// // COPIED FROM [[StickyPopupPlugin]] TO ELIMINATE PLUGIN DEPENDENCY
//{{{
if (config.options.chkStickyPopups==undefined) config.options.chkStickyPopups=false;
try{removeEvent(document,"click",Popup.onDocumentClick);}catch(e){};
try{removeEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
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 not a sticky popup... use normal handling
	if (!p) {
		// HACK: if flag is set, ignore this click (and clear the flag)
		if (Popup.ignoreClick) Popup.ignoreClick=false; 
		else Popup.onDocumentClick(ev);
	}
	return true;
};
try{addEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
//}}}
// // hijack: page background popup menu (ALT-CLICK)
//{{{
if (!document.getElementById('panelManagerPopupRoot')) { // only once
	var root=createTiddlyElement(document.body,'span','panelManagerPopupRoot');
	var s=root.style; s.width=0; s.height=0; s.top=0; s.left=0;
	s.display='inline'; s.overflow='visible'; s.position='absolute'; 
	document.onmousedown_panelmanager=document.onmousedown;
	document.onmousedown=function(ev) {
		var ev=ev||window.event; var target=resolveTarget(ev); var cmm=config.macros.moveablePanel;
		if (!ev||!ev.altKey) { // if not ALT-CLICK... handle event normally
			if (document.onmousedown_panelmanager==undefined) return;
			return document.onmousedown_panelmanager.apply(target,arguments);
		}
		var root=document.getElementById('panelManagerPopupRoot');
		var mX=findMouseX(ev); var mY=findMouseY(ev);
		root.style.left=mX+'px'; root.style.top =mY+'px';
		var p=cmm.getPanel(target); var t=story.findContainingTiddler(target);
		var id=p?p.pid:(t?t.getAttribute('tiddler'):'')
		// HACK: ignore next click on doc background (prevents IE from closing popup)
		Popup.ignoreClick=config.browser.isIE;
		cmm.manager.popup(root,ev,id);
		return cmm.processed(ev);
	}
}
//}}}
// // hijack: refresh map viewers when window is scrolled
//{{{
if (window.onscroll_panelManager_init===undefined) { // only once
	window.onscroll_panelManager_init=true;
	window.onscroll_panelManager=window.onscroll;
	window.onscroll=function() {
		config.macros.moveablePanel.manager.notify('refresh');
		if (window.onscroll_panelManager)
			return window.onscroll_panelManager.apply(this,arguments);
	}
}
//}}}
// // hijacks: refresh map viewers when tiddlers or nested sliders are opened/closed
//{{{
if (Story.prototype.displayTiddler_panelManager===undefined) { // only once
	Story.prototype.displayTiddler_panelManager=Story.prototype.displayTiddler;
	Story.prototype.displayTiddler=function() {
		var r=this.displayTiddler_panelManager.apply(this,arguments);
		config.macros.moveablePanel.manager.notify('refresh');
		return r;
	}
	Story.prototype.closeTiddler_panelManager=Story.prototype.closeTiddler;
	Story.prototype.closeTiddler=function() {
		var r=this.closeTiddler_panelManager.apply(this,arguments);
		// NOTE: ASYNC wait for core animation to finish, then update viewers
		var delay=config.options.chkAnimate?config.animDuration+100:0;
		setTimeout("config.macros.moveablePanel.manager.notify('refresh')",delay);
		return r;
	}
}
if (window.onClickNestedSlider && (window.onClickNestedSlider_panelManager===undefined)) { // only once
	window.onClickNestedSlider_panelManager=window.onClickNestedSlider;
	window.onClickNestedSlider=function() {
		var r=window.onClickNestedSlider_panelManager.apply(window,arguments);
		// NOTE: ASYNC wait for core animation to finish, then update viewers
		var delay=config.options.chkAnimate?config.animDuration+100:0;
		setTimeout("config.macros.moveablePanel.manager.notify('refresh')",delay);
		return r;
	}
}
//}}}
<!--{{{-->
<div class='moveablePanel'>
<div class='toolbar'>
	<span macro='moveablePanel load:{{tiddler?tiddler.title:""}} label:"load this map"'></span>
	<span macro='toolbar [[ToolbarCommands::ViewToolbar]]'></span>
</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='tagged' macro='tags'></div>
<div class='tagging' macro='tagging'></div>
<div class='viewer'>
	<div class='content' macro='view text wikified'></div>
</div>
<div class='tagClear'></div>
<div macro='moveablePanel name:{{story.findContainingTiddler(place).getAttribute("tiddler")}} undocked fold hover height:auto'></div>
</div>
<!--}}}-->
@@display:block;margin:0 .2em;padding:.2em .3em;goto@@<<gotoTiddler>><<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal "DD MMM YYYY" "journal">><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel "options »" "Change TiddlyWiki advanced options">><<moveablePanel menu label:"panels">>
<br>^^~TiddlyWiki v<<version>> plus MoveablePanelPackage^^
^^@@font-size:80%;{{block{
 ''//a [[TiddlyTools|http://www.TiddlyTools.com]] ~QuickStart&trade; document.  All rights retained.//''}}}@@^^
[[moveable.html|http://www.TiddlyTools.com/quickstart/moveable.html]]
[[MoveableTiddlerStyles]]	/* styles for moveable tiddlers */

/*{{{*/
/* GENERAL STYLE TWEAKS */
body { background:#ffe; }
.headerForeground, .headerShadow
	{ padding:.5em; }
.headerShadow
	{ color:[[ColorPalette::Background]]; }
.headerShadow a
	{ color:[[ColorPalette::PrimaryPale]]; }
.headerForeground
	{ display:none; }
.undocked .headerShadow
	{ color:black; }
.undocked .headerShadow a
	{ color:green; }
.undocked .headerForeground
	{ display:block; }
#messageArea
	{ -moz-border-radius:1em; -webkit-border-radius:1em; }
.popup
	{ -moz-border-radius:.5em; -webkit-border-radius:.5em; }
.popup li a
	{ padding:2px; }
#mainMenu
	{ margin-left:1em; width:auto; text-align:center; background:#fff;
	border:1px solid; padding:1em; -moz-border-radius:1em; -webkit-border-radius:1em; }
#sidebarOptions
	{ padding-left:1em; margin-left:-1em; border-left:1px solid transparent; }
#sidebarOptions:hover
	{ border-left:1px dotted; }
.editor textarea
	{ font-family:monospace; line-height:110%; }
.tagged, .tagging
	{ -moz-border-radius:.5em; -webkit-border-radius:.5em; }
.selected .tagged, .selected .tagging
	{ border:1px solid; }
.tagging
	{ margin-left:1em; }

/*}}}*/
/***
|Name|TaggedTemplateTweak|
|Source|http://www.TiddlyTools.com/#TaggedTemplateTweak|
|Documentation|http://www.TiddlyTools.com/#TaggedTemplateTweakInfo|
|Version|1.5.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.chooseTemplateForTiddler()|
|Description|use alternative ViewTemplate/EditTemplate for tiddler's tagged with specific tag values|
This tweak extends story.chooseTemplateForTiddler() so that ''whenever a tiddler is marked with a specific tag value, it can be viewed and/or edited using alternatives to the standard tiddler templates.'' 
!!!!!Documentation
>see [[TaggedTemplateTweakInfo]]
!!!!!Revisions
<<<
2008.12.18 [1.5.0] added handling for using tiddler //title// as prefix (e.g., {{{SomeTiddlerViewTemplate}}}) 
| please see [[TaggedTemplateTweakInfo]] for previous revision details |
2007.06.11 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.TaggedTemplateTweak= {major: 1, minor: 5, revision: 0, date: new Date(2008,12,18)};

Story.prototype.taggedTemplate_chooseTemplateForTiddler = Story.prototype.chooseTemplateForTiddler
Story.prototype.chooseTemplateForTiddler = function(title,template)
{
	// get default template from core
	var coreTemplate=this.taggedTemplate_chooseTemplateForTiddler.apply(this,arguments);

	// if the tiddler doesn't exist yet, return core result
	var tiddler=store.getTiddler(title); if (!tiddler) return coreTemplate;

	// split core template into theme prefix and template name
	var theme="";
	var template=coreTemplate;
	var parts=template.split(config.textPrimitives.sectionSeparator);
	if (parts[1]) { theme=parts[0]; template=parts[1]; }
	else theme=config.options.txtTheme||""; // fallback if theme is not specified
	theme+=config.textPrimitives.sectionSeparator;

	// look for template whose prefix matches a *tag* on this tiddler (if any)
	for (i=0; i<tiddler.tags.length; i++) {
		var t=tiddler.tags[i]+template; // add tag prefix to template
		var c=t.substr(0,1).toUpperCase()+t.substr(1); // capitalized for WikiWord title
		if (store.getTiddlerText(theme+t))	{ return theme+t; } // theme##tagTemplate
		if (store.getTiddlerText(theme+c))	{ return theme+c; } // theme##TagTemplate
		if (store.getTiddlerText(t)) 		{ return t; }	    // tagTemplate
		if (store.getTiddlerText(c))		{ return c; }	    // TagTemplate
	}

	// if no tagged template found, and tiddler title is not itself a tag,
	// then look for the template whose prefix matches the *title* of this tiddler
	var isTag=store.getTaggedTiddlers(title).length;
	if (!isTag && store.getTiddlerText(title+template)) { return title+template; }

	// no matching tag OR title prefix... return core result
	return coreTemplate;
}
//}}}
|           !panelname|   !x |   !y |   !w |   !h |   !z | !folded |h
|               header|    15|    15|   245|  auto|      |         |
|             mainmenu|   255|    30|  auto|  auto|      |         |
|           StyleSheet|   340|    95|   600|  auto|     2|         |
|           DefaultMap|  1454|  1346|   843|  auto|     3|         |
|                 tabs|   -50|   235|      |      |     4|         |
|        CoreTweaks444|  1238| 33072|   600|  auto|     5|         |
|         EditTemplate|   285|   175|   600|  auto|     6|         |
|         PageTemplate|    74|   133|   600|  auto|     7|         |
|         ViewTemplate|   190|   240|   600|  auto|     8|         |
|  MoveablePanelPlugin|    52|   134|   843|  auto|     9|         |
|              options|   -30|    30|      |      |    10|         |
|              TestMap|   181|    25|   865|  auto|    11|         |
/***
|Name|TextAreaPlugin|
|Source|http://www.TiddlyTools.com/#TextAreaPlugin|
|Documentation|http://www.TiddlyTools.com/#TextAreaPluginInfo|
|Version|2.1.9|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.focusTiddler|
|Options|##Configuration|
|Description|Adds Find/Again keyboard search, autosize, and 'stretch bar' resize for textarea controls|
* ''Control-F'' and ''control-G'' will ''"Find text"'' and ''"find text aGain"'', respectively, allowing you to copy, find, paste, findagain, paste, etc to perform "search-and-replace" actions.  
* ''autosizeEditor'' - toggles the tiddler editor textarea height between fixed-height and "automatically fit the contents".
* ''resizeEditor'' - adds 'grab handle' below textarea to stretch field height
!!!!!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
<<<
2008.01.08 [2.1.9] fixed default setting of uninitialized option values so that "false" is not treated as "undefined"
|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: 1, revision: 9, date: new Date(2008,1,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';
		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;
		e.button.innerHTML=config.commands.autosizeEditor.text;
		e.maxed=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]);
	}
}

// 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 cross-browser (IE) compatibility, including:
//    fixups and adjustments to CSS styles,
//    use 'old style' assignment of mouse event handlers instead of using addEventListener(),
//    use window.event if event param is null,
//    use offsetHeight instead of getComputedStyle()
//    use explicit window.* global scope declaration for functions called from event handlers

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
		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)
		this.handle.style.width=(this.element.offsetWidth-4)+"px"; // 4-pixel fudge factor for textarea border edge
		// 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 = "";
	}
};
//}}}
|~ViewToolbar|closeTiddler closeOthers +editTiddler > fields syncing permalink references jump|
|~EditToolbar|+saveTiddler -cancelTiddler deleteTiddler|
<!--{{{-->
<div class='moveablePanel'>
<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='tagged' macro='tags'></div>
<div class='tagging' macro='tagging'></div>
<div class='viewer'>
	<div class='content' macro='view text wikified'></div>
</div>
<div class='tagClear'></div>
<div macro='moveablePanel name:{{story.findContainingTiddler(place).getAttribute("tiddler")}} undocked fold hover height:auto'></div>
</div>
<!--}}}-->

Topic revision: r1 - 2008.12.17 - PaulReiber
 
Copyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.