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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none ! important;}
#displayArea {margin: 1em 1em 0em 1em;}
/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>

</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>

<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>

</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>

<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->

<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>

<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>

<!--}}}-->
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

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

<<option txtUserName>>
<<option chkSaveBackups>> SaveBackups

<<option chkAutoSave>> AutoSave
<<option chkRegExpSearch>> RegExpSearch
<<option chkCaseSensitiveSearch>> CaseSensitiveSearch

<<option chkAnimate>> EnableAnimations

----
Also see [[AdvancedOptions]]
<<importTiddlers>>
Type the text for 'Abaddon'
!Regras Básicas
Estas săo as duas versőes do Cabal RPG. A primeira versăo é mais simples e direta, e a segunda é mais detalhada e realista. Ambas săo funcionais e coexistem, e vocę pode escolher qual é a melhor para seu jogo ou usar elementos de uma sobre a outra ou como base para suas próprias modificaçőes.
* 1Ş Versăo (316 KB).
* 2Ş Versăo (446 KB).
!O sistema
O sistema Cabal utiliza valores de 0 a 10, empregando para todos os testes um único dado de dez faces, ou "d10". Nesse dado, o resultado dez é considerado zero. O teste é bem sucedido quando o resultado do dado é igual ou menor que o valor testado, e a medida do sucesso é a diferença obtida, ou DIF. Quando o resultado do dado é zero, joga-se novamente o dado; se houver novo sucesso, ocorre um sucesso crítico, somando-se a DIF do novo teste ŕ do primeiro. Quando o resultado do dado é nove, entretanto, também joga-se novamente o dado; se houver nova falha, ocorre uma falha crítica, um resultado desastroso para o teste.

A mecânica de diferenças permite facilmente resolver controvérsias durante o jogo, pois produz valores numéricos que podem ser usados facilmente, como diferenças requeridas para o sucesso de outros testes, bônus ou penalidades para testes, variáveis como duraçăo e tamanho.
!!A proposta do sistema
Cabal é um sistema de RPG que busca ser tręs coisas: simples, maleável e funcional.

Existem ótimos sistemas de RPG que acabam espantando mestres e jogadores por serem complexos demais. Tabelas sem fim, uma infinidade de nomes e valores a serem decorados, relaçőes entre as regras que causam confusăo ou, nas piores hipóteses, regras mesmas que demoram tanto para solucionar os problemas de jogo, que este passa a ser um exercício de matemática em vez de diversăo.

Cabal utiliza um único dado de dez faces para todos os testes. Com qualquer método para gerar um valor aleatório entre 0 e 9, vocę poderá se divertir onde quer que esteja. As poucas tabelas do sistema cabem em uma folha de papel, e a construçăo da mecânica de jogo foi feita da maneira mais lógica e amigável possível.

Pode-se dizer que năo há sistema fixo que seja realmente genérico, pois para climas de jogo diferentes, requerem-se soluçőes diferentes. Há como se jogar excelentes jogos de açăo com determinado sistema, mas ele năo será bom para jogos de profundidade dramática. Em contrapartida, sistemas realistas năo prestam para jogos fantásticos ou cinematográficos.

Cabal pretende ser maleável exatamente por conter mecânicas numéricas simples. Com a alteraçăo do comportamento de alguns valores, ou mesmo modificando-os, vocę pode adaptar o sistema para seu cenário. Para alguns exemplos, veja Cenários.

Finalmente, a falha de muitos sistemas é simplesmente que năo solucionam problemas, ou, mais absurdo, năo permitir intençőes ou năo "responder" a elas. Um sistema năo "responde" a uma intençăo quando um jogador comunica que seu personagem quer fazer algo, mas o sistema năo prevę isso. E isso explica-se: é impossível um sistema de RPG prever todas as idéias de um jogador e transformá-las em números específicos.

Cabal apresenta um sistema fácil de soluçăo de controvérsias, que permite levar em conta as intençőes dos jogadores e responder a elas. Quando necessárias, as intençőes dos jogadores facilmente se convertem em testes rápidos, que produzem resultados imediatos.

O sistema Cabal pode ser a única ferramenta que um mestre precise para conduzir um bom jogo, em cenários tirados da imaginaçăo ou adaptados de quaisquer fontes.
Informaçőes legais

Os direitos autorais sobre Cabal RPG, seus cenários oficiais e esta página pertencem a seu autor, Eduardo Capistrano da Silva. Todo o material disponibilizado ou qualquer reproduçăo feita dele é exclusivamente para uso pessoal, năo sendo permitida sua utilizaçăo para comercializaçăo ou obtençăo de vantagem por qualquer meio sem autorizaçăo expressa do autor.
Type the text for 'Cachorros na Chuva'
*[[Abaddon]]: visite uma Terra onde o Apocalipse começou... para nunca terminar (PARA MAIORES DE IDADE).
*[[Cachorros na Chuva]]: seja um dos muitos canalhas de um mundo căo (PARA MAIORES DE IDADE).
*[[Cosmopolis]]: encontre incontáveis raças alienígenas e navegue por toda uma galáxia.
*[[Daemon]]: seja um deus esquecido preso na Terra em forma humana.
*[[Dança Macabra]]: a hora de morrer chega para todos... ou será que năo?
*[[Desconhecido]]: entre no mundo igualmente horrível e ridículo dos filmes "B".
*[[Fasantia]]: um mundo de fantasia onde a magia vem de entidades com poderes divinos.
*[[Terra S.A.]]: ofereça seus serviços para as corporaçőes que dominam um futuro cyberpunk.
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #ff0000
PrimaryMid: #660000
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
Type the text for 'Cosmopolis'
Type the text for 'Daemon'
Type the text for 'Dança Macabra'
[[Início]]
Type the text for 'Desconhecido'
<<option txtUserName>>
<<option chkSaveBackups>> SaveBackups

<<option chkAutoSave>> AutoSave
<<option chkRegExpSearch>> RegExpSearch
<<option chkCaseSensitiveSearch>> CaseSensitiveSearch
<<option chkAnimate>> EnableAnimations

<<tabs txtMainTab "Timeline" "Timeline" TabTimeline "All" "All tiddlers" TabAll "Tags" "All tags" TabTags "More" "More lists" TabMore>>
Type the text for 'Fasantia'
config.options.chkHttpReadOnly = true;
!Reinauguraçăo - 1ş de Maio de 2009
Para facilidade de atualizaçăo, a página foi reformatada utilizando o [[TiddlyWiki|http://www.tiddlywiki.com]].
[[Início]]
[[Sistemas]]
[[Cenários]]
[[Contato]]

[img[acreader.gif]]
^^TiddlyWiki <<version>>[[.|Dot]]
<<option txtUserName>>
<<option chkSaveBackups>> SaveBackups
<<option chkAutoSave>> AutoSave
<<option chkRegExpSearch>> RegExpSearch
<<option chkCaseSensitiveSearch>> CaseSensitiveSearch
<<option chkAnimate>> EnableAnimations
<!--{{{-->
<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>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>

</div>

<!--}}}-->
<<search>><<closeAll>><<permaview>><<newTiddler label:"novo tiddler">><<newJournal "DD MMM YYYY" "journal" label:"novo diário">><<saveChanges>>
*[[Cabal]]: sistema genérico, universal e modular que utiliza apenas um dado de dez faces.
*[[Xerazade]]: sistema sem dados, focado em narraçăo, com resoluçăo de controvérsias baseado no perfil dos personagens e na interpretaçăo.
cenários e sistemas de RPG por Eduardo Capistrano
Cabal RPG
Type the text for 'Terra S.A.'
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><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>
<!--}}}-->
Type the text for 'Xerazade'
section of the TiddlyWiki HTML file", MarkupPostBody: "This tiddler is inserted at the end of the
section of the TiddlyWiki HTML file immediately after 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", StyleSheetColors: "This shadow tiddler contains CSS definitions related to the color of page elements. ''DO NOT EDIT THIS TIDDLER'', instead make your changes in the StyleSheet shadow tiddler", StyleSheet: "This tiddler can contain custom CSS definitions", StyleSheetLayout: "This shadow tiddler contains CSS definitions related to the layout of page elements. ''DO NOT EDIT THIS TIDDLER'', instead make your changes in the StyleSheet shadow tiddler", 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", ToolbarCommands: "This shadow tiddler determines which commands are shown in tiddler toolbars", 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 var anim = typeof Animator == "function" ? new Animator() : null; // 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 showBackstage; // Whether to include the backstage area 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) && (document.location.toString().substr(0,4) != "http"); // Starting up function main() { var t10,t9,t8,t7,t6,t5,t4,t3,t2,t1,t0 = new Date(); startingUp = true; jQuery.noConflict(); 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) { plugin.log.push(config.messages.pluginVersionError); return false; } } return true; } function isPluginEnabled(plugin) { if(plugin.tiddler.isTagged("systemConfigDisable")) { plugin.log.push(config.messages.pluginDisabled); return false; } return true; } function invokeMacro(place,macro,params,wikifier,tiddler) { try { var m = config.macros[macro]; if(m && m.handler) { var tiddlerElem = story.findContainingTiddler(place); window.tiddler = tiddlerElem ? store.getTiddler(tiddlerElem.getAttribute("tiddler")) : null; window.place = place; 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 = decodeURIComponent(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 i=1; i") { // 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?|
\\n?", handler: function(w) { createTiddlyElement(w.output,"hr"); } }, { name: "monospacedByLine", match: "^(?:/\\*\\{\\{\\{\\*/|\\{\\{\\{|//\\{\\{\\{|)\\n", element: "pre", handler: function(w) { switch(w.matchText) { case "/*{{{*/\n": // CSS this.lookaheadRegExp = /\/\*\{\{\{\*\/\n*((?:^[^\n]*\n)+?)(\n*^\/\*\}\}\}\*\/$\n?)/mg; break; case "{{{\n": // monospaced block this.lookaheadRegExp = /^\{\{\{\n((?:^[^\n]*\n)+?)(^\}\}\}$\n?)/mg; break; case "//{{{\n": // plugin this.lookaheadRegExp = /^\/\/\{\{\{\n\n*((?:^[^\n]*\n)+?)(\n*^\/\/\}\}\}$\n?)/mg; break; case "\n": //template this.lookaheadRegExp = /\n*((?:^[^\n]*\n)+?)(\n*^$\n?)/mg; break; default: break; } config.formatterHelpers.enclosedTextHelper.call(this,w); } }, { name: "wikifyComment", match: "^(?:/\\*\\*\\*|\n)/mg); w.subWikifyTerm(w.output,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,decodeURIComponent(link),false,null,w.isStatic,w.tiddler); } else { // Simple bracketted link e = createTiddlyLink(w.output,decodeURIComponent(text),false,null,w.isStatic,w.tiddler); } createTiddlyText(e,text); w.nextMatch = this.lookaheadRegExp.lastIndex; } } }, { name: "wikiLink", match: config.textPrimitives.unWikiLink+"?"+config.textPrimitives.wikiLink, handler: function(w) { if(w.matchText.substr(0,1) == config.textPrimitives.unWikiLink) { w.outputText(w.output,w.matchStart+1,w.nextMatch); return; } 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 || 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.setAttribute("alt",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: "characterFormat", match: "''|//|__|\\^\\^|~~|--(?!\\s|$)|\\{\\{\\{", handler: function(w) { switch(w.matchText) { case "''": w.subWikifyTerm(w.output.appendChild(document.createElement("strong")),/('')/mg); break; case "//": w.subWikifyTerm(createTiddlyElement(w.output,"em"),/(\/\/)/mg); break; case "__": w.subWikifyTerm(createTiddlyElement(w.output,"u"),/(__)/mg); break; case "^^": w.subWikifyTerm(createTiddlyElement(w.output,"sup"),/(\^\^)/mg); break; case "~~": w.subWikifyTerm(createTiddlyElement(w.output,"sub"),/(~~)/mg); break; case "--": w.subWikifyTerm(createTiddlyElement(w.output,"strike"),/(--)/mg); break; case "{{{": var lookaheadRegExp = /\{\{\{((?:.|\n)*?)\}\}\}/mg; lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { createTiddlyElement(w.output,"code",null,null,lookaheadMatch[1]); w.nextMatch = lookaheadRegExp.lastIndex; } break; } } }, { name: "customFormat", match: "@@|\\{\\{", handler: function(w) { switch(w.matchText) { case "@@": 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,/(@@)/mg); break; case "{{": var lookaheadRegExp = /\{\{[\s]*([\w]+[\s\w]*)[\s]*\{(\n?)/mg; lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = lookaheadRegExp.exec(w.source); if(lookaheadMatch) { w.nextMatch = lookaheadRegExp.lastIndex; e = createTiddlyElement(w.output,lookaheadMatch[2] == "\n" ? "div" : "span",null,lookaheadMatch[1]); w.subWikifyTerm(e,/(\}\}\})/mg); } break; } } }, { name: "mdash", match: "--", handler: function(w) { createTiddlyElement(w.output,"span").innerHTML = "—"; } }, { 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: "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; } } ]; //-- //-- 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) { var wikifier = new Wikifier(source,getParser(tiddler),highlightRegExp,tiddler); var t0 = new Date(); wikifier.subWikify(output); if(tiddler && config.options.chkDisplayInstrumentation) displayMessage("wikify:" +tiddler.title+ " in " + (new Date()-t0) + " ms"); } } function wikifyStatic(source,highlightRegExp,tiddler,format) { var e = createTiddlyElement(document.body,"pre"); e.style.display = "none"; var html = ""; if(source && source != "") { if(!tiddler) tiddler = new Tiddler("temp"); var wikifier = new Wikifier(source,getParser(tiddler,format),highlightRegExp,tiddler); wikifier.isStatic = true; wikifier.subWikify(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) { 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"); e.style.display = "none"; this.subWikify(e); var text = getPlainText(e); removeNode(e); return text; }; Wikifier.prototype.subWikify = function(output,terminator) { try { if(terminator) this.subWikifyTerm(output,new RegExp("(" + terminator + ")","mg")); else this.subWikifyUnterm(output); } catch(ex) { showException(ex); } }; Wikifier.prototype.subWikifyUnterm = function(output) { 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 = params[0] ? now.formatString(params[0].trim()) : now.toLocaleString(); createTiddlyElement(place,"span",null,null,text); }; config.macros.version.handler = function(place) { createTiddlyElement(place,"span",null,null,formatVersion()); }; config.macros.list.handler = function(place,macroName,params) { var type = 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.list.filter.handler = function(params) { var filter = params[1]; var results = []; if(filter) { var tiddlers = store.filterTiddlers(filter); for(var t=0; t=last; t--) { var tiddler = tiddlers[t]; var theDay = tiddler[field].convertToLocalYYYYMMDDHHMM().substr(0,8); if(theDay != lastDay) { var ul = document.createElement("ul"); place.appendChild(ul); createTiddlyElement(ul,"li",null,"listTitle",tiddler[field].formatString(dateFormat)); lastDay = theDay; } createTiddlyElement(ul,"li",null,"listLink").appendChild(createTiddlyLink(place,tiddler.title,true)); } }; config.macros.tiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler) { params = paramString.parseParams("name",null,true,false,true); var names = params[0]["name"]; var tiddlerName = names[0]; var className = names[1] || null; var args = params[0]["with"]; var wrapper = createTiddlyElement(place,"span",null,className); if(!args) { 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> config.macros.gradient.handler = function(place,macroName,params,wikifier,paramString,tiddler) { var panel = wikifier ? createTiddlyElement(place,"div",null,"gradient") : place; panel.style.position = "relative"; panel.style.overflow = "hidden"; panel.style.zIndex = "0"; if(wikifier) { var styles = config.formatterHelpers.inlineCssHelper(wikifier); config.formatterHelpers.applyCssHelper(panel,styles); } params = paramString.parseParams("color"); var locolors = [], hicolors = []; for(var t=2; t>"); if(document.all) { panel.style.height = "100%"; panel.style.width = "100%"; } }; config.macros.message.handler = function(place,macroName,params) { if(params[0]) { var names = params[0].split("."); var lookupMessage = function(root,nameIndex) { if(names[nameIndex] in root) { if(nameIndex < names.length-1) return (lookupMessage(root[names[nameIndex]],nameIndex+1)); else return root[names[nameIndex]]; } else return null; }; var m = lookupMessage(config,0); if(m == null) m = lookupMessage(window,0); createTiddlyText(place,m.toString().format(params.splice(1))); } }; config.macros.view.views = { text: function(value,place,params,wikifier,paramString,tiddler) { highlightify(value,place,highlightHack,tiddler); }, link: function(value,place,params,wikifier,paramString,tiddler) { createTiddlyLink(place,value,true); }, wikified: function(value,place,params,wikifier,paramString,tiddler) { if(params[2]) value=params[2].unescapeLineBreaks().format([value]); wikify(value,place,highlightHack,tiddler); }, date: function(value,place,params,wikifier,paramString,tiddler) { value = Date.convertFromYYYYMMDDHHMM(value); createTiddlyText(place,value.formatString(params[2] ? params[2] : config.views.wikified.dateFormat)); } }; config.macros.view.handler = function(place,macroName,params,wikifier,paramString,tiddler) { if((tiddler instanceof Tiddler) && params[0]) { var value = store.getValue(tiddler,params[0]); if(value) { var type = params[1] || config.macros.view.defaultView; var handler = config.macros.view.views[type]; if(handler) handler(value,place,params,wikifier,paramString,tiddler); } } }; config.macros.edit.handler = function(place,macroName,params,wikifier,paramString,tiddler) { var field = params[0]; var rows = params[1] || 0; var defVal = params[2] || ''; if((tiddler instanceof Tiddler) && field) { story.setDirty(tiddler.title,true); var e,v; if(field != "text" && !rows) { e = createTiddlyElement(null,"input"); if(tiddler.isReadOnly()) e.setAttribute("readOnly","readOnly"); e.setAttribute("edit",field); e.setAttribute("type","text"); e.value = store.getValue(tiddler,field) || defVal; e.setAttribute("size","40"); e.setAttribute("autocomplete","off"); place.appendChild(e); } else { var wrapper1 = createTiddlyElement(null,"fieldset",null,"fieldsetFix"); var wrapper2 = createTiddlyElement(wrapper1,"div"); e = createTiddlyElement(wrapper2,"textarea"); if(tiddler.isReadOnly()) e.setAttribute("readOnly","readOnly"); e.value = v = store.getValue(tiddler,field) || defVal; rows = rows || 10; var lines = v.match(/\n/mg); var maxLines = Math.max(parseInt(config.options.txtMaxEditRows),5); if(lines != null && lines.length > rows) rows = lines.length + 5; rows = Math.min(rows,maxLines); e.setAttribute("rows",rows); e.setAttribute("edit",field); place.appendChild(wrapper1); } return e; } }; config.macros.tagChooser.onClick = function(ev) { var e = ev || window.event; var lingo = config.views.editor.tagChooser; var popup = Popup.create(this); var tags = store.getTags(this.getAttribute("tags")); if(tags.length == 0) createTiddlyText(createTiddlyElement(popup,"li"),lingo.popupNone); for(var t=0; t 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") { title = new Date().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"); if(!customFields && !store.isShadowTiddler(title)) customFields = String.encodeHashMap(config.defaultCustomFields); story.displayTiddler(null,title,template,false,null,null); var tiddlerElem = story.getTiddler(title); if(customFields) story.addCustomFields(tiddlerElem,customFields); var text = this.getAttribute("newText"); if(typeof text == "string" && story.getTiddlerField(title,"text")) story.getTiddlerField(title,"text").value = text.format([title]); for(var t=0;t 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 || 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(config.options.chkIncrementalSearch) { 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(); }; //-- //-- Tabs macro //-- config.macros.tabs.handler = function(place,macroName,params) { var cookie = params[0]; var numTabs = (params.length-1)/3; var wrapper = createTiddlyElement(null,"div",null,"tabsetWrapper " + cookie); var tabset = createTiddlyElement(wrapper,"div",null,"tabset"); tabset.setAttribute("cookie",cookie); var validTab = false; for(var t=0; t': 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 className = ""; switch(c.substr(0,1)) { case "+": className = "defaultCommand"; c = c.substr(1); break; case "-": className = "cancelCommand"; c = c.substr(1); break; } if(c in config.commands) this.createCommand(place,c,tiddler,className); break; } } }; //-- //-- Menu and toolbar commands //-- config.commands.closeTiddler.handler = function(event,src,title) { if(story.isDirty(title) && !readOnly) { if(!confirm(config.commands.cancelTiddler.warning.format([title]))) return false; } story.setDirty(title,false); 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 = story.getTiddler(title); var fields = tiddlerElem.getAttribute("tiddlyFields"); story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE,false,null,fields); story.focusTiddler(title,config.options.txtEditorFocus||"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 = ""; this.modifier = null; this.created = new Date(); this.modified = this.created; 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(var 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,10) : 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']; } }; Tiddler.prototype.doNotSave = function() { return this.fields['doNotSave']; }; // 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; }; // 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 text = this.text; // remove 'quoted' text before scanning tiddler source text = text.replace(/\/%((?:.|\n)*?)%\//g,""). replace(/\{{3}((?:.|\n)*?)\}{3}/g,""). replace(/"""((?:.|\n)*?)"""/g,""). replace(/\((?:.|\n)*?)\<\/nowiki\>/g,""). replace(/\((?:.|\n)*?)\<\/html\>/g,""). replace(/\/g,""); var t = this.autoLinkWikiWords() ? 0 : 1; var tiddlerLinkRegExp = t==0 ? config.textPrimitives.tiddlerAnyLinkRegExp : config.textPrimitives.tiddlerForcedLinkRegExp; tiddlerLinkRegExp.lastIndex = 0; var formatMatch = tiddlerLinkRegExp.exec(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(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(text); } this.linksUpdated = true; }; Tiddler.prototype.getSubtitle = function() { var modifier = this.modifier; if(!modifier) modifier = config.messages.subtitleUnknown; var modified = this.modified; if(modified) modified = modified.toLocaleString(); else modified = config.messages.subtitleUnknown; return config.messages.tiddlerLinkTooltip.format([this.title,modifier,modified]); }; 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['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(); return serverType ? new config.adaptors[serverType]() : 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) { var t = tiddlers[title]; return t instanceof Tiddler ? t : null; }; 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.tiddlerExists = function(title) { var t = this.fetchTiddler(title); return t != undefined; }; TiddlyWiki.prototype.isShadowTiddler = function(title) { return config.shadowTiddlers[title] === undefined ? false : true; }; TiddlyWiki.prototype.createTiddler = function(title) { var tiddler = this.fetchTiddler(title); if(!tiddler) { tiddler = new Tiddler(title); this.addTiddler(tiddler); this.setDirty(true); } return tiddler; }; TiddlyWiki.prototype.getTiddler = function(title) { var t = this.fetchTiddler(title); if(t != undefined) return t; else return null; }; TiddlyWiki.prototype.getShadowTiddlerText = function(title) { if(typeof config.shadowTiddlers[title] == "string") return config.shadowTiddlers[title]; else return ""; }; TiddlyWiki.prototype.getTiddlerText = function(title,defaultText) { if(!title) return defaultText; var pos = title.indexOf(config.textPrimitives.sectionSeparator); var section = null; if(pos != -1) { section = title.substr(pos + config.textPrimitives.sectionSeparator.length); title = title.substr(0,pos); } pos = title.indexOf(config.textPrimitives.sliceSeparator); if(pos != -1) { var slice = this.getTiddlerSlice(title.substr(0,pos),title.substr(pos + config.textPrimitives.sliceSeparator.length)); if(slice) return slice; } var tiddler = this.fetchTiddler(title); if(tiddler) { if(!section) return tiddler.text; var re = new RegExp("(^!{1,6}" + section.escapeRegExp() + "[ \t]*\n)","mg"); re.lastIndex = 0; var match = re.exec(tiddler.text); if(match) { var t = tiddler.text.substr(match.index+match[1].length); var re2 = /^!/mg; re2.lastIndex = 0; match = re2.exec(t); //# search for the next heading if(match) t = t.substr(0,match.index-1);//# don't include final \n return t; } return defaultText; } if(this.isShadowTiddler(title)) return this.getShadowTiddlerText(title); if(defaultText != undefined) return defaultText; return null; }; TiddlyWiki.prototype.getRecursiveTiddlerText = function(title,defaultText,depth) { var bracketRegExp = new RegExp("(?:\\[\\[([^\\]]+)\\]\\])","mg"); var text = this.getTiddlerText(title,null); if(text == null) return defaultText; var textOut = []; var lastPos = 0; do { var match = bracketRegExp.exec(text); if(match) { textOut.push(text.substr(lastPos,match.index-lastPos)); if(match[1]) { if(depth <= 0) textOut.push(match[1]); else textOut.push(this.getRecursiveTiddlerText(match[1],"[[" + match[1] + "]]",depth-1)); } lastPos = match.index + match[0].length; } else { textOut.push(text.substr(lastPos)); } } while(match); return textOut.join(""); }; TiddlyWiki.prototype.slicesRE = /(?:^([\'\/]{0,2})~?([\.\w]+)\:\1[\t\x20]*([^\n]+)[\t\x20]*$)|(?:^\|([\'\/]{0,2})~?([\.\w]+)\:?\4\|[\t\x20]*([^\n]+)[\t\x20]*\|$)/gm; // @internal TiddlyWiki.prototype.calcAllSlices = function(title) { var slices = {}; var text = this.getTiddlerText(title,""); this.slicesRE.lastIndex = 0; var m = this.slicesRE.exec(text); while(m) { if(m[2]) slices[m[2]] = m[3]; else slices[m[5]] = m[6]; m = this.slicesRE.exec(text); } return slices; }; // Returns the slice of text of the given name TiddlyWiki.prototype.getTiddlerSlice = function(title,sliceName) { var slices = this.slices[title]; if(!slices) { slices = this.calcAllSlices(title); this.slices[title] = slices; } return slices[sliceName]; }; // Build an hashmap of the specified named slices of a tiddler TiddlyWiki.prototype.getTiddlerSlices = function(title,sliceNames) { var r = {}; 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 an array of tiddlers matching a search regular expression TiddlyWiki.prototype.search = function(searchRegExp,sortField,excludeTag,match) { var candidates = this.reverseLookup("tags",excludeTag,!!match); 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(containerId,idPrefix) { this.container = containerId; this.idPrefix = idPrefix; this.highlightRegExp = null; this.tiddlerId = function(title) { var id = this.idPrefix + title; return id==this.container ? this.idPrefix + "_" + title : id; }; this.containerId = function() { return this.container; }; } Story.prototype.getTiddler = function(title) { return document.getElementById(this.tiddlerId(title)); }; Story.prototype.getContainer = function() { return document.getElementById(this.containerId()); }; Story.prototype.forEachTiddler = function(fn) { var place = this.getContainer(); 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.displayDefaultTiddlers = function() { this.displayTiddlers(null,store.filterTiddlers(store.getTiddlerText("DefaultTiddlers"))); }; 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,tiddler,template,animate,unused,customFields,toggle,animationSrc) { var title = (tiddler instanceof Tiddler) ? tiddler.title : tiddler; var tiddlerElem = this.getTiddler(title); if(tiddlerElem) { if(toggle) this.closeTiddler(title,true); else this.refreshTiddler(title,template,false,customFields); } else { var place = this.getContainer(); var before = this.positionTiddler(srcElement); tiddlerElem = this.createTiddler(place,before,title,template,customFields); } if(animationSrc && typeof animationSrc !== "string") { srcElement = animationSrc; } 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 = this.getContainer(); 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.tiddlerId(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 || {}); 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,"onGetTiddler"); }, onGetTiddler: function(context) { var tiddler = context.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 = this.getTiddler(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) { tiddler = new Tiddler(); if(store.isShadowTiddler(title)) { var tags = []; tiddler.set(title,store.getTiddlerText(title),config.views.wikified.shadowModifier,version.date,tags,version.date); } else { var text = template=="EditTemplate" ? config.views.editor.defaultText.format([title]) : config.views.wikified.defaultText.format([title]); text = 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); tiddlerElem.onmouseover = this.onTiddlerMouseOver; tiddlerElem.onmouseout = this.onTiddlerMouseOut; tiddlerElem.ondblclick = this.onTiddlerDblClick; tiddlerElem[window.event?"onkeydown":"onkeypress"] = this.onTiddlerKeyPress; tiddlerElem.innerHTML = this.getTemplateForTiddler(title,template,tiddler); applyHtmlMacros(tiddlerElem,tiddler); if(store.getTaggedTiddlers(title).length > 0) addClass(tiddlerElem,"isTag"); else removeClass(tiddlerElem,"isTag"); if(store.tiddlerExists(title)) { removeClass(tiddlerElem,"shadow"); removeClass(tiddlerElem,"missing"); } else { addClass(tiddlerElem,store.isShadowTiddler(title) ? "shadow" : "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(force) { var e = this.getContainer().firstChild; while(e) { var template = e.getAttribute("template"); if(template && e.getAttribute("dirty") != "true") { this.refreshTiddler(e.getAttribute("tiddler"),force ? null : template,true); } e = e.nextSibling; } }; 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 || window.event; var target = resolveTarget(e); if(target && target.nodeName.toLowerCase() != "input" && target.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; } return false; }; Story.prototype.onTiddlerKeyPress = function(ev) { var e = 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 = this.getTiddler(title); var e = null; if(tiddlerElem ) { var children = tiddlerElem.getElementsByTagName("*"); for(var t=0; t 0) displayMessage(config.macros.search.successMsg.format([matches.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(context) { var tiddler = context.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(context) { var title = context.title; var syncItem = st.syncItems.findByField("title",title); if(syncItem !== null) { syncItem = st.syncItems[syncItem]; store.resetTiddler(title); if(context.status) { 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); if(syncItem.syncStatus.display) syncItem.rowElement.style.display = syncItem.syncStatus.display; if(syncItem.syncStatus.className) syncItem.rowElement.className = syncItem.syncStatus.className; }; config.macros.sync.doSync = function(e) { var rowNames = ListView.getSelectedRows(currSync.listView); var sl = config.macros.sync.syncStatusList; for(var i=0; i=0; t--) stash.appendChild(nodes[t]); } var wrapper = document.getElementById("contentWrapper"); var isAvailable = function(title) { var s = title ? title.indexOf(config.textPrimitives.sectionSeparator) : -1; if(s!=-1) title = title.substr(0,s); return store.tiddlerExists(title) || store.isShadowTiddler(title); }; if(!title || !isAvailable(title)) title = config.refresherData.pageTemplate; if(!isAvailable(title)) title = config.refresherData.defaultPageTemplate; //# this one is always avaialable wrapper.innerHTML = store.getRecursiveTiddlerText(title,null,10); applyHtmlMacros(wrapper); refreshElements(wrapper); display = story.getContainer(); removeChildren(display); if(!display) display = createTiddlyElement(wrapper,"div",story.containerId()); 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) { setStylesheet(title == null ? "" : store.getRecursiveTiddlerText(title,"",10),title,doc || document); } function refreshColorPalette(title) { if(!startingUp) refreshAll(); } function refreshAll() { refreshPageTemplate(); refreshDisplay(); refreshStyles("StyleSheetLayout"); refreshStyles("StyleSheetColors"); refreshStyles(config.refresherData.styleSheet); refreshStyles("StyleSheetPrint"); } //-- //-- Options 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" + convertUnicodeToFileFormat(store.getRecursiveTiddlerText(tiddlerName,"")) + "\n"); } function updateOriginal(original,posDiv,localPath) { 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" + convertUnicodeToFileFormat(store.allTiddlersAsHtml()) + "\n" + original.substr(posDiv[1]); var newSiteTitle = convertUnicodeToFileFormat(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); } function loadOriginal(localPath) { return loadFile(localPath); } // Save this tiddlywiki with the pending changes function saveChanges(onlyIfDirty,tiddlers) { if(onlyIfDirty && !store.isDirty()) return; clearMessage(); var t0 = new Date(); var originalPath = document.location.toString(); 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); var original = loadOriginal(localPath); if(original == null) { alert(config.messages.cantSaveError); if(store.tiddlerExists(config.messages.saveInstructions)) story.displayTiddler(null,config.messages.saveInstructions); return; } var posDiv = locateStoreArea(original); if(!posDiv) { alert(config.messages.invalidFileError.format([localPath])); return; } saveMain(localPath,original,posDiv); if(config.options.chkSaveBackups) saveBackup(localPath,original); if(config.options.chkSaveEmptyTemplate) saveEmpty(localPath,original,posDiv); if(config.options.chkGenerateAnRssFeed && saveRss instanceof Function) saveRss(localPath); if(config.options.chkDisplayInstrumentation) displayMessage("saveChanges " + (new Date()-t0) + " ms"); } function saveMain(localPath,original,posDiv) { var save; try { var revised = updateOriginal(original,posDiv,localPath); 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 saveBackup(localPath,original) { var backupPath = getBackupPath(localPath); var backup = copyFile(backupPath,localPath); if(!backup) backup = saveFile(backupPath,original); if(backup) displayMessage(config.messages.backupSaved,"file://" + backupPath); else alert(config.messages.backupFailed); } function saveEmpty(localPath,original,posDiv) { var emptyPath,p; if((p = localPath.lastIndexOf("http://br.geocities.com/")) != -1) emptyPath = localPath.substr(0,p) + "/"; else if((p = localPath.lastIndexOf("\\")) != -1) emptyPath = localPath.substr(0,p) + "\\"; else emptyPath = localPath + "."; emptyPath += "http://br.geocities.com/cabalrpg/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 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://br.geocities.com/","g"),"\\"); else if(originalPath.indexOf("file://///") == 0) // FireFox pc network file localPath = "\\\\" + unescape(originalPath.substr(10)).replace(new RegExp("http://br.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://br.geocities.com/","g"),"\\"); return localPath; } function getBackupPath(localPath,title,extension) { var slash = "\\"; var dirPathPos = localPath.lastIndexOf("\\"); if(dirPathPos == -1) { dirPathPos = localPath.lastIndexOf("http://br.geocities.com/"); slash = "http://br.geocities.com/"; } var backupFolder = config.options.txtBackupFolder; if(!backupFolder || backupFolder == "") backupFolder = "."; var backupPath = localPath.substr(0,dirPathPos) + slash + backupFolder + localPath.substr(dirPathPos); backupPath = backupPath.substr(0,backupPath.lastIndexOf(".")) + "."; if(title) backupPath += title.replace(/[\\\/\*\?\":<> ]/g,"_") + "."; backupPath += (new Date()).convertToYYYYMMDDHHMMSSMMM() + "." + (extension || "html"); return backupPath; } //-- //-- RSS Saving //-- function saveRss(localPath) { var rssPath = localPath.substr(0,localPath.lastIndexOf(".")) + ".xml"; if(saveFile(rssPath,convertUnicodeToFileFormat(generateRss()))) displayMessage(config.messages.rssSaved,"file://" + rssPath); else alert(config.messages.rssFailed); } tiddlerToRssItem = function(tiddler,uri) { var s = "" + tiddler.title.htmlEncode() + "\n"; s += "" + wikifyStatic(tiddler.text,null,tiddler).htmlEncode() + "\n"; for(var i=0; i\n"; s += "" + uri + "#" + encodeURIComponent(String.encodeTiddlyLink(tiddler.title)) + "\n"; s +="" + tiddler.modified.toGMTString() + "\n"; return s; }; 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("" + config.locale + ""); 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 " + formatVersion() + ""); // The body var tiddlers = store.getTiddlers("modified","excludeLists"); var n = config.numRssItems > tiddlers.length ? 0 : tiddlers.length-config.numRssItems; for(var i=tiddlers.length-1; i>=n; i--) { s.push("\n" + tiddlerToRssItem(tiddlers[i],u) + "\n"); } // And footer s.push(""); s.push(""); // Save it all return s.join("\n"); } //-- //-- Filesystem code //-- function convertUTF8ToUnicode(u) { return config.browser.isOpera || !window.netscape ? manualConvertUTF8ToUnicode(u) : 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 convertUnicodeToFileFormat(s) { return config.browser.isOpera || !window.netscape ? convertUnicodeToHtmlEntities(s) : mozConvertUnicodeToUTF8(s); } function convertUnicodeToHtmlEntities(s) { var re = /[^\u0000-\u007F]/g; return s.replace(re,function($0) {return "&#" + $0.charCodeAt(0).toString() + ";";}); } function convertUnicodeToUTF8(s) { // return convertUnicodeToFileFormat to allow plugin migration return convertUnicodeToFileFormat(s); } function manualConvertUnicodeToUTF8(s) { return unescape(encodeURIComponent(s)); } 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(); return fin.length > 0 ? u + fin : 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 copyFile(dest,source) { return config.browser.isIE ? ieCopyFile(dest,source) : false; } function saveFile(fileUrl,content) { var r = mozillaSaveFile(fileUrl,content); if(!r) r = ieSaveFile(fileUrl,content); if(!r) r = javaSaveFile(fileUrl,content); return r; } function loadFile(fileUrl) { var r = mozillaLoadFile(fileUrl); if((r == null) || (r == false)) r = ieLoadFile(fileUrl); if((r == null) || (r == false)) r = javaLoadFile(fileUrl); return r; } function ieCreatePath(path) { try { var fso = new ActiveXObject("Scripting.FileSystemObject"); } catch(ex) { return null; } var pos = path.lastIndexOf("\\"); if(pos==-1) pos = path.lastIndexOf("http://br.geocities.com/"); if(pos!=-1) path = path.substring(0,pos+1); var scan = [path]; var parent = fso.GetParentFolderName(path); while(parent && !fso.FolderExists(parent)) { scan.push(parent); parent = fso.GetParentFolderName(parent); } for(i=scan.length-1;i>=0;i--) { if(!fso.FolderExists(scan[i])) { fso.CreateFolder(scan[i]); } } return true; } // Returns null if it can't do it, false if there's an error, true if it saved OK function ieSaveFile(filePath,content) { ieCreatePath(filePath); 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) { ieCreatePath(dest); 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); var contents = sInputStream.read(sInputStream.available()); sInputStream.close(); inputStream.close(); return contents; } 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(":"); return i > 0 ? url.substring(i-1) : 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 base class //-- function AdaptorBase() { this.host = null; this.store = null; return this; } AdaptorBase.prototype.close = function() { return true; }; AdaptorBase.prototype.fullHostName = function(host) { if(!host) return ''; host = host.trim(); if(!host.match(/:\/\//)) host = 'http://' + host; if(host.substr(host.length-1) == 'http://br.geocities.com/') host = host.substr(0,host.length-1); return host; }; AdaptorBase.minHostName = function(host) { return host ? host.replace(/^http:\/\//,'').replace(/\/$/,'') : ''; }; AdaptorBase.prototype.setContext = function(context,userParams,callback) { if(!context) context = {}; context.userParams = userParams; if(callback) context.callback = callback; context.adaptor = this; if(!context.host) context.host = this.host; context.host = this.fullHostName(context.host); if(!context.workspace) context.workspace = this.workspace; return context; }; // Open the specified host AdaptorBase.prototype.openHost = function(host,context,userParams,callback) { this.host = host; context = this.setContext(context,userParams,callback); context.status = true; if(callback) window.setTimeout(function() {context.callback(context,userParams);},10); return true; }; // Open the specified workspace AdaptorBase.prototype.openWorkspace = function(workspace,context,userParams,callback) { this.workspace = workspace; context = this.setContext(context,userParams,callback); context.status = true; if(callback) window.setTimeout(function() {callback(context,userParams);},10); return true; }; //-- //-- Server adaptor for talking to static TiddlyWiki files //-- function FileAdaptor() { } FileAdaptor.prototype = new AdaptorBase(); FileAdaptor.serverType = 'file'; FileAdaptor.serverLabel = 'TiddlyWiki'; FileAdaptor.loadTiddlyWikiCallback = function(status,context,responseText,url,xhr) { context.status = status; if(!status) { context.statusText = "Error reading file"; } else { context.adaptor.store = new TiddlyWiki(); if(!context.adaptor.store.importTiddlyWiki(responseText)) { context.statusText = config.messages.invalidFileError.format([url]); context.status = false; } } context.complete(context,context.userParams); }; // Get the list of workspaces on a given server FileAdaptor.prototype.getWorkspaceList = function(context,userParams,callback) { context = this.setContext(context,userParams,callback); context.workspaces = [{title:"(default)"}]; context.status = true; if(callback) 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,filter) { context = this.setContext(context,userParams,callback); if(!context.filter) context.filter = filter; context.complete = FileAdaptor.getTiddlerListComplete; if(this.store) { var ret = context.complete(context,context.userParams); } else { ret = loadRemoteFile(context.host,FileAdaptor.loadTiddlyWikiCallback,context); if(typeof ret != "string") ret = true; } return ret; }; FileAdaptor.getTiddlerListComplete = function(context,userParams) { if(context.status) { if(context.filter) { context.tiddlers = context.adaptor.store.filterTiddlers(context.filter); } else { context.tiddlers = []; context.adaptor.store.forEachTiddler(function(title,tiddler) {context.tiddlers.push(tiddler);}); } for(var i=0; ix2) return -1; } x1 = v1.beta || 9999; x2 = v2.beta || 9999; if(x1 x2 ? -1 : 0; } function createTiddlyButton(parent,text,tooltip,action,className,id,accessKey,attribs) { var btn = document.createElement("a"); if(action) { btn.onclick = action; btn.setAttribute("href","javascript:;"); } if(tooltip) btn.setAttribute("title",tooltip); if(text) btn.appendChild(document.createTextNode(text)); btn.className = className || "button"; if(id) btn.id = id; if(attribs) { for(var i in attribs) { btn.setAttribute(i,attribs[i]); } } if(parent) parent.appendChild(btn); if(accessKey) btn.setAttribute("accessKey",accessKey); return btn; } function createTiddlyLink(place,title,includeText,className,isStatic,linkedFromTiddler,noToggle) { var text = includeText ? title : null; var i = getTiddlyLinkInfo(title,className); var btn = isStatic ? createExternalLink(place,store.getTiddlerText("SiteUrl",null) + "#" + title) : createTiddlyButton(place,text,i.subTitle,onClickTiddlerLink,i.classes); if(isStatic) btn.className += ' ' + className; 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(typeof config.annotations[title]=="string") subTitle = config.annotations[title]; return {classes: classes.join(" "),subTitle: subTitle}; } function createExternalLink(place,url) { var link = document.createElement("a"); link.className = "externalLink"; link.href = url; link.title = config.messages.externalLinkTooltip.format([url]); if(config.options.chkOpenInNewWindow) link.target = "_blank"; place.appendChild(link); return link; } // Event handler for clicking on a tiddly link function onClickTiddlerLink(ev) { var e = ev || window.event; var target = resolveTarget(e); var link = target; var title = null; var fields = null; var noToggle = null; do { title = link.getAttribute("tiddlyLink"); fields = link.getAttribute("tiddlyFields"); noToggle = link.getAttribute("noToggle"); link = link.parentNode; } while(title == null && link != 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; if(store.getTiddler(title)) fields = null; story.displayTiddler(target,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,title,tooltip) { var btn = createTiddlyButton(place,title||tag,(tooltip||config.views.wikified.tag.tooltip).format([tag]),onClickTag); btn.setAttribute("tag",tag); if(excludeTiddler) btn.setAttribute("tiddler",excludeTiddler); return btn; } // Event handler for clicking on a tiddler tag function onClickTag(ev) { var e = 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) { 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,className) { var stackPosition = this.find(root,"popup"); Popup.remove(stackPosition+1); var popup = createTiddlyElement(document.body,elem || "ol","popup",className || "popup"); popup.stackPosition = stackPosition; Popup.stack.push({root: root, popup: popup}); return popup; }; Popup.onDocumentClick = function(ev) { var e = 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(valign,halign,offset) { var curr = Popup.stack[Popup.stack.length-1]; this.place(curr.root,curr.popup,valign,halign,offset); 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,valign,halign,offset) { if(!offset) var offset = {x:0,y:0}; if(popup.stackPosition >= 0 && !valign && !halign) { offset.x = offset.x + root.offsetWidth; } else { offset.x = (halign == 'right') ? offset.x + root.offsetWidth : offset.x; offset.y = (valign == 'top') ? offset.y : offset.y + root.offsetHeight; } var rootLeft = findPosX(root); var rootTop = findPosY(root); var popupLeft = rootLeft + offset.x; var popupTop = rootTop + offset.y; var winWidth = findWindowWidth(); if(popup.offsetWidth > winWidth*0.75) popup.style.width = winWidth*0.75 + "px"; var popupWidth = popup.offsetWidth; var scrollWidth = winWidth - document.body.offsetWidth; if(popupLeft + popupWidth > winWidth - scrollWidth - 1) { if(halign == 'right') popupLeft = popupLeft - root.offsetWidth - popupWidth; else popupLeft = winWidth - popupWidth - scrollWidth - 1; } popup.style.left = popupLeft + "px"; popup.style.top = popupTop + "px"; popup.style.display = "block"; }; Popup.find = function(e) { var pos = -1; for (var t=this.stack.length-1; t>=0; t--) { if(isDescendant(e,this.stack[t].popup)) pos = t; } return pos; }; Popup.remove = function(pos) { if(!pos) var pos = 0; if(Popup.stack.length > pos) { Popup.removeFrom(pos); } }; 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 this.getFullYear() + 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 this.getUTCFullYear() + 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 this.getUTCFullYear() + 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) { var hh = d.substr(8,2) || "00"; var mm = d.substr(10,2) || "00"; 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(hh,10), parseInt(mm,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=[]; 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 function add32(a,b) { var lsw=(a&0xFFFF)+(b&0xFFFF); var msw=(a>>16)+(b>>16)+(lsw>>16); return (msw<<16)|(lsw&0xFFFF); } function AA(a,b,c,d,e) { b=(b>>>27)|(b<<5); 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); } function RR(w,j) { var n=w[j-3]^w[j-8]^w[j-14]^w[j-16]; return (n>>>31)|(n<<1); } var len=blen*8; x[len>>5] |= 0x80 << (24-len%32); x[((len+64>>9)<<4)+15]=len; var w=new 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>>2)|(b<<30); b=a; a=t; j++; } while(j<20) { w[j]=RR(w,j); t=AA(e,a,d^(b&(c^d)),w[j],k1); e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++; } while(j<40) { w[j]=RR(w,j); t=AA(e,a,b^c^d,w[j],k2); e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++; } while(j<60) { w[j]=RR(w,j); t=AA(e,a,(b&c)|(d&(b|c)),w[j],k3); e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++; } while(j<80) { w[j]=RR(w,j); t=AA(e,a,b^c^d,w[j],k4); e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++; } h0=add32(h0,a); h1=add32(h1,b); h2=add32(h2,c); h3=add32(h3,d); h4=add32(h4,e); } return [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,locolors,hicolors) { if(!hicolors) hicolors = locolors; 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 p = t/100*(locolors.length-1); var hc = hicolors[Math.floor(p)]; if(typeof hc == "string") hc = new RGB(hc); var lc = locolors[Math.ceil(p)]; if(typeof lc == "string") lc = new RGB(lc); bar.style.backgroundColor = hc.mix(lc,p-Math.floor(p)).toString(); } } function createTiddlyText(parent,text) { return parent.appendChild(document.createTextNode(text)); } function createTiddlyCheckbox(parent,caption,checked,onChange) { var cb = document.createElement("input"); cb.setAttribute("type","checkbox"); cb.onclick = onChange; parent.appendChild(cb); cb.checked = checked; cb.className = "chkOptionInput"; if(caption) wikify(caption,parent); return cb; } function createTiddlyElement(parent,element,id,className,text,attribs) { var e = document.createElement(element); if(className != null) e.className = className; if(id != null) e.setAttribute("id",id); if(text != null) e.appendChild(document.createTextNode(text)); if(attribs) { for(var n in attribs) { e.setAttribute(n,attribs[n]); } } if(parent != null) parent.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,className) { var currClass = e.className.split(" "); if(currClass.indexOf(className) == -1) e.className += " " + className; } function removeClass(e,className) { var currClass = e.className.split(" "); var i = currClass.indexOf(className); while(i != -1) { currClass.splice(i,1); i = currClass.indexOf(className); } e.className = currClass.join(" "); } function hasClass(e,className) { if(e.className && e.className.split(" ").indexOf(className) != -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 || "tagName"; 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; } // Prevent an event from bubbling function stopEvent(e) { var ev = e || window.event; ev.cancelBubble = true; if(ev.stopPropagation) ev.stopPropagation(); return false; } // 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 || document.documentElement.clientWidth; } // Get the current height of the display window function findWindowHeight() { return window.innerHeight || document.documentElement.clientHeight; } // Get the current horizontal page scroll position function findScrollX() { return window.scrollX || document.documentElement.scrollLeft; } // Get the current vertical page scroll position function findScrollY() { return 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 && 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); } } } function removeStyleSheet(id) { var e = document.getElementById(id); if(e) e.parentNode.removeChild(e); } // Force the browser to do a document reflow when needed to workaround browser bugs function forceReflow() { if(config.browser.isGecko) { setStylesheet("body {top:0px;margin-top:0px;}","forceReflow"); setTimeout(function() {setStylesheet("","forceReflow");},1); } } // 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; } // Returns true if the element e has a given ancestor element function isDescendant(e,ancestor) { while(e) { if(e === ancestor) return true; e = e.parentNode; } return false; } //-- //-- LoaderBase and SaverBase //-- function LoaderBase() {} LoaderBase.prototype.loadTiddler = function(store,node,tiddlers) { var title = this.getTitle(store,node); if(safeMode && store.isShadowTiddler(title)) return; 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++) { if(!tiddlers[t].doNotSave()) 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; var modified = tiddler.modified; var attributes = tiddler.modifier ? ' modifier="' + tiddler.modifier.htmlEncode() + '"' : ""; attributes += (usePre && created == version.date) ? "" :' created="' + created.convertToYYYYMMDDHHMM() + '"'; attributes += (usePre && modified == created) ? "" : ' modified="' + modified.convertToYYYYMMDDHHMM() +'"'; 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])); } }; //]]>
Hosted by www.Geocities.ws

1