Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which use a logographic writing system and need larger font sizes.
***/

/*{{{*/
body {font-size:0.8em;}

#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}

.subtitle {font-size:0.8em;}

.viewer table.listView {font-size:0.95em;}

.htmlarea .toolbarHA table {border:1px solid ButtonFace; margin:0em 0em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #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 closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

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

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

----
Also see AdvancedOptions
This started out with the intent of doing a significant upgrade to the Squier Strat.  It has transformed into a "from scratch" project using all new parts.

Most parts come from Carvin except for the pickups and pickup covers.  So essentially its a Carvin Bolt kit with Seymour Duncan Vintage for Strat SSL-2 Flat pickups.

Details and current progress will be posted on [[this blog|http://blue-zebra-guitar.blogspot.com]].

Here's my current plan for finishing the body... I want a high contrast, dark grain vs blue stain effect -- i.e., fill pores with dark grain filler, sand back, stain blue.   After that I'll follow the standard sand/sealer, clear lacquer, and polish schedule.

[[Timeline|2008 Guitar Project Timeline]]


* January 16, 2008 - I ordered a [[Carvin replacement neck|https://www.carvinguitars.com/products/single.php?product=BN]] w/ standard ebony fretboard and 12" radius.  I also ordered locking tuners and am I'm having them tung oil the back of the neck for me.
* Feb 11, 2008 - I ordered a set of 3 Seymour Duncan Vintage Flat ~SSL-2 pickups from West LA Music.  I got the call on Feb 27th that they had arrived and I picked them up the next day.
* March 4th - ordered shielding supplies from the Carvin website.   
* March 5th - the neck arrived today - it looks great! 
* March 6th - shielding supplies arrive.
* March 18th - This is no longer a squire upgrade.  After getting about half of the black paint off of the body using a combination of blow torching  and razor blade, I've found that the body is at least 5 pieces - 3 pieces of alder plus a thin wood laminate over the the top and bottom.  Underneath the black paint is a harder clear plastic coating over the wood.    Its going to be too much effort to get it down to bare wood in good condition, so I'm going to buy another body and all of the electronics, etc for a completely new guitar.
* March 21 - Ordered the body and remaining supplies from Carvin (except the pickup covers and screws, which they don't sell).
* March 28 - Body and parts arrive, kind of surprising since they said it would be 4 or 5 weeks to manufacture and ship the body.
* April 3 - Stopped at the House of Hardwood in WLA and picked up a piece of scrap ash.  I'll use this to experiment with the finish process.
* April 6 - Order stain, grain filler, sanding sealer, sand paper packs, and polish from ~ReRanch.com
* April 10 - ~ReRanch order arrives.  Picked up 6 cans of Deft clear gloss aerosol lacquer from Home Depot (3 for refinishing the Squier).
Quick facts:
* Born in 1962. &nbsp;I am married, have a son, and three dogs.
* I live in Culver City, California.
* I am a software engineer.
* I play guitar. &nbsp;In 2008 I am [[assembling a custom a guitar|2008 Guitar Project]].
* I tinker with audio and MIDI software on Linux to create backing tracks for playing guitar.
* Every Thursday evening during spring and summer I race with my Dad on his sailboat.
* About once a year I [[brew beer|Homebrew]].
The cost of creating my [[dream guitar|Dream Guitar Project]] is likely to be pretty high, so I've looked for off-the shelf guitars that match my specs.   &nbsp;All of these are rear-routed Strat style guitars.  &nbsp;The notes indicate how each guitar deviates from my specs.

|!Guitar |!Description |
|[[Zion Radicaster|http://www.zionguitars.com/main.asp?template=products&level1=Radicaster]] |Zion has options or will customize to match my [[dream guitar specs|Dream Guitar Project]].  &nbsp;Two piece neck.  &nbsp;Approx $3125. |
|[[Carvin Contour C66T |http://www.carvin.com/products/guitar.php?ItemNumber=C66]] |Unspecified body wood with flame/quilt maple top.  HSS option available.  $1200. |
|[[Fender FMT HSS Deluxe Strat|http://www.fender.com/products//search.php?partno=0101570852]] |Ebony fretboard, flame maple over alder body, only two color options, HSS noiseless pickup configuration.  $1400. |
|[[Washburn X33|http://www.washburn.com/products/electrics/x/x33.aspx]] |Website specs not detailed, limited options, multi-piece alder body, probably doesn't ship with locking tuners, sunburst body with rosewood fingerboard, black body with maple fingerboard.  Good reviews. ~$420.00 |
I plan on creating a [[custom guitar|Dream Guitar Project]].  In preparation, I found the following suppliers of parts.  &nbsp;This is not an exhaustive list -- I find a new one every time I search the web -- there are a lot of small custom guitar shops out there!   In order to make the list, the shop must at least sell replacement guitar necks or bodies. &nbsp;For ratings, I've been looking at [[Harmony Central|http://reviews.harmony-central.com/]].

|! Name |! Notes|
|[[WD Music|http://wdmusic.com/index.html]] |PDF Catalog only. Necks and lots of parts, electronics, etc. &nbsp;They offer quite a few necks, but wont build to custom specs as far as I can tell. |
|[[USA Custom Guitars|http://www.usacustomguitars.com]] |Lots of choices for necks and bodies, will build to custom specs, good ratings, expensive.  So far they have my [[favorite body|http://www.usacustomguitars.com/carvedtop-s.html]]. |
|[[AllParts|http://www.allparts.com]] |Necks and lots of parts, no bodies that I can see.  &nbsp;They offer quite a few necks, but wont build to custom specs as far as I can tell. |
|[[Warmoth|http://www.warmoth.com]] |Necks, bodies and more with lots of choices, and will build to custom specs. &nbsp;Looks like a great option at first, but for the last two years they've been getting trashed in all reviews on Harmony Central. |
|[[Musikraft|http://musikraft.3dcartstores.com/]] |Necks, bodies, and parts -- will build to custom specs. &nbsp;Reasonable prices, good ratings, but not too many options on the bodies (e.g., just standard front/rear routed Tele and Strat stuff - no carved tops). &nbsp;This is my current choice for the neck. |
|[[B Hefner Guitars|http://edenhaus.com]] |Reasonable number of neck and body options, the most expensive I've found so far. |
|[[Stewart Macdonald|http://www.stewmac.com]] |Everything for building and repairing strings instruments. |
|[[Mighty Mite|http://www.mightymite.com/index.html]] |Replacement necks, bodies and other parts.  One friend gave a good personal recommendation for these guys and most on-line reviews are OK, but customer support specific ratings are in the dumps. |
|[[Guitar Parts USA|http://www.guitarpartsusa.com]] | |
|[[Mojo Bodies|http://www.mojobodies.com]] |Custom bodies only. |
|[[Best Guitar Parts|http://www.bestguitarparts.com]] | |
|[[Lucas 3D Wood Duplicating|http://www.lucas3dwd.com]] |Custom bodies only. |
|[[Carvin|http://www.carvin.com/products/group.php?CID=KBN]] | |



[[About Me]]
[[Software Projects]]
In summary, it is a solid-body Strat with a rear routed body.  &nbsp;It might have a carved top. 

It might look like this:
[img[Guitar Mockup Image|http://www.geocities.com/kellinwood/blue_mockup_guitar.png]]

The current plan is to do most of the assembly myself after purchasing the neck, body, and hardware. &nbsp;I feel confident that I can do almost everything myself including the soldering. &nbsp;I have two neighbors that have full workshops so I should be able to borrow or use their tools when necessary.  &nbsp;In case I run into trouble I can always turn it over to my guitar tech, which I might do for the final setup anyway.

!!!Features
Here are the features I'd like:
* Locking tuners.
* No string retainers/trees (tilt back head or LSR roller nut?).
* Nut width 1.6875 inches.
* One piece quarter sawn maple neck (matte finish on the back of the neck, high gloss finish on the fretboard).
* 9.5" fretboard radius.
* 25.5" scale.
* 22 medium-jumbo frets.
* Modern C neck shape.
* Swamp Ash Stratorcaster-style solid body, rear routed or maybe a [[carved top|http://www.usacustomguitars.com/carvedtop-s.html]].
* Transparent blue body finish.
* All black hardware (tuners, switches, knobs, pup covers, bridge, etc).
* Seymour Duncan California 50's RW/RP pickups - not sure, keep changing my mind on this.  Bridge humbucker?
* Wilkinson tremolo bridge w/ push-in bar.
* Fully shielded and properly grounded wiring.
* Pickup switching to include standard Strat modes plus extras such as bridge+neck, all on, series/parallel, etc -- ([[some ideas|http://alexplorer.net/guitar/]]). 
* Hardshell case.
!!!Cost
Here's how much this guitar might cost to build...  &nbsp;[[cost analysis spreadsheet|http://www.geocities.com/kellinwood/dream_guitar_cost.html]].
!!!Alternatives
Several people have suggested buying an off-the-shelf guitar instead of building one. &nbsp;Here's a list of some [[commercial alternatives|Commercial Alternatives to My Custom Guitar]] that either meet the specs above, or get pretty close.



Five years ago I bought my first electric guitar for $140.00 -- a 20th Anniversary Edition Squire Stratocaster.&nbsp; Last year I finally "upgraded" to a Line 6 Variax 600.&nbsp; Although the Variax 600 is a much higher quality instrument, it did little to satisfy my urge to acquire more guitars. &nbsp;In fact it had quite the opposite effect -- I began thinking of the Squire as a spare guitar which could be customized by upgrading its parts. &nbsp;At first I thought I would customize in phases -- replacing the neck, then the body, and finally the electronics -- eventually resulting in a completely new guitar. &nbsp;On the plus side financing is easier when spending $500-$600 per phase over time and also eliminates the need to justify a one-time $1600 guitar purchase to my wife.&nbsp; But sometimes I get nervous about buying a neck for the Squire and then moving it to a custom-ordered body later -- a strategy my guitar tech has also warned against. &nbsp;Something about the neck pocket on Squires being non-standard due to the large variety of manufacturing locations, he says. &nbsp;So I've been waffling back and forth between a plan to [[tweak the Squire|Squire Upgrade Project]] and building my [[dream guitar|Dream Guitar Project]].

[[2008 Guitar Project]]
[[Squire Upgrade Project]]
[[Dream Guitar Project Details|Dream Guitar Project]]
[[Bodies & Neck Supplier List|Custom Guitar Bodies and Necks]]
[[Guitar Part Supplier List|Guitar Part Suppliers]]
[[Guitar Building/Modification Links]]
[[Guitar Tech Tips]]


|!Link |!Description |
|[[Project Guitar|http://www.projectguitar.com]] |Lots of information on setup, modification, building. &nbsp;The good links are at the bottom of the page. |
|[[Alexplorer's Axe Hacks|http://alexplorer.net/guitar/]] |All sorts of info on modifying guitar electronics. |
|[[Guitar Nuts|http://www.guitarnuts.com/index.php]] |Guitar wiring, shielding and more. |
Here's a very short list of guitar suppliers of guitar parts.  I'm getting lazy or this list might be longer.

|!Name |!Description |
|[[Guitar Fetish|http://www.guitarfetish.com]] |Low cost supplier of parts.  &nbsp;Nice web site.  &nbsp;Prices seem too good to be true. |
|[[Stewart Macdonald|http://www.stewmac.com]] |Everything for building and repairing strings instruments. |
|[[AllParts|http://www.allparts.com]] | |
|[[GuitarElectronics.com|http://www.guitarelectronics.com]] |Lots of electronic related parts for guitar. |
|[[Kinman Pickups|http://www.kinman.com/]] |Noiseless pickups for Strats and Teles plus lots of information on guitar tone. |
Collection of tips on guitar setup...

[[Pickup Height|http://www.ibanezrules.com/tech/setup/pickup_height.htm]]
Here's some recent activity in the beer brewing department.  My brewing partner is German Hernandez.

!!! Evil Monkey Pale Ale - Dec 2, 2007
This recipe is almost identical to our last batch brewed over 2 years ago.  The only difference is in the type and amount of hops -- the last batch ended up a little too bitter since the London ale yeast results in a relatively dry beer.  This time we've reduced the bittering units to get a result more balanced with the residual sugars.
* 2.5 gallons tap water for the boil
* 6lbs Alexander Light Malt Extract
* 1oz Kent Goldings hop pellets, 6.0% acid for 60 minutes
* 1oz Kent Goldings hop pellets, 6.0% acid for 30 minutes
* 1oz Kent Goldings hop pellets, 6.0% acid for 0 minutes (added right before we transferred the wort to the fermenter)
* 2.5+ gallons of Arrowhead bottled water added to the carboy
* 28 ~IBUs calculated
* Original gravity measured at 1040
* London ale yeast (Wyeast #1028)

To get the wort down to pitching temperature we put the carboy in a 40 gallon trash bin with water and 7lbs of ice.  Eight hours later the yeast was added.

!!! Bottling - December 16th

Final gravity measured at 1012.  German named it "Evil Monkey Pale Ale".   It tastes good now and should be great in about 4-6 weeks.
/***
|''Name:''|LegacyStrikeThroughPlugin|
|''Description:''|Support for legacy (pre 2.1) strike through formatting|
|''Version:''|1.0.2|
|''Date:''|Jul 21, 2006|
|''Source:''|http://www.tiddlywiki.com/#LegacyStrikeThroughPlugin|
|''Author:''|MartinBudden (mjbudden (at) gmail (dot) com)|
|''License:''|[[BSD open source license]]|
|''CoreVersion:''|2.1.0|
***/

//{{{
// Ensure that the LegacyStrikeThrough Plugin is only installed once.
if(!version.extensions.LegacyStrikeThroughPlugin) {
version.extensions.LegacyStrikeThroughPlugin = {installed:true};

config.formatters.push(
{
	name: "legacyStrikeByChar",
	match: "==",
	termRegExp: /(==)/mg,
	element: "strike",
	handler: config.formatterHelpers.createElementAndWikify
});

} //# end of "install only once"
//}}}
[[About Me]]
[[Guitar]]
[[Software|Software Projects]]
[[Favorites|My Favorite Things]]
[[Homebrew]]

New favorite stuff I've "discovered"

!!!2008
* [[Guitar Refinishing and Restoration Forum|http://www.reranch.com/reranch/viewforum.php?f=1]]
* My Fender Deluxe Reverb Reissue, purchased from craigslist.com
* [[iMacros|http://www.iopus.com/imacros/home/fx/welcome.htm]]
* [[Greasemonkey|https://addons.mozilla.org/en-US/firefox/addon/748]]

!!!2007
* [[TiddlyWiki|http://www.tiddlywiki.com]] - if you're reading this you're running it!
* [[Sweet Baby Ray's Barbecue Sauce|http://www.sweetbabyrays.com/]] - the sauce behind [[Versailles|http://www.versaillescuban.com]] great BBQ chicken.
* [[Facebook|http://www.facebook.com]]
* Text Messaging
** [[Google SMS|http://www.google.com/intl/en_us/mobile/sms]]
** [[Facebook Mobile|http://www.facebook.com/apps/application.php?id=2915120374&b]]
** [[SportsAlert.net|http://sportsalert.net]]
* [[Ruby|http://www.ruby-lang.org/]], and [[Ruby on Rails|http://www.rubyonrails.org/]]
** ~ActiveRecord is way cool, check out [[this tutorial|http://www.railsenvy.com/2007/8/8/activerecord-tutorial]] 

!!! 2006
* [[Variax 600|http://line6.com/variax]] and the [[PODxt Live|http://line6.com/podxtlive]]
* KCRW and NPR Podcasts
* [[Debian Linux|http://www.debian.org]]
* Toyota Prius
more data points for the information age
Ken Ellinwood
Sometimes I use my spare time to write software.  &nbsp;Here are some of my creations:
|bgcolor(#e0e0ff): Project Name |bgcolor(#e0e0ff): Link |bgcolor(#e0e0ff): Description |
|Simfish |http://www.geocities.com/kellinwood/simfish |A simple predator/prey simulation implemented as a Java Applet. |
|~FluidGUI |http://fluidgui.sourceforge.net |A GUI for the ~FluidSynth sound-font based synthesizer. Implemented in Java. |
|~RawMIDI2SMF |http://www.geocities.com/kellinwood/rawmidi2smf |Converts raw midi generated by the Linux 'amidi' utility into a Standard MIDI File. |
|Starboard Tack Scoring |http://sts.sourceforge.net |A yacht race/series scoring program. STS is ~RRS2005-2008 Appendix A compliant. |
|jpmidi |http://www.geocities.com/kellinwood/jpmidi |A simple Jack-based command line MIDI sequencer. |
At one point I was going to upgrade the Squier Strat.  Here are the 'before' pics and audio recordings.   After getting off enough paint to realize that the body is non-refinishable, I abandoned this project in favor of assembling a completely new guitar.   I'm thinking of refinishing the body in a solid color.  So far I like the (low cost) suggestion to use [[Deft Aerosol Lacquer|http://www.deftfinishes.com/trade/OurProducts/details.cfm?ProductID=4]] over [[Krylon Interior/Exterior Spray Paint|http://www.krylon.com/main/product_template.cfm?levelid=5&sub_levelid=9&productid=1745&content=product_details]].   Apparently the two products are chemically compatible.   Sanding sealer would be applied before the paint, of course.

!!! Pics
''Before''
[img[Front View|http://www.geocities.com/kellinwood/squire/before/small/front.jpg][http://www.geocities.com/kellinwood/squire/before/front.jpg]] &nbsp;[img[Angled View|http://www.geocities.com/kellinwood/squire/before/small/front_angled.jpg][http://www.geocities.com/kellinwood/squire/before/front_angled.jpg]] &nbsp;[img[Body Front|http://www.geocities.com/kellinwood/squire/before/small/body_front_close.jpg][http://www.geocities.com/kellinwood/squire/before/body_front_close.jpg]] &nbsp;[img[Body Rear|http://www.geocities.com/kellinwood/squire/before/small/body_rear_close.jpg][http://www.geocities.com/kellinwood/squire/before/body_rear_close.jpg]] &nbsp;[img[Headstock|http://www.geocities.com/kellinwood/squire/before/small/headstock.jpg][http://www.geocities.com/kellinwood/squire/before/headstock.jpg]]

!!! Audio

The recordings in each row were made with the same equipment and settings.

|bgcolor(#e0e0ff): Description |bgcolor(#e0e0ff): Before |bgcolor(#e0e0ff): After |
|Just handling the guitar without much playing to demonstrate how noisy or silent the guitar is.  The Variax comparison reveals just how much room for improvement there is. |[[squire_noise.mp3|http://www.geocities.com/kellinwood/squire/before/squire_noise.mp3]]  [[variax_silence.mp3|http://www.geocities.com/kellinwood/squire/before/variax_silence.mp3]] | |
|Shine on You Crazy Diamond intro played using the neck pickup.  |[[shine_on_intro.mp3|http://www.geocities.com/kellinwood/squire/before/neck_pickup_shine_on_intro.mp3]] | |
|Neck+middle pickups |[[hideaway.mp3|http://www.geocities.com/kellinwood/squire/before/neck_middle_hideaway.mp3]] | |
|Middle pickup |[[ram_bunk_shush.mp3|http://www.geocities.com/kellinwood/squire/before/middle_ram_bunk_shush.mp3]] | |
|Bridge pickup |[[penetration.mp3|http://www.geocities.com/kellinwood/squire/before/bridge_penetration.mp3]] | |
http://www.tiddlywiki.com/
section of the TiddlyWiki HTML file", MarkupPostBody: "This tiddler is inserted at the end of the
section of the TiddlyWiki HTML file immediately before the script block", OptionsPanel: "This shadow tiddler is used as the contents of the options panel slider in the right-hand sidebar", PageTemplate: "The HTML template in this shadow tiddler determines the overall ~TiddlyWiki layout", PluginManager: "This shadow tiddler provides access to the plugin manager", SideBarOptions: "This shadow tiddler is used as the contents of the option panel in the right-hand sidebar", SideBarTabs: "This shadow tiddler is used as the contents of the tabs panel in the right-hand sidebar", SiteSubtitle: "This shadow tiddler is used as the second part of the page title", SiteTitle: "This shadow tiddler is used as the first part of the page title", SiteUrl: "This shadow tiddler should be set to the full target URL for publication", StyleSheetColours: "This shadow tiddler contains CSS definitions related to the color of page elements", StyleSheet: "This tiddler can contain custom CSS definitions", StyleSheetLayout: "This shadow tiddler contains CSS definitions related to the layout of page elements", StyleSheetLocale: "This shadow tiddler contains CSS definitions related to the translation locale", StyleSheetPrint: "This shadow tiddler contains CSS definitions for printing", TabAll: "This shadow tiddler contains the contents of the 'All' tab in the right-hand sidebar", TabMore: "This shadow tiddler contains the contents of the 'More' tab in the right-hand sidebar", TabMoreMissing: "This shadow tiddler contains the contents of the 'Missing' tab in the right-hand sidebar", TabMoreOrphans: "This shadow tiddler contains the contents of the 'Orphans' tab in the right-hand sidebar", TabMoreShadowed: "This shadow tiddler contains the contents of the 'Shadowed' tab in the right-hand sidebar", TabTags: "This shadow tiddler contains the contents of the 'Tags' tab in the right-hand sidebar", TabTimeline: "This shadow tiddler contains the contents of the 'Timeline' tab in the right-hand sidebar", ViewTemplate: "The HTML template in this shadow tiddler determines how tiddlers look" }); //-- //-- Main //-- var params = null; // Command line parameters var store = null; // TiddlyWiki storage var story = null; // Main story var formatter = null; // Default formatters for the wikifier config.parsers = {}; // Hashmap of alternative parsers for the wikifier var anim = new Animator(); // Animation engine var readOnly = false; // Whether we're in readonly mode var highlightHack = null; // Embarrassing hack department... var hadConfirmExit = false; // Don't warn more than once var safeMode = false; // Disable all plugins and cookies var installedPlugins = []; // Information filled in when plugins are executed var startingUp = false; // Whether we're in the process of starting up var pluginInfo,tiddler; // Used to pass information to plugins in loadPlugins() // Whether to use the JavaSaver applet var useJavaSaver = config.browser.isSafari || config.browser.isOpera; // Starting up function main() { var t9,t8,t7,t6,t5,t4,t3,t2,t1,t0 = new Date(); startingUp = true; window.onbeforeunload = function(e) {if(window.confirmExit) return confirmExit();}; params = getParameters(); if(params) params = params.parseParams("open",null,false); store = new TiddlyWiki(); invokeParamifier(params,"oninit"); story = new Story("tiddlerDisplay","tiddler"); addEvent(document,"click",Popup.onDocumentClick); saveTest(); loadOptionsCookie(); for(var s=0; s 0) return verifyTail(plugin,false,config.messages.pluginVersionError); } return true; } function isPluginEnabled(plugin) { if(plugin.tiddler.isTagged("systemConfigDisable")) return verifyTail(plugin,false,config.messages.pluginDisabled); return true; } function verifyTail(plugin,result,message) { plugin.log.push(message); return result; } function invokeMacro(place,macro,params,wikifier,tiddler) { try { var m = config.macros[macro]; if(m && m.handler) m.handler(place,macro,params.readMacroParams(),wikifier,params,tiddler); else createTiddlyError(place,config.messages.macroError.format([macro]),config.messages.macroErrorDetails.format([macro,config.messages.missingMacro])); } catch(ex) { createTiddlyError(place,config.messages.macroError.format([macro]),config.messages.macroErrorDetails.format([macro,ex.toString()])); } } //-- //-- Paramifiers //-- function getParameters() { var p = null; if(window.location.hash) { p = decodeURI(window.location.hash.substr(1)); if(config.browser.firefoxDate != null && config.browser.firefoxDate[1] < "20051111") p = convertUTF8ToUnicode(p); } return p; } function invokeParamifier(params,handler) { if(!params || params.length == undefined || params.length <= 1) return; for(var t=1; t") { // Colspan colSpanCount++; w.nextMatch = this.cellRegExp.lastIndex-1; } else if(cellMatch[2]) { // End of row if(prevCell && colSpanCount > 1) { prevCell.setAttribute("colspan",colSpanCount); prevCell.setAttribute("colSpan",colSpanCount); // Needed for IE } w.nextMatch = this.cellRegExp.lastIndex; break; } else { // Cell w.nextMatch++; var styles = config.formatterHelpers.inlineCssHelper(w); var spaceLeft = false; var chr = w.source.substr(w.nextMatch,1); while(chr == " ") { spaceLeft = true; w.nextMatch++; chr = w.source.substr(w.nextMatch,1); } var cell; if(chr == "!") { cell = createTiddlyElement(e,"th"); w.nextMatch++; } else { cell = createTiddlyElement(e,"td"); } prevCell = cell; prevColumns[col] = {rowSpanCount:1,element:cell}; if(colSpanCount > 1) { cell.setAttribute("colspan",colSpanCount); cell.setAttribute("colSpan",colSpanCount); // Needed for IE colSpanCount = 1; } config.formatterHelpers.applyCssHelper(cell,styles); w.subWikifyTerm(cell,this.cellTermRegExp); if(w.matchText.substr(w.matchText.length-2,1) == " ") // spaceRight cell.align = spaceLeft ? "center" : "left"; else if(spaceLeft) cell.align = "right"; w.nextMatch--; } col++; this.cellRegExp.lastIndex = w.nextMatch; cellMatch = this.cellRegExp.exec(w.source); } } }, { name: "heading", match: "^!{1,6}", termRegExp: /(\n)/mg, handler: function(w) { w.subWikifyTerm(createTiddlyElement(w.output,"h" + w.matchLength),this.termRegExp); } }, { name: "list", match: "^(?:[\\*#;:]+)", lookaheadRegExp: /^(?:(?:(\*)|(#)|(;)|(:))+)/mg, termRegExp: /(\n)/mg, handler: function(w) { var stack = [w.output]; var currLevel = 0, currType = null; var listLevel, listType, itemType, baseType; w.nextMatch = w.matchStart; this.lookaheadRegExp.lastIndex = w.nextMatch; var lookaheadMatch = this.lookaheadRegExp.exec(w.source); while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) { if(lookaheadMatch[1]) { listType = "ul"; itemType = "li"; } else if(lookaheadMatch[2]) { listType = "ol"; itemType = "li"; } else if(lookaheadMatch[3]) { listType = "dl"; itemType = "dt"; } else if(lookaheadMatch[4]) { listType = "dl"; itemType = "dd"; } if (!baseType) baseType = listType; listLevel = lookaheadMatch[0].length; w.nextMatch += lookaheadMatch[0].length; var t; if(listLevel > currLevel) { for(t=currLevel; tlistLevel; t--) stack.pop(); } else if(listLevel == currLevel && listType != currType) { stack.pop(); stack.push(createTiddlyElement(stack[stack.length-1].lastChild,listType)); } currLevel = listLevel; currType = listType; var e = createTiddlyElement(stack[stack.length-1],itemType); w.subWikifyTerm(e,this.termRegExp); this.lookaheadRegExp.lastIndex = w.nextMatch; lookaheadMatch = this.lookaheadRegExp.exec(w.source); } } }, { name: "quoteByBlock", match: "^<<<\\n", termRegExp: /(^<<<(\n|$))/mg, element: "blockquote", handler: config.formatterHelpers.createElementAndWikify }, { name: "quoteByLine", match: "^>+", lookaheadRegExp: /^>+/mg, termRegExp: /(\n)/mg, element: "blockquote", handler: function(w) { var stack = [w.output]; var currLevel = 0; var newLevel = w.matchLength; var t; do { if(newLevel > currLevel) { for(t=currLevel; tnewLevel; t--) stack.pop(); } currLevel = newLevel; w.subWikifyTerm(stack[stack.length-1],this.termRegExp); createTiddlyElement(stack[stack.length-1],"br"); this.lookaheadRegExp.lastIndex = w.nextMatch; var lookaheadMatch = this.lookaheadRegExp.exec(w.source); var matched = lookaheadMatch && lookaheadMatch.index == w.nextMatch; if(matched) { newLevel = lookaheadMatch[0].length; w.nextMatch += lookaheadMatch[0].length; } } while(matched); } }, { name: "rule", match: "^----+$\\n?", handler: function(w) { createTiddlyElement(w.output,"hr"); } }, { name: "monospacedByLine", match: "^\\{\\{\\{\\n", lookaheadRegExp: /^\{\{\{\n((?:^[^\n]*\n)+?)(^\}\}\}$\n?)/mg, element: "pre", handler: config.formatterHelpers.enclosedTextHelper }, { name: "monospacedByLineForCSS", match: "^/\\*\\{\\{\\{\\*/\\n", lookaheadRegExp: /\/\*\{\{\{\*\/\n*((?:^[^\n]*\n)+?)(\n*^\/\*\}\}\}\*\/$\n?)/mg, element: "pre", handler: config.formatterHelpers.enclosedTextHelper }, { name: "monospacedByLineForPlugin", match: "^//\\{\\{\\{\\n", lookaheadRegExp: /^\/\/\{\{\{\n\n*((?:^[^\n]*\n)+?)(\n*^\/\/\}\}\}$\n?)/mg, element: "pre", handler: config.formatterHelpers.enclosedTextHelper }, { name: "monospacedByLineForTemplate", match: "^\\n", lookaheadRegExp: /\n*((?:^[^\n]*\n)+?)(\n*^$\n?)/mg, element: "pre", handler: config.formatterHelpers.enclosedTextHelper }, { name: "wikifyCommentForPlugin", match: "^/\\*\\*\\*\\n", termRegExp: /(^\*\*\*\/\n)/mg, handler: function(w) { w.subWikifyTerm(w.output,this.termRegExp); } }, { name: "wikifyCommentForTemplate", match: "^\n)/mg, handler: function(w) { w.subWikifyTerm(w.output,this.termRegExp); } }, { name: "macro", match: "<<", lookaheadRegExp: /<<([^>\s]+)(?:\s*)((?:[^>]|(?:>(?!>)))*)>>/mg, handler: function(w) { this.lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = this.lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart && lookaheadMatch[1]) { w.nextMatch = this.lookaheadRegExp.lastIndex; invokeMacro(w.output,lookaheadMatch[1],lookaheadMatch[2],w,w.tiddler); } } }, { name: "prettyLink", match: "\\[\\[", lookaheadRegExp: /\[\[(.*?)(?:\|(~)?(.*?))?\]\]/mg, handler: function(w) { this.lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = this.lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { var e; var text = lookaheadMatch[1]; if(lookaheadMatch[3]) { // Pretty bracketted link var link = lookaheadMatch[3]; e = (!lookaheadMatch[2] && config.formatterHelpers.isExternalLink(link)) ? createExternalLink(w.output,link) : createTiddlyLink(w.output,link,false,null,w.isStatic,w.tiddler); } else { // Simple bracketted link e = createTiddlyLink(w.output,text,false,null,w.isStatic,w.tiddler); } createTiddlyText(e,text); w.nextMatch = this.lookaheadRegExp.lastIndex; } } }, { name: "unWikiLink", match: config.textPrimitives.unWikiLink+config.textPrimitives.wikiLink, handler: function(w) { w.outputText(w.output,w.matchStart+1,w.nextMatch); } }, { name: "wikiLink", match: config.textPrimitives.wikiLink, handler: function(w) { if(w.matchStart > 0) { var preRegExp = new RegExp(config.textPrimitives.anyLetterStrict,"mg"); preRegExp.lastIndex = w.matchStart-1; var preMatch = preRegExp.exec(w.source); if(preMatch.index == w.matchStart-1) { w.outputText(w.output,w.matchStart,w.nextMatch); return; } } if(w.autoLinkWikiWords == true || store.isShadowTiddler(w.matchText)) { var link = createTiddlyLink(w.output,w.matchText,false,null,w.isStatic,w.tiddler); w.outputText(link,w.matchStart,w.nextMatch); } else { w.outputText(w.output,w.matchStart,w.nextMatch); } } }, { name: "urlLink", match: config.textPrimitives.urlPattern, handler: function(w) { w.outputText(createExternalLink(w.output,w.matchText),w.matchStart,w.nextMatch); } }, { name: "image", match: "\\[[<>]?[Ii][Mm][Gg]\\[", lookaheadRegExp: /\[([<]?)(>?)[Ii][Mm][Gg]\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg, handler: function(w) { this.lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = this.lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { var e = w.output; if(lookaheadMatch[5]) { var link = lookaheadMatch[5]; e = config.formatterHelpers.isExternalLink(link) ? createExternalLink(w.output,link) : createTiddlyLink(w.output,link,false,null,w.isStatic,w.tiddler); addClass(e,"imageLink"); } var img = createTiddlyElement(e,"img"); if(lookaheadMatch[1]) img.align = "left"; else if(lookaheadMatch[2]) img.align = "right"; if(lookaheadMatch[3]) img.title = lookaheadMatch[3]; img.src = lookaheadMatch[4]; w.nextMatch = this.lookaheadRegExp.lastIndex; } } }, { name: "html", match: "<[Hh][Tt][Mm][Ll]>", lookaheadRegExp: /<[Hh][Tt][Mm][Ll]>((?:.|\n)*?)<\/[Hh][Tt][Mm][Ll]>/mg, handler: function(w) { this.lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = this.lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { createTiddlyElement(w.output,"span").innerHTML = lookaheadMatch[1]; w.nextMatch = this.lookaheadRegExp.lastIndex; } } }, { name: "commentByBlock", match: "/%", lookaheadRegExp: /\/%((?:.|\n)*?)%\//mg, handler: function(w) { this.lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = this.lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) w.nextMatch = this.lookaheadRegExp.lastIndex; } }, { name: "boldByChar", match: "''", termRegExp: /('')/mg, element: "strong", handler: config.formatterHelpers.createElementAndWikify }, { name: "italicByChar", match: "//", termRegExp: /(\/\/)/mg, element: "em", handler: config.formatterHelpers.createElementAndWikify }, { name: "underlineByChar", match: "__", termRegExp: /(__)/mg, element: "u", handler: config.formatterHelpers.createElementAndWikify }, { name: "strikeByChar", match: "--(?!\\s|$)", termRegExp: /((?!\s)--|(?=\n\n))/mg, element: "strike", handler: config.formatterHelpers.createElementAndWikify }, { name: "superscriptByChar", match: "\\^\\^", termRegExp: /(\^\^)/mg, element: "sup", handler: config.formatterHelpers.createElementAndWikify }, { name: "subscriptByChar", match: "~~", termRegExp: /(~~)/mg, element: "sub", handler: config.formatterHelpers.createElementAndWikify }, { name: "monospacedByChar", match: "\\{\\{\\{", lookaheadRegExp: /\{\{\{((?:.|\n)*?)\}\}\}/mg, handler: function(w) { this.lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = this.lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { createTiddlyElement(w.output,"code",null,null,lookaheadMatch[1]); w.nextMatch = this.lookaheadRegExp.lastIndex; } } }, { name: "styleByChar", match: "@@", termRegExp: /(@@)/mg, handler: function(w) { var e = createTiddlyElement(w.output,"span"); var styles = config.formatterHelpers.inlineCssHelper(w); if(styles.length == 0) e.className = "marked"; else config.formatterHelpers.applyCssHelper(e,styles); w.subWikifyTerm(e,this.termRegExp); } }, { name: "lineBreak", match: "\\n|
", handler: function(w) { createTiddlyElement(w.output,"br"); } }, { name: "rawText", match: "\\\"{3}|", lookaheadRegExp: /(?:\"{3}|)((?:.|\n)*?)(?:\"{3}|<\/nowiki>)/mg, handler: function(w) { this.lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = this.lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { createTiddlyElement(w.output,"span",null,null,lookaheadMatch[1]); w.nextMatch = this.lookaheadRegExp.lastIndex; } } }, { name: "mdash", match: "--", handler: function(w) { createTiddlyElement(w.output,"span").innerHTML = "—"; } }, { name: "htmlEntitiesEncoding", match: "(?:(?:&#?[a-zA-Z0-9]{2,8};|.)(?:&#?(?:x0*(?:3[0-6][0-9a-fA-F]|1D[c-fC-F][0-9a-fA-F]|20[d-fD-F][0-9a-fA-F]|FE2[0-9a-fA-F])|0*(?:76[89]|7[7-9][0-9]|8[0-7][0-9]|761[6-9]|76[2-7][0-9]|84[0-3][0-9]|844[0-7]|6505[6-9]|6506[0-9]|6507[0-1]));)+|&#?[a-zA-Z0-9]{2,8};)", handler: function(w) { createTiddlyElement(w.output,"span").innerHTML = w.matchText; } }, { name: "customClasses", match: "\\{\\{", termRegExp: /(\}\}\})/mg, lookaheadRegExp: /\{\{[\s]*([\w]+[\s\w]*)[\s]*\{(\n?)/mg, handler: function(w) { this.lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = this.lookaheadRegExp.exec(w.source); if(lookaheadMatch) { var e = createTiddlyElement(w.output,lookaheadMatch[2] == "\n" ? "div" : "span",null,lookaheadMatch[1]); w.nextMatch = this.lookaheadRegExp.lastIndex; w.subWikifyTerm(e,this.termRegExp); } } } ]; //-- //-- Wikifier //-- function getParser(tiddler,format) { if(tiddler) { if(!format) format = tiddler.fields["wikiformat"]; var i; if(format) { for(i in config.parsers) { if(format == config.parsers[i].format) return config.parsers[i]; } } else { for(i in config.parsers) { if(tiddler.isTagged(config.parsers[i].formatTag)) return config.parsers[i]; } } } return formatter; } function wikify(source,output,highlightRegExp,tiddler) { if(source && source != "") { var wikifier = new Wikifier(source,getParser(tiddler),highlightRegExp,tiddler); wikifier.subWikifyUnterm(output); } } function wikifyStatic(source,highlightRegExp,tiddler,format) { var e = createTiddlyElement(document.body,"div"); e.style.display = "none"; var html = ""; if(source && source != "") { var wikifier = new Wikifier(source,getParser(tiddler,format),highlightRegExp,tiddler); wikifier.isStatic = true; wikifier.subWikifyUnterm(e); html = e.innerHTML; removeNode(e); } return html; } function wikifyPlain(title,theStore,limit) { if(!theStore) theStore = store; if(theStore.tiddlerExists(title) || theStore.isShadowTiddler(title)) { return wikifyPlainText(theStore.getTiddlerText(title),limit,tiddler); } else { return ""; } } function wikifyPlainText(text,limit,tiddler) { if(limit > 0) text = text.substr(0,limit); var wikifier = new Wikifier(text,formatter,null,tiddler); return wikifier.wikifyPlain(); } function highlightify(source,output,highlightRegExp,tiddler) { if(source && source != "") { var wikifier = new Wikifier(source,formatter,highlightRegExp,tiddler); wikifier.outputText(output,0,source.length); } } function Wikifier(source,formatter,highlightRegExp,tiddler) { this.source = source; this.output = null; this.formatter = formatter; this.nextMatch = 0; this.autoLinkWikiWords = tiddler && tiddler.autoLinkWikiWords() == false ? false : true; this.highlightRegExp = highlightRegExp; this.highlightMatch = null; this.isStatic = false; if(highlightRegExp) { highlightRegExp.lastIndex = 0; this.highlightMatch = highlightRegExp.exec(source); } this.tiddler = tiddler; } Wikifier.prototype.wikifyPlain = function() { var e = createTiddlyElement(document.body,"div"); this.subWikify(e); var text = getPlainText(e); removeNode(e); return text; }; Wikifier.prototype.subWikify = function(output,terminator) { if(terminator) this.subWikifyTerm(output,new RegExp("(" + terminator + ")","mg")); else this.subWikifyUnterm(output); }; Wikifier.prototype.subWikifyUnterm = function(output) { // subWikify() can be indirectly recursive, so we need to save the old output pointer var oldOutput = this.output; this.output = output; this.formatter.formatterRegExp.lastIndex = this.nextMatch; var formatterMatch = this.formatter.formatterRegExp.exec(this.source); while(formatterMatch) { // Output any text before the match if(formatterMatch.index > this.nextMatch) this.outputText(this.output,this.nextMatch,formatterMatch.index); // Set the match parameters for the handler this.matchStart = formatterMatch.index; this.matchLength = formatterMatch[0].length; this.matchText = formatterMatch[0]; this.nextMatch = this.formatter.formatterRegExp.lastIndex; for(var t=1; t this.nextMatch) this.outputText(this.output,this.nextMatch,terminatorMatch.index); this.matchText = terminatorMatch[1]; this.matchLength = terminatorMatch[1].length; this.matchStart = terminatorMatch.index; this.nextMatch = this.matchStart + this.matchLength; this.output = oldOutput; return; } if(formatterMatch.index > this.nextMatch) this.outputText(this.output,this.nextMatch,formatterMatch.index); this.matchStart = formatterMatch.index; this.matchLength = formatterMatch[0].length; this.matchText = formatterMatch[0]; this.nextMatch = this.formatter.formatterRegExp.lastIndex; for(var t=1; t startPos) && (this.highlightMatch.index < endPos) && (startPos < endPos)) { if(this.highlightMatch.index > startPos) { createTiddlyText(place,this.source.substring(startPos,this.highlightMatch.index)); startPos = this.highlightMatch.index; } var highlightEnd = Math.min(this.highlightRegExp.lastIndex,endPos); var theHighlight = createTiddlyElement(place,"span",null,"highlight",this.source.substring(startPos,highlightEnd)); startPos = highlightEnd; if(startPos >= this.highlightRegExp.lastIndex) this.highlightMatch = this.highlightRegExp.exec(this.source); } if(startPos < endPos) { createTiddlyText(place,this.source.substring(startPos,endPos)); } }; //-- //-- Macro definitions //-- config.macros.today.handler = function(place,macroName,params) { var now = new Date(); var text; if(params[0]) text = now.formatString(params[0].trim()); else text = now.toLocaleString(); createTiddlyElement(place,"span",null,null,text); }; config.macros.version.handler = function(place) { createTiddlyElement(place,"span",null,null,version.major + "." + version.minor + "." + version.revision + (version.beta ? " (beta " + version.beta + ")" : "")); }; config.macros.list.handler = function(place,macroName,params) { var type = params[0] ? params[0] : "all"; var list = document.createElement("ul"); place.appendChild(list); if(this[type].prompt) createTiddlyElement(list,"li",null,"listTitle",this[type].prompt); var results; if(this[type].handler) results = this[type].handler(params); for(var t = 0; t < results.length; t++) { var li = document.createElement("li"); list.appendChild(li); createTiddlyLink(li,typeof results[t] == "string" ? results[t] : results[t].title,true); } }; config.macros.list.all.handler = function(params) { return store.reverseLookup("tags","excludeLists",false,"title"); }; config.macros.list.missing.handler = function(params) { return store.getMissingLinks(); }; config.macros.list.orphans.handler = function(params) { return store.getOrphans(); }; config.macros.list.shadowed.handler = function(params) { return store.getShadowed(); }; config.macros.list.touched.handler = function(params) { return store.getTouched(); }; config.macros.allTags.handler = function(place,macroName,params) { var tags = store.getTags(params[0]); var ul = createTiddlyElement(place,"ul"); if(tags.length == 0) createTiddlyElement(ul,"li",null,"listTitle",this.noTags); for(var t=0; t=last; t--) { var tiddler = tiddlers[t]; var theDay = tiddler[field].convertToLocalYYYYMMDDHHMM().substr(0,8); if(theDay != lastDay) { var theDateList = document.createElement("ul"); place.appendChild(theDateList); createTiddlyElement(theDateList,"li",null,"listTitle",tiddler[field].formatString(dateFormat)); lastDay = theDay; } var theDateListItem = createTiddlyElement(theDateList,"li",null,"listLink"); theDateListItem.appendChild(createTiddlyLink(place,tiddler.title,true)); } }; config.macros.search.handler = function(place,macroName,params) { var searchTimeout = null; var btn = createTiddlyButton(place,this.label,this.prompt,this.onClick); var txt = createTiddlyElement(place,"input",null,"txtOptionInput"); if(params[0]) txt.value = params[0]; txt.onkeyup = this.onKeyPress; txt.onfocus = this.onFocus; txt.setAttribute("size",this.sizeTextbox); txt.setAttribute("accessKey",this.accessKey); txt.setAttribute("autocomplete","off"); txt.setAttribute("lastSearchText",""); if(config.browser.isSafari) { txt.setAttribute("type","search"); txt.setAttribute("results","5"); } else { txt.setAttribute("type","text"); } }; // Global because there's only ever one outstanding incremental search timer config.macros.search.timeout = null; config.macros.search.doSearch = function(txt) { if(txt.value.length > 0) { story.search(txt.value,config.options.chkCaseSensitiveSearch,config.options.chkRegExpSearch); txt.setAttribute("lastSearchText",txt.value); } }; config.macros.search.onClick = function(e) { config.macros.search.doSearch(this.nextSibling); return false; }; config.macros.search.onKeyPress = function(ev) { var e = ev ? ev : window.event; switch(e.keyCode) { case 13: // Ctrl-Enter case 10: // Ctrl-Enter on IE PC config.macros.search.doSearch(this); break; case 27: // Escape this.value = ""; clearMessage(); break; } if(this.value.length > 2) { if(this.value != this.getAttribute("lastSearchText")) { if(config.macros.search.timeout) clearTimeout(config.macros.search.timeout); var txt = this; config.macros.search.timeout = setTimeout(function() {config.macros.search.doSearch(txt);},500); } } else { if(config.macros.search.timeout) clearTimeout(config.macros.search.timeout); } }; config.macros.search.onFocus = function(e) { this.select(); }; config.macros.tiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler) { params = paramString.parseParams("name",null,true,false,true); var names = params[0]["name"]; var tiddlerName = names[0]; var className = names[1] ? names[1] : null; var args = params[0]["with"]; var wrapper = createTiddlyElement(place,"span",null,className); if(!args) { wrapper.setAttribute("refresh","content"); wrapper.setAttribute("tiddler",tiddlerName); } var text = store.getTiddlerText(tiddlerName); if(text) { var stack = config.macros.tiddler.tiddlerStack; if(stack.indexOf(tiddlerName) !== -1) return; stack.push(tiddlerName); try { var n = args ? Math.min(args.length,9) : 0; for(var i=0; i 0) btn.setAttribute("params",tags.join("|")); btn.setAttribute("newFocus",newFocus); btn.setAttribute("newTemplate",getParam(params,"template",DEFAULT_EDIT_TEMPLATE)); if(customFields !== "") btn.setAttribute("customFields",customFields); var text = getParam(params,"text"); if(text !== undefined) btn.setAttribute("newText",text); return btn; }; config.macros.newTiddler.onClickNewTiddler = function() { var title = this.getAttribute("newTitle"); if(this.getAttribute("isJournal") == "true") { var now = new Date(); title = now.formatString(title.trim()); } var params = this.getAttribute("params"); var tags = params ? params.split("|") : []; var focus = this.getAttribute("newFocus"); var template = this.getAttribute("newTemplate"); var customFields = this.getAttribute("customFields"); story.displayTiddler(null,title,template,false,null,null); var tiddlerElem = document.getElementById(story.idPrefix + title); if(customFields) story.addCustomFields(tiddlerElem,customFields); var text = this.getAttribute("newText"); if(typeof text == "string") story.getTiddlerField(title,"text").value = text.format([title]); for(var t=0;t max) max = v; data.push(v); } if(data.length < 1) return; var box = createTiddlyElement(place,"span",null,"sparkline",String.fromCharCode(160)); box.title = data.join(","); var w = box.offsetWidth; var h = box.offsetHeight; box.style.paddingRight = (data.length * 2 - w) + "px"; box.style.position = "relative"; for(var d=0; d> config.macros.gradient.handler = function(place,macroName,params,wikifier) { var terminator = ">>"; var panel; if(wikifier) panel = createTiddlyElement(place,"div",null,"gradient"); else panel = place; panel.style.position = "relative"; panel.style.overflow = "hidden"; panel.style.zIndex = "0"; var t; if(wikifier) { var styles = config.formatterHelpers.inlineCssHelper(wikifier); config.formatterHelpers.applyCssHelper(panel,styles); } var colours = []; for(t=1; t rows) rows = lines.length + 5; rows = Math.min(rows,maxLines); e.setAttribute("rows",rows); e.setAttribute("edit",field); place.appendChild(wrapper1); } } }; config.macros.tagChooser.onClick = function(ev) { var e = ev ? ev : window.event; var lingo = config.views.editor.tagChooser; var popup = Popup.create(this); var tags = store.getTags(); if(tags.length == 0) createTiddlyText(createTiddlyElement(popup,"li"),lingo.popupNone); for(var t=0; t': var btn = createTiddlyButton(place,this.moreLabel,this.morePrompt,config.macros.toolbar.onClickMore); addClass(btn,"moreCommand"); var e = createTiddlyElement(place,"span",null,"moreCommand"); e.style.display = "none"; place = e; break; default: var theClass = ""; switch(c.substr(0,1)) { case "+": theClass = "defaultCommand"; c = c.substr(1); break; case "-": theClass = "cancelCommand"; c = c.substr(1); break; } if(c in config.commands) this.createCommand(place,c,tiddler,theClass); break; } } }; config.macros.refreshDisplay.handler = function(place) { createTiddlyButton(place,this.label,this.prompt,this.onClick); }; config.macros.refreshDisplay.onClick = function(e) { refreshAll(); return false; }; config.macros.annotations.handler = function(place,macroName,params,wikifier,paramString,tiddler) { var title = tiddler ? tiddler.title : null; var a = title ? config.annotations[title] : null; if(!tiddler || !title || !a) return; var text = a.format([title]); wikify(text,createTiddlyElement(place,"div",null,"annotation"),null,tiddler); }; //-- //-- Menu and toolbar commands //-- config.commands.closeTiddler.handler = function(event,src,title) { story.closeTiddler(title,true); return false; }; config.commands.closeOthers.handler = function(event,src,title) { story.closeAllTiddlers(title); return false; }; config.commands.editTiddler.handler = function(event,src,title) { clearMessage(); var tiddlerElem = document.getElementById(story.idPrefix + title); var fields = tiddlerElem.getAttribute("tiddlyFields"); story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE,false,null,fields); story.focusTiddler(title,"text"); return false; }; config.commands.saveTiddler.handler = function(event,src,title) { var newTitle = story.saveTiddler(title,event.shiftKey); if(newTitle) story.displayTiddler(null,newTitle); return false; }; config.commands.cancelTiddler.handler = function(event,src,title) { if(story.hasChanges(title) && !readOnly) { if(!confirm(this.warning.format([title]))) return false; } story.setDirty(title,false); story.displayTiddler(null,title); return false; }; config.commands.deleteTiddler.handler = function(event,src,title) { var deleteIt = true; if (config.options.chkConfirmDelete) deleteIt = confirm(this.warning.format([title])); if (deleteIt) { store.removeTiddler(title); story.closeTiddler(title,true); autoSaveChanges(); } return false; }; config.commands.permalink.handler = function(event,src,title) { var t = encodeURIComponent(String.encodeTiddlyLink(title)); if(window.location.hash != t) window.location.hash = t; return false; }; config.commands.references.handlePopup = function(popup,title) { var references = store.getReferringTiddlers(title); var c = false; for(var r=0; r 0) ListView.create(popup,items,this.listViewTemplate); else createTiddlyElement(popup,"div",null,null,this.emptyText); }; //-- //-- Tiddler() object //-- function Tiddler(title) { this.title = title; this.text = null; this.modifier = null; this.modified = new Date(); this.created = new Date(); this.links = []; this.linksUpdated = false; this.tags = []; this.fields = {}; return this; } Tiddler.prototype.getLinks = function() { if(this.linksUpdated==false) this.changed(); return this.links; }; // Returns the fields that are inherited in string field:"value" field2:"value2" format Tiddler.prototype.getInheritedFields = function() { var f = {}; for(i in this.fields) { if(i=="server.host" || i=="server.workspace" || i=="wikiformat"|| i=="server.type") { f[i] = this.fields[i]; } } return String.encodeHashMap(f); }; // Increment the changeCount of a tiddler Tiddler.prototype.incChangeCount = function() { var c = this.fields['changecount']; c = c ? parseInt(c) : 0; this.fields['changecount'] = String(c+1); }; // Clear the changeCount of a tiddler Tiddler.prototype.clearChangeCount = function() { if(this.fields['changecount']) { delete this.fields['changecount']; } }; // Returns true if the tiddler has been updated since the tiddler was created or downloaded Tiddler.prototype.isTouched = function() { var changeCount = this.fields['changecount']; if(changeCount === undefined) changeCount = 0; return changeCount > 0; }; // Format the text for storage in an RSS item Tiddler.prototype.saveToRss = function(url) { var s = []; s.push(""); s.push("" + this.title.htmlEncode() + ""); s.push("" + wikifyStatic(this.text,null,this).htmlEncode() + ""); for(var t=0; t" + this.tags[t] + ""); s.push("" + url + "#" + encodeURIComponent(String.encodeTiddlyLink(this.title)) + ""); s.push("" + this.modified.toGMTString() + ""); s.push(""); return s.join("\n"); }; // Change the text and other attributes of a tiddler Tiddler.prototype.set = function(title,text,modifier,modified,tags,created,fields) { this.assign(title,text,modifier,modified,tags,created,fields); this.changed(); return this; }; // Change the text and other attributes of a tiddler without triggered a tiddler.changed() call Tiddler.prototype.assign = function(title,text,modifier,modified,tags,created,fields) { if(title != undefined) this.title = title; if(text != undefined) this.text = text; if(modifier != undefined) this.modifier = modifier; if(modified != undefined) this.modified = modified; if(created != undefined) this.created = created; if(fields != undefined) this.fields = fields; if(tags != undefined) this.tags = (typeof tags == "string") ? tags.readBracketedList() : tags; else if(this.tags == undefined) this.tags = []; return this; }; // Get the tags for a tiddler as a string (space delimited, using [[brackets]] for tags containing spaces) Tiddler.prototype.getTags = function() { return String.encodeTiddlyLinkList(this.tags); }; // Test if a tiddler carries a tag Tiddler.prototype.isTagged = function(tag) { return this.tags.indexOf(tag) != -1; }; // Static method to convert "\n" to newlines, "\s" to "\" Tiddler.unescapeLineBreaks = function(text) { return text ? text.unescapeLineBreaks() : ""; }; // Convert newlines to "\n", "\" to "\s" Tiddler.prototype.escapeLineBreaks = function() { return this.text.escapeLineBreaks(); }; // Updates the secondary information (like links[] array) after a change to a tiddler Tiddler.prototype.changed = function() { this.links = []; var t = this.autoLinkWikiWords() ? 0 : 1; var tiddlerLinkRegExp = t==0 ? config.textPrimitives.tiddlerAnyLinkRegExp : config.textPrimitives.tiddlerForcedLinkRegExp; tiddlerLinkRegExp.lastIndex = 0; var formatMatch = tiddlerLinkRegExp.exec(this.text); while(formatMatch) { var lastIndex = tiddlerLinkRegExp.lastIndex; if(t==0 && formatMatch[1] && formatMatch[1] != this.title) { // wikiWordLink if(formatMatch.index > 0) { var preRegExp = new RegExp(config.textPrimitives.unWikiLink+"|"+config.textPrimitives.anyLetter,"mg"); preRegExp.lastIndex = formatMatch.index-1; var preMatch = preRegExp.exec(this.text); if(preMatch.index != formatMatch.index-1) this.links.pushUnique(formatMatch[1]); } else { this.links.pushUnique(formatMatch[1]); } } else if(formatMatch[2-t] && !config.formatterHelpers.isExternalLink(formatMatch[3-t])) // titledBrackettedLink this.links.pushUnique(formatMatch[3-t]); else if(formatMatch[4-t] && formatMatch[4-t] != this.title) // brackettedLink this.links.pushUnique(formatMatch[4-t]); tiddlerLinkRegExp.lastIndex = lastIndex; formatMatch = tiddlerLinkRegExp.exec(this.text); } this.linksUpdated = true; }; Tiddler.prototype.getSubtitle = function() { var theModifier = this.modifier; if(!theModifier) theModifier = config.messages.subtitleUnknown; var theModified = this.modified; if(theModified) theModified = theModified.toLocaleString(); else theModified = config.messages.subtitleUnknown; return config.messages.tiddlerLinkTooltip.format([this.title,theModifier,theModified]); }; Tiddler.prototype.isReadOnly = function() { return readOnly; }; Tiddler.prototype.autoLinkWikiWords = function() { return !(this.isTagged("systemConfig") || this.isTagged("excludeMissing")); }; Tiddler.prototype.generateFingerprint = function() { return "0x" + Crypto.hexSha1Str(this.text); }; Tiddler.prototype.getServerType = function() { var serverType = null; if(this.fields && this.fields['server.type']) serverType = this.fields['server.type']; if(!serverType) serverType = this.fields['wikiformat']; if(serverType && !config.adaptors[serverType]) serverType = null; return serverType; }; Tiddler.prototype.getAdaptor = function() { var serverType = this.getServerType(); if(serverType) return new config.adaptors[serverType]; else return null; }; //-- //-- TiddlyWiki() object contains Tiddler()s //-- function TiddlyWiki() { var tiddlers = {}; // Hashmap by name of tiddlers this.tiddlersUpdated = false; this.namedNotifications = []; // Array of {name:,notify:} of notification functions this.notificationLevel = 0; this.slices = {}; // map tiddlerName->(map sliceName->sliceValue). Lazy. this.clear = function() { tiddlers = {}; this.setDirty(false); }; this.fetchTiddler = function(title) { return tiddlers[title]; }; this.deleteTiddler = function(title) { delete this.slices[title]; delete tiddlers[title]; }; this.addTiddler = function(tiddler) { delete this.slices[tiddler.title]; tiddlers[tiddler.title] = tiddler; }; this.forEachTiddler = function(callback) { for(var t in tiddlers) { var tiddler = tiddlers[t]; if(tiddler instanceof Tiddler) callback.call(this,t,tiddler); } }; } TiddlyWiki.prototype.setDirty = function(dirty) { this.dirty = dirty; }; TiddlyWiki.prototype.isDirty = function() { return this.dirty; }; TiddlyWiki.prototype.suspendNotifications = function() { this.notificationLevel--; }; TiddlyWiki.prototype.resumeNotifications = function() { this.notificationLevel++; }; // Invoke the notification handlers for a particular tiddler TiddlyWiki.prototype.notify = function(title,doBlanket) { if(!this.notificationLevel) { for(var t=0; t<" + "body>" + text.substring(posDiv[0],posDiv[1] + endSaveArea.length) + "<" + "/body><" + "/html>"; // Create the iframe var iframe = document.createElement("iframe"); iframe.style.display = "none"; document.body.appendChild(iframe); var doc = iframe.document; if(iframe.contentDocument) doc = iframe.contentDocument; // For NS6 else if(iframe.contentWindow) doc = iframe.contentWindow.document; // For IE5.5 and IE6 // Put the content in the iframe doc.open(); doc.writeln(content); doc.close(); // Load the content into a TiddlyWiki() object var storeArea = doc.getElementById("storeArea"); this.loadFromDiv(storeArea,"store"); // Get rid of the iframe iframe.parentNode.removeChild(iframe); return this; }; TiddlyWiki.prototype.updateTiddlers = function() { this.tiddlersUpdated = true; this.forEachTiddler(function(title,tiddler) { tiddler.changed(); }); }; // Return all tiddlers formatted as an HTML string TiddlyWiki.prototype.allTiddlersAsHtml = function() { return store.getSaver().externalize(store); }; // Return an array of tiddlers matching a search regular expression TiddlyWiki.prototype.search = function(searchRegExp,sortField,excludeTag) { var candidates = this.reverseLookup("tags",excludeTag,false); var results = []; for(var t=0; tString value = value instanceof Date ? value.convertToYYYYMMDDHHMMSSMMM() : String(value); if(oldValue == value) return; t.fields[fieldName] = value; } } // When we are here the tiddler/store really was changed. this.notify(t.title,true); if(!fieldName.match(/^temp\./)) this.setDirty(true); }; // Returns the value of the given field of the tiddler. // The fieldName is case-insensitive. // Will only return String values (or undefined). TiddlyWiki.prototype.getValue = function(tiddler,fieldName) { var t = this.resolveTiddler(tiddler); if(!t) return undefined; fieldName = fieldName.toLowerCase(); var accessor = TiddlyWiki.standardFieldAccess[fieldName]; if(accessor) { return accessor.get(t); } return t.fields[fieldName]; }; // Calls the callback function for every field in the tiddler. // When callback function returns a non-false value the iteration stops // and that value is returned. // The order of the fields is not defined. // @param callback a function(tiddler,fieldName,value). TiddlyWiki.prototype.forEachField = function(tiddler,callback,onlyExtendedFields) { var t = this.resolveTiddler(tiddler); if(!t) return undefined; var n,result; for(n in t.fields) { result = callback(t,n,t.fields[n]); if(result) return result; } if(onlyExtendedFields) return undefined; for(n in TiddlyWiki.standardFieldAccess) { if(n == "tiddler") // even though the "title" field can also be referenced through the name "tiddler" // we only visit this field once. continue; result = callback(t,n,TiddlyWiki.standardFieldAccess[n].get(t)); if(result) return result; } return undefined; }; //-- //-- Story functions //-- function Story(container,idPrefix) { this.container = container; this.idPrefix = idPrefix; this.highlightRegExp = null; } Story.prototype.forEachTiddler = function(fn) { var place = document.getElementById(this.container); if(!place) return; var e = place.firstChild; while(e) { var n = e.nextSibling; var title = e.getAttribute("tiddler"); fn.call(this,title,e); e = n; } }; Story.prototype.displayTiddlers = function(srcElement,titles,template,animate,unused,customFields,toggle) { for(var t = titles.length-1;t>=0;t--) this.displayTiddler(srcElement,titles[t],template,animate,unused,customFields); }; Story.prototype.displayTiddler = function(srcElement,title,template,animate,unused,customFields,toggle) { var place = document.getElementById(this.container); var tiddlerElem = document.getElementById(this.idPrefix + title); if(tiddlerElem) { if(toggle) this.closeTiddler(title,true); else this.refreshTiddler(title,template,false,customFields); } else { var before = this.positionTiddler(srcElement); tiddlerElem = this.createTiddler(place,before,title,template,customFields); } if(srcElement && typeof srcElement !== "string") { if(config.options.chkAnimate && (animate == undefined || animate == true) && anim && typeof Zoomer == "function" && typeof Scroller == "function") anim.startAnimating(new Zoomer(title,srcElement,tiddlerElem),new Scroller(tiddlerElem)); else window.scrollTo(0,ensureVisible(tiddlerElem)); } }; Story.prototype.positionTiddler = function(srcElement) { var place = document.getElementById(this.container); var before = null; if(typeof srcElement == "string") { switch(srcElement) { case "top": before = place.firstChild; break; case "bottom": before = null; break; } } else { var after = this.findContainingTiddler(srcElement); if(after == null) { before = place.firstChild; } else if(after.nextSibling) { before = after.nextSibling; if(before.nodeType != 1) before = null; } } return before; }; Story.prototype.createTiddler = function(place,before,title,template,customFields) { var tiddlerElem = createTiddlyElement(null,"div",this.idPrefix + title,"tiddler"); tiddlerElem.setAttribute("refresh","tiddler"); if(customFields) tiddlerElem.setAttribute("tiddlyFields",customFields); place.insertBefore(tiddlerElem,before); var defaultText = null; if(!store.tiddlerExists(title) && !store.isShadowTiddler(title)) defaultText = this.loadMissingTiddler(title,customFields,tiddlerElem); this.refreshTiddler(title,template,false,customFields,defaultText); return tiddlerElem; }; Story.prototype.loadMissingTiddler = function(title,fields,tiddlerElem) { var tiddler = new Tiddler(title); tiddler.fields = typeof fields == "string" ? fields.decodeHashMap() : (fields ? fields : {}); var serverType = tiddler.getServerType(); var host = tiddler.fields['server.host']; var workspace = tiddler.fields['server.workspace']; if(!serverType | !host) return null; var sm = new SyncMachine(serverType,{ start: function() { return this.openHost(host,"openWorkspace"); }, openWorkspace: function() { return this.openWorkspace(workspace,"getTiddler"); }, getTiddler: function() { return this.getTiddler(title,"gotTiddler"); }, gotTiddler: function(tiddler) { if(tiddler && tiddler.text) { var downloaded = new Date(); if(!tiddler.created) tiddler.created = downloaded; if(!tiddler.modified) tiddler.modified = tiddler.created; store.saveTiddler(tiddler.title,tiddler.title,tiddler.text,tiddler.modifier,tiddler.modified,tiddler.tags,tiddler.fields,true,tiddler.created); autoSaveChanges(); } delete this; return true; }, error: function(message) { displayMessage("Error loading missing tiddler from %0: %1".format([host,message])); } }); sm.go(); return config.messages.loadingMissingTiddler.format([title,serverType,host,workspace]); }; Story.prototype.chooseTemplateForTiddler = function(title,template) { if(!template) template = DEFAULT_VIEW_TEMPLATE; if(template == DEFAULT_VIEW_TEMPLATE || template == DEFAULT_EDIT_TEMPLATE) template = config.tiddlerTemplates[template]; return template; }; Story.prototype.getTemplateForTiddler = function(title,template,tiddler) { return store.getRecursiveTiddlerText(template,null,10); }; Story.prototype.refreshTiddler = function(title,template,force,customFields,defaultText) { var tiddlerElem = document.getElementById(this.idPrefix + title); if(tiddlerElem) { if(tiddlerElem.getAttribute("dirty") == "true" && !force) return tiddlerElem; template = this.chooseTemplateForTiddler(title,template); var currTemplate = tiddlerElem.getAttribute("template"); if((template != currTemplate) || force) { var tiddler = store.getTiddler(title); if(tiddler) { var f = tiddler.fields; if(customFields) f = merge(customFields.decodeHashMap(),f); customFields = String.encodeHashMap(f); } else { tiddler = new Tiddler(); if(store.isShadowTiddler(title)) { tiddler.set(title,store.getTiddlerText(title),config.views.wikified.shadowModifier,version.date,[],version.date); } else { var text = template=="EditTemplate" ? config.views.editor.defaultText.format([title]) : config.views.wikified.defaultText.format([title]); text = defaultText ? defaultText : text; var fields = customFields ? customFields.decodeHashMap() : null; tiddler.set(title,text,config.views.wikified.defaultModifier,version.date,[],version.date,fields); } } tiddlerElem.setAttribute("tags",tiddler.tags.join(" ")); tiddlerElem.setAttribute("tiddler",title); tiddlerElem.setAttribute("template",template); var me = this; tiddlerElem.onmouseover = this.onTiddlerMouseOver; tiddlerElem.onmouseout = this.onTiddlerMouseOut; tiddlerElem.ondblclick = this.onTiddlerDblClick; tiddlerElem[window.event?"onkeydown":"onkeypress"] = this.onTiddlerKeyPress; var html = this.getTemplateForTiddler(title,template,tiddler); tiddlerElem.innerHTML = html; applyHtmlMacros(tiddlerElem,tiddler); if(store.getTaggedTiddlers(title).length > 0) addClass(tiddlerElem,"isTag"); else removeClass(tiddlerElem,"isTag"); if(!store.tiddlerExists(title)) { if(store.isShadowTiddler(title)) addClass(tiddlerElem,"shadow"); else addClass(tiddlerElem,"missing"); } else { removeClass(tiddlerElem,"shadow"); removeClass(tiddlerElem,"missing"); } if(customFields) this.addCustomFields(tiddlerElem,customFields); forceReflow(); } } return tiddlerElem; }; Story.prototype.addCustomFields = function(place,customFields) { var fields = customFields.decodeHashMap(); var w = document.createElement("div"); w.style.display = "none"; place.appendChild(w); for(var t in fields) { var e = document.createElement("input"); e.setAttribute("type","text"); e.setAttribute("value",fields[t]); w.appendChild(e); e.setAttribute("edit",t); } }; Story.prototype.refreshAllTiddlers = function() { var place = document.getElementById(this.container); var e = place.firstChild; if(!e) return; this.refreshTiddler(e.getAttribute("tiddler"),e.getAttribute("template"),true); while((e = e.nextSibling) != null) this.refreshTiddler(e.getAttribute("tiddler"),e.getAttribute("template"),true); }; Story.prototype.onTiddlerMouseOver = function(e) { if(window.addClass instanceof Function) addClass(this,"selected"); }; Story.prototype.onTiddlerMouseOut = function(e) { if(window.removeClass instanceof Function) removeClass(this,"selected"); }; Story.prototype.onTiddlerDblClick = function(ev) { var e = ev ? ev : window.event; var theTarget = resolveTarget(e); if(theTarget && theTarget.nodeName.toLowerCase() != "input" && theTarget.nodeName.toLowerCase() != "textarea") { if(document.selection && document.selection.empty) document.selection.empty(); config.macros.toolbar.invokeCommand(this,"defaultCommand",e); e.cancelBubble = true; if(e.stopPropagation) e.stopPropagation(); return true; } else { return false; } }; Story.prototype.onTiddlerKeyPress = function(ev) { var e = ev ? ev : window.event; clearMessage(); var consume = false; var title = this.getAttribute("tiddler"); var target = resolveTarget(e); switch(e.keyCode) { case 9: // Tab if(config.options.chkInsertTabs && target.tagName.toLowerCase() == "textarea") { replaceSelection(target,String.fromCharCode(9)); consume = true; } if(config.isOpera) { target.onblur = function() { this.focus(); this.onblur = null; }; } break; case 13: // Ctrl-Enter case 10: // Ctrl-Enter on IE PC case 77: // Ctrl-Enter is "M" on some platforms if(e.ctrlKey) { blurElement(this); config.macros.toolbar.invokeCommand(this,"defaultCommand",e); consume = true; } break; case 27: // Escape blurElement(this); config.macros.toolbar.invokeCommand(this,"cancelCommand",e); consume = true; break; } e.cancelBubble = consume; if(consume) { if(e.stopPropagation) e.stopPropagation(); // Stop Propagation e.returnValue = true; // Cancel The Event in IE if(e.preventDefault ) e.preventDefault(); // Cancel The Event in Moz } return !consume; }; Story.prototype.getTiddlerField = function(title,field) { var tiddlerElem = document.getElementById(this.idPrefix + title); var e = null; if(tiddlerElem != null) { var children = tiddlerElem.getElementsByTagName("*"); for(var t=0; t 0) displayMessage(config.macros.search.successMsg.format([titles.length.toString(),q + text + q])); else displayMessage(config.macros.search.failureMsg.format([q + text + q])); }; Story.prototype.findContainingTiddler = function(e) { while(e && !hasClass(e,"tiddler")) e = e.parentNode; return e; }; Story.prototype.gatherSaveFields = function(e,fields) { if(e && e.getAttribute) { var f = e.getAttribute("edit"); if(f) fields[f] = e.value.replace(/\r/mg,""); if(e.hasChildNodes()) { var c = e.childNodes; for(var t=0; t 0) { if(!confirm(config.macros.importTiddlers.confirmOverwriteText.format([overwrite.join(", ")]))) return false; } wizard.addStep(config.macros.importTiddlers.step4Title.format([rowNames.length]),config.macros.importTiddlers.step4Html); for(t=0; t si.tiddler.fields['server.page.revision']) { si.syncStatus = config.macros.sync.syncStatusList[si.isTouched ? 'changedBoth' : 'changedServer']; } } else { si.syncStatus = config.macros.sync.syncStatusList.notFound; } config.macros.sync.updateSyncStatus(si); } }, getTiddler: function(title) { return this.getTiddler(title,"onGetTiddler"); }, onGetTiddler: function(tiddler) { var syncItem = st.syncItems.findByField("title",tiddler.title); if(syncItem !== null) { syncItem = st.syncItems[syncItem]; store.saveTiddler(tiddler.title, tiddler.title, tiddler.text, tiddler.modifier, tiddler.modified, tiddler.tags, tiddler.fields, true, tiddler.created); syncItem.syncStatus = config.macros.sync.syncStatusList.gotFromServer; config.macros.sync.updateSyncStatus(syncItem); } }, putTiddler: function(tiddler) { return this.putTiddler(tiddler,"onPutTiddler"); }, onPutTiddler: function(tiddler) { var syncItem = st.syncItems.findByField("title",tiddler.title); if(syncItem !== null) { syncItem = st.syncItems[syncItem]; store.resetTiddler(tiddler.title); syncItem.syncStatus = config.macros.sync.syncStatusList.putToServer; config.macros.sync.updateSyncStatus(syncItem); } } }); st.syncMachine.go(); return st; }; config.macros.sync.updateSyncStatus = function(syncItem) { var e = syncItem.colElements["status"]; removeChildren(e); createTiddlyText(e,syncItem.syncStatus.text); syncItem.rowElement.style.backgroundColor = syncItem.syncStatus.color; }; config.macros.sync.doSync = function(e) { var rowNames = ListView.getSelectedRows(currSync.listView); for(var t=0; t=0; t--) stash.appendChild(nodes[t]); } var wrapper = document.getElementById("contentWrapper"); if(!title) title = "PageTemplate"; var html = store.getRecursiveTiddlerText(title,null,10); wrapper.innerHTML = html; applyHtmlMacros(wrapper); refreshElements(wrapper); display = document.getElementById("tiddlerDisplay"); removeChildren(display); if(!display) display = createTiddlyElement(wrapper,"div","tiddlerDisplay"); nodes = stash.childNodes; for(t=nodes.length-1; t>=0; t--) display.appendChild(nodes[t]); removeNode(stash); } function refreshDisplay(hint) { if(typeof hint == "string") hint = [hint]; var e = document.getElementById("contentWrapper"); refreshElements(e,hint); if(backstage.isPanelVisible()) { e = document.getElementById("backstage"); refreshElements(e,hint); } } function refreshPageTitle() { document.title = getPageTitle(); } function getPageTitle() { var st = wikifyPlain("SiteTitle"); var ss = wikifyPlain("SiteSubtitle"); return st + ((st == "" || ss == "") ? "" : " - ") + ss; } function refreshStyles(title,doc) { if(!doc) doc = document; setStylesheet(title == null ? "" : store.getRecursiveTiddlerText(title,"",10),title,doc); } function refreshColorPalette(title) { if(!startingUp) refreshAll(); } function refreshAll() { refreshPageTemplate(); refreshDisplay(); refreshStyles("StyleSheetLayout"); refreshStyles("StyleSheetColors"); refreshStyles("StyleSheet"); refreshStyles("StyleSheetPrint"); } //-- //-- Options cookie stuff //-- config.optionHandlers = { 'txt': { get: function(name) {return encodeCookie(config.options[name].toString());}, set: function(name,value) {config.options[name] = decodeCookie(value);} }, 'chk': { get: function(name) {return config.options[name] ? "true" : "false";}, set: function(name,value) {config.options[name] = value == "true";} } }; function loadOptionsCookie() { if(safeMode) return; var cookies = document.cookie.split(";"); for(var c=0; c'; // Split up into two so that indexOf() of this source doesn't find it var endSaveArea = ''; // If there are unsaved changes, force the user to confirm before exitting function confirmExit() { hadConfirmExit = true; if((store && store.isDirty && store.isDirty()) || (story && story.areAnyDirty && story.areAnyDirty())) return config.messages.confirmExit; } // Give the user a chance to save changes before exitting function checkUnsavedChanges() { if(store && store.isDirty && store.isDirty() && window.hadConfirmExit === false) { if(confirm(config.messages.unsavedChangesWarning)) saveChanges(); } } function updateLanguageAttribute(s) { if(config.locale) { var mRE = /(/; var m = mRE.exec(s); if(m) { var t = m[1]; if(m[2]) t += ' xml:lang="' + config.locale + '"'; if(m[3]) t += ' lang="' + config.locale + '"'; t += ">"; s = s.substr(0,m.index) + t + s.substr(m.index+m[0].length); } } return s; } function updateMarkupBlock(s,blockName,tiddlerName) { return s.replaceChunk( "".format([blockName]), "".format([blockName]), "\n" + store.getRecursiveTiddlerText(tiddlerName,"") + "\n"); } function updateOriginal(original,posDiv) { if(!posDiv) posDiv = locateStoreArea(original); if(!posDiv) { alert(config.messages.invalidFileError.format([localPath])); return null; } var revised = original.substr(0,posDiv[0] + startSaveArea.length) + "\n" + convertUnicodeToUTF8(store.allTiddlersAsHtml()) + "\n" + original.substr(posDiv[1]); var newSiteTitle = convertUnicodeToUTF8(getPageTitle()).htmlEncode(); revised = revised.replaceChunk("",""," " + newSiteTitle + " "); revised = updateLanguageAttribute(revised); revised = updateMarkupBlock(revised,"PRE-HEAD","MarkupPreHead"); revised = updateMarkupBlock(revised,"POST-HEAD","MarkupPostHead"); revised = updateMarkupBlock(revised,"PRE-BODY","MarkupPreBody"); revised = updateMarkupBlock(revised,"POST-SCRIPT","MarkupPostBody"); return revised; } function locateStoreArea(original) { // Locate the storeArea div's var posOpeningDiv = original.indexOf(startSaveArea); var limitClosingDiv = original.indexOf("<"+"!--POST-STOREAREA--"+">"); if(limitClosingDiv == -1) limitClosingDiv = original.indexOf("<"+"!--POST-BODY-START--"+">"); var posClosingDiv = original.lastIndexOf(endSaveArea,limitClosingDiv == -1 ? original.length : limitClosingDiv); return (posOpeningDiv != -1 && posClosingDiv != -1) ? [posOpeningDiv,posClosingDiv] : null; } function autoSaveChanges(onlyIfDirty,tiddlers) { if(config.options.chkAutoSave) saveChanges(onlyIfDirty,tiddlers); } // Save this tiddlywiki with the pending changes function saveChanges(onlyIfDirty,tiddlers) { if(onlyIfDirty && !store.isDirty()) return; clearMessage(); // Get the URL of the document var originalPath = document.location.toString(); // Check we were loaded from a file URL if(originalPath.substr(0,5) != "file:") { alert(config.messages.notFileUrlError); if(store.tiddlerExists(config.messages.saveInstructions)) story.displayTiddler(null,config.messages.saveInstructions); return; } var localPath = getLocalPath(originalPath); // Load the original file var original = loadFile(localPath); if(original == null) { alert(config.messages.cantSaveError); if(store.tiddlerExists(config.messages.saveInstructions)) story.displayTiddler(null,config.messages.saveInstructions); return; } // Locate the storeArea div's var posDiv = locateStoreArea(original); if(!posDiv) { alert(config.messages.invalidFileError.format([localPath])); return; } saveBackup(localPath,original); saveRss(localPath); saveEmpty(localPath,original,posDiv); saveMain(localPath,original,posDiv); } function saveBackup(localPath,original) { // Save the backup if(config.options.chkSaveBackups) { var backupPath = getBackupPath(localPath); var backup = config.browser.isIE ? ieCopyFile(backupPath,localPath) : saveFile(backupPath,original); if(backup) displayMessage(config.messages.backupSaved,"file://" + backupPath); else alert(config.messages.backupFailed); } } function saveRss(localPath) { if(config.options.chkGenerateAnRssFeed) { var rssPath = localPath.substr(0,localPath.lastIndexOf(".")) + ".xml"; var rssSave = saveFile(rssPath,convertUnicodeToUTF8(generateRss())); if(rssSave) displayMessage(config.messages.rssSaved,"file://" + rssPath); else alert(config.messages.rssFailed); } } function saveEmpty(localPath,original,posDiv) { if(config.options.chkSaveEmptyTemplate) { var emptyPath,p; if((p = localPath.lastIndexOf("http://www.geocities.com/")) != -1) emptyPath = localPath.substr(0,p) + "/empty.html"; else if((p = localPath.lastIndexOf("\\")) != -1) emptyPath = localPath.substr(0,p) + "\\empty.html"; else emptyPath = localPath + ".empty.html"; var empty = original.substr(0,posDiv[0] + startSaveArea.length) + original.substr(posDiv[1]); var emptySave = saveFile(emptyPath,empty); if(emptySave) displayMessage(config.messages.emptySaved,"file://" + emptyPath); else alert(config.messages.emptyFailed); } } function saveMain(localPath,original,posDiv) { var save; try { var revised = updateOriginal(original,posDiv); save = saveFile(localPath,revised); } catch (ex) { showException(ex); } if(save) { displayMessage(config.messages.mainSaved,"file://" + localPath); store.setDirty(false); } else { alert(config.messages.mainFailed); } } function getLocalPath(origPath) { var originalPath = convertUriToUTF8(origPath,config.options.txtFileSystemCharSet); // Remove any location or query part of the URL var argPos = originalPath.indexOf("?"); if(argPos != -1) originalPath = originalPath.substr(0,argPos); var hashPos = originalPath.indexOf("#"); if(hashPos != -1) originalPath = originalPath.substr(0,hashPos); // Convert file://localhost/ to file:/// if(originalPath.indexOf("file:////localhost/") == 0) originalPath = "file://" + originalPath.substr(16); // Convert to a native file format var localPath; if(originalPath.charAt(9) == ":") // pc local file localPath = unescape(originalPath.substr(8)).replace(new RegExp("http://www.geocities.com/","g"),"\\"); else if(originalPath.indexOf("file://///") == 0) // FireFox pc network file localPath = "\\\\" + unescape(originalPath.substr(10)).replace(new RegExp("http://www.geocities.com/","g"),"\\"); else if(originalPath.indexOf("file:///") == 0) // mac/unix local file localPath = unescape(originalPath.substr(7)); else if(originalPath.indexOf("file:/") == 0) // mac/unix local file localPath = unescape(originalPath.substr(5)); else // pc network file localPath = "\\\\" + unescape(originalPath.substr(7)).replace(new RegExp("http://www.geocities.com/","g"),"\\"); return localPath; } function getBackupPath(localPath) { var backSlash = true; var dirPathPos = localPath.lastIndexOf("\\"); if(dirPathPos == -1) { dirPathPos = localPath.lastIndexOf("http://www.geocities.com/"); backSlash = false; } var backupFolder = config.options.txtBackupFolder; if(!backupFolder || backupFolder == "") backupFolder = "."; var backupPath = localPath.substr(0,dirPathPos) + (backSlash ? "\\" : "/") + backupFolder + localPath.substr(dirPathPos); backupPath = backupPath.substr(0,backupPath.lastIndexOf(".")) + "." + (new Date()).convertToYYYYMMDDHHMMSSMMM() + ".html"; return backupPath; } function generateRss() { var s = []; var d = new Date(); var u = store.getTiddlerText("SiteUrl"); // Assemble the header s.push("<" + "?xml version=\"1.0\"?" + ">"); s.push(""); s.push(""); s.push("" + wikifyPlain("SiteTitle").htmlEncode() + ""); if(u) s.push("" + u.htmlEncode() + ""); s.push("" + wikifyPlain("SiteSubtitle").htmlEncode() + ""); s.push("en-us"); s.push("Copyright " + d.getFullYear() + " " + config.options.txtUserName.htmlEncode() + ""); s.push("" + d.toGMTString() + ""); s.push("" + d.toGMTString() + ""); s.push("http://blogs.law.harvard.edu/tech/rss"); s.push("TiddlyWiki " + version.major + "." + version.minor + "." + version.revision + ""); // The body var tiddlers = store.getTiddlers("modified","excludeLists"); var n = config.numRssItems > tiddlers.length ? 0 : tiddlers.length-config.numRssItems; for (var t=tiddlers.length-1; t>=n; t--) s.push(tiddlers[t].saveToRss(u)); // And footer s.push(""); s.push(""); // Save it all return s.join("\n"); } //-- //-- Filesystem code //-- function convertUTF8ToUnicode(u) { if(window.netscape == undefined) return manualConvertUTF8ToUnicode(u); else return mozConvertUTF8ToUnicode(u); } function manualConvertUTF8ToUnicode(utf) { var uni = utf; var src = 0; var dst = 0; var b1, b2, b3; var c; while(src < utf.length) { b1 = utf.charCodeAt(src++); if(b1 < 0x80) { dst++; } else if(b1 < 0xE0) { b2 = utf.charCodeAt(src++); c = String.fromCharCode(((b1 & 0x1F) << 6) | (b2 & 0x3F)); uni = uni.substring(0,dst++).concat(c,utf.substr(src)); } else { b2 = utf.charCodeAt(src++); b3 = utf.charCodeAt(src++); c = String.fromCharCode(((b1 & 0xF) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F)); uni = uni.substring(0,dst++).concat(c,utf.substr(src)); } } return uni; } function mozConvertUTF8ToUnicode(u) { try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); converter.charset = "UTF-8"; } catch(ex) { return manualConvertUTF8ToUnicode(u); } // fallback var s = converter.ConvertToUnicode(u); var fin = converter.Finish(); return (fin.length > 0) ? s+fin : s; } function convertUnicodeToUTF8(s) { if(window.netscape == undefined) return manualConvertUnicodeToUTF8(s); else return mozConvertUnicodeToUTF8(s); } function manualConvertUnicodeToUTF8(s) { var re = /[^\u0000-\u007F]/g ; return s.replace(re,function($0) {return "&#" + $0.charCodeAt(0).toString() + ";";}); } function mozConvertUnicodeToUTF8(s) { try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); converter.charset = "UTF-8"; } catch(ex) { return manualConvertUnicodeToUTF8(s); } // fallback var u = converter.ConvertFromUnicode(s); var fin = converter.Finish(); if(fin.length > 0) return u + fin; else return u; } function convertUriToUTF8(uri,charSet) { if(window.netscape == undefined || charSet == undefined || charSet == "") return uri; try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var converter = Components.classes["@mozilla.org/intl/utf8converterservice;1"].getService(Components.interfaces.nsIUTF8ConverterService); } catch(ex) { return uri; } return converter.convertURISpecToUTF8(uri,charSet); } function saveFile(fileUrl,content) { var r = null; if(!r) r = mozillaSaveFile(fileUrl,content); if(!r) r = ieSaveFile(fileUrl,content); if(!r) r = javaSaveFile(fileUrl,content); return r; } function loadFile(fileUrl) { var r = null; if((r == null) || (r == false)) r = mozillaLoadFile(fileUrl); if((r == null) || (r == false)) r = ieLoadFile(fileUrl); if((r == null) || (r == false)) r = javaLoadFile(fileUrl); return r; } // Returns null if it can't do it, false if there's an error, true if it saved OK function ieSaveFile(filePath,content) { try { var fso = new ActiveXObject("Scripting.FileSystemObject"); } catch(ex) { return null; } var file = fso.OpenTextFile(filePath,2,-1,0); file.Write(content); file.Close(); return true; } // Returns null if it can't do it, false if there's an error, or a string of the content if successful function ieLoadFile(filePath) { try { var fso = new ActiveXObject("Scripting.FileSystemObject"); var file = fso.OpenTextFile(filePath,1); var content = file.ReadAll(); file.Close(); } catch(ex) { return null; } return content; } function ieCopyFile(dest,source) { try { var fso = new ActiveXObject("Scripting.FileSystemObject"); fso.GetFile(source).Copy(dest); } catch(ex) { return false; } return true; } // Returns null if it can't do it, false if there's an error, true if it saved OK function mozillaSaveFile(filePath,content) { if(window.Components) { try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); file.initWithPath(filePath); if(!file.exists()) file.create(0,0664); var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream); out.init(file,0x20|0x02,00004,null); out.write(content,content.length); out.flush(); out.close(); return true; } catch(ex) { return false; } } return null; } // Returns null if it can't do it, false if there's an error, or a string of the content if successful function mozillaLoadFile(filePath) { if(window.Components) { try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); file.initWithPath(filePath); if(!file.exists()) return null; var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream); inputStream.init(file,0x01,00004,null); var sInputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream); sInputStream.init(inputStream); return sInputStream.read(sInputStream.available()); } catch(ex) { return false; } } return null; } function javaUrlToFilename(url) { var f = "//localhost"; if(url.indexOf(f) == 0) return url.substring(f.length); var i = url.indexOf(":"); if(i > 0) return url.substring(i-1); return url; } function javaSaveFile(filePath,content) { try { if(document.applets["TiddlySaver"]) return document.applets["TiddlySaver"].saveFile(javaUrlToFilename(filePath),"UTF-8",content); } catch(ex) { } try { var s = new java.io.PrintStream(new java.io.FileOutputStream(javaUrlToFilename(filePath))); s.print(content); s.close(); } catch(ex) { return null; } return true; } function javaLoadFile(filePath) { try { if(document.applets["TiddlySaver"]) return String(document.applets["TiddlySaver"].loadFile(javaUrlToFilename(filePath),"UTF-8")); } catch(ex) { } var content = []; try { var r = new java.io.BufferedReader(new java.io.FileReader(javaUrlToFilename(filePath))); var line; while((line = r.readLine()) != null) content.push(new String(line)); r.close(); } catch(ex) { return null; } return content.join("\n"); } //-- //-- Server adaptor for talking to static files //-- function FileAdaptor() { this.host = null; this.store = null; return this; } FileAdaptor.NotLoadedError = "TiddlyWiki file has not been loaded"; FileAdaptor.serverType = 'file'; // Open the specified host/server FileAdaptor.prototype.openHost = function(host,context,userParams,callback) { this.host = host; if(!context) context = {}; context.adaptor = this; context.callback = callback; context.userParams = userParams; var ret = loadRemoteFile(host,FileAdaptor.openHostCallback,context); return typeof(ret) == "string" ? ret : true; }; FileAdaptor.openHostCallback = function(status,context,responseText,url,xhr) { var adaptor = context.adaptor; context.status = status; if(!status) { context.statusText = "Error reading file: " + xhr.statusText; } else { // Load the content into a TiddlyWiki() object adaptor.store = new TiddlyWiki(); if(!adaptor.store.importTiddlyWiki(responseText)) context.statusText = config.messages.invalidFileError.format([url]); } context.callback(context,context.userParams); }; // Gets the list of workspaces on a given server FileAdaptor.prototype.getWorkspaceList = function(context,userParams,callback) { if(!context) context = {}; context.workspaces = [{title:"(default)"}]; context.status = true; window.setTimeout(function() {callback(context,userParams);},10); return true; }; // Open the specified workspace FileAdaptor.prototype.openWorkspace = function(workspace,context,userParams,callback) { if(!context) context = {}; context.status = true; window.setTimeout(function() {callback(context,userParams);},10); return true; }; // Gets the list of tiddlers within a given workspace FileAdaptor.prototype.getTiddlerList = function(context,userParams,callback) { if(!this.store) return FileAdaptor.NotLoadedError; if(!context) context = {}; context.tiddlers = []; this.store.forEachTiddler(function(title,tiddler) { var t = new Tiddler(title); t.text = tiddler.text; t.modified = tiddler.modified; t.modifier = tiddler.modifier; t.fields['server.page.revision'] = tiddler.modified.convertToYYYYMMDDHHMM(); t.tags = tiddler.tags; context.tiddlers.push(t); }); context.status = true; window.setTimeout(function() {callback(context,userParams);},10); return true; }; FileAdaptor.prototype.generateTiddlerInfo = function(tiddler) { var info = {}; info.uri = tiddler.fields['server.host'] + "#" + tiddler.title; return info; }; // Retrieves a tiddler from a given workspace on a given server FileAdaptor.prototype.getTiddler = function(title,context,userParams,callback) { if(!this.store) return FileAdaptor.NotLoadedError; if(!context) context = {}; context.tiddler = this.store.fetchTiddler(title); if(context.tiddler) { context.tiddler.fields['server.type'] = FileAdaptor.serverType; context.tiddler.fields['server.host'] = this.host; context.tiddler.fields['server.page.revision'] = context.tiddler.modified.convertToYYYYMMDDHHMM(); } context.status = true; if(context.allowSynchronous) { context.isSynchronous = true; callback(context,userParams); } else { window.setTimeout(function() {callback(context,userParams);},10); } return true; }; FileAdaptor.prototype.close = function() { delete this.store; this.store = null; }; config.adaptors[FileAdaptor.serverType] = FileAdaptor; //-- //-- Remote HTTP requests //-- function loadRemoteFile(url,callback,params) { return doHttp("GET",url,null,null,null,null,callback,params,null); } // HTTP status codes var httpStatus = { OK: 200, ContentCreated: 201, NoContent: 204, Unauthorized: 401, Forbidden: 403, NotFound: 404, MethodNotAllowed: 405 }; function doHttp(type,url,data,contentType,username,password,callback,params,headers) { // Get an xhr object var x = getXMLHttpRequest(); if(!x) return "Can't create XMLHttpRequest object"; // Install callback x.onreadystatechange = function() { if (x.readyState == 4 && callback && (x.status !== undefined)) { if([0, httpStatus.OK, httpStatus.ContentCreated, httpStatus.NoContent].contains(x.status)) callback(true,params,x.responseText,url,x); else callback(false,params,null,url,x); x.onreadystatechange = function(){}; x = null; } }; // Send request if(window.Components && window.netscape && window.netscape.security && document.location.protocol.indexOf("http") == -1) window.netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); try { url = url + (url.indexOf("?") < 0 ? "?" : "&") + "nocache=" + Math.random(); x.open(type,url,true,username,password); if (data) x.setRequestHeader("Content-Type", contentType ? contentType : "application/x-www-form-urlencoded"); if (x.overrideMimeType) x.setRequestHeader("Connection", "close"); if(headers) { for(n in headers) x.setRequestHeader(n,headers[n]); } x.setRequestHeader("X-Requested-With", "TiddlyWiki " + version.major + "." + version.minor + "." + version.revision + (version.beta ? " (beta " + version.beta + ")" : "")); x.send(data); } catch (ex) { return exceptionText(ex); } return x; } function getXMLHttpRequest() { try { var x = new XMLHttpRequest(); // Modern } catch(ex) { try { x = new ActiveXObject("Msxml2.XMLHTTP"); // IE 6 } catch (ex2) { return null; } } return x; } //-- //-- TiddlyWiki-specific utility functions //-- function createTiddlyButton(theParent,theText,theTooltip,theAction,theClass,theId,theAccessKey) { var theButton = document.createElement("a"); if(theAction) { theButton.onclick = theAction; theButton.setAttribute("href","javascript:;"); } if(theTooltip) theButton.setAttribute("title",theTooltip); if(theText) theButton.appendChild(document.createTextNode(theText)); if(theClass) theButton.className = theClass; else theButton.className = "button"; if(theId) theButton.id = theId; if(theParent) theParent.appendChild(theButton); if(theAccessKey) theButton.setAttribute("accessKey",theAccessKey); return theButton; } function createTiddlyLink(place,title,includeText,theClass,isStatic,linkedFromTiddler,noToggle) { var text = includeText ? title : null; var i = getTiddlyLinkInfo(title,theClass); var btn = isStatic ? createExternalLink(place,store.getTiddlerText("SiteUrl",null) + "#" + title) : createTiddlyButton(place,text,i.subTitle,onClickTiddlerLink,i.classes); btn.setAttribute("refresh","link"); btn.setAttribute("tiddlyLink",title); if(noToggle) btn.setAttribute("noToggle","true"); if(linkedFromTiddler) { var fields = linkedFromTiddler.getInheritedFields(); if(fields) btn.setAttribute("tiddlyFields",fields); } return btn; } function refreshTiddlyLink(e,title) { var i = getTiddlyLinkInfo(title,e.className); e.className = i.classes; e.title = i.subTitle; } function getTiddlyLinkInfo(title,currClasses) { var classes = currClasses ? currClasses.split(" ") : []; classes.pushUnique("tiddlyLink"); var tiddler = store.fetchTiddler(title); var subTitle; if(tiddler) { subTitle = tiddler.getSubtitle(); classes.pushUnique("tiddlyLinkExisting"); classes.remove("tiddlyLinkNonExisting"); classes.remove("shadow"); } else { classes.remove("tiddlyLinkExisting"); classes.pushUnique("tiddlyLinkNonExisting"); if(store.isShadowTiddler(title)) { subTitle = config.messages.shadowedTiddlerToolTip.format([title]); classes.pushUnique("shadow"); } else { subTitle = config.messages.undefinedTiddlerToolTip.format([title]); classes.remove("shadow"); } } if(config.annotations[title]) subTitle = config.annotations[title]; return {classes: classes.join(" "),subTitle: subTitle}; } function createExternalLink(place,url) { var theLink = document.createElement("a"); theLink.className = "externalLink"; theLink.href = url; theLink.title = config.messages.externalLinkTooltip.format([url]); if(config.options.chkOpenInNewWindow) theLink.target = "_blank"; place.appendChild(theLink); return theLink; } // Event handler for clicking on a tiddly link function onClickTiddlerLink(e) { if(!e) e = window.event; var theTarget = resolveTarget(e); var theLink = theTarget; var title = null; var fields = null; var noToggle = null; do { title = theLink.getAttribute("tiddlyLink"); fields = theLink.getAttribute("tiddlyFields"); noToggle = theLink.getAttribute("noToggle"); theLink = theLink.parentNode; } while(title == null && theLink != null); if(!store.isShadowTiddler(title)) { var f = fields ? fields.decodeHashMap() : {}; fields = String.encodeHashMap(merge(f,config.defaultCustomFields,true)); } if(title) { var toggling = e.metaKey || e.ctrlKey; if(config.options.chkToggleLinks) toggling = !toggling; if(noToggle) toggling = false; story.displayTiddler(theTarget,title,null,true,null,fields,toggling); } clearMessage(); return false; } // Create a button for a tag with a popup listing all the tiddlers that it tags function createTagButton(place,tag,excludeTiddler) { var theTag = createTiddlyButton(place,tag,config.views.wikified.tag.tooltip.format([tag]),onClickTag); theTag.setAttribute("tag",tag); if(excludeTiddler) theTag.setAttribute("tiddler",excludeTiddler); return theTag; } // Event handler for clicking on a tiddler tag function onClickTag(ev) { var e = ev ? ev : window.event; var popup = Popup.create(this); var tag = this.getAttribute("tag"); var title = this.getAttribute("tiddler"); if(popup && tag) { var tagged = store.getTaggedTiddlers(tag); var titles = []; var li,r; for(r=0;r 0) { var openAll = createTiddlyButton(createTiddlyElement(popup,"li"),lingo.openAllText.format([tag]),lingo.openAllTooltip,onClickTagOpenAll); openAll.setAttribute("tag",tag); createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div"); for(r=0; r= this.endTime) { this.stop(); return false; } return true; }; //-- //-- Zoomer animation //-- function Zoomer(text,startElement,targetElement,unused) { var e = createTiddlyElement(document.body,"div",null,"zoomer"); createTiddlyElement(e,"div",null,null,text); var winWidth = findWindowWidth(); var winHeight = findWindowHeight(); var p = [ {style: 'left', start: findPosX(startElement), end: findPosX(targetElement), template: '%0px'}, {style: 'top', start: findPosY(startElement), end: findPosY(targetElement), template: '%0px'}, {style: 'width', start: Math.min(startElement.scrollWidth,winWidth), end: Math.min(targetElement.scrollWidth,winWidth), template: '%0px', atEnd: 'auto'}, {style: 'height', start: Math.min(startElement.scrollHeight,winHeight), end: Math.min(targetElement.scrollHeight,winHeight), template: '%0px', atEnd: 'auto'}, {style: 'fontSize', start: 8, end: 24, template: '%0pt'} ]; var c = function(element,properties) {removeNode(element);}; return new Morpher(e,config.animDuration,p,c); } //-- //-- Scroller animation //-- function Scroller(targetElement,unused) { var p = [ {style: '-tw-vertScroll', start: findScrollY(), end: ensureVisible(targetElement)} ]; return new Morpher(targetElement,config.animDuration,p); } //-- //-- Slider animation //-- // deleteMode - "none", "all" [delete target element and it's children], [only] "children" [but not the target element] function Slider(element,opening,unused,deleteMode) { element.style.overflow = 'hidden'; if(opening) element.style.height = '0px'; // Resolves a Firefox flashing bug element.style.display = 'block'; var left = findPosX(element); var width = element.scrollWidth; var height = element.scrollHeight; var winWidth = findWindowWidth(); var p = []; var c = null; if(opening) { p.push({style: 'height', start: 0, end: height, template: '%0px', atEnd: 'auto'}); p.push({style: 'opacity', start: 0, end: 1, template: '%0'}); p.push({style: 'filter', start: 0, end: 100, template: 'alpha(opacity:%0)'}); } else { p.push({style: 'height', start: height, end: 0, template: '%0px'}); p.push({style: 'display', atEnd: 'none'}); p.push({style: 'opacity', start: 1, end: 0, template: '%0'}); p.push({style: 'filter', start: 100, end: 0, template: 'alpha(opacity:%0)'}); switch(deleteMode) { case "all": c = function(element,properties) {removeNode(element);}; break; case "children": c = function(element,properties) {removeChildren(element);}; break; } } return new Morpher(element,config.animDuration,p,c); } //-- //-- Popup menu //-- var Popup = { stack: [] // Array of objects with members root: and popup: }; Popup.create = function(root,elem,theClass) { Popup.remove(); var popup = createTiddlyElement(document.body,elem ? elem : "ol","popup",theClass ? theClass : "popup"); Popup.stack.push({root: root, popup: popup}); return popup; }; Popup.onDocumentClick = function(ev) { var e = ev ? ev : window.event; if(e.eventPhase == undefined) Popup.remove(); else if(e.eventPhase == Event.BUBBLING_PHASE || e.eventPhase == Event.AT_TARGET) Popup.remove(); return true; }; Popup.show = function(unused1,unused2) { var curr = Popup.stack[Popup.stack.length-1]; this.place(curr.root,curr.popup); addClass(curr.root,"highlight"); if(config.options.chkAnimate && anim && typeof Scroller == "function") anim.startAnimating(new Scroller(curr.popup)); else window.scrollTo(0,ensureVisible(curr.popup)); }; Popup.place = function(root,popup,offset) { if(!offset) var offset = {x:0, y:0}; var rootLeft = findPosX(root); var rootTop = findPosY(root); var rootHeight = root.offsetHeight; var popupLeft = rootLeft + offset.x; var popupTop = rootTop + rootHeight + offset.y; var winWidth = findWindowWidth(); if(popup.offsetWidth > winWidth*0.75) popup.style.width = winWidth*0.75 + "px"; var popupWidth = popup.offsetWidth; if(popupLeft + popupWidth > winWidth) popupLeft = winWidth - popupWidth; popup.style.left = popupLeft + "px"; popup.style.top = popupTop + "px"; popup.style.display = "block"; }; Popup.remove = function() { if(Popup.stack.length > 0) { Popup.removeFrom(0); } }; Popup.removeFrom = function(from) { for(var t=Popup.stack.length-1; t>=from; t--) { var p = Popup.stack[t]; removeClass(p.root,"highlight"); removeNode(p.popup); } Popup.stack = Popup.stack.slice(0,from); }; //-- //-- Wizard support //-- function Wizard(elem) { if(elem) { this.formElem = findRelated(elem,"wizard","className"); this.bodyElem = findRelated(this.formElem.firstChild,"wizardBody","className","nextSibling"); this.footElem = findRelated(this.formElem.firstChild,"wizardFooter","className","nextSibling"); } else { this.formElem = null; this.bodyElem = null; this.footElem = null; } } Wizard.prototype.setValue = function(name,value) { if(this.formElem) this.formElem[name] = value; }; Wizard.prototype.getValue = function(name) { return this.formElem ? this.formElem[name] : null; }; Wizard.prototype.createWizard = function(place,title) { this.formElem = createTiddlyElement(place,"form",null,"wizard"); createTiddlyElement(this.formElem,"h1",null,null,title); this.bodyElem = createTiddlyElement(this.formElem,"div",null,"wizardBody"); this.footElem = createTiddlyElement(this.formElem,"div",null,"wizardFooter"); }; Wizard.prototype.clear = function() { removeChildren(this.bodyElem); }; Wizard.prototype.setButtons = function(buttonInfo,status) { removeChildren(this.footElem); for(var t=0; t max) c = max; return c; }; // Add indexOf function if browser does not support it if(!Array.indexOf) { Array.prototype.indexOf = function(item,from) { if(!from) from = 0; for(var i=from; i "backgroundColor") String.prototype.unDash = function() { var s = this.split("-"); if(s.length > 1) { for(var t=1; t currPos) r.push(this.substring(currPos,match.index)); r.push(substrings[parseInt(match[1])]); currPos = subRegExp.lastIndex; } } while(match); if(currPos < this.length) r.push(this.substring(currPos,this.length)); return r.join(""); }; // Escape any special RegExp characters with that character preceded by a backslash String.prototype.escapeRegExp = function() { var s = "\\^$*+?()=!|,{}[]."; var c = this; for(var t=0; t to ">" and " to """ String.prototype.htmlEncode = function() { return this.replace(/&/mg,"&").replace(//mg,">").replace(/\"/mg,"""); }; // Convert "&" to &, "<" to <, ">" to > and """ to " String.prototype.htmlDecode = function() { return this.replace(/</mg,"<").replace(/>/mg,">").replace(/"/mg,"\"").replace(/&/mg,"&"); }; // Convert a string to it's JSON representation by encoding control characters, double quotes and backslash. See json.org String.prototype.toJSONString = function() { var m = { '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t', '"' : '\\"', '\\': '\\\\' }; var replaceFn = function(a,b) { var c = m[b]; if(c) return c; c = b.charCodeAt(); return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16); }; if(/["\\\x00-\x1f]/.test(this)) return '"' + this.replace(/([\x00-\x1f\\"])/g,replaceFn) + '"'; return '"' + this + '"'; }; // Parse a space-separated string of name:value parameters // The result is an array of objects: // result[0] = object with a member for each parameter name, value of that member being an array of values // result[1..n] = one object for each parameter, with 'name' and 'value' members String.prototype.parseParams = function(defaultName,defaultValue,allowEval,noNames,cascadeDefaults) { var parseToken = function(match,p) { var n; if(match[p]) // Double quoted n = match[p]; else if(match[p+1]) // Single quoted n = match[p+1]; else if(match[p+2]) // Double-square-bracket quoted n = match[p+2]; else if(match[p+3]) // Double-brace quoted try { n = match[p+3]; if(allowEval) n = window.eval(n); } catch(ex) { throw "Unable to evaluate {{" + match[p+3] + "}}: " + exceptionText(ex); } else if(match[p+4]) // Unquoted n = match[p+4]; else if(match[p+5]) // empty quote n = ""; return n; }; var r = [{}]; var dblQuote = "(?:\"((?:(?:\\\\\")|[^\"])+)\")"; var sngQuote = "(?:'((?:(?:\\\\\')|[^'])+)')"; var dblSquare = "(?:\\[\\[((?:\\s|\\S)*?)\\]\\])"; var dblBrace = "(?:\\{\\{((?:\\s|\\S)*?)\\}\\})"; var unQuoted = noNames ? "([^\"'\\s]\\S*)" : "([^\"':\\s][^\\s:]*)"; var emptyQuote = "((?:\"\")|(?:''))"; var skipSpace = "(?:\\s*)"; var token = "(?:" + dblQuote + "|" + sngQuote + "|" + dblSquare + "|" + dblBrace + "|" + unQuoted + "|" + emptyQuote + ")"; var re = noNames ? new RegExp(token,"mg") : new RegExp(skipSpace + token + skipSpace + "(?:(\\:)" + skipSpace + token + ")?","mg"); var params = []; do { var match = re.exec(this); if(match) { var n = parseToken(match,1); if(noNames) { r.push({name:"",value:n}); } else { var v = parseToken(match,8); if(v == null && defaultName) { v = n; n = defaultName; } else if(v == null && defaultValue) { v = defaultValue; } r.push({name:n,value:v}); if(cascadeDefaults) { defaultName = n; defaultValue = v; } } } } while(match); // Summarise parameters into first element for(var t=1; t 12 ? h-12 : ( h > 0 ? h : 12 ); }; Date.prototype.getAmPm = function() { return this.getHours() >= 12 ? config.messages.dates.pm : config.messages.dates.am; }; Date.prototype.daySuffix = function() { return config.messages.dates.daySuffixes[this.getDate()-1]; }; // Convert a date to local YYYYMMDDHHMM string format Date.prototype.convertToLocalYYYYMMDDHHMM = function() { return String.zeroPad(this.getFullYear(),4) + String.zeroPad(this.getMonth()+1,2) + String.zeroPad(this.getDate(),2) + String.zeroPad(this.getHours(),2) + String.zeroPad(this.getMinutes(),2); }; // Convert a date to UTC YYYYMMDDHHMM string format Date.prototype.convertToYYYYMMDDHHMM = function() { return String.zeroPad(this.getUTCFullYear(),4) + String.zeroPad(this.getUTCMonth()+1,2) + String.zeroPad(this.getUTCDate(),2) + String.zeroPad(this.getUTCHours(),2) + String.zeroPad(this.getUTCMinutes(),2); }; // Convert a date to UTC YYYYMMDD.HHMMSSMMM string format Date.prototype.convertToYYYYMMDDHHMMSSMMM = function() { return String.zeroPad(this.getUTCFullYear(),4) + String.zeroPad(this.getUTCMonth()+1,2) + String.zeroPad(this.getUTCDate(),2) + "." + String.zeroPad(this.getUTCHours(),2) + String.zeroPad(this.getUTCMinutes(),2) + String.zeroPad(this.getUTCSeconds(),2) + String.zeroPad(this.getUTCMilliseconds(),4); }; // Static method to create a date from a UTC YYYYMMDDHHMM format string Date.convertFromYYYYMMDDHHMM = function(d) { return new Date(Date.UTC(parseInt(d.substr(0,4),10), parseInt(d.substr(4,2),10)-1, parseInt(d.substr(6,2),10), parseInt(d.substr(8,2),10), parseInt(d.substr(10,2),10),0,0)); }; //-- //-- Crypto functions and associated conversion routines //-- // Crypto "namespace" function Crypto() {} // Convert a string to an array of big-endian 32-bit words Crypto.strToBe32s = function(str) { var be = Array(); var len = Math.floor(str.length/4); var i, j; for(i=0, j=0; i>2] |= (str.charCodeAt(j)&0xff)<<(24-(j*8)%32); j++; } return be; }; // Convert an array of big-endian 32-bit words to a string Crypto.be32sToStr = function(be) { var str = ""; for(var i=0;i>5]>>>(24-i%32)) & 0xff); return str; }; // Convert an array of big-endian 32-bit words to a hex string Crypto.be32sToHex = function(be) { var hex = "0123456789ABCDEF"; var str = ""; for(var i=0;i>2]>>((3-i%4)*8+4))&0xF) + hex.charAt((be[i>>2]>>((3-i%4)*8))&0xF); return str; }; // Return, in hex, the SHA-1 hash of a string Crypto.hexSha1Str = function(str) { return Crypto.be32sToHex(Crypto.sha1Str(str)); }; // Return the SHA-1 hash of a string Crypto.sha1Str = function(str) { return Crypto.sha1(Crypto.strToBe32s(str),str.length); }; // Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words Crypto.sha1 = function(x,blen) { // Add 32-bit integers, wrapping at 32 bits add32 = function(a,b) { var lsw = (a&0xFFFF)+(b&0xFFFF); var msw = (a>>16)+(b>>16)+(lsw>>16); return (msw<<16)|(lsw&0xFFFF); }; // Add five 32-bit integers, wrapping at 32 bits add32x5 = function(a,b,c,d,e) { var lsw = (a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF); var msw = (a>>16)+(b>>16)+(c>>16)+(d>>16)+(e>>16)+(lsw>>16); return (msw<<16)|(lsw&0xFFFF); }; // Bitwise rotate left a 32-bit integer by 1 bit rol32 = function(n) { return (n>>>31)|(n<<1); }; var len = blen*8; // Append padding so length in bits is 448 mod 512 x[len>>5] |= 0x80 << (24-len%32); // Append length x[((len+64>>9)<<4)+15] = len; var w = Array(80); var k1 = 0x5A827999; var k2 = 0x6ED9EBA1; var k3 = 0x8F1BBCDC; var k4 = 0xCA62C1D6; var h0 = 0x67452301; var h1 = 0xEFCDAB89; var h2 = 0x98BADCFE; var h3 = 0x10325476; var h4 = 0xC3D2E1F0; for(var i=0;i>>27)|(a<<5),d^(b&(c^d)),w[j],k1); e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; } for(j=16;j<20;j++) { w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]); t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1); e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; } for(j=20;j<40;j++) { w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]); t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k2); e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; } for(j=40;j<60;j++) { w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]); t = add32x5(e,(a>>>27)|(a<<5),(b&c)|(d&(b|c)),w[j],k3); e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; } for(j=60;j<80;j++) { w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]); t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k4); e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; } h0 = add32(h0,a); h1 = add32(h1,b); h2 = add32(h2,c); h3 = add32(h3,d); h4 = add32(h4,e); } return Array(h0,h1,h2,h3,h4); }; //-- //-- RGB colour object //-- // Construct an RGB colour object from a '#rrggbb', '#rgb' or 'rgb(n,n,n)' string or from separate r,g,b values function RGB(r,g,b) { this.r = 0; this.g = 0; this.b = 0; if(typeof r == "string") { if(r.substr(0,1) == "#") { if(r.length == 7) { this.r = parseInt(r.substr(1,2),16)/255; this.g = parseInt(r.substr(3,2),16)/255; this.b = parseInt(r.substr(5,2),16)/255; } else { this.r = parseInt(r.substr(1,1),16)/15; this.g = parseInt(r.substr(2,1),16)/15; this.b = parseInt(r.substr(3,1),16)/15; } } else { var rgbPattern = /rgb\s*\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/; var c = r.match(rgbPattern); if(c) { this.r = parseInt(c[1],10)/255; this.g = parseInt(c[2],10)/255; this.b = parseInt(c[3],10)/255; } } } else { this.r = r; this.g = g; this.b = b; } return this; } // Mixes this colour with another in a specified proportion // c = other colour to mix // f = 0..1 where 0 is this colour and 1 is the new colour // Returns an RGB object RGB.prototype.mix = function(c,f) { return new RGB(this.r + (c.r-this.r) * f,this.g + (c.g-this.g) * f,this.b + (c.b-this.b) * f); }; // Return an rgb colour as a #rrggbb format hex string RGB.prototype.toString = function() { return "#" + ("0" + Math.floor(this.r.clamp(0,1) * 255).toString(16)).right(2) + ("0" + Math.floor(this.g.clamp(0,1) * 255).toString(16)).right(2) + ("0" + Math.floor(this.b.clamp(0,1) * 255).toString(16)).right(2); }; //-- //-- DOM utilities - many derived from www.quirksmode.org //-- function drawGradient(place,horiz,colours) { for(var t=0; t<= 100; t+=2) { var bar = document.createElement("div"); place.appendChild(bar); bar.style.position = "absolute"; bar.style.left = horiz ? t + "%" : 0; bar.style.top = horiz ? 0 : t + "%"; bar.style.width = horiz ? (101-t) + "%" : "100%"; bar.style.height = horiz ? "100%" : (101-t) + "%"; bar.style.zIndex = -1; var f = t/100; var p = f*(colours.length-1); bar.style.backgroundColor = colours[Math.floor(p)].mix(colours[Math.ceil(p)],p-Math.floor(p)).toString(); } } function createTiddlyText(theParent,theText) { return theParent.appendChild(document.createTextNode(theText)); } function createTiddlyCheckbox(theParent,caption,checked,onChange) { var cb = document.createElement("input"); cb.setAttribute("type","checkbox"); cb.onclick = onChange; theParent.appendChild(cb); cb.checked = checked; cb.className = "chkOptionInput"; if(caption) wikify(caption,theParent); return cb; } function createTiddlyElement(theParent,theElement,theID,theClass,theText) { var e = document.createElement(theElement); if(theClass != null) e.className = theClass; if(theID != null) e.setAttribute("id",theID); if(theText != null) e.appendChild(document.createTextNode(theText)); if(theParent != null) theParent.appendChild(e); return e; } function addEvent(obj,type,fn) { if(obj.attachEvent) { obj['e'+type+fn] = fn; obj[type+fn] = function(){obj['e'+type+fn](window.event);}; obj.attachEvent('on'+type,obj[type+fn]); } else { obj.addEventListener(type,fn,false); } } function removeEvent(obj,type,fn) { if(obj.detachEvent) { obj.detachEvent('on'+type,obj[type+fn]); obj[type+fn] = null; } else { obj.removeEventListener(type,fn,false); } } function addClass(e,theClass) { var currClass = e.className.split(" "); if(currClass.indexOf(theClass) == -1) e.className += " " + theClass; } function removeClass(e,theClass) { var currClass = e.className.split(" "); var i = currClass.indexOf(theClass); while(i != -1) { currClass.splice(i,1); i = currClass.indexOf(theClass); } e.className = currClass.join(" "); } function hasClass(e,theClass) { if(e.className) { if(e.className.split(" ").indexOf(theClass) != -1) return true; } return false; } // Find the closest relative with a given property value (property defaults to tagName, relative defaults to parentNode) function findRelated(e,value,name,relative) { name = name ? name : "tagName"; relative = relative ? relative : "parentNode"; if(name == "className") { while(e && !hasClass(e,value)) { e = e[relative]; } } else { while(e && e[name] != value) { e = e[relative]; } } return e; } // Resolve the target object of an event function resolveTarget(e) { var obj; if(e.target) obj = e.target; else if(e.srcElement) obj = e.srcElement; if(obj.nodeType == 3) // defeat Safari bug obj = obj.parentNode; return obj; } // Return the content of an element as plain text with no formatting function getPlainText(e) { var text = ""; if(e.innerText) text = e.innerText; else if(e.textContent) text = e.textContent; return text; } // Get the scroll position for window.scrollTo necessary to scroll a given element into view function ensureVisible(e) { var posTop = findPosY(e); var posBot = posTop + e.offsetHeight; var winTop = findScrollY(); var winHeight = findWindowHeight(); var winBot = winTop + winHeight; if(posTop < winTop) { return posTop; } else if(posBot > winBot) { if(e.offsetHeight < winHeight) return posTop - (winHeight - e.offsetHeight); else return posTop; } else { return winTop; } } // Get the current width of the display window function findWindowWidth() { return window.innerWidth ? window.innerWidth : document.documentElement.clientWidth; } // Get the current height of the display window function findWindowHeight() { return window.innerHeight ? window.innerHeight : document.documentElement.clientHeight; } // Get the current horizontal page scroll position function findScrollX() { return window.scrollX ? window.scrollX : document.documentElement.scrollLeft; } // Get the current vertical page scroll position function findScrollY() { return window.scrollY ? window.scrollY : document.documentElement.scrollTop; } function findPosX(obj) { var curleft = 0; while(obj.offsetParent) { curleft += obj.offsetLeft; obj = obj.offsetParent; } return curleft; } function findPosY(obj) { var curtop = 0; while(obj.offsetParent) { curtop += obj.offsetTop; obj = obj.offsetParent; } return curtop; } // Blur a particular element function blurElement(e) { if(e != null && e.focus && e.blur) { e.focus(); e.blur(); } } // Create a non-breaking space function insertSpacer(place) { var e = document.createTextNode(String.fromCharCode(160)); if(place) place.appendChild(e); return e; } // Remove all children of a node function removeChildren(e) { while(e && e.hasChildNodes()) removeNode(e.firstChild); } // Remove a node and all it's children function removeNode(e) { scrubNode(e); e.parentNode.removeChild(e); } // Remove any event handlers or non-primitve custom attributes function scrubNode(e) { if(!config.browser.isIE) return; var att = e.attributes; if(att) { for(var t=0; t" + s + ""); } else { if(n) { n.replaceChild(doc.createTextNode(s),n.firstChild); } else { n = doc.createElement("style"); n.type = "text/css"; n.id = id; n.appendChild(doc.createTextNode(s)); doc.getElementsByTagName("head")[0].appendChild(n); } } } // Force the browser to do a document reflow when needed to workaround browser bugs function forceReflow() { if(config.browser.isGecko) { setStylesheet("body {top:-1em;margin-top:1em;}"); setStylesheet(""); } } // Replace the current selection of a textarea or text input and scroll it into view function replaceSelection(e,text) { if(e.setSelectionRange) { var oldpos = e.selectionStart; var isRange = e.selectionEnd > e.selectionStart; e.value = e.value.substr(0,e.selectionStart) + text + e.value.substr(e.selectionEnd); e.setSelectionRange(isRange ? oldpos : oldpos + text.length,oldpos + text.length); var linecount = e.value.split('\n').length; var thisline = e.value.substr(0,e.selectionStart).split('\n').length-1; e.scrollTop = Math.floor((thisline - e.rows / 2) * e.scrollHeight / linecount); } else if(document.selection) { var range = document.selection.createRange(); if(range.parentElement() == e) { var isCollapsed = range.text == ""; range.text = text; if(!isCollapsed) { range.moveStart('character', -text.length); range.select(); } } } } // Returns the text of the given (text) node, possibly merging subsequent text nodes function getNodeText(e) { var t = ""; while(e && e.nodeName == "#text") { t += e.nodeValue; e = e.nextSibling; } return t; } //-- //-- LoaderBase and SaverBase //-- function LoaderBase() {} LoaderBase.prototype.loadTiddler = function(store,node,tiddlers) { var title = this.getTitle(store,node); if(title) { var tiddler = store.createTiddler(title); this.internalizeTiddler(store,tiddler,title,node); tiddlers.push(tiddler); } }; LoaderBase.prototype.loadTiddlers = function(store,nodes) { var tiddlers = []; for(var t = 0; t < nodes.length; t++) { try { this.loadTiddler(store,nodes[t],tiddlers); } catch(ex) { showException(ex,config.messages.tiddlerLoadError.format([this.getTitle(store,nodes[t])])); } } return tiddlers; }; function SaverBase() {} SaverBase.prototype.externalize = function(store) { var results = []; var tiddlers = store.getTiddlers("title"); for(var t = 0; t < tiddlers.length; t++) results.push(this.externalizeTiddler(store,tiddlers[t])); return results.join("\n"); }; //-- //-- TW21Loader (inherits from LoaderBase) //-- function TW21Loader() {} TW21Loader.prototype = new LoaderBase(); TW21Loader.prototype.getTitle = function(store,node) { var title = null; if(node.getAttribute) { title = node.getAttribute("title"); if(!title) title = node.getAttribute("tiddler"); } if(!title && node.id) { var lenPrefix = store.idPrefix.length; if (node.id.substr(0,lenPrefix) == store.idPrefix) title = node.id.substr(lenPrefix); } return title; }; TW21Loader.prototype.internalizeTiddler = function(store,tiddler,title,node) { var e = node.firstChild; var text = null; if(node.getAttribute("tiddler")) { text = getNodeText(e).unescapeLineBreaks(); } else { while(e.nodeName!="PRE" && e.nodeName!="pre") { e = e.nextSibling; } text = e.innerHTML.replace(/\r/mg,"").htmlDecode(); } var modifier = node.getAttribute("modifier"); var c = node.getAttribute("created"); var m = node.getAttribute("modified"); var created = c ? Date.convertFromYYYYMMDDHHMM(c) : version.date; var modified = m ? Date.convertFromYYYYMMDDHHMM(m) : created; var tags = node.getAttribute("tags"); var fields = {}; var attrs = node.attributes; for(var i = attrs.length-1; i >= 0; i--) { var name = attrs[i].name; if (attrs[i].specified && !TiddlyWiki.isStandardField(name)) { fields[name] = attrs[i].value.unescapeLineBreaks(); } } tiddler.assign(title,text,modifier,modified,tags,created,fields); return tiddler; }; //-- //-- TW21Saver (inherits from SaverBase) //-- function TW21Saver() {} TW21Saver.prototype = new SaverBase(); TW21Saver.prototype.externalizeTiddler = function(store,tiddler) { try { var extendedAttributes = ""; var usePre = config.options.chkUsePreForStorage; store.forEachField(tiddler, function(tiddler,fieldName,value) { // don't store stuff from the temp namespace if(typeof value != "string") value = ""; if (!fieldName.match(/^temp\./)) extendedAttributes += ' %0="%1"'.format([fieldName,value.escapeLineBreaks().htmlEncode()]); },true); var created = tiddler.created.convertToYYYYMMDDHHMM(); var modified = tiddler.modified.convertToYYYYMMDDHHMM(); var vdate = version.date.convertToYYYYMMDDHHMM(); var attributes = tiddler.modifier ? ' modifier="' + tiddler.modifier.htmlEncode() + '"' : ""; attributes += (usePre && modified == created) ? "" : ' modified="' + modified +'"'; attributes += (usePre && created == vdate) ? "" :' created="' + created + '"'; var tags = tiddler.getTags(); if(!usePre || tags) attributes += ' tags="' + tags.htmlEncode() + '"'; return ('
%4').format([ usePre ? "title" : "tiddler", tiddler.title.htmlEncode(), attributes, extendedAttributes, usePre ? "\n
" + tiddler.text.htmlEncode() + "
\n" : tiddler.text.escapeLineBreaks().htmlEncode() ]); } catch (ex) { throw exceptionText(ex,config.messages.tiddlerSaveError.format([tiddler.title])); } }; //-- //-- Deprecated code //-- // @Deprecated: Use createElementAndWikify and this.termRegExp instead config.formatterHelpers.charFormatHelper = function(w) { w.subWikify(createTiddlyElement(w.output,this.element),this.terminator); }; // @Deprecated: Use enclosedTextHelper and this.lookaheadRegExp instead config.formatterHelpers.monospacedByLineHelper = function(w) { var lookaheadRegExp = new RegExp(this.lookahead,"mg"); lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { var text = lookaheadMatch[1]; if(config.browser.isIE) text = text.replace(/\n/g,"\r"); createTiddlyElement(w.output,"pre",null,null,text); w.nextMatch = lookaheadRegExp.lastIndex; } }; // @Deprecated: Use
or
instead of <
> config.macros.br.handler = function(place) { createTiddlyElement(place,"br"); }; // Find an entry in an array. Returns the array index or null // @Deprecated: Use indexOf instead Array.prototype.find = function(item) { var i = this.indexOf(item); return i == -1 ? null : i; }; // Load a tiddler from an HTML DIV. The caller should make sure to later call Tiddler.changed() // @Deprecated: Use store.getLoader().internalizeTiddler instead Tiddler.prototype.loadFromDiv = function(divRef,title) { return store.getLoader().internalizeTiddler(store,this,title,divRef); }; // Format the text for storage in an HTML DIV // @Deprecated Use store.getSaver().externalizeTiddler instead. Tiddler.prototype.saveToDiv = function() { return store.getSaver().externalizeTiddler(store,this); }; // @Deprecated: Use store.allTiddlersAsHtml() instead function allTiddlersAsHtml() { return store.allTiddlersAsHtml(); } // @Deprecated: Use refreshPageTemplate instead function applyPageTemplate(title) { refreshPageTemplate(title); } // @Deprecated: Use story.displayTiddlers instead function displayTiddlers(srcElement,titles,template,unused1,unused2,animate,unused3) { story.displayTiddlers(srcElement,titles,template,animate); } // @Deprecated: Use story.displayTiddler instead function displayTiddler(srcElement,title,template,unused1,unused2,animate,unused3) { story.displayTiddler(srcElement,title,template,animate); } // @Deprecated: Use functions on right hand side directly instead var createTiddlerPopup = Popup.create; var scrollToTiddlerPopup = Popup.show; var hideTiddlerPopup = Popup.remove; // @Deprecated: Use right hand side directly instead var regexpBackSlashEn = new RegExp("\\\\n","mg"); var regexpBackSlash = new RegExp("\\\\","mg"); var regexpBackSlashEss = new RegExp("\\\\s","mg"); var regexpNewLine = new RegExp("\n","mg"); var regexpCarriageReturn = new RegExp("\r","mg"); //-- //-- End of scripts //-- //]]>
Hosted by www.Geocities.ws

1