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
<!--{{{-->
<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>
<!--}}}-->
When getting started, you may want to: * Set your username for signing your edits: <<option txtUserName>> * Change the page [[title|SiteTitle]] (now "<<tiddler SiteTitle>>") and [[subtitle|SiteSubtitle]] (now "<<tiddler SiteSubtitle>>"); they also set the browser tab title * Create a tiddler where your content "starts" ** Use the button on the sidebar or [[link|My first tiddler]] it here, follow the link, edit, and click "done" ** It will be shown in the Timeline (usually on the right), but you may want to link it in the MainMenu (usually on the left) ** and/or make it open when the ~TiddlyWiki is opened by editing the list of [[DefaultTiddlers]] (separate links with spaces or linebreaks) * Save your ~TiddlyWiki ** Although "download saving" works in any browser, it's not that convenient, so you'll probably want to use [[a dedicated saver|https://classic.tiddlywiki.com/#%5B%5BSetting up saving%5D%5D]]
<<importTiddlers>>
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
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]]
<!--{{{-->
<div class='header' role='banner'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' role='navigation' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' role='navigation' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' role='complementary' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea' role='main'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
/*{{{*/
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]]; }
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}
.txtOptionInput {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.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: -moz-linear-gradient(to bottom, [[ColorPalette::PrimaryLight]], [[ColorPalette::PrimaryMid]]);
background: linear-gradient(to bottom, [[ColorPalette::PrimaryLight]], [[ColorPalette::PrimaryMid]]);
}
.header a:hover {background:transparent;}
.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::Foreground]];
background:[[ColorPalette::Background]];
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 {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]]; }
.wizard__title { color:[[ColorPalette::PrimaryDark]]; border:none; }
.wizard__subtitle { color:[[ColorPalette::Foreground]]; border:none; }
.wizardStep { background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]]; }
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizardFooter .status a { color: [[ColorPalette::PrimaryPale]]; }
.wizard .button {
color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
border-color:[[ColorPalette::SecondaryDark]];
}
.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 { background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; box-shadow: 1px 2px 5px [[ColorPalette::TertiaryMid]]; }
.messageToolbar__button { color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none; }
.messageToolbar__button_withIcon { background:inherit; }
.messageToolbar__button_withIcon:active { background:inherit; border:none; }
.tw-icon line { stroke: [[ColorPalette::TertiaryDark]]; }
.messageToolbar__button:hover .tw-icon line { stroke: [[ColorPalette::Foreground]]; }
.popup {
background: [[ColorPalette::Background]];
color: [[ColorPalette::TertiaryDark]];
box-shadow: 1px 2px 5px [[ColorPalette::TertiaryMid]];
}
.popup li a, .popup li a:visited, .popup li a:hover, .popup li a:active {
color:[[ColorPalette::Foreground]]; border: none;
}
.popup li a:hover { background:[[ColorPalette::SecondaryLight]]; }
.popup li a:active { background:[[ColorPalette::SecondaryPale]]; }
.popup li.disabled { color:[[ColorPalette::TertiaryMid]]; }
.popupHighlight {color:[[ColorPalette::Foreground]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}
.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}
.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: 2px solid [[ColorPalette::TertiaryPale]]; }
.selected .tagging, .selected .tagged { border: 2px solid [[ColorPalette::TertiaryLight]]; }
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button { border:none; }
.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}
.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}
.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}
.imageLink, #displayArea .imageLink {background:transparent;}
.annotation { background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
.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 th, .viewer thead td, .twtable th, .twtable thead td { background: [[ColorPalette::SecondaryMid]]; color: [[ColorPalette::Background]]; }
.viewer td, .viewer tr, .twtable td, .twtable tr { border: 1px solid [[ColorPalette::TertiaryLight]]; }
.twtable caption { color: [[ColorPalette::TertiaryMid]]; }
.viewer pre {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]]; background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%; background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}
.readOnly {background:[[ColorPalette::TertiaryPale]];}
#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:alpha(opacity=60);}
/*}}}*/
/*{{{*/
body { font-size:.75em; font-family:arial,helvetica,sans-serif; margin:0; padding:0; }
* html .tiddler {height:1%;}
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;}
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; border-width: 1px; }
#contentWrapper .chkOptionInput {border:0;}
.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}
a {text-decoration:none;}
.externalLink {text-decoration:underline;}
.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;}
.headerShadow {position:relative; padding:3em 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:3em 0 1em 1em; left:0; top:0;}
.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}
#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}
#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}
.wizard { padding:0.1em 2em 0; }
.wizard__title { font-size:2em; }
.wizard__subtitle { font-size:1.2em; }
.wizard__title, .wizard__subtitle { font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em; }
.wizardStep { padding:1em; }
.wizardFooter { padding: 0.8em 0; }
.wizardFooter .status { display: inline-block; line-height: 1.5; padding: 0.3em 1em; }
.wizardFooter .button { margin:0.5em 0 0; font-size:1.2em; padding:0.2em 0.5em; }
#messageArea { position:fixed; top:2em; right:0; margin:0.5em; padding:0.7em 1em; z-index:2000; }
.messageToolbar { text-align:right; padding:0.2em 0; }
.messageToolbar__button { text-decoration:underline; }
.messageToolbar__button_withIcon { display: inline-block; }
.tw-icon { height: 1em; width: 1em; } /* width for IE */
.tw-icon line { stroke-width: 1; stroke-linecap: round; }
.messageArea__text a { text-decoration:underline; }
.popup {position:absolute; z-index:300; font-size:.9em; padding:0.3em 0; list-style:none; margin:0;}
.popup .popupMessage, .popup li.disabled, .popup li a { padding: 0.3em 0.7em; }
.popup li a {display:block; font-weight:normal; cursor:pointer;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}
.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}
.tabset {padding:1em 0 0 0.5em;}
.tab {display: inline-block; white-space: nowrap; position: relative; bottom: -0.7px; margin: 0 0.25em 0 0; padding:0.2em;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}
#contentWrapper {display:block;}
#splashScreen {display:none;}
#displayArea {margin:1em 17em 0 14em;}
.toolbar {text-align:right; font-size:.9em;}
.tiddler { padding: 1em; }
.title { font-size: 1.6em; font-weight: bold; }
.subtitle { font-size: 1.1em; }
.missing .viewer, .missing .title { font-style: italic; }
.missing .subtitle { display: none; }
.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;}
.tagged li, .tagging li { margin: 0.3em 0; }
.tagClear {clear:both;}
.footer {font-size:.9em;}
.footer li {display:inline;}
.annotation { padding: 0.5em 0.8em; margin: 0.5em 1px; }
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}
.viewer table, table.twtable { border-collapse: collapse; margin: 0.8em 0; }
.viewer th, .viewer td, .viewer tr, .viewer caption, .twtable th, .twtable td, .twtable tr, .twtable caption { padding: 0.2em 0.4em; }
.twtable caption { font-size: 0.9em; }
table.listView { margin: 0.8em 1.0em; }
table.listView th, table.listView td, table.listView tr { text-align: left; }
.listView > thead { position: sticky; top: 0; }
* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer pre {padding:0.5em; overflow:auto;}
pre, code { font-family: monospace, monospace; font-size: 1em; }
.viewer pre, .viewer code { line-height: 1.4em; }
.editor {font-size:1.1em; line-height:1.4em;}
.editor input, .editor textarea {display:block; width:100%; box-sizing: border-box; font:inherit;}
.editorFooter {padding:0.25em 0; font-size:.9em;}
.editorFooter .button {padding-top:0; padding-bottom:0;}
.fieldsetFix {border:0; padding:0; margin:1px 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;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding: 0.3em 0.5em; display: inline-block;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel { display:none; z-index:100; position:absolute; width:90%; margin:0 5%; }
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}
.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea { display: none !important; }
#displayArea { margin: 1em 1em 0em; }
}
/*}}}*/
<!--{{{-->
<div class='toolbar' role='navigation' 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>
<!--}}}-->
/***
|Description|Allows to store any number of tiddlers as external files and more|
|Version|1.1.3|
|Source|https://github.com/YakovL/TiddlyWiki_TiddlerInFilePlugin|
|Author|Yakov Litvin|
|License|MIT|
!!!Usage
Once the plugin is installed (copy - tag {{{systemConfig}}} - reload) storing tiddlers in files is done via 2 steps:
# list (describe) those in [[ExternalTiddlersList]] by writing {{{<<external>>}}} macros there
# if the file exists and the tiddler doesn't, reload TW (external tiddler will be loaded on startup);<br>if the tiddler exists and the file doesn't, just save your TW
Here's how the macro is used:
{{{
<<external [[MyTestTiddler]]>>
}}}
will store the tiddler's text in {{{MyTestTiddler.txt}}} in the same folder as TW. There's a number of other options:
{{{
<<external [[tiddler name]]
[file:<relative path with or without filename and extension>]
[format:{externalized | text}]
[keepInternal:true]
[plugin:true]
>>
}}}
Examples of the {{{file}}} param usage:
* {{{<<external [[MyTestTiddler]] file:"other name">>}}} makes file name different from tiddler name
* {{{<<external [[MyPlugin]] file:"MyPlugin.js" plugin:true>>}}} sets a custom file extension (see also the {{{plugin}}} option below)
* {{{<<external [[MyLog]] file:"../logs/">>}}} will store the file in another folder (note that omitted filename after {{{/}}} means "use tiddler name as filename and default extension")
* the plugin doesn't take care of forbidden characters yet ({{{*}}}, {{{?}}}, {{{"}}} etc), so be careful about those
Supported formats are
* {{{text}}} (default) – only tiddler text is stored in the file with {{{.txt}}} extension; and
* {{{externalized}}} – whole tiddler is stored in the same format as in TW store, file has {{{.tid.html}}} extension and is displayed is monospace tiddler text when opened in browser
Formats can be added by extending {{{config.macros.external.fileFormats}}}.
The {{{keepInternal}}} option makes TW save the tiddler in both external file and TW itself. This, for instance, affects tiddlers stored in {{{text}}} format: without it, all fields like creator, modified etc are destroyed on reload (since are not saved), but with it they are preserved.
The {{{plugin}}} option makes TW evaluate the tiddler like it does with plugins. Note that it doesn't handle plugin dependencies yet. @@color:red;Warning@@: TIFP doesn't currently take care of installing only once, so use {{{plugin}}} with {{{keepInternal}}} ''only'' if you understand the outcome (for instance, some plugins may create infinite loops; also remember that internal version will be always installed first).
***/
//{{{
config.macros.external = {
fileFormats: {
text: {
extension: 'txt',
externalize: function(tiddler) { return tiddler.text },
// changes tiddler as a side-effect not to remove existing fields
internalize: function(tiddler, source) {
tiddler.text = source;
}
},
externalized: {
extension: 'tid.html',
externalize: function(tiddler) {
return store.getSaver().externalizeTiddler(store, tiddler);
},
// like for 'text', extends tiddler, doesn't create from scratch
internalize: function(tiddler, source) {
var div = createTiddlyElement(document.body, 'div');
div.setAttribute('style','display:none;');
div.innerHTML = source;
store.getLoader().internalizeTiddler(store, tiddler,
tiddler.title, div.firstChild);
div.remove();
}
}/*,
tid: { extension: 'tid' },
json: { extension: 'tid.json' }
externalizedWithFormatter? sane to implement?
*/
},
// here and below "meta" means "info about registered external tiddler,
// be it loaded or not"
getExtension: function(meta) {
const format = this.fileFormats[meta.fileFormat];
if(!format) return; //# ok??
return format.extension;
},
externalizeTiddler: function(meta) {
const format = this.fileFormats[meta.fileFormat];
if(!format) return; //# ok??
return format.externalize(meta.tiddler);
},
internalizeTiddler: function(meta, source) {
const format = this.fileFormats[meta.fileFormat];
if(!format) return; //# ok??
const tiddler = store.fetchTiddler(meta.tiddlerName) ||
new Tiddler(meta.tiddlerName);
format.internalize(tiddler, source); //# pass meta to tiddler?
tiddler.doNotSave = function() { return !meta.keepInTW; };
meta.tiddler = tiddler;
return tiddler;
},
listName: "ExternalTiddlersList",
// read files list, load
init: function() {
const listTiddler = store.fetchTiddler(this.listName);
if(!listTiddler || !listTiddler.text) return;
wikify(listTiddler.text, createTiddlyElement(null, 'div'));
for(let meta of this.tiddlersMeta) this.loadExternal(meta);
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
// parse params, register
const defaultParam = 'tiddler';
const pParams = paramString.parseParams(defaultParam, null, true);
const meta = {};
meta.tiddlerName = getParam(pParams, defaultParam);
if(!meta.tiddlerName) return;
// although called .fileName, it actually can contain relative part of a path
// fallback to meta.tiddlerName is set when calculating the full path
meta.fileName = getParam(pParams, 'file', '');
//# check if contains "bad" characters (like " or * ..for local paths only)
meta.fileFormat = getParam(pParams, 'format', 'text');
meta.isPlugin = getFlag(pParams, 'plugin'); //# allow just "plugin" instead of "plugin:true"?
const keepInternal = getParam(pParams, 'keepInternal');
meta.keepInTW = !!keepInternal && keepInternal !== 'false'; //# ~
this.registerExternal(meta);
// visual feedback
const macroText = wikifier.source.substring(wikifier.matchStart, wikifier.nextMatch);
createTiddlyText(place, 'external ');
createTiddlyLink(place, meta.tiddlerName, true);
createTiddlyText(place, ' (');
createTiddlyElement(place, 'code', '', '', macroText.slice(2 + macroName.length + 1, -2));
createTiddlyText(place, ')');
},
// describes tiddlers registered as external, not necessarily loaded
tiddlersMeta: [],
registerExternal: function(meta) {
//# check if already registered, don't register twice
this.tiddlersMeta.push(meta);
},
getMetaFor: function(tiddlerOrTitle) {
var isTitle = typeof tiddlerOrTitle == "string";
for(meta of this.tiddlersMeta)
if(isTitle && meta.tiddlerName == tiddlerOrTitle ||
!isTitle && meta.tiddler == tiddlerOrTitle)
return meta;
},
loadExternal: function(meta) {
// sync loading fails on startup because TF injects new mozillaLoadFile too late
// var tiddlerText = loadFile(getLocalPath(getFullPath(meta.fileName)));
// onExternalTiddlerLoad(tiddlerText !== null, meta, tiddlerText);
// so we use async instead:
const callback = this.onExternalTiddlerLoad
const path = getFullPath(meta.fileName, meta.tiddlerName, this.getExtension(meta));
// httpReq("GET", path, callback, meta) uses default dataType,
// which causes js to get evaluated on load. To avoid this, we customize the ajax call:
jQuery.ajax({
type: "GET",
url: path,
dataType: "text",
processData: false,
cache: false,
complete: function(xhr, textStatus) {
if((!xhr.status && location.protocol === "file:") || (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)
callback(true, meta, xhr.responseText, path, xhr)
else
callback(false, meta, null, path, xhr)
}
})
//# rename onExternalTiddlerLoad into internalizeAndRegister?
},
onExternalTiddlerLoad: function(success, meta, responseText) {
if(!success) return; //# notify somehow? may fail because file is not created yet or ...
const tiddler = config.macros.external.internalizeTiddler(meta, responseText);
store.addTiddler(tiddler);
//# what if tiddler already exists?
if(meta.isPlugin) {
// make it look normally
tiddler.tags.push('systemConfig');
const author = store.getTiddlerText(tiddler.title + "::Author");
if(author) {
tiddler.creator = tiddler.creator || author;
tiddler.modifier = tiddler.modifier || tiddler.creator;
}
eval(tiddler.text);
// for plugins introducing macros, formatters etc (may be adjusted in the future)
refreshAll();
}
//meta.lastLoaded = responseText;
},
saveExternal: function(meta, callback) {
const fullPath = getFullPath(meta.fileName, meta.tiddlerName, this.getExtension(meta));
// we don't try to save remote files (yet)
if(!isLocalAbsolutePath(fullPath)) {
//# if(callback) callback(.., '[saving remote is not supported]')
return;
}
const localPath = getLocalPath(fullPath);
const contentToSave = this.externalizeTiddler(meta);
// save only if have something to save
//if(contentToSave != meta.lastLoaded) {
saveFile(localPath, contentToSave);
//# get result of saving, return it
//# or move externalizing into a separate helper?
// meta.lastLoaded = contentToSave;
//# this assumes saving didn't fail, which may be wrong
//}
//# if(callback) callback(.., '[...]')
},
saveAll: function() {
let overallSuccess = true;
for(let meta of this.tiddlersMeta) {
// a tiddler may got created after registration
if(!meta.tiddler) {
let tiddlerInStore = store.fetchTiddler(meta.tiddlerName);
if(tiddlerInStore) {
meta.tiddler = tiddlerInStore;
} else
// tiddler doesn't exist and we do nothing
continue;
//# based on config, we can show a warning instead
}
//# if(meta.tiddler.title != meta.tiddlerName)
// means tiddler got renamed → change meta.tiddlerName &
// update this.listName . If store contains another tiddler
// with that name, still keep the registered one?
overallSuccess = this.saveExternal(meta) && overallSuccess;
//# if saving failed, do something! (.oO dirty, notifying)
}
return overallSuccess;
}
};
//# see implementations in STP (share to the core?)
function isAbsolutePath(path) {
// covers http:, https:, file:, other schemas, windows paths (D:\...)
if(/^\w+\:/.exec(path))
return true;
// unix absolute paths, starting with /
if(/^\//.exec(path))
return true;
return false;
}
function isLocalAbsolutePath(path) {
//# rename? we're going to check whether an absolute path is local, not path is absolute local
return /^\w\:/.exec(path) || /^\//.exec(path) || /^file\:/.exec(path);
}
function getFullPath(subPath, nameFallback, extension) {
const fileNamePosition = subPath.lastIndexOf('/') + 1;
const fileName = subPath.substr(fileNamePosition);
if(fileName && fileName.indexOf('.') == -1)
subPath += '.' + extension;
if(!fileName)
subPath += nameFallback + '.' + extension;
if(isAbsolutePath(subPath))
return subPath;
const url = window.location.toString();
const base = url.substr(0, url.lastIndexOf('/') + 1);
return base + subPath;
}
//# ideally, don't save main store if it were not changed
if(!config.macros.external.orig_saveChanges) {
config.macros.external.orig_saveChanges = saveChanges;
saveChanges = function(onlyIfDirty, tiddlers) {
config.macros.external.saveAll();
//# should we do smth about setDirty (if saving of a tiddler failed)?
return config.macros.external.orig_saveChanges.apply(this, arguments);
}
}
// hijack method of store (since not present in TiddlyWiki.prototype)
if(!config.macros.external.orig_deleteTiddler) {
config.macros.external.orig_deleteTiddler = store.deleteTiddler;
store.deleteTiddler = function(title) {
var registeredMeta = config.macros.external.getMetaFor(title);
if(registeredMeta) registeredMeta.tiddler = null;
return config.macros.external.orig_deleteTiddler.apply(this, arguments);
}
}
//}}}
<<external [[TwFormulaPlugin]] file:"TwFormulaPlugin.js" plugin:true>>
~TwFormulaPlugin
plugin to display ~LaTeX formulae in TW / $e^{i \pi} = -1, \sum\limits_{n=0}^∞ {1\over n^2} = {π^2\over 6}$
<!--{{{-->
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2280%22>🌘</text></svg>">
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
[[Intro]] TwFormulaPlugin
[[Intro]]
The most widely used format for writing math formulae is {{{LaTeX}}}. TwFormulaPlugin implements rendering math in TW using {{{LaTeX}}} and 3d party libraries. See examples:
* [[Different types of formulae]]
* [[Escaping, non-latin letters, numeration]]
Note: in this demo, you can switch the used library, too. See the instructions in the plugin's "Installation and configuring" section. As you will see, different libraries will support different subsets of ~LaTeX in the examples above.
!The ~Cauchy-Schwarz Inequality
\[ \left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2
\right) \left( \sum_{k=1}^n b_k^2 \right) \]
!A Cross Product Formula
\[\mathbf{V}_1 \times \mathbf{V}_2 = \left|\begin{array}{ccc}
\mathbf{i} & \mathbf{j} & \mathbf{k} \\
\frac{\partial X}{\partial u} & \frac{\partial Y}{\partial u} & 0 \\
\frac{\partial X}{\partial v} & \frac{\partial Y}{\partial v}
& 0
\end{array}\right| \]
!The probability of getting \(k\) heads when flipping \(n\) coins is:
\[P(E) = {n \choose k} p^k (1-p)^{ n-k} \]
!An Identity of Ramanujan
\[ \frac{1}{\left(\sqrt{\phi \sqrt{5}}-\phi\right) e^{\frac25 \pi}} =
1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}}
{1+\frac{e^{-8\pi}} {1+\ldots} } } } \]
!The Lorenz Equations
\[\begin{eqnarray}
\dot{x} & = & \sigma(y-x) \\
\dot{y} & = & \rho x - y - xz \\
\dot{z} & = & -\beta z + xy
\end{eqnarray}\]
!A ~Rogers-Ramanujan Identity
\[ 1 + \frac{q^2}{(1-q)}+\frac{q^6}{(1-q)(1-q^2)}+\cdots =
\prod_{j=0}^{\infty}\frac{1}{(1-q^{5j+2})(1-q^{5j+3})},
\quad\quad \textrm{for}\quad |q|<1. \]
!Maxwell's Equations
\[\begin{eqnarray}
\nabla \times \vec{\mathbf{B}} -\, \frac1c\,\frac{\partial\vec{\mathbf{E}}}{\partial t} & = & \frac{4\pi}{c}\vec{\mathbf{j}} \\
\nabla \cdot \vec{\mathbf{E}} & = & 4 \pi \rho \\
\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\,\frac{\partial\vec{\mathbf{B}}}{\partial t} & = &\vec{\mathbf{0}} \\
\nabla \cdot \vec{\mathbf{B}} & = & 0
\end{eqnarray}\]
Finally, while display equations look good for a page of samples, the ability to mix math and text in a paragraph is also important. This expression \(\sqrt{3x-1}+(1+x)^2\) is an example of an inline equation. As you see, ~MathJax equations can be used this way as well, without unduly disturbing the spacing between lines.
Escaping:
* lunch \$7.53 (dollar char)
* backslash char: \\
Non-latin letters in formulas (font size should be correct):
$${1 Н \over 2 м^2} = 0,5 Па$$
$${1 N\over 2 m^2} = 0.5 Pa$$
(Auto)numeration (uses {{{\begin{equation}...\end{equation}}}} inside {{{$$...$$}}}):
$$\begin{equation}
\operatorname{erfc}(x) =
\frac{2}{\sqrt{\pi}} \int\limits_x^{\infty} e^{-t^2}\,dt =
\frac{e^{-x^2}}{x\sqrt{\pi}}\sum_{n=0}^\infty (-1)^n \frac{(2n)!}{n!(2x)^{2n}}
\end{equation}$$
/***
|Version|1.7.0|
***/
//{{{
// styling helpers
var getStylesFromSection = function(sectionName) {
var css = store.getTiddlerText("SetCommonStylesPlugin##"+sectionName,"");
return css.replace("{{{","/"+"*{{{*"+"/").replace("}}}","/"+"*}}}*"+"/");
};
var setCssShadow = function(sectionName,shadowName) {
config.shadowTiddlers[shadowName] = getStylesFromSection(sectionName);
store.addNotification(shadowName, refreshStyles);
store.addNotification("ColorPalette",function(smth,doc) {
refreshStyles(shadowName,doc);
});
};
// set styles
setCssShadow("Typographics", "CommonTypographicsStyleSheet");
setCssShadow("Semantics", "CommonSemanticsStyleSheet");
setCssShadow("Representation", "CommonRepresenationStyleSheet");
setCssShadow("Representation tools", "CommonRepresToolsStyleSheet");
//if(jQuery.browser.mozilla) // now done via CSS
setCssShadow("FireFox CSS", "FireFoxFixesStyleSheet");
/*var csp_orig_wikify = wikify;
wikify = function(source,output,highlightRegExp,tiddler) {
csp_orig_wikify.apply(this,arguments);
// no longer needed, left as an example:
jQuery(".LimitGeneral").each(function(){
// avoid multiple wrapping because of ~ wikifications:
if(!jQuery(this.parentNode).hasClass("LimitGeneralWrap"))
jQuery(this).wrap("<span class='LimitGeneralWrap'></span>");
});
};*/
// to get green underlined, add a wrapper with the NTermWrap class; apply the styling to both wrappers (.NTermWrap) and the element itself (.NTerm)
//}}}
// // hide message area on click elsewhere (useful for touchscreen devices)
//{{{
jQuery(document).on("click",function(e) {
if(!jQuery(e.target).closest('#messageArea').length) // click outside messageArea
clearMessage();
return true;
});
// prevent message from being closed by click on a saveChanges button
if(!config.extensions.postponeMsg) {
config.extensions.postponeMsg = true;
config.extensions.orig_displayMessage = displayMessage;
displayMessage = function(a,b) {
var doDisplay = function() { config.extensions.orig_displayMessage(a,b); };
setTimeout(doDisplay,100);
};
}
//}}}
/***
!!!Typographics
{{{
#messageArea {
top: 1.5em; padding: 0.7em 1em;
max-height: calc(100vh - 5em);
max-width: calc(100vw - 4em);
overflow: auto;
}
.editor { line-height: 1.4em; }
}}}
!!!Typographics details
* this section is meant to be incorporated to the core
* messageArea: paddings enlarged; dimensions restricted not to go beyond page boundaries
** {{DDn{padding-bottom "doesn't work" when the content is large.. change `box-sizing`?}}}
** {{PoG{horizontal margin is ok; top should be removed; bottom – ...}}}
** {{DDn{magic numbers 5em and 4em are not nice, though}}}
** `#messageArea .button { background: inherit; }` – non-BEM selector here until we modify the core
!!!Semantics
{{{
div[tags~="code"] .editor, #tiddlerStyleSheet .editor,
div[tags~="systemConfig"] .editor, pre, code {
font-family: Consolas, monospace;
}
.viewer pre, .viewer code {
font-size: inherit;
}
.tiddler[tags~="notepad"] textarea,
.tiddler[tags~="notepad"] .viewer {
font-family: Consolas, monospace;
white-space: pre;
}
.PoG, .PoGc { color: green; }
.DDn, .DDnc { color: purple; }
.FpG, .FpGc { color: #0000CC; }
.PoGc:before, .DDnc:before, .FpGc:before,
.c:before { content: "["; color: [[ColorPalette::Foreground]]; }
.PoGc:after, .DDnc:after, .FpGc:after,
.c:after { content: "]"; color: [[ColorPalette::Foreground]]; }
.NTerm { text-decoration: underline; text-decoration-color: #00aa00; }
.LimitGeneral { text-decoration: underline; text-decoration-color: #0000ff; }
}}}
!!!Semantics details
* "возможности роста" (possibilities of growth), в т.ч. комментарии (comments): `.PoG`, `.PoGc`
* сделанное/написанное с изъяном (done [written] to be done, but not ideally): `.DDn`, `.DDnc`
* подчёркнуто "замороженные" точки роста (frozen ~PoG or ~DDn): `.FpG`, `.FpGc` (dimmer than blue)
* комментарии/"подразумеваемые" вещи: `.c`
* тэг `code` улучшает редактор для CSS, JS и т.п. (в edit mode)
* тэг `notepad` задаёт отображение и редактор ~как в блокноте~
** {{PoG{add also save-in-edit-mode button}}}
** {{PoG{disable wikiwords}}}
!!!Representation
{{{
#sidebarOptions .sliderPanel { background-color:[[ColorPalette::Background]];
font-size: 95%; }
#tiddlerStyleSheet .viewer pre { clear: both !important; }
.headerForeground,
.headerShadow { padding-top: 1em; }
#displayArea { margin-bottom: 30%; }
body { letter-spacing: 0.02em; }
code, pre { letter-spacing: 0; }
.viewer img { max-width: 100%; }
.toolbar a { display: inline-block; }
.toolbar { float: right; }
}}}
!!!Representation details
* ...
* `margin-bottom` of `#displayArea` – to be able to keep the content on the eye level
* `letter-spacing` gives less tight font; non-zero breaks monospace when tabs are used, so we remove `letter-spacing` for code
!!!Representation tools
{{{
table.borderless,
table.borderless > tbody > tr,
table.borderless > tbody > tr > td,
table.borderless > tbody > tr > th { border: 0 !important; }
div[tags~="hideTagged"]
.tagging { display: none; }
div[tags~="hideTags"]
.tagged { display: none; }
}}}
!!!Representation tools details
* ...
!!!FireFox CSS
{{{
@-moz-document url-prefix() {
pre, code, div[tags~="code"] .editor,
div[tags~="systemConfig"] .editor,
#tiddlerStyleSheet .editor {
font-family: 'Droid Sans Mono', Consolas, monospace !important;
font-size: 100% !important;
}
}
}}}
!!!!
***/