Welcome to TiddlyWiki created by Jeremy Ruston; Copyright © 2004-2007 Jeremy Ruston, Copyright © 2007-2011 UnaMesa Association
<<gotoTiddler>>
* Plugins <<list filter "[tag[systemConfig]]>>
* Layout <<list filter "[tag[layout]]>>
* Tasks <<list filter "[tag[task]]>>
* Interests <<list filter "[tag[interest]]>>
<<dropMenu>>
@@display:none;<<tiddler SetTiddlerColumns >>@@
<!--{{{-->
<div class='header' role='banner'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitleShadow'></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='storyMenu' refresh='content' force='true' tiddler='StoryMenu'></div>
<div id='tiddlersBar' refresh='none' ondblclick='config.macros.tiddlersBar.onTiddlersBarAction(event)'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
/***
|Name|ReminderPlugin|
|Source| |
|Documentation| |
|Version|1.0|
|Author|Matthieu Nottale|
|License|CC-by-SA http://creativecommons.org/licenses/by-sa/3.0/|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Reminder macro, displaying remaining/overdue time|
! Usage
Simply put <<reminder NAME INTERVAL>> anywhere. INTERVAL is a string made
of duration and one-leter unit: second,minute,hour,day,Month. (Like 1d, 2h...).
To mark as done and reset the timer. ctrl-click on the displayed time.
!!!Code
***/
//{{{
// Parse property tiddler keyed with name and return a directory with the content.
(function() {
function getPropTiddler(name)
{
var txt = store.getTiddlerText("_prop_" + name) || '';
var lines = txt.split("\n");
var res = {};
for (var i=0; i< lines.length; ++i)
{
key = lines[i].split(":", 1)[0];
value = lines[i].substr(key.length + 1);
res[key] = value;
}
return res;
}
// Update property tiddler keyed 'name' with key=value.
function setPropTiddler(name, key, value)
{
var props = getPropTiddler(name);
if (!props)
props = {};
props[key] = value;
var txt = "";
for (var i in props)
{
txt += i + ":" + props[i] + "\n";
}
store.saveTiddler("_prop_" + name, "_prop_" + name, txt);
saveChanges();
}
/** Return d increased by time represented by deltaString.
* Format: [DELTA] DELTA: VALUE UNIT UNIT:{smhdMy} VALUE: integer
*/
function increaseDate(d, deltaString)
{
var res = new Date(d);
while (deltaString)
{
console.log("ID: " + res +" delta " + deltaString);
var v = parseInt(deltaString);
var vString = '' + v;
deltaString = deltaString.substr(vString.length);
var unit = deltaString[0];
deltaString = deltaString.substr(1);
var index = "smhdMy".indexOf(unit);
if (index == -1)
throw "Invalid unit letter: " + unit;
var methods = ['Seconds','Minutes','Hours','Date','Month','Year']
var current = res['get' + methods[index]].call(res);
res['set' + methods[index]].call(res, current + v);
console.log("ID inc " + methods[index] +" " + v + " : " + res);
}
return res;
}
/// Return Human-friendly representation of positive interval in milliseconds
function intervalString(delta)
{
delta /= 1000;
var periods = [1, 60, 3600, 3600 * 24, 3600 * 24 * 30];
var periodNames = ['seconds', 'minutes', 'hours', 'days', 'monthes'];
var displayTime = '';
var hit = 0;
for (var i = periods.length-1; i >= 0; --i)
{
if (delta / periods[i] < 1 && (i || delta) && !hit)
continue;
displayTime += Math.floor(delta/periods[i]);
displayTime += ' ' + periodNames[i] + ' ';
delta %= periods[i];
++hit;
if (hit >= 2)
break;
}
if (!displayTime)
displayTime = "NOW!";
return displayTime;
}
/** Reminder macro. Usage: <<reminder NAME PERIOD>>.
* Stores last time executed in a property. Display remaining/overdue time.
* Use ctrl-click to mark as done and reset timer.
*/
config.macros.reminder = {
handler: function(place,macroName,params,wikifier,paramString,tiddler)
{
var tiddlerName = tiddler.title;
var prop = tiddlerName + params[0];
var targetInterval = params[1];
var redisplay = function()
{
var delta = new Date().getTime() - parseInt(getPropTiddler("reminder")[prop]) || new Date().getTime();
span.css('color', delta > 0 ? 'red':'green');
var displayTime = intervalString(Math.abs(delta));
span[0].innerText = displayTime;
};
var span = jQuery("<span/>")
.text('calculating...')
.click(function(ev)
{
gEv = ev;
if (!ev.ctrlKey)
return;
var d = new Date();
d = increaseDate(d, targetInterval);
setPropTiddler("reminder", prop, d.getTime());
redisplay();
});
span.appendTo(place);
window.setInterval(redisplay, 5000);
redisplay();
}
};
})();
//}}}
/***
|Name|GotoPlugin|
|Source|http://www.TiddlyTools.com/#GotoPlugin|
|Documentation|http://www.TiddlyTools.com/#GotoPluginInfo|
|Version|1.9.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|view any tiddler by entering it's title - displays list of possible matches|
''View a tiddler by typing its title and pressing //enter//.'' As you type, a list of possible matches is displayed. You can scroll-and-click (or use arrows+enter) to select/view a tiddler, or press escape to close the listbox to resume typing. When the listbox is not displayed, pressing //escape// clears the current input.
!!!Documentation
>see [[GotoPluginInfo]]
!!!Configuration
<<<
*Match titles only after {{twochar{<<option txtIncrementalSearchMin>>}}} or more characters are entered.<br>Use down-arrow to start matching with shorter input. //Note: This option value is also set/used by [[SearchOptionsPlugin]]//.
*To set the maximum height of the listbox, you can create a tiddler tagged with <<tag systemConfig>>, containing:
//{{{
config.macros.gotoTiddler.listMaxSize=10; // change this number
//}}}
<<<
!!!Revisions
<<<
2009.05.22 [1.9.2] use reverseLookup() for IncludePlugin
|please see [[GotoPluginInfo]] for additional revision details|
2006.05.05 [0.0.0] started
<<<
!!!Code
***/
//{{{
version.extensions.GotoPlugin= {major: 1, minor: 9, revision: 2, date: new Date(2009,5,22)};
// automatically tweak shadow SideBarOptions to add <<gotoTiddler>> macro above <<search>>
config.shadowTiddlers.SideBarOptions=config.shadowTiddlers.SideBarOptions.replace(/<<search>>/,"{{button{goto}}}\n<<gotoTiddler>><<search>>");
if (config.options.txtIncrementalSearchMin===undefined) config.options.txtIncrementalSearchMin=3;
config.macros.gotoTiddler= {
listMaxSize: 10,
listHeading: 'Found %0 matching title%1...',
searchItem: "Search for '%0'...",
handler:
function(place,macroName,params,wikifier,paramString,tiddler) {
var quiet =params.contains("quiet");
var showlist =params.contains("showlist");
var search =params.contains("search");
params = paramString.parseParams("anon",null,true,false,false);
var instyle =getParam(params,"inputstyle","");
var liststyle =getParam(params,"liststyle","");
var filter =getParam(params,"filter","");
var html=this.html;
var keyevent=window.event?"onkeydown":"onkeypress"; // IE event fixup for ESC handling
html=html.replace(/%keyevent%/g,keyevent);
html=html.replace(/%search%/g,search);
html=html.replace(/%quiet%/g,quiet);
html=html.replace(/%showlist%/g,showlist);
html=html.replace(/%display%/g,showlist?'block':'none');
html=html.replace(/%position%/g,showlist?'static':'absolute');
html=html.replace(/%instyle%/g,instyle);
html=html.replace(/%liststyle%/g,liststyle);
html=html.replace(/%filter%/g,filter);
if (config.browser.isIE) html=this.IEtableFixup.format([html]);
var span=createTiddlyElement(place,'span');
span.innerHTML=html; var form=span.getElementsByTagName("form")[0];
if (showlist) this.fillList(form.list,'',filter,search,0);
},
html:
'<form onsubmit="return false" style="display:inline;margin:0;padding:0">\
<input name=gotoTiddler type=text autocomplete="off" accesskey="G" style="%instyle%"\
title="Enter title text... ENTER=goto, SHIFT-ENTER=search for text, DOWN=select from list"\
onfocus="this.select(); this.setAttribute(\'accesskey\',\'G\');"\
%keyevent%="return config.macros.gotoTiddler.inputEscKeyHandler(event,this,this.form.list,%search%,%showlist%);"\
onkeyup="return config.macros.gotoTiddler.inputKeyHandler(event,this,%quiet%,%search%,%showlist%);">\
<select name=list style="display:%display%;position:%position%;%liststyle%"\
onchange="if (!this.selectedIndex) this.selectedIndex=1;"\
onblur="this.style.display=%showlist%?\'block\':\'none\';"\
%keyevent%="return config.macros.gotoTiddler.selectKeyHandler(event,this,this.form.gotoTiddler,%showlist%);"\
onclick="return config.macros.gotoTiddler.processItem(this.value,this.form.gotoTiddler,this,%showlist%);">\
</select><input name="filter" type="hidden" value="%filter%">\
</form>',
IEtableFixup:
"<table style='width:100%;display:inline;padding:0;margin:0;border:0;'>\
<tr style='padding:0;margin:0;border:0;'><td style='padding:0;margin:0;border:0;'>\
%0</td></tr></table>",
getItems:
function(list,val,filter) {
if (!list.cache || !list.cache.length || val.length<=config.options.txtIncrementalSearchMin) {
// starting new search, fetch and cache list of tiddlers/shadows/tags
list.cache=new Array();
if (filter.length) {
var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
var tiddlers=store.sortTiddlers(fn.apply(store,[filter]),'title');
} else
var tiddlers=store.reverseLookup('tags','excludeLists');
for(var t=0; t<tiddlers.length; t++) list.cache.push(tiddlers[t].title);
if (!filter.length) {
for (var t in config.shadowTiddlers) list.cache.pushUnique(t);
var tags=store.getTags();
for(var t=0; t<tags.length; t++) list.cache.pushUnique(tags[t][0]);
}
}
var found = [];
var match=val.toLowerCase();
for(var i=0; i<list.cache.length; i++)
if (list.cache[i].toLowerCase().indexOf(match)!=-1) found.push(list.cache[i]);
return found;
},
getItemSuffix:
function(t) {
if (store.tiddlerExists(t)) return ""; // tiddler
if (store.isShadowTiddler(t)) return " (shadow)"; // shadow
return " (tag)"; // tag
},
fillList:
function(list,val,filter,search,key) {
if (list.style.display=="none") return; // not visible... do nothing!
var indent='\xa0\xa0\xa0';
var found = this.getItems(list,val,filter); // find matching items...
found.sort(); // alpha by title
while (list.length > 0) list.options[0]=null; // clear list
var hdr=this.listHeading.format([found.length,found.length==1?"":"s"]);
list.options[0]=new Option(hdr,"",false,false);
for (var t=0; t<found.length; t++) list.options[list.length]=
new Option(indent+found[t]+this.getItemSuffix(found[t]),found[t],false,false);
if (search)
list.options[list.length]=new Option(this.searchItem.format([val]),"*",false,false);
list.size=(list.length<this.listMaxSize?list.length:this.listMaxSize); // resize list...
list.selectedIndex=key==38?list.length-1:key==40?1:0;
},
keyProcessed:
function(ev) { // utility function
ev.cancelBubble=true; // IE4+
try{event.keyCode=0;}catch(e){}; // IE5
if (window.event) ev.returnValue=false; // IE6
if (ev.preventDefault) ev.preventDefault(); // moz/opera/konqueror
if (ev.stopPropagation) ev.stopPropagation(); // all
return false;
},
inputEscKeyHandler:
function(event,here,list,search,showlist) {
if (event.keyCode==27) {
if (showlist) { // clear input, reset list
here.value=here.defaultValue;
this.fillList(list,'',here.form.filter.value,search,0);
}
else if (list.style.display=="none") // clear input
here.value=here.defaultValue;
else list.style.display="none"; // hide list
return this.keyProcessed(event);
}
return true; // key bubbles up
},
inputKeyHandler:
function(event,here,quiet,search,showlist) {
var key=event.keyCode;
var list=here.form.list;
var filter=here.form.filter;
// non-printing chars bubble up, except for a few:
if (key<48) switch(key) {
// backspace=8, enter=13, space=32, up=38, down=40, delete=46
case 8: case 13: case 32: case 38: case 40: case 46: break; default: return true;
}
// blank input... if down/enter... fall through (list all)... else, and hide or reset list
if (!here.value.length && !(key==40 || key==13)) {
if (showlist) this.fillList(here.form.list,'',here.form.filter.value,search,0);
else list.style.display="none";
return this.keyProcessed(event);
}
// hide list if quiet, or below input minimum (and not showlist)
list.style.display=(!showlist&&(quiet||here.value.length<config.options.txtIncrementalSearchMin))?'none':'block';
// non-blank input... enter=show/create tiddler, SHIFT-enter=search for text
if (key==13 && here.value.length) return this.processItem(event.shiftKey?'*':here.value,here,list,showlist);
// up or down key, or enter with blank input... shows and moves to list...
if (key==38 || key==40 || key==13) { list.style.display="block"; list.focus(); }
this.fillList(list,here.value,filter.value,search,key);
return true; // key bubbles up
},
selectKeyHandler:
function(event,list,editfield,showlist) {
if (event.keyCode==27) // escape... hide list, move to edit field
{ editfield.focus(); list.style.display=showlist?'block':'none'; return this.keyProcessed(event); }
if (event.keyCode==13 && list.value.length) // enter... view selected item
{ this.processItem(list.value,editfield,list,showlist); return this.keyProcessed(event); }
return true; // key bubbles up
},
processItem:
function(title,here,list,showlist) {
if (!title.length) return;
list.style.display=showlist?'block':'none';
if (title=="*") { story.search(here.value); return false; } // do full-text search
if (!showlist) here.value=title;
story.displayTiddler(null,title); // show selected tiddler
return false;
}
}
//}}}
a sandbox tiddler for fun
<<digraph $fright
a->b->c;
d->e->f;
>>
more text, but where does it go?
rauiseautr
ranusetrauie
/***
| Name:|CaptureKeysMacro|
| Purpose:|Makes an easy way to capture a key and stop the browser from doing its default action|
| Creator:|BradleyMeck|
| Ideas:|BradleyMeck & SaqImtiaz|
| Source:|http://tiddlyspot.com/BradleyMeck/#CaptureKeysMacro|
| Requires:|Javascript|
| Version|1.0 (July 24, 2006)|
!History
** First release
!Usage
config.macros.captureKey(object,handler,keyCode,SHIFT,ALT,CTRL);
|''object''|Where (element, document, etc.) to try to capture the event at (useful because of stopPropagation).|
|''handler''|Function to execute when this key is captured.|
|''keyCode''|The keyCode to execute this function if this key is depressed.|
|''SHIFT''|Should the Shift key be depressed when this event occurs?|
|''ALT''|Should the Alt key be depressed when this event occurs?|
|''CTRL''|Should the Ctrl key be depressed when this event occurs?|
!Notes
|If something changes the element's onkeydown/press handlers and the browser does not support addEventListener or attachEvent, the key capturing will be ruined.|
|Please use the removeCaptureKey function to remove the capture keys if you dont want them to occur anymore, please? However, removing the 'F1' key does not make onhelp work again.|
|config.macros.captureKeys.preventDefault(), config.macros.captureKeys.stopPropagation(), config.macros.captureKeys.getRealKey(event) are good functions to use in other plugins as well|
!Examples
For 'CTRL'+'S' Saving
{{{
config.macros.captureKeys.captureKey(document,saveChanges,"S",false,false,true);
}}}
!Code
!!!Virtual Keyboard
***/
//{{{
config.macros.captureKeys = {};
config.macros.captureKeys.VK = {
/*KEYS ARE MAPPED FROM TOP LEFT TO BOTTOM RIGHT,
THE NAMES ARE TAKEN FROM THE JAVA VK*/
"ESCAPE": 27,
"F1": 112,
"F2": 113,
"F3": 114,
"F4": 115,
"F5": 116,
"F6": 117,
"F7": 118,
"F8": 119,
"F9": 120,
"F10": 121,
"F11": 122,
"F12": 123,
"PRINT_SCREEN": 44,
"SCROLL_LOCK": 145,
"PAUSE": 19,
"BACK_QUOTE": 192,
"1": 49,
"2": 50,
"3": 51,
"4": 52,
"5": 53,
"6": 54,
"7": 55,
"8": 56,
"9": 57,
"0": 48,
"MINUS": 109,
"EQUALS": 61,
"BACKSPACE": 8,
"INSERT": 45,
"HOME": 36,
"PAGE_UP": 33,
"NUM_LOCK": 144,
"NUMPADDIVIDE": 111,
"MULTIPLY": 106,
"NUMPADMINUS": 109,
"TAB": 9,
"Q": 81,
"W": 87,
"E": 69,
"R": 82,
"T": 84,
"Y": 89,
"U": 85,
"I": 73,
"O": 79,
"P": 80,
"OPEN_BRACKET": 219,
"CLOSE_BRACKET": 221,
"BACK_SLASH": 220,
"DELETE": 46,
"END": 35,
"PAGE_DOWN": 34,
"NUMPAD7": 103,
"NUMPAD8": 104,
"NUMPAD9": 105,
"PLUS": 107,
"CAPS_LOCK": 20,
"A": 65,
"S": 83,
"D": 68,
"F": 70,
"G": 71,
"H": 72,
"J": 74,
"K": 75,
"L": 76,
"SEMICOLON": 59,
"QUOTE": 222,
"ENTER": 13,
"NUMPAD4": 100,
"NUMPAD5": 101,
"NUMPAD6": 102,
"SHIFT": 16,
"Z": 90,
"X": 88,
"C": 67,
"V": 86,
"B": 66,
"N": 78,
"M": 77,
"COMMA": 188,
"PERIOD": 190,
"DIVIDE": 191,
"UP": 38,
"NUMPAD1": 97,
"NUMPAD2": 98,
"NUMPAD3": 99,
"CONTROL": 17,
"ALT": 18,
"SPACE": 32,
"LEFT": 37,
"DOWN": 40,
"RIGHT": 39,
"NUMPAD0": 96,
"NUMPADPERIOD": 110
}
config.macros.captureKeys.UNICodeToAsciiVK =
{
33 : 49,
34 : 222,
35 : 51,
36 : 52,
37 : 53,
38 : 55,
39 : 222,
40 : 57,
41 : 48,
42 : 56,
43 : 61,
44 :188,
45 :109,
46 :190,
47 :191,
48 : 96,
49 : 97,
50 : 98,
51 : 99,
52 :100,
53 :101,
54 :102,
55 :103,
56 :104,
57 :105,
58 : 59,
60 :188,
62 :190,
63 :191,
64 : 50,
91 :219,
92 :220,
93 :221,
94 : 54,
95 :109,
96 :192,
97 : 65,
98 : 66,
99 : 67,
100: 68,
101: 69,
102: 70,
103: 71,
104: 72,
105: 73,
106: 74,
107: 75,
108: 76,
109: 77,
110: 78,
111: 79,
112: 80,
113: 81,
114: 82,
115: 83,
116: 84,
117: 85,
118: 86,
119: 87,
120: 88,
121: 89,
122: 90,
123:219,
124:220,
125:221,
126:192
}
//}}}
/***
!!!!captureKey function
***/
//{{{
window.captureKey = config.macros.captureKeys.captureKey = function(elem,handler,keyCode,shiftButton,altButton,ctrlButton)
{
if(!elem.captureKeys)
{
elem.captureKeys = [];
}
var keyEvent = {};
keyEvent.key = config.macros.captureKeys.VK[keyCode]?config.macros.captureKeys.VK[keyCode]:keyCode;
keyEvent.shift = shiftButton;
keyEvent.alt = altButton;
keyEvent.ctrl = ctrlButton;
keyEvent.func = handler;
elem.captureKeys.push(keyEvent);
// IE needs onkeyDown
// moz needs onkeypress
if(window.event)
{
// For some reason cancelling the f1 keypress doesnt stop it from loading the help?
if(keyCode == 112){document.onhelp = function(event){if(!event)var event=window.event;config.macros.captureKeys.preventDefault(event)}}
if(!config.macros.captureKeys.hasEventListener(elem,"keydown",config.macros.captureKeys.captureKeyHandler)){
config.macros.captureKeys.addEventListener(elem,"keydown",config.macros.captureKeys.captureKeyHandler);}
}
else
{
if(!config.macros.captureKeys.hasEventListener(elem,"keypress",config.macros.captureKeys.captureKeyHandler))
config.macros.captureKeys.addEventListener(elem,"keypress",config.macros.captureKeys.captureKeyHandler);
}
return keyEvent;
}
config.macros.captureKeys.captureKeyHandler = function(event)
{
if(!this.captureKeys)return null;
var keyCode = config.macros.captureKeys.getRealKey(event)
for(var i = 0; i < this.captureKeys.length; i++)
{
if(this.captureKeys[i].key == keyCode && this.captureKeys[i].shift == event.shiftKey && this.captureKeys[i].alt == event.altKey && this.captureKeys[i].ctrl == event.ctrlKey)
{
this.captureKeys[i].func.call(this,event);
config.macros.captureKeys.preventDefault(event);
}
}
}
config.macros.captureKeys.getRealKey = function(event)
{
var keyCode = event.keyCode;
if(!keyCode || (keyCode && keyCode == 0))
{
var unicode=event.which? event.which: event.charCode;
keyCode = (config.macros.captureKeys.UNICodeToAsciiVK[unicode]?config.macros.captureKeys.UNICodeToAsciiVK[unicode]:unicode);
}
return keyCode;
}
config.macros.captureKeys.removeCaptureKey = function(elem,handler,keyCode,shiftButton,altButton,ctrlButton)
{
if(!elem.captureKeys)return null;
for(var i = 0; i < elem.captureKeys.length; i++)
{
if(elem.captureKeys[i].key == keyCode && elem.captureKeys[i].shift == shiftButton && elem.captureKeys[i].alt == altButton && elem.captureKeys[i].ctrl == ctrlButton && elem.captureKeys[i].func == handler)
{
if(!elem.captureKeys || (elem.captureKeys && elem.captureKeys.length == 1))
{
elem.captureKeys = null;
config.macros.captureKeys.removeEventListener(elem,window.event?"keydown":"keypress",config.macros.captureKeys.captureKeyHandler);
return false;
}
else
{
elem.captureKeys.splice(i,1)
}
}
}
}
config.macros.captureKeys.addEventListener = function(target,eventType,func,capturing)
{
if(!target.eventListeners)
{
target.eventListeners = {};
}
if(!target.eventListeners[eventType])
{
target.eventListeners[eventType] = [];
}
if(target.addEventListener)
{
target.addEventListener(eventType,func,capturing);
target.eventListeners[eventType].push(func);
return func;
}
else if(target.attachEvent)
{
var handler = function(event)
{
if(!event)var event = window.event;
func.call(target,event);
};
handler.originalFunction = func;
target.attachEvent("on"+eventType,handler);
target.eventListeners[eventType].push(handler);
return handler;
}
else
{
if(target.eventListeners[eventType].length == 0)
{
if(target["on"+eventType])
{
target.eventListeners[eventType].push(target["on"+eventType]);
}
target["on"+eventType] = api.event.standardEventHandler;
}
target.eventListeners[eventType].push(func);
}
}
config.macros.captureKeys.standardEventHandler = function(event)
{
if(!event)var event = window.event;
if(!this.eventListeners || !this.eventListeners[event.type])return null;
for(var i = 0; i < this.eventListeners[event.type].length; i++)
{
this.eventListeners[event.type][i].call(this,event);
}
}
config.macros.captureKeys.removeEventListener = function(target,eventType,func,capturing)
{
if(!target.eventListeners || !target.eventListeners[eventType])
{
return null;
}
if(target.removeEventListener)
{
target.removeEventListener(eventType,func,capturing);
target.eventListeners[eventType].splice(target.eventListeners[eventType].indexOf(func),1);
}
else if(target.detachEvent)
{
var trueFunc = null;
var i = 0;
for(; i < target.eventListeners.length; i++)
{
if(target.eventListeners[i].originalFunction = func)
{
trueFunc = target.eventListeners[i];
break;
}
}
if(trueFunc)
{
target.detachEvent("on"+eventType,trueFunc);
target.eventListeners[eventType].splice(i,1);
}
}
else
{
target.eventListeners[eventType].splice(target.eventListeners[eventType].indexOf(func),1);
if(target.eventListeners[eventType].length == 0)target["on"+eventType] = null;
}
if(target.eventListeners[eventType].length == 0)
{
delete target.eventListeners[eventType];
}
for(var i in target.eventListeners)
{
return;
}
target.eventListeners = undefined;
}
config.macros.captureKeys.hasEventListener = function(elem,eventType,func)
{
if(!elem.eventListeners || !elem.eventListeners[eventType]) return false;
if(elem.eventListeners[eventType].indexOf(func)!=null)return true;
return false;
}
config.macros.captureKeys.preventDefault = function(event){
try
{
event.keyCode = 0; // Kills old IE
}
catch(exeption)
{
}
if(window.event)
{
event.returnValue=false;
}
if(event.preventDefault)
{
event.preventDefault();
}
return event;
}
config.macros.captureKeys.stopPropagation = function(event){
if(event.cancelBubble)
{
event.cancelBubble=false;
}
if(event.stopPropagation)
{
event.stopPropagation();
}
return event;
}
//}}}
A famous result due to [[Euler|http://www-groups.dcs.st-and.ac.uk/~history/Mathematicians/Euler.html]] in ~LaTeX: $\sum_{n=1}^{+\infty}{\frac1{n^2}=\frac{\pi^2}6$
and again as a centered equation using {{{$$ ... $$}}}$$\sum_{n=1}^{+\infty} \frac{1}{n^2}=\frac{\pi^2}{6}.$$
or using {{{\[ ... \]}}} \[\sum_{n=1}^{+\infty} \frac{1}{n^2}=\frac{\pi^2}{6}.\]
Here is a graph of $x-\frac{x^3}{6}$ and $\sin(x)$
<div class='SVGgraph' options='width:300,height:150,scales:[-6.29,6.29]'>
grid({dx:1,stroke:"green"});
axes({marker:">"});
plot("sin(x)",{stroke:"red"})
plot("x-pow(x,3)/6",{min:-4,max:4,stroke:"blue", strokedasharray:"10,10"})
text([-2,-2.5],"Close friends near 0!",{id:"rot",fontsize:18,fontfill:"orange"});
rotate("rot",PI/18,{center:[-5,-3]});
</div>
and a diagram illustrating why Pythagoras' Theorem holds:
<div class='SVGgraph' options='width:400,height:150,scales:[-4,4,1,4]'>
setOptions({fill:"yellow"});
rect([1,1],[4,4])
rect([-4,1],[-1,4])
setOptions({fill:"red"});
rect([-2,1],[-1,2])
setOptions({fill:"blue"});
rect([-4,2],[-2,4])
setOptions({fill:"green"});
path([[1,2],[2,4],[4,3],[3,1],[1,2]])
setOptions({fill:"none"});
path([[-4,1],[-2,2],[-1,4]])
</div>
+++[layout]
<<list filter "[tag[layout]]>>
===
+++[tasks]
<<list filter "[tag[task]]>>
===
+++[interests]
<<list filter "[tag[interest]]>>
===
/***
Just set the absolute path for static resources
***/
//{{{
config.formatterHelpers.resolvePath = function(src)
{
console.log(src);
if (src[0] == "/")
src = "/static" + src;
src = src.replace("recipes/default", "static");
return src;
}
//}}}
/***
|Name|RearrangeTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#RearrangeTiddlersPlugin|
|Version|2.0.0|
|Author|Eric Shulman|
|OriginalAuthor|Joe Raii|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|drag tiddlers by title to re-order story column display|
adapted from: http://www.cs.utexas.edu/~joeraii/dragn/#Draggable
changes by ELS:
* hijack refreshTiddler() instead of overridding createTiddler()
* find title element by className instead of elementID
* set cursor style via code instead of stylesheet
* set tooltip help text
* set tiddler "position:relative" when starting drag event, restore saved value when drag ends
* update 2006.08.07: use getElementsByTagName("*") to find title element, even when it is 'buried' deep in tiddler DOM elements (due to custom template usage)
* update 2007.03.01: use apply() to invoke hijacked core function
* update 2008.01.13: only hijack core function once. (allows for dynamic loading of plugin via bookmarklet)
* update 2008.10.19: added onclick popup menu with 'move to top' and 'move to bottom' commands
* update 2010.11.30: use story.getTiddler()
***/
//{{{
if (Story.prototype.rearrangeTiddlersHijack_refreshTiddler===undefined) {
Story.prototype.rearrangeTiddlersHijack_refreshTiddler = Story.prototype.refreshTiddler;
Story.prototype.refreshTiddler = function(title,template)
{
this.rearrangeTiddlersHijack_refreshTiddler.apply(this,arguments);
var theTiddler = this.getTiddler(title); if (!theTiddler) return;
var theHandle;
var children=theTiddler.getElementsByTagName("*");
for (var i=0; i<children.length; i++) if (hasClass(children[i],"title")) { theHandle=children[i]; break; }
if (!theHandle) return theTiddler;
Drag.init(theHandle, theTiddler, 0, 0, null, null);
theHandle.style.cursor="move";
theHandle.title="drag title to re-arrange tiddlers, click for more options..."
theTiddler.onDrag = function(x,y,myElem) {
if (this.style.position!="relative")
{ this.savedstyle=this.style.position; this.style.position="relative"; }
y = myElem.offsetTop;
var next = myElem.nextSibling;
var prev = myElem.previousSibling;
if (next && y + myElem.offsetHeight > next.offsetTop + next.offsetHeight/2) {
myElem.parentNode.removeChild(myElem);
next.parentNode.insertBefore(myElem, next.nextSibling);//elems[pos+1]);
myElem.style["top"] = -next.offsetHeight/2+"px";
}
if (prev && y < prev.offsetTop + prev.offsetHeight/2) {
myElem.parentNode.removeChild(myElem);
prev.parentNode.insertBefore(myElem, prev);
myElem.style["top"] = prev.offsetHeight/2+"px";
}
};
theTiddler.onDragEnd = function(x,y,myElem) {
myElem.style["top"] = "0px";
if (this.savedstyle!=undefined)
this.style.position=this.savedstyle;
};
theHandle.onclick=function(ev) {
ev=ev||window.event;
var p=Popup.create(this); if (!p) return;
var b=createTiddlyButton(createTiddlyElement(p,"li"),
"\u25B2 move to top of column ","move this tiddler to the top of the story column",
function() {
var t=story.getTiddler(this.getAttribute("tid"));
t.parentNode.insertBefore(t,t.parentNode.firstChild); // move to top of column
window.scrollTo(0,ensureVisible(t));
return false;
});
b.setAttribute("tid",title);
var b=createTiddlyButton(createTiddlyElement(p,"li"),
"\u25BC move to bottom of column ","move this tiddler to the bottom of the story column",
function() {
var t=story.getTiddler(this.getAttribute("tid"));
t.parentNode.insertBefore(t,null); // move to bottom of column
window.scrollTo(0,ensureVisible(t));
return false;
});
b.setAttribute("tid",title);
Popup.show();
ev.cancelBubble=true; if (ev.stopPropagation) ev.stopPropagation(); return(false);
};
return theTiddler;
}
}
/**************************************************
* dom-drag.js
* 09.25.2001
* www.youngpup.net
**************************************************
* 10.28.2001 - fixed minor bug where events
* sometimes fired off the handle, not the root.
**************************************************/
var Drag = {
obj:null,
init:
function(o, oRoot, minX, maxX, minY, maxY) {
o.onmousedown = Drag.start;
o.root = oRoot && oRoot != null ? oRoot : o ;
if (isNaN(parseInt(o.root.style.left))) o.root.style.left="0px";
if (isNaN(parseInt(o.root.style.top))) o.root.style.top="0px";
o.minX = typeof minX != 'undefined' ? minX : null;
o.minY = typeof minY != 'undefined' ? minY : null;
o.maxX = typeof maxX != 'undefined' ? maxX : null;
o.maxY = typeof maxY != 'undefined' ? maxY : null;
o.root.onDragStart = new Function();
o.root.onDragEnd = new Function();
o.root.onDrag = new Function();
},
start:
function(e) {
var o = Drag.obj = this;
e = Drag.fixE(e);
var y = parseInt(o.root.style.top);
var x = parseInt(o.root.style.left);
o.root.onDragStart(x, y, Drag.obj.root);
o.lastMouseX = e.clientX;
o.lastMouseY = e.clientY;
if (o.minX != null) o.minMouseX = e.clientX - x + o.minX;
if (o.maxX != null) o.maxMouseX = o.minMouseX + o.maxX - o.minX;
if (o.minY != null) o.minMouseY = e.clientY - y + o.minY;
if (o.maxY != null) o.maxMouseY = o.minMouseY + o.maxY - o.minY;
document.onmousemove = Drag.drag;
document.onmouseup = Drag.end;
Drag.obj.root.style["z-index"] = "10";
return false;
},
drag:
function(e) {
e = Drag.fixE(e);
var o = Drag.obj;
var ey = e.clientY;
var ex = e.clientX;
var y = parseInt(o.root.style.top);
var x = parseInt(o.root.style.left);
var nx, ny;
if (o.minX != null) ex = Math.max(ex, o.minMouseX);
if (o.maxX != null) ex = Math.min(ex, o.maxMouseX);
if (o.minY != null) ey = Math.max(ey, o.minMouseY);
if (o.maxY != null) ey = Math.min(ey, o.maxMouseY);
nx = x + (ex - o.lastMouseX);
ny = y + (ey - o.lastMouseY);
Drag.obj.root.style["left"] = nx + "px";
Drag.obj.root.style["top"] = ny + "px";
Drag.obj.lastMouseX = ex;
Drag.obj.lastMouseY = ey;
Drag.obj.root.onDrag(nx, ny, Drag.obj.root);
return false;
},
end:
function() {
document.onmousemove = null;
document.onmouseup = null;
Drag.obj.root.style["z-index"] = "0";
Drag.obj.root.onDragEnd(parseInt(Drag.obj.root.style["left"]), parseInt(Drag.obj.root.style["top"]), Drag.obj.root);
Drag.obj = null;
},
fixE:
function(e) {
if (typeof e == 'undefined') e = window.event;
if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
return e;
}
};
//}}}
//{{{
shell_formatter = {
name: "shellCmd",
match: " \\#[^\\n]+\\n",
handler: function(w)
{
createTiddlyElement(w.output,"span",null,"verbatim", w.matchText.substr(2));
createTiddlyElement(w.output, "br", null, null, null);
}
};
config.formatters.unshift(shell_formatter);
//}}}
//{{{
// Sum lines up as long as they start by a number
config.macros.sum = {handler: function(place)
{
data = place.innerText;
sum = 0;
lines = data.split("\n");
for (var i= lines.length-2; i>=0; --i)
{
v = parseInt(lines[i]);
if (isNaN(v))
break;
sum += v;
}
jQuery("<span/>").text(sum).appendTo(place);
}
};
// sum lines up, stopping when two NaN lines are met
config.macros.sumSkip = {handler: function(place)
{
skip = 0;
data = place.innerText;
sum = 0;
lines = data.split("\n");
for (var i= lines.length-2; i>=0; --i)
{
v = parseInt(lines[i]);
if (isNaN(v))
{
skip = skip + 1;
if (skip >= 2) break;
}
else { skip = 0; sum += v;}
}
jQuery("<span/>").text(sum).appendTo(place);
}
};
//}}}
Welcome to this dump of relevant TiddlyWiki macros and plugins.
Things of interest (some by me, some by others):
! Layout
* Drop-down menus for quick access to some tags in [[SiteTitle]]
* Configureable column count in SetTiddlerColumns.
! Input
* WYSIWYGPlugin for wysiwyg edit mode. To enable, just type <html> as sole content, re-open, et voila.
* JsMathPlugin and MathSVGPlugin (see MathSvgExampl, this rocks).
* GraphPlugin to draw graphs using graphviz syntax.
* MyFormatters: verbatim mode
! Interaction
* ImageSizePlugin for basic image manipulation in view mode
* ReminderPlugin for a very basic task reminder. ctrl-click to reset. One minute: <<reminder test 60s>>.
* MyMacros: sum
/***
|Name|Plugin: jsMath|
|Created by|BobMcElrath|
|Email|my first name at my last name dot org|
|Location|http://bob.mcelrath.org/tiddlyjsmath.html|
|Version|1.5.1|
|Requires|[[TiddlyWiki|http://www.tiddlywiki.com]] ≥ 2.0.3, [[jsMath|http://www.math.union.edu/~dpvc/jsMath/]] ≥ 3.0|
!Description
LaTeX is the world standard for specifying, typesetting, and communicating mathematics among scientists, engineers, and mathematicians. For more information about LaTeX itself, visit the [[LaTeX Project|http://www.latex-project.org/]]. This plugin typesets math using [[jsMath|http://www.math.union.edu/~dpvc/jsMath/]], which is an implementation of the TeX math rules and typesetting in javascript, for your browser. Notice the small button in the lower right corner which opens its control panel.
!Installation
In addition to this plugin, you must also [[install jsMath|http://www.math.union.edu/~dpvc/jsMath/download/jsMath.html]] on the same server as your TiddlyWiki html file. If you're using TiddlyWiki without a web server, then the jsMath directory must be placed in the same location as the TiddlyWiki html file.
I also recommend modifying your StyleSheet use serif fonts that are slightly larger than normal, so that the math matches surrounding text, and \\small fonts are not unreadable (as in exponents and subscripts).
{{{
.viewer {
line-height: 125%;
font-family: serif;
font-size: 12pt;
}
}}}
If you had used a previous version of [[Plugin: jsMath]], it is no longer necessary to edit the main tiddlywiki.html file to add the jsMath <script> tag. [[Plugin: jsMath]] now uses ajax to load jsMath.
!History
* 11-Nov-05, version 1.0, Initial release
* 22-Jan-06, version 1.1, updated for ~TW2.0, tested with jsMath 3.1, editing tiddlywiki.html by hand is no longer necessary.
* 24-Jan-06, version 1.2, fixes for Safari, Konqueror
* 27-Jan-06, version 1.3, improved error handling, detect if ajax was already defined (used by ZiddlyWiki)
* 12-Jul-06, version 1.4, fixed problem with not finding image fonts
* 26-Feb-07, version 1.5, fixed problem with Mozilla "unterminated character class".
* 27-Feb-07, version 1.5.1, Runs compatibly with TW 2.1.0+, by Bram Chen
!Examples
|!Source|!Output|h
|{{{The variable $x$ is real.}}}|The variable $x$ is real.|
|{{{The variable \(y\) is complex.}}}|The variable \(y\) is complex.|
|{{{This \[\int_a^b x = \frac{1}{2}(b^2-a^2)\] is an easy integral.}}}|This \[\int_a^b x = \frac{1}{2}(b^2-a^2)\] is an easy integral.|
|{{{This $$\int_a^b \sin x = -(\cos b - \cos a)$$ is another easy integral.}}}|This $$\int_a^b \sin x = -(\cos b - \cos a)$$ is another easy integral.|
|{{{Block formatted equations may also use the 'equation' environment \begin{equation} \int \tan x = -\ln \cos x \end{equation} }}}|Block formatted equations may also use the 'equation' environment \begin{equation} \int \tan x = -\ln \cos x \end{equation}|
|{{{Equation arrays are also supported \begin{eqnarray} a &=& b \\ c &=& d \end{eqnarray} }}}|Equation arrays are also supported \begin{eqnarray} a &=& b \\ c &=& d \end{eqnarray} |
|{{{I spent \$7.38 on lunch.}}}|I spent \$7.38 on lunch.|
|{{{I had to insert a backslash (\\) into my document}}}|I had to insert a backslash (\\) into my document|
!Code
***/
//{{{
// AJAX code adapted from http://timmorgan.org/mini
// This is already loaded by ziddlywiki...
if(typeof(window["ajax"]) == "undefined") {
ajax = {
x: function(){try{return new ActiveXObject('Msxml2.XMLHTTP')}catch(e){try{return new ActiveXObject('Microsoft.XMLHTTP')}catch(e){return new XMLHttpRequest()}}},
gets: function(url){var x=ajax.x();x.open('GET',url,false);x.send(null);return x.responseText}
}
}
// Load jsMath
jsMath = {
Setup: {inited: 1}, // don't run jsMath.Setup.Body() yet
Autoload: {root: "https://www.nottale.net/jsMath-3.6e/"} // URL to jsMath directory, change if necessary
};
var jsMathstr;
try {
jsMathstr = ajax.gets(jsMath.Autoload.root+"jsMath.js");
} catch(e) {
alert("jsMath was not found: you must place the 'jsMath' directory in the same place as this file. "
+"The error was:\n"+e.name+": "+e.message);
throw(e); // abort eval
}
try {
window.eval(jsMathstr);
} catch(e) {
alert("jsMath failed to load. The error was:\n"+e.name + ": " + e.message + " on line " + e.lineNumber);
}
jsMath.Setup.inited=0; // allow jsMath.Setup.Body() to run again
// Define wikifers for latex
config.formatterHelpers.mathFormatHelper = function(w) {
var e = document.createElement(this.element);
e.className = this.className;
var endRegExp = new RegExp(this.terminator, "mg");
endRegExp.lastIndex = w.matchStart+w.matchLength;
var matched = endRegExp.exec(w.source);
if(matched) {
var txt = w.source.substr(w.matchStart+w.matchLength,
matched.index-w.matchStart-w.matchLength);
if(this.keepdelim) {
txt = w.source.substr(w.matchStart, matched.index+matched[0].length-w.matchStart);
}
e.appendChild(document.createTextNode(txt));
w.output.appendChild(e);
w.nextMatch = endRegExp.lastIndex;
}
}
config.formatters.push({
name: "displayMath1",
match: "\\\$\\\$",
terminator: "\\\$\\\$\\n?", // 2.0 compatibility
termRegExp: "\\\$\\\$\\n?",
element: "div",
className: "math",
handler: config.formatterHelpers.mathFormatHelper
});
config.formatters.push({
name: "inlineMath1",
match: "\\\$",
terminator: "\\\$", // 2.0 compatibility
termRegExp: "\\\$",
element: "span",
className: "math",
handler: config.formatterHelpers.mathFormatHelper
});
var backslashformatters = new Array(0);
backslashformatters.push({
name: "inlineMath2",
match: "\\\\\\\(",
terminator: "\\\\\\\)", // 2.0 compatibility
termRegExp: "\\\\\\\)",
element: "span",
className: "math",
handler: config.formatterHelpers.mathFormatHelper
});
backslashformatters.push({
name: "displayMath2",
match: "\\\\\\\[",
terminator: "\\\\\\\]\\n?", // 2.0 compatibility
termRegExp: "\\\\\\\]\\n?",
element: "div",
className: "math",
handler: config.formatterHelpers.mathFormatHelper
});
backslashformatters.push({
name: "displayMath3",
match: "\\\\begin\\{equation\\}",
terminator: "\\\\end\\{equation\\}\\n?", // 2.0 compatibility
termRegExp: "\\\\end\\{equation\\}\\n?",
element: "div",
className: "math",
handler: config.formatterHelpers.mathFormatHelper
});
// These can be nested. e.g. \begin{equation} \begin{array}{ccc} \begin{array}{ccc} ...
backslashformatters.push({
name: "displayMath4",
match: "\\\\begin\\{eqnarray\\}",
terminator: "\\\\end\\{eqnarray\\}\\n?", // 2.0 compatibility
termRegExp: "\\\\end\\{eqnarray\\}\\n?",
element: "div",
className: "math",
keepdelim: true,
handler: config.formatterHelpers.mathFormatHelper
});
// The escape must come between backslash formatters and regular ones.
// So any latex-like \commands must be added to the beginning of
// backslashformatters here.
backslashformatters.push({
name: "escape",
match: "\\\\.",
handler: function(w) {
w.output.appendChild(document.createTextNode(w.source.substr(w.matchStart+1,1)));
w.nextMatch = w.matchStart+2;
}
});
config.formatters=backslashformatters.concat(config.formatters);
window.wikify = function(source,output,highlightRegExp,tiddler)
{
if(source && source != "") {
if(version.major == 2 && version.minor > 0) {
var wikifier = new Wikifier(source,getParser(tiddler),highlightRegExp,tiddler);
wikifier.subWikifyUnterm(output);
} else {
var wikifier = new Wikifier(source,formatter,highlightRegExp,tiddler);
wikifier.subWikify(output,null);
}
jsMath.ProcessBeforeShowing();
}
}
//}}}
/***
|Name|EncryptionPlugin|
|Source|http://www.dataspill.org/EncryptionPlugin.html|
|Version|0.0.4|
|Author|redpig@dataspill.org|
|License|GPLv2|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Encrypt/decrypt tiddlers with AES|
!!!!!Usage
This plugin adds AES encryption support to TiddlyWiki. There are several interfaces to do so:
* Tag-wide encryption/decryption with a macro:
{{{<<<encrypt_tag "tagname" "password-realm" "button text">>>}}}
As shown above, passwords are cached on a per-zone basis where a zone may be
something like "work" or "home". This does not have to have any relation to
your tag, but if omitted, will be the same.
* If you're done encrypting/decrypting, you may want to clear the cached password. This can be done with another button creating macro:
{{{<<<encrypt_clear "password-realm">>>}}}
* If you want to take a peek at some encrypted data without fear of saving it, you can add a preview button to your toolbar. If you are using the normal ViewTemplate, just add ''peekcrypt'' like below:
{{{<div class='toolbar' macro='toolbar ... peekcrypt>...}}}
* If you want to just encrypt/decrypt one tiddler at a time, you can add an
''autocrypt'' button to the toolbar:
{{{<div class='toolbar' macro='toolbar ... autocrypt>...}}}
* Note: the entropy collection is not particularly great so far. If this is very sensitive datæ, you may want to consider a more secure solution or help beef this one up!
!!!!!Options
<<option chkEncryptTags>> Encrypt tiddler tags
<<option chkEncryptTitles>> Encrypt tiddler titles and references
!!!!!TODO
* Add versioning and reader/writer for encrypted tiddlers w.out needing a tag.
* Encrypt-on-save: auto re-encrypt specifically tagged items
** Alternately add a decrypt-to-edit/encrypt-on-save for a specific tiddler
* Add toolbar commands for encrypt/decrypt
* Embed per-tiddler encryption options and autodetect otherwise
* Add macro-wrapped encryption (think tasklist/tasksum)
* Make previews more like light boxes
* Encrypt all object data for a tiddler and not just text/title/tags (JSON?)
* Compressed or minjs'd code
* Make reference title-encryption replacement safer (e.g. proper replace())
* Clean up code encapsulation some more
* Automatic password updating (e.g. decrypt/re-encrypt all tiddlers)
* Configurable key bits (allow user to use stronger keys than 128 bit)
* Local-file key support (load a key file that is optionally password-protected)
* Encapsulate the rumsby's entropy collector slightly better
!!!!!Installation
import (or copy/paste) the following tiddlers into your document:
''EncryptTiddlerPlugin'' (tagged with <<tag systemConfig>>)
!!!!!Revisions
!"2007.03.24 [0.0.4]"
* Replaced entropy gathering functions with Math.random.
!''2007.02.20 [0.0.3]''
* Added EncryptionPayload: an extensible payload object for safe forward compat
* Cleaned up peekcrypt and the askUser object
* Added support for encrypt/decrypt in the toolbar: autocrypt
!''2007.02.18 [0.0.2]''
* Added informational messages
* Added AESprng from Steve Rumsby's Encryption plugin
* Namespaced the Rijndael plugin on ''Rijndael''
* Added .encrypt/.decrypt to Tiddler prototype
* Kinda encapsulated my code in encryptionPlugin
* Moved encrypted zone name into the encrypted tiddler to make previewing easy
* Added previewSecret toolbar command to allow previewing of data
* Added two checkbox options: encrypt tags and encrypt titles
* Separate tag-wide encryption from password zones/realms. encrypt_tag now supports that.
* Updated the usage a little bit
* Added a loop which ensures that entropy collection continues.
'!'2007.02.15 [0.0.1]''
* first cut.
!!!!!Credits
Based on copyTiddlerPlugin developed by EricShulman from [[ELS Design Studios|http://www.elsdesign.com]]
AES implementation courtesy of Fritz Schneider. Thanks Fritz!
!!!!!HTML tidbits
<html>
<style>
.previewToolbar {
display: block;
text-align: right;
}
</style>
<div id='previewArea' style="position:absolute; top:10%; right:50%; margin: 0.5em; padding: 0.5em; position:fixed !important; z-index:99; border: 1px solid #841; background: #db4; color: #014; display:none;">
</div>
</html>
!!!!!Code
***/
//{{{
/* An encapsulated version of Fritz Schneider's Rijndael implementation:
* Copyright (c) 2001 Fritz Schneider
* http://www-cse.ucsd.edu/~fritz/rijndael.html
* Encapsulation by Will Drewry, 2007
*/
function Rijndael() {}; // namesapce
/* Configurable variables:
* Valid values are 128, 192, or 256
*/
Rijndael.keySizeInBits = 128;
Rijndael.blockSizeInBits = 128;
// Private date
// Note: in the following code the two dimensional arrays are indexed as
// you would probably expect, as array[row][column]. The state arrays
// are 2d arrays of the form state[4][Nb].
// The number of rounds for the cipher, indexed by [Nk][Nb]
Rijndael.roundsArray = [ ,,,,[,,,,10,, 12,, 14],,
[,,,,12,, 12,, 14],,
[,,,,14,, 14,, 14] ];
// The number of bytes to shift by in shiftRow, indexed by [Nb][row]
Rijndael.shiftOffsets = [ ,,,,[,1, 2, 3],,[,1, 2, 3],,[,1, 3, 4] ];
// The round constants used in subkey expansion
Rijndael.Rcon = [
0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc,
0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4,
0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ];
// Precomputed lookup table for the SBox
Rijndael.SBox = [
99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171,
118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164,
114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113,
216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226,
235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214,
179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203,
190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69,
249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245,
188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68,
23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42,
144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73,
6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109,
141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37,
46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62,
181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225,
248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187,
22 ];
// Precomputed lookup table for the inverse SBox
Rijndael.SBoxInverse = [
82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215,
251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222,
233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66,
250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73,
109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92,
204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21,
70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247,
228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2,
193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220,
234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173,
53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29,
41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75,
198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168,
51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81,
127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160,
224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97,
23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12,
125 ];
// Cipher parameters ... do not change these
Rijndael.Nk = Rijndael.keySizeInBits / 32;
Rijndael.Nb = Rijndael.blockSizeInBits / 32;
Rijndael.Nr = Rijndael.roundsArray[Rijndael.Nk][Rijndael.Nb];
/* Functions */
// This method circularly shifts the array left by the number of elements
// given in its parameter. It returns the resulting array and is used for
// the ShiftRow step. Note that shift() and push() could be used for a more
// elegant solution, but they require IE5.5+, so I chose to do it manually.
Rijndael.cyclicShiftLeft = function(theArray, positions) {
var temp = theArray.slice(0, positions);
theArray = theArray.slice(positions).concat(temp);
return theArray;
};
// Multiplies the element "poly" of GF(2^8) by x. See the Rijndael spec.
Rijndael.xtime = function(poly) {
poly <<= 1;
return ((poly & 0x100) ? (poly ^ 0x11B) : (poly));
};
// Multiplies the two elements of GF(2^8) together and returns the result.
// See the Rijndael spec, but should be straightforward: for each power of
// the indeterminant that has a 1 coefficient in x, add y times that power
// to the result. x and y should be bytes representing elements of GF(2^8)
Rijndael.mult_GF256 = function(x, y) {
var bit, result = 0;
for (bit = 1; bit < 256; bit *= 2, y = Rijndael.xtime(y)) {
if (x & bit)
result ^= y;
}
return result;
};
// Performs the substitution step of the cipher. State is the 2d array of
// state information (see spec) and direction is string indicating whether
// we are performing the forward substitution ("encrypt") or inverse
// substitution (anything else)
Rijndael.byteSub = function(state, direction) {
var S;
if (direction == "encrypt") // Point S to the SBox we're using
S = Rijndael.SBox;
else
S = Rijndael.SBoxInverse;
for (var i = 0; i < 4; i++) // Substitute for every byte in state
for (var j = 0; j < Rijndael.Nb; j++)
state[i][j] = S[state[i][j]];
};
// Performs the row shifting step of the cipher.
Rijndael.shiftRow = function(state, direction) {
for (var i=1; i<4; i++) // Row 0 never shifts
if (direction == "encrypt")
state[i] = Rijndael.cyclicShiftLeft(state[i], Rijndael.shiftOffsets[Rijndael.Nb][i]);
else
state[i] = Rijndael.cyclicShiftLeft(state[i], Rijndael.Nb - Rijndael.shiftOffsets[Rijndael.Nb][i]);
};
// Performs the column mixing step of the cipher. Most of these steps can
// be combined into table lookups on 32bit values (at least for encryption)
// to greatly increase the speed.
Rijndael.mixColumn = function(state, direction) {
var b = []; // Result of matrix multiplications
for (var j = 0; j < Rijndael.Nb; j++) { // Go through each column...
for (var i = 0; i < 4; i++) { // and for each row in the column...
if (direction == "encrypt")
b[i] = Rijndael.mult_GF256(state[i][j], 2) ^ // perform mixing
Rijndael.mult_GF256(state[(i+1)%4][j], 3) ^
state[(i+2)%4][j] ^
state[(i+3)%4][j];
else
b[i] = Rijndael.mult_GF256(state[i][j], 0xE) ^
Rijndael.mult_GF256(state[(i+1)%4][j], 0xB) ^
Rijndael.mult_GF256(state[(i+2)%4][j], 0xD) ^
Rijndael.mult_GF256(state[(i+3)%4][j], 9);
}
for (var i = 0; i < 4; i++) // Place result back into column
state[i][j] = b[i];
}
};
// Adds the current round key to the state information. Straightforward.
Rijndael.addRoundKey = function(state, roundKey) {
for (var j = 0; j < Rijndael.Nb; j++) { // Step through columns...
state[0][j] ^= (roundKey[j] & 0xFF); // and XOR
state[1][j] ^= ((roundKey[j]>>8) & 0xFF);
state[2][j] ^= ((roundKey[j]>>16) & 0xFF);
state[3][j] ^= ((roundKey[j]>>24) & 0xFF);
}
};
// This function creates the expanded key from the input (128/192/256-bit)
// key. The parameter key is an array of bytes holding the value of the key.
// The returned value is an array whose elements are the 32-bit words that
// make up the expanded key.
Rijndael.keyExpansion = function(key) {
var expandedKey = new Array();
var temp;
// in case the key size or parameters were changed...
Rijndael.Nk = Rijndael.keySizeInBits / 32;
Rijndael.Nb = Rijndael.blockSizeInBits / 32;
Rijndael.Nr = Rijndael.roundsArray[Rijndael.Nk][Rijndael.Nb];
for (var j=0; j < Rijndael.Nk; j++) // Fill in input key first
expandedKey[j] =
(key[4*j]) | (key[4*j+1]<<8) | (key[4*j+2]<<16) | (key[4*j+3]<<24);
// Now walk down the rest of the array filling in expanded key bytes as
// per Rijndael's spec
for (j = Rijndael.Nk; j < Rijndael.Nb * (Rijndael.Nr + 1); j++) { // For each word of expanded key
temp = expandedKey[j - 1];
if (j % Rijndael.Nk == 0)
temp = ( (Rijndael.SBox[(temp>>8) & 0xFF]) |
(Rijndael.SBox[(temp>>16) & 0xFF]<<8) |
(Rijndael.SBox[(temp>>24) & 0xFF]<<16) |
(Rijndael.SBox[temp & 0xFF]<<24) ) ^ Rijndael.Rcon[Math.floor(j / Rijndael.Nk) - 1];
else if (Rijndael.Nk > 6 && j % Rijndael.Nk == 4)
temp = (Rijndael.SBox[(temp>>24) & 0xFF]<<24) |
(Rijndael.SBox[(temp>>16) & 0xFF]<<16) |
(Rijndael.SBox[(temp>>8) & 0xFF]<<8) |
(Rijndael.SBox[temp & 0xFF]);
expandedKey[j] = expandedKey[j-Rijndael.Nk] ^ temp;
}
return expandedKey;
};
// Rijndael's round functions...
Rijndael.Round = function(state, roundKey) {
Rijndael.byteSub(state, "encrypt");
Rijndael.shiftRow(state, "encrypt");
Rijndael.mixColumn(state, "encrypt");
Rijndael.addRoundKey(state, roundKey);
};
Rijndael.InverseRound = function(state, roundKey) {
Rijndael.addRoundKey(state, roundKey);
Rijndael.mixColumn(state, "decrypt");
Rijndael.shiftRow(state, "decrypt");
Rijndael.byteSub(state, "decrypt");
};
Rijndael.FinalRound = function(state, roundKey) {
Rijndael.byteSub(state, "encrypt");
Rijndael.shiftRow(state, "encrypt");
Rijndael.addRoundKey(state, roundKey);
};
Rijndael.InverseFinalRound = function(state, roundKey){
Rijndael.addRoundKey(state, roundKey);
Rijndael.shiftRow(state, "decrypt");
Rijndael.byteSub(state, "decrypt");
};
// encrypt is the basic encryption function. It takes parameters
// block, an array of bytes representing a plaintext block, and expandedKey,
// an array of words representing the expanded key previously returned by
// keyExpansion(). The ciphertext block is returned as an array of bytes.
Rijndael.encrypt = function(block, expandedKey) {
var i;
if (!block || block.length*8 != Rijndael.blockSizeInBits)
return;
if (!expandedKey)
return;
block = Rijndael.packBytes(block);
Rijndael.addRoundKey(block, expandedKey);
for (i=1; i<Rijndael.Nr; i++)
Rijndael.Round(block, expandedKey.slice(Rijndael.Nb*i, Rijndael.Nb*(i+1)));
Rijndael.FinalRound(block, expandedKey.slice(Rijndael.Nb*Rijndael.Nr));
return Rijndael.unpackBytes(block);
};
// decrypt is the basic decryption function. It takes parameters
// block, an array of bytes representing a ciphertext block, and expandedKey,
// an array of words representing the expanded key previously returned by
// keyExpansion(). The decrypted block is returned as an array of bytes.
Rijndael.decrypt = function(block, expandedKey) {
var i;
if (!block || block.length*8 != Rijndael.blockSizeInBits)
return;
if (!expandedKey)
return;
block = Rijndael.packBytes(block);
Rijndael.InverseFinalRound(block, expandedKey.slice(Rijndael.Nb*Rijndael.Nr));
for (i = Rijndael.Nr - 1; i>0; i--)
Rijndael.InverseRound(block, expandedKey.slice(Rijndael.Nb*i, Rijndael.Nb*(i+1)));
Rijndael.addRoundKey(block, expandedKey);
return Rijndael.unpackBytes(block);
};
/** byte array code - may move to a separate object later **/
// This method takes a byte array (byteArray) and converts it to a string by
// applying String.fromCharCode() to each value and concatenating the result.
// The resulting string is returned. Note that this function SKIPS zero bytes
// under the assumption that they are padding added in formatPlaintext().
// Obviously, do not invoke this method on raw data that can contain zero
// bytes. It is really only appropriate for printable ASCII/Latin-1
// values. Roll your own function for more robust functionality :)
Rijndael.byteArrayToString = function(byteArray) {
var result = "";
for(var i=0; i<byteArray.length; i++)
if (byteArray[i] != 0)
result += String.fromCharCode(byteArray[i]);
return result;
};
// Reverses the above method
Rijndael.stringToByteArray = function(text) {
var i;
// if primitive string or String instance
if (typeof text == "string" || text.indexOf) {
text = text.split("");
// Unicode issues here (ignoring high byte)
for (i=0; i<text.length; i++)
text[i] = text[i].charCodeAt(0) & 0xFF;
}
return text;
};
// This function takes an array of bytes (byteArray) and converts them
// to a hexadecimal string. Array element 0 is found at the beginning of
// the resulting string, high nibble first. Consecutive elements follow
// similarly, for example [16, 255] --> "10ff". The function returns a
// string.
Rijndael.byteArrayToHex = function(byteArray) {
var result = "";
if (!byteArray)
return;
for (var i=0; i<byteArray.length; i++)
result += ((byteArray[i]<16) ? "0" : "") + byteArray[i].toString(16);
return result;
};
// This function converts a string containing hexadecimal digits to an
// array of bytes. The resulting byte array is filled in the order the
// values occur in the string, for example "10FF" --> [16, 255]. This
// function returns an array.
Rijndael.hexToByteArray = function(hexString) {
var byteArray = [];
if (hexString.length % 2) // must have even length
return;
if (hexString.indexOf("0x") == 0 || hexString.indexOf("0X") == 0)
hexString = hexString.substring(2);
for (var i = 0; i<hexString.length; i += 2)
byteArray[Math.floor(i/2)] = parseInt(hexString.slice(i, i+2), 16);
return byteArray;
};
// This function packs an array of bytes into the four row form defined by
// Rijndael. It assumes the length of the array of bytes is divisible by
// four. Bytes are filled in according to the Rijndael spec (starting with
// column 0, row 0 to 3). This function returns a 2d array.
Rijndael.packBytes = function(octets) {
var state = new Array();
if (!octets || octets.length % 4)
return;
state[0] = new Array(); state[1] = new Array();
state[2] = new Array(); state[3] = new Array();
for (var j=0; j<octets.length; j+= 4) {
state[0][j/4] = octets[j];
state[1][j/4] = octets[j+1];
state[2][j/4] = octets[j+2];
state[3][j/4] = octets[j+3];
}
return state;
};
// This function unpacks an array of bytes from the four row format preferred
// by Rijndael into a single 1d array of bytes. It assumes the input "packed"
// is a packed array. Bytes are filled in according to the Rijndael spec.
// This function returns a 1d array of bytes.
Rijndael.unpackBytes = function(packed) {
var result = new Array();
for (var j=0; j<packed[0].length; j++) {
result[result.length] = packed[0][j];
result[result.length] = packed[1][j];
result[result.length] = packed[2][j];
result[result.length] = packed[3][j];
}
return result;
};
/* Back to Rijndael helpers */
// This function takes a prospective plaintext (string or array of bytes)
// and pads it with zero bytes if its length is not a multiple of the block
// size. If plaintext is a string, it is converted to an array of bytes
// in the process. The type checking can be made much nicer using the
// instanceof operator, but this operator is not available until IE5.0 so I
// chose to use the heuristic below.
Rijndael.formatPlaintext = function(plaintext) {
var bpb = Rijndael.blockSizeInBits / 8; // bytes per block
var i;
// if primitive string or String instance
if (typeof plaintext == "string" || plaintext.indexOf) {
plaintext = plaintext.split("");
// Unicode issues here (ignoring high byte)
for (i=0; i<plaintext.length; i++)
plaintext[i] = plaintext[i].charCodeAt(0) & 0xFF;
}
for (i = bpb - (plaintext.length % bpb); i > 0 && i < bpb; i--)
plaintext[plaintext.length] = 0;
return plaintext;
};
// Returns an array containing "howMany" random bytes, but uses Math.random() instead
// of Fritz's fixed example.
Rijndael.getRandomBytes = function(howMany) {
var hex = "0123456789ABCEF";
var i;
var byte_string = "";
for (i=0; i<howMany*2; i++)
byte_string += hex.charAt(Math.random() * 16);
return Rijndael.hexToByteArray(byte_string);
};
/* Public API */
// rijndaelEncrypt(plaintext, key, mode)
// Encrypts the plaintext using the given key and in the given mode.
// The parameter "plaintext" can either be a string or an array of bytes.
// The parameter "key" must be an array of key bytes. If you have a hex
// string representing the key, invoke hexToByteArray() on it to convert it
// to an array of bytes. The third parameter "mode" is a string indicating
// the encryption mode to use, either "ECB" or "CBC". If the parameter is
// omitted, ECB is assumed.
//
// An array of bytes representing the cihpertext is returned. To convert
// this array to hex, invoke byteArrayToHex() on it. If you are using this
// "for real" it is a good idea to change the function getRandomBytes() to
// something that returns truly random bits.
Rijndael.rijndaelEncrypt = function(plaintext, key, mode) {
var expandedKey, i, aBlock;
var bpb = Rijndael.blockSizeInBits / 8; // bytes per block
var ct; // ciphertext
if (!plaintext || !key)
return;
if (key.length*8 != Rijndael.keySizeInBits)
return;
if (mode == "CBC")
ct = Rijndael.getRandomBytes(bpb); // get IV
else {
mode = "ECB";
ct = new Array();
}
// convert plaintext to byte array and pad with zeros if necessary.
plaintext = Rijndael.formatPlaintext(plaintext);
expandedKey = Rijndael.keyExpansion(key);
for (var block=0; block<plaintext.length / bpb; block++) {
aBlock = plaintext.slice(block*bpb, (block+1)*bpb);
if (mode == "CBC")
for (var i=0; i<bpb; i++)
aBlock[i] ^= ct[block*bpb + i];
ct = ct.concat(Rijndael.encrypt(aBlock, expandedKey));
}
return ct;
};
// rijndaelDecrypt(ciphertext, key, mode)
// Decrypts the using the given key and mode. The parameter "ciphertext"
// must be an array of bytes. The parameter "key" must be an array of key
// bytes. If you have a hex string representing the ciphertext or key,
// invoke hexToByteArray() on it to convert it to an array of bytes. The
// parameter "mode" is a string, either "CBC" or "ECB".
//
// An array of bytes representing the plaintext is returned. To convert
// this array to a hex string, invoke byteArrayToHex() on it. To convert it
// to a string of characters, you can use byteArrayToString().
Rijndael.rijndaelDecrypt = function(ciphertext, key, mode) {
var expandedKey;
var bpb = Rijndael.blockSizeInBits / 8; // bytes per block
var pt = new Array(); // plaintext array
var aBlock; // a decrypted block
var block; // current block number
if (!ciphertext || !key || typeof ciphertext == "string")
return;
if (key.length*8 != Rijndael.keySizeInBits)
return;
if (!mode)
mode = "ECB"; // assume ECB if mode omitted
expandedKey = Rijndael.keyExpansion(key);
// work backwards to accomodate CBC mode
for (block=(ciphertext.length / bpb)-1; block>0; block--) {
aBlock =
Rijndael.decrypt(ciphertext.slice(block*bpb,(block+1)*bpb), expandedKey);
if (mode == "CBC")
for (var i=0; i<bpb; i++)
pt[(block-1)*bpb + i] = aBlock[i] ^ ciphertext[(block-1)*bpb + i];
else
pt = aBlock.concat(pt);
}
// do last block if ECB (skips the IV in CBC)
if (mode == "ECB")
pt = Rijndael.decrypt(ciphertext.slice(0, bpb), expandedKey).concat(pt);
return pt;
};
/* end Rijndael */
/** EncryptionPayload object **/
// For reading/writing encrypted Tiddlers
function EncryptionPayload() {
// Arbitrary unicode unlikely to start an entry
this.MAGIC = EncryptionPayload.MAGIC;
this.VERSION = EncryptionPayload.VERSION;
this.FIELD_SEPARATOR = EncryptionPayload.FIELD_SEPARATOR;
this.SUBFIELD_SEPARATOR = EncryptionPayload.SUBFIELD_SEPARATOR;
this.LAYOUT = EncryptionPayload.LAYOUT
// Initialize
for (var i = 2; i < this.LAYOUT.length; ++i) {
if (this.LAYOUT[i] == 'TAGS') {
this[this.LAYOUT[i].toLowerCase()] = []
} else {
this[this.LAYOUT[i].toLowerCase()] = '';
}
}
/** Functions **/
this.load = function(text) {
payload = text.split(this.FIELD_SEPARATOR);
if (payload.length < 2) {
//displayMessage("Payload too short");
return false;
}
for (var i = 0; i < this.LAYOUT.length; ++i) {
var field = this.LAYOUT[i];
var value = '';
if (payload[i]) value = payload[i];
switch (field) {
case 'MAGIC':
if (value != this.MAGIC) {
// TODO: proper exception
//displayMessage("Invalid payload magic");
return false;
}
break;
case 'VERSION':
if (value > this.VERSION) {
//displayMessage("Invalid payload version");
return false;
}
break;
case 'TAGS':
this[field.toLowerCase()] = value.split(this.SUBFIELD_SEPARATOR);
break;
default:
this[field.toLowerCase()] = value;
}
}
return true;
};
this.serialize = function() {
var payload = new Array(this.LAYOUT.length);
for (var i = 0; i < this.LAYOUT.length; ++i) {
var field = this.LAYOUT[i];
switch (field) {
case 'MAGIC':
payload[i] = this.MAGIC;
break;
case 'VERSION':
payload[i] = this.VERSION;
break;
case 'TAGS':
payload[i] = this['tags'].join(this.SUBFIELD_SEPARATOR);
break;
default:
payload[i] = this[field.toLowerCase()];
}
}
return payload.join(this.FIELD_SEPARATOR);
};
}
// Setup EncryptionPayload Constants
EncryptionPayload.MAGIC = "\u25CB\u25D4\u25D1\u25D5\u25CF";
EncryptionPayload.VERSION = 1;
EncryptionPayload.FIELD_SEPARATOR = "$";
EncryptionPayload.SUBFIELD_SEPARATOR = ",";
/* Version 1 format
* magic$version$zone$title$text$tag1|tag2$
* Future fields can be added after the tags.
*
* These are the indices.
*/
EncryptionPayload.LAYOUT = [
'MAGIC',
'VERSION',
'OPTIONS',
'ZONE',
'TITLE',
'TEXT',
'TAGS',
];
/*-----------------------*/
config.options.chkEncryptTitles = true;
config.options.chkEncryptTags = true;
config.options.encryptionDefaultZone = 'global';
config.messages.encryptionPasswordPrompt = "Enter password for zone %0:";
config.messages.encryptionZonePrompt = "Enter zone:";
config.messages.encryptionWorkStart = "Performing encryption tasks...";
config.messages.encryptionWorkDoneHeader = "Encryption tasks completed:";
config.messages.encryptionWorkDoneDecrypt = "decrypted: '%0'";
config.messages.encryptionWorkDoneEncrypt = "encrypted: '%0'";
config.messages.encryptionTagSyntaxError = "encrypt_tag syntax error: a tag must be specified";
config.messages.encryptionInputMissingDiv = "Unable to open input prompt. No message DIV!";
config.messages.encryptionEncryptedTitle = "Encrypted:%0";
config.messages.encryptionCleared = "Credentials for '%0' cleared.";
/* Wraps a string irrespective of existing newlines */
function wrapText(length, text) { var result = ''; var sep = '\n'; for(var i = 0; i < text.length;) {result += text.substr(i, length); result += sep; i += length; }; return result;}
/*** plugin globals ***/
// global cached passphrase
// TODO(redpig): add levels by annotating encrypted pages.
// add structured data to the tiddler which
// allows for detecting encryption
// make decrypt not save.
//
encryptionPlugin = function() {} // namespace
encryptionPlugin.engine = {}
encryptionPlugin.uniqueId = 0;
encryptionPlugin.newEngine = function(zone, key, mode) {
encryptionPlugin.engine[zone].key = key;
encryptionPlugin.engine[zone].mode = mode;
encryptionPlugin.engine[zone].encrypt = function(pt) {
return Rijndael.byteArrayToHex(
Rijndael.rijndaelEncrypt(
pt,
Rijndael.stringToByteArray(encryptionPlugin.engine[zone].key),
encryptionPlugin.engine[zone].mode)
);
};
encryptionPlugin.engine[zone].decrypt = function(ct) {
// Only hex strings
var input = ct.replace(/[^A-Za-z0-9]/g, "");
return Rijndael.byteArrayToString(
Rijndael.rijndaelDecrypt(
Rijndael.hexToByteArray(input),
Rijndael.stringToByteArray(encryptionPlugin.engine[zone].key),
encryptionPlugin.engine[zone].mode)
);
};
};
encryptionPlugin.askUser = {
idPrefix: "askUser:",
closure: undefined, // stores what to do on prompt exit
reset: function() {encryptionPlugin.askUser.closure = undefined;},
onAnswer: function(e) {
var suffix = config.options.encryptionDefaultZone;
if(!e) var e = window.event;
switch(e.keyCode) {
case 13: // Enter
case 10: // Ctrl-Enter on IE PC
// Initialize engine from id
// First strip of password:
var id = this.getAttribute("id");
var prefixlen = encryptionPlugin.askUser.idPrefix.length;
if (id && id.length > prefixlen) {
suffix = id.substring(prefixlen, id.length);
}
// Call the closure to continue if one was set.
if (encryptionPlugin.askUser.continuation)
encryptionPlugin.askUser.continuation([suffix, this.value]);
break;
case 27: // Escape
this.value = "";
clearMessage();
break;
}
encryptionPlugin.askUser.reset();
return false;
},
display: function(msg,type,suffix) {
clearMessage();
var e = getMessageDiv();
if(!e) {
alert(config.messages.encryptionInputMissingDiv);
return;
}
var ele = createTiddlyElement(e,"input",null,null,null);
if (type)
ele.setAttribute("type",type);
ele.setAttribute("id", encryptionPlugin.askUser.idPrefix+suffix);
ele.onkeyup = encryptionPlugin.askUser.onAnswer;
e.appendChild(document.createTextNode(msg));
e.appendChild(ele);
return;
},
};
encryptionPlugin.displayArrayMessage = function(text) {
var e = getMessageDiv();
if (!e) {
alert(text);
return;
}
for (var i = 0; i < text.length; ++i) {
e.appendChild(document.createTextNode(text[i]));
e.appendChild(document.createElement("br"));
}
};
encryptionPlugin.uniqueTitle = function() {
var ts = (new Date()).formatString("YYYY0MM0DDhhmmss");
return (ts + (encryptionPlugin.uniqueId++));
};
encryptionPlugin.getPwAndContinue = function(name, continuation) {
var setupEngineAndContinue = function(params) {
var zone = params[0];
var key = params[1];
encryptionPlugin.engine[zone] = {};
// Pad to keysizeinbits/8 length
var diff = Rijndael.keySizeInBits - (key.length*8);
if (diff < 0) { // truncate
key = key.substring(0,Rijndael.keySizeInBits/8);
} else if (diff > 0) { // pad with zero
for (var ch = 0; ch < diff/8; ch++) {
key += "0";
}
}
// Setup a new engine
encryptionPlugin.newEngine(zone, key,"CBC");
this.value = "";
clearMessage();
continuation(params);
};
if (!name)
name = config.options.encryptionDefaultZone;
var msg = config.messages.encryptionPasswordPrompt.format([name]);
encryptionPlugin.askUser.continuation = setupEngineAndContinue;
encryptionPlugin.askUser.display(msg, "password", name);
};
encryptionPlugin.getZonePwAndContinue = function(continuation) {
var getZone = function(params) {
var zone = params[1];
if (encryptionPlugin.engine[zone] == undefined) { // have password, run cont
encryptionPlugin.getPwAndContinue(zone, continuation);
} else {
continuation(params);
}
};
var msg = config.messages.encryptionZonePrompt;
encryptionPlugin.askUser.continuation = getZone;
encryptionPlugin.askUser.display(msg, "text", "ignored");
};
// Clears the stored passphrase for a given name/zone
encryptionPlugin.clearCredentials = function(name) {
if (encryptionPlugin.engine[name])
delete encryptionPlugin.engine[name];
};
// Returns an anonymous function which will clear the credentials
// for the given zone/tag on call.
encryptionPlugin.clearCredentialsWrapper = function(zone) {
return function() {
encryptionPlugin.clearCredentials(zone);
displayMessage(config.messages.encryptionCleared.format([zone]));
return false;
};
};
// Wraps autoCryptTag and returns a function that will perform the action.
encryptionPlugin.autoCryptTagWrapper = function(tag, zone) {
return function() {encryptionPlugin.autoCryptTag(tag, zone);return false;};
};
// Takes a tag and an encryption zone and automatically encrypts or decrypts each Tiddler
// in the tag group using the given zone passphrase.
encryptionPlugin.autoCryptTag = function(tag, zone) {
var doWork = function(params) {
var workDone = new Array();
var tmp = '';
displayMessage(config.messages.encryptionWorkStart);
workDone.pushUnique(config.messages.encryptionWorkDoneHeader);
store.forEachTiddler(function(title,tiddler) {
if (tiddler.tags.find(tag) != null) {
// Decrypt if the format is recognized, else encrypt!
var payload = new EncryptionPayload();
if (payload.load(tiddler.text)) { // decrypt
tiddler.decrypt(tag, payload);
workDone.pushUnique(config.messages.encryptionWorkDoneDecrypt.format([tiddler.title]));
} else { // encrypt
tmp = tiddler.title;
tiddler.encrypt(zone, tag);
workDone.pushUnique(config.messages.encryptionWorkDoneEncrypt.format([tmp]));
}
}
});
story.refreshAllTiddlers();
clearMessage();
encryptionPlugin.displayArrayMessage(workDone);
};
if (encryptionPlugin.engine[zone] == undefined)
encryptionPlugin.getPwAndContinue(zone, doWork);
else
doWork();
};
/** macros **/
version.extensions.EncryptTiddler = { major: 0, minor: 0, revision: 3, date: new Date(2007, 1, 20)};
// Usage: encrypt_clear "zone"
config.macros.encrypt_clear = {
default_label: "encrypt_clear %0",
prompt: "Clears the passphrase for a given zone"
};
config.macros.encrypt_clear.handler = function(place,macroName,params) {
var zone = config.options.encryptionDefaultZone;
if (params[0])
zone = params[0];
var label = this.default_label.format([zone]);
if (params[1] != undefined)
label = params[1];
createTiddlyButton(place,label,this.prompt, encryptionPlugin.clearCredentialsWrapper(zone),null,null,this.accessKey);
};
// Usage: encrypt_tag ["tag" ["zone"]] ["label"]
config.macros.encrypt_tag = {
default_label: "encrypt_tag: %0",
prompt: "Encrypt/decrypt tiddlers of a given tag and zone"
};
config.macros.encrypt_tag.handler = function(place,macroName,params) {
if (!params[0]) {
displayMessage(config.messages.encryptionTagSyntaxError);
return false;
}
var tag = params[0];
var zone = params[0];
var label = this.default_label.format([zone]);
if (params[1])
label = params[1];
if (params[2]) {
zone = params[1];
label = params[2];
}
createTiddlyButton(place,label,this.prompt,
encryptionPlugin.autoCryptTagWrapper(tag, zone),
null,null,this.accessKey);
};
/*** HELPERS ***/
function getPreviewDiv()
{
var msgArea = document.getElementById("previewArea");
if(!msgArea)
return null;
if(!msgArea.hasChildNodes()) {
createTiddlyButton(createTiddlyElement(msgArea,"div",null,"previewToolbar"),
"x",
config.messages.messageClose.tooltip,
clearPreview);
}
msgArea.style.display = "block";
return createTiddlyElement(msgArea,"div");
}
function displayPreview(text)
{
var e = getPreviewDiv();
if(!e)
{
alert(text);
return;
}
e.innerHTML += text;
}
function clearPreview()
{
var msgArea = document.getElementById("previewArea");
if(msgArea)
{
removeChildren(msgArea);
msgArea.style.display = "none";
}
return false;
}
/*** HELPERS ***/
config.commands.peekcrypt = {
text: 'preview',
hideReadOnly: false,
tooltip: 'Preview this tiddler decrypted',
handler: function(event,src,title) {
var tiddler = store.getTiddler(title);
var payload = new EncryptionPayload();
if (!payload.load(tiddler.text)) {
clearMessage();
displayMessage("Tiddler does not appears to be encrypted");
return false;
}
// Decrypt just the body for preview
var doWork = function(params) {
var body = encryptionPlugin.engine[payload.zone].decrypt(payload.text);
clearPreview();
displayMessage(body);
};
// Ensure we have an engine
if (encryptionPlugin.engine[payload.zone] == undefined)
encryptionPlugin.getPwAndContinue(payload.zone, doWork);
else doWork();
return false;
}
};
config.commands.autocrypt = {
text: 'autocrypt',
hideReadOnly: false,
tooltip: 'Encrypts or decrypts this tiddler',
handler: function(event,src,title) {
var tiddler = store.getTiddler(title);
// See if this is æn encrypted payload
var payload = new EncryptionPayload();
if (!payload.load(tiddler.text)) { // encrypt
var doWork = function(params) {
tiddler.encrypt(params[1],undefined,params[2], params[3]);
};
encryptionPlugin.getZonePwAndContinue(doWork);
} else { // decrypt
var doWork = function(params) {tiddler.decrypt(undefined, payload);};
if (encryptionPlugin.engine[payload.zone] == undefined)
encryptionPlugin.getPwAndContinue(payload.zone, doWork);
else
tiddler.decrypt(undefined, payload);
}
return false;
}
};
/** Core extensions **/
// Allow overriding of globals with encrypt*
Tiddler.prototype.encrypt = function(zone, tag, overrideTitles, overrideTags) {
var isOpen = false;
var title = this.title;
var encryptTitles = config.options.chkEncryptTitles;
var encryptTags = config.options.chkEncryptTags;
if (overrideTitles) encryptTitles = overrideTitles;
if (overrideTags) encryptTags = overrideTags;
// Start the payload with the zone
var payload = new EncryptionPayload();
payload.zone = zone;
// Encrypt title
var etitle = title;
if (encryptTitles) {
etitle = config.messages.encryptionEncryptedTitle.format(
[encryptionPlugin.uniqueTitle()]);
payload.title = encryptionPlugin.engine[zone].encrypt(title);
// Look for the old title and replace it with the encrypted one.
var references = store.getReferringTiddlers(title);
for(var r = 0; r < references.length; ++r) {
if (tag == undefined || !references[r].isTagged(tag)) {
var titleRE = new RegExp(title,"g");
references[r].text = references[r].text.replace(titleRE, etitle);
references[r].changed();
}
}
story.refreshAllTiddlers();
}
payload.text = encryptionPlugin.engine[zone].encrypt(this.text)
this.title = etitle;
if (encryptTags) {
var new_tags = new Array();
if (tag) new_tags.pushUnique(tag);
for (var t = 0; t < this.tags.length; ++t) {
payload.tags.push(encryptionPlugin.engine[zone].encrypt(this.tags[t]));
}
this.tags = new_tags;
}
this.text = wrapText(60, payload.serialize());
// Add the new tiddler
store.addTiddler(this);
// If the tiddler is visible, close and reopen
var tiddlerElem = document.getElementById(story.idPrefix + title);
if (tiddlerElem) {
story.displayTiddler(tiddlerElem,this.title);
story.closeTiddler(title);
// Avoid wonky scrolling. TODO: make this better!
window.scrollTo(0,0);
}
// Delete it by its old name
if (etitle != title) store.deleteTiddler(title);
return false;
}
Tiddler.prototype.decrypt = function(tag, optional_payload_object) {
// TODO(redpig): add title and reference encryption
var title = this.title;
var payload = null;
// Assume an already prepped object if supplied
if (optional_payload_object != undefined) {
payload = optional_payload_object;
} else {
payload = new EncryptionPayload();
if (payload.load(this.text) == false) {
displayMessage("Unable to decrypt tiddler: " + this.title);
return false;
}
}
// Decrypt title
var ptitle = title;
if (payload.title != '') { // if it was encrypted, decrypt it
ptitle = encryptionPlugin.engine[payload.zone].decrypt(payload.title);
this.title = ptitle;
// Look for the old title and replace it with the encrypted one.
var references = store.getReferringTiddlers(title);
for(var r = 0; r < references.length; ++r) {
// TODO: add zones based on zone:tag
if (tag == undefined || !references[r].isTagged(tag)) {
var titleRE = new RegExp(title,"g");;
references[r].text = references[r].text.replace(titleRE, ptitle);
references[r].changed();
}
}
}
plainText = encryptionPlugin.engine[payload.zone].decrypt(payload.text);
this.text = plainText;
if (payload.tags.length > 0) { // if there are encrypted tags, decrypt!
for (var t = 3; t < payload.tags; ++t) {
if (payload.tags[t] != '')
this.tags.pushUnique(
encryptionPlugin.engine[payload.zone].decrypt(payload.tags[t]));
}
}
// Add the new tiddler
store.addTiddler(this);
// If the tiddler is visible, close and reopen
var tiddlerElem = document.getElementById(story.idPrefix + title);
if (tiddlerElem) {
story.displayTiddler(tiddlerElem,this.title);
story.closeTiddler(title);
// Avoid wonky scrolling. TODO: make this better!
window.scrollTo(0,0);
}
// Delete it by its old name
if (ptitle != title) store.deleteTiddler(title);
return false;
}
//}}}
/***
|Name|ImageSizePlugin|
|Source|http://www.TiddlyTools.com/#ImageSizePlugin|
|Version|1.2.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|adds support for resizing images|
This plugin adds optional syntax to scale an image to a specified width and height and/or interactively resize the image with the mouse.
!!!!!Usage
<<<
The extended image syntax is:
{{{
[img(w+,h+)[...][...]]
}}}
where ''(w,h)'' indicates the desired width and height (in CSS units, e.g., px, em, cm, in, or %). Use ''auto'' (or a blank value) for either dimension to scale that dimension proportionally (i.e., maintain the aspect ratio). You can also calculate a CSS value 'on-the-fly' by using a //javascript expression// enclosed between """{{""" and """}}""". Appending a plus sign (+) to a dimension enables interactive resizing in that dimension (by dragging the mouse inside the image). Use ~SHIFT-click to show the full-sized (un-scaled) image. Use ~CTRL-click to restore the starting size (either scaled or full-sized).
<<<
!!!!!Examples
<<<
{{{
[img(100px+,75px+)[images/meow2.jpg]]
}}}
[img(100px+,75px+)[images/meow2.jpg]]
{{{
[<img(34%+,+)[images/meow.gif]]
[<img(21% ,+)[images/meow.gif]]
[<img(13%+, )[images/meow.gif]]
[<img( 8%+, )[images/meow.gif]]
[<img( 5% , )[images/meow.gif]]
[<img( 3% , )[images/meow.gif]]
[<img( 2% , )[images/meow.gif]]
[img( 1%+,+)[images/meow.gif]]
}}}
[<img(34%+,+)[images/meow.gif]]
[<img(21% ,+)[images/meow.gif]]
[<img(13%+, )[images/meow.gif]]
[<img( 8%+, )[images/meow.gif]]
[<img( 5% , )[images/meow.gif]]
[<img( 3% , )[images/meow.gif]]
[<img( 2% , )[images/meow.gif]]
[img( 1%+,+)[images/meow.gif]]
{{tagClear{
}}}
<<<
!!!!!Revisions
<<<
2011.09.03 [1.2.3] bypass addStretchHandlers() if no '+' suffix is used (i.e., not resizable)
2010.07.24 [1.2.2] moved tip/dragtip text to config.formatterHelpers.imageSize object to enable customization
2009.02.24 [1.2.1] cleanup width/height regexp, use '+' suffix for resizing
2009.02.22 [1.2.0] added stretchable images
2008.01.19 [1.1.0] added evaluated width/height values
2008.01.18 [1.0.1] regexp for "(width,height)" now passes all CSS values to browser for validation
2008.01.17 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.ImageSizePlugin= {major: 1, minor: 2, revision: 3, date: new Date(2011,9,3)};
//}}}
//{{{
var f=config.formatters[config.formatters.findByField("name","image")];
f.match="\\[[<>]?[Ii][Mm][Gg](?:\\([^,]*,[^\\)]*\\))?\\[";
f.lookaheadRegExp=/\[([<]?)(>?)[Ii][Mm][Gg](?:\(([^,]*),([^\)]*)\))?\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg;
f.handler=function(w) {
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var floatLeft=lookaheadMatch[1];
var floatRight=lookaheadMatch[2];
var width=lookaheadMatch[3];
var height=lookaheadMatch[4];
var tooltip=lookaheadMatch[5];
var src=lookaheadMatch[6];
var link=lookaheadMatch[7];
// Simple bracketted link
var e = w.output;
if(link) { // LINKED IMAGE
if (config.formatterHelpers.isExternalLink(link)) {
if (config.macros.attach && config.macros.attach.isAttachment(link)) {
// see [[AttachFilePluginFormatters]]
e = createExternalLink(w.output,link);
e.href=config.macros.attach.getAttachment(link);
e.title = config.macros.attach.linkTooltip + link;
} else
e = createExternalLink(w.output,link);
} else
e = createTiddlyLink(w.output,link,false,null,w.isStatic);
addClass(e,"imageLink");
}
var img = createTiddlyElement(e,"img");
if(floatLeft) img.align="left"; else if(floatRight) img.align="right";
if(width||height) {
var x=width.trim(); var y=height.trim();
var stretchW=(x.substr(x.length-1,1)=='+'); if (stretchW) x=x.substr(0,x.length-1);
var stretchH=(y.substr(y.length-1,1)=='+'); if (stretchH) y=y.substr(0,y.length-1);
if (x.substr(0,2)=="{{")
{ try{x=eval(x.substr(2,x.length-4))} catch(e){displayMessage(e.description||e.toString())} }
if (y.substr(0,2)=="{{")
{ try{y=eval(y.substr(2,y.length-4))} catch(e){displayMessage(e.description||e.toString())} }
img.style.width=x.trim(); img.style.height=y.trim();
if (stretchW||stretchH) config.formatterHelpers.addStretchHandlers(img,stretchW,stretchH);
}
if(tooltip) img.title = tooltip;
// GET IMAGE SOURCE
if (config.macros.attach && config.macros.attach.isAttachment(src))
src=config.macros.attach.getAttachment(src); // see [[AttachFilePluginFormatters]]
else if (config.formatterHelpers.resolvePath) { // see [[ImagePathPlugin]]
if (config.browser.isIE || config.browser.isSafari) {
img.onerror=(function(){
nsrc = config.formatterHelpers.resolvePath(this.src,false);
if (this.src != nsrc)
this.src=nsrc;
return false;
});
} else
src=config.formatterHelpers.resolvePath(src,true);
}
img.src=src;
w.nextMatch = this.lookaheadRegExp.lastIndex;
}
}
config.formatterHelpers.imageSize={
tip: 'SHIFT-CLICK=show full size, CTRL-CLICK=restore initial size',
dragtip: 'DRAG=stretch/shrink, '
}
config.formatterHelpers.addStretchHandlers=function(e,stretchW,stretchH) {
e.title=((stretchW||stretchH)?this.imageSize.dragtip:'')+this.imageSize.tip;
e.statusMsg='width=%0, height=%1';
e.style.cursor='move';
e.originalW=e.style.width;
e.originalH=e.style.height;
e.minW=Math.max(e.offsetWidth/20,10);
e.minH=Math.max(e.offsetHeight/20,10);
e.stretchW=stretchW;
e.stretchH=stretchH;
e.onmousedown=function(ev) { var ev=ev||window.event;
this.sizing=true;
this.startX=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX());
this.startY=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY());
this.startW=this.offsetWidth;
this.startH=this.offsetHeight;
return false;
};
e.onmousemove=function(ev) { var ev=ev||window.event;
if (this.sizing) {
var s=this.style;
var currX=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX());
var currY=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY());
var newW=(currX-this.offsetLeft)/(this.startX-this.offsetLeft)*this.startW;
var newH=(currY-this.offsetTop )/(this.startY-this.offsetTop )*this.startH;
if (this.stretchW) s.width =Math.floor(Math.max(newW,this.minW))+'px';
if (this.stretchH) s.height=Math.floor(Math.max(newH,this.minH))+'px';
clearMessage(); displayMessage(this.statusMsg.format([s.width,s.height]));
}
return false;
};
e.onmouseup=function(ev) { var ev=ev||window.event;
if (ev.shiftKey) { this.style.width=this.style.height=''; }
if (ev.ctrlKey) { this.style.width=this.originalW; this.style.height=this.originalH; }
this.sizing=false;
clearMessage();
return false;
};
e.onmouseout=function(ev) { var ev=ev||window.event;
this.sizing=false;
clearMessage();
return false;
};
}
//}}}
//{{{
jQuery.getScript("https://www.nottale.net/jquery-ui-1.10.3.custom.min.js");
//}}}
<html><br><div>HTML <b>sandbox</b> to get wysiwyg mode</div><div><br></div><div><h1><i>Ca c'est fort!</i></h1><div><br></div></div><div><img></div></html>
/***
|Name|ZEncryptPlugin|
|Source| |
|Documentation| |
|Version|1.0|
|Author|Matthieu Nottale|
|License|CC-by-SA http://creativecommons.org/licenses/by-sa/3.0/|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Encrypt tiddlers with AES. Tiddlyweb-compatible|
'' Mark a tiddler with tag "encrypt:realmName" and tiddler will be stored encrypted.''
!!!Documentation
This plugin allows you to mark tiddlers with tag "encrypt:cryptRealm" to have
them stored encrypted with AES (using CryptoJS).
Tiddlers will be automatically decrypted when editing them, and encrypted when
saved. Command decryptTiddler can be used to manually decrypt one tiddler.
Per-realm passwords are cached and prompted for only once.
Since there is no password confirmation field, it is recommended to always
decrypt an existing tiddler with a given realm, before encrypting a new tiddler
with same realm. That way you will avoid ending up with multiple different
passwords for the same realm.
!!! Warning
Using this plugin does not protect you against a compromised storage server, as
it is the one serving you the javascript that performs the encryption.
!!! Installation and configuration
Mark this tiddly with tag 'systemConfig' to enable the plugin.
Since this plugin must be able to 'abort' save operations when prompting for
passwords, it must be the last in save/edit stacks, so keep the Z in the name.
- Add 'decryptTiddler' to [[ToolbarCommands]] if you want to be able to
decrypt a tiddler without editing it.
- Call macro """<<clearCryptCache realm text tooltip>>""" anywhere you want to
create a button that will clear crypt cache and recrypt visible tiddlers
for given realm (default all) when pressed.
- Call macro """<<decryptRealm realm text tooltip>>""" create a button that
prompts for password and decrypt all tiddlers will given realm
!!!Code
***/
//{{{
/*
* TODO:
* - safety if encrypt tag is removed (maybe a mistake)
* - some check for bad decrypt
* - cache cleanup
*/
(function() {
var cache = {};
var fetchOrMark = function(realm, operation, tiddler)
{
if (! cache[realm])
cache[realm] = { decryptAll: false, toSave: [], toRedisplay: [], toDecrypt: [], toEdit: []};
if (!cache[realm].key)
{
if (operation == "decryptAll")
cache[realm].decryptAll = true;
else
cache[realm][operation].push(tiddler);
promptForKey(realm);
return null;
}
else
return cache[realm].key;
}
var onPromptResult = function(realm, result)
{
if (!result)
return;
var c = cache[realm];
c.key = result;
// Perform pending operations
if (c.decryptAll)
decryptAll(realm);
for (var i=0; i<c.toDecrypt.length && c.key; ++i)
{
config.commands.decryptTiddler.handler(null, null, c.toDecrypt[i]);
}
// decryption failure will reset the key
if (!c.key)
{
setTimeout(400, function() { promptForKey(realm)});
return;
}
c.toDecrypt = [];
for (var i=0; i<c.toEdit.length && c.key;++i)
{
config.commands.editTiddler.handler(null, null, c.toEdit[i]);
}
if (!c.key)
{
setTimeout(400, function() { promptForKey(realm)});
return;
}
c.toEdit = [];
for (var i=0; i<c.toSave.length;++i)
{
story.saveTiddler(c.toSave[i], false);
}
c.toSave = [];
for (var i=0; i<c.toRedisplay.length;++i)
{
config.commands.saveTiddler.handler({}, null, c.toRedisplay[i]);
}
c.toRedisplay = [];
}
var promptForKey = function(realm)
{
var ctx = {passwordPrompt: "Password for " + realm};
setTimeout(function() {
PasswordPrompt.prompt(function(ctx) { onPromptResult(realm, ctx.password);}, ctx);
}, 100);
}
story.saveTiddler_crypt = story.saveTiddler;
story.saveTiddler = function(title, isMinor, fromFrontend)
{
// Check if we are on
var tagElem = this.getTiddlerField(title, "tags");
if (!tagElem)
return this.saveTiddler_crypt(title, isMinor);
var tags = tagElem.value.split(" ");
if (!tags.length)
return this.saveTiddler_crypt(title, isMinor);
var tag0elems = tags[0].split(":");
if (tag0elems[0] != "encrypt")
return this.saveTiddler_crypt(title, isMinor);
var realm = tag0elems[1];
// Check if we have key in cache for realm
var key = fetchOrMark(realm, fromFrontend?"toRedisplay":"toSave", title);
if (key)
{
var content = this.getTiddlerField(title, "text").value;
// marker to detect bad key..
content = content+"CRYPT";
content = CryptoJS.AES.encrypt(content, key).toString();
content = "@@display:none;---" + content + "---@@\n ****\n";
this.getTiddlerField(title, "text").value = content;
tags = ["decrypt:"+realm].concat(tags.slice(1,tags.length));
this.getTiddlerField(title, "tags").value = tags.join(" ");
return this.saveTiddler_crypt(title, isMinor);
}
}
// Recrypt decrypted tiddler.
config.commands.hideCryptedTiddler =
{
text: "recrypt",
tooltip: "Recrypt tiddler",
isEnabled: function(tiddler) {
return tiddler.tags.join("*").indexOf('encrypt:') != -1 && !! tiddler.cipherText;
},
handler: function(event, src, title) {
var tiddler = store.getTiddler(title);
tiddler.text = tiddler.cipherText;
for (var i = 0; i < tiddler.tags.length; ++i)
{
var tt = tiddler.tags[i].split(":");
if (tt[0] == "encrypt")
tiddler.tags[i] = "decrypt:" + tt[1];
}
story.refreshAllTiddlers();
}
};
function decryptAll(realm)
{
if (!fetchOrMark(realm, "decryptAll", true))
return; // no key, prompt, will be called again asynchronously
store.forEachTiddler(function(name) {
if (!cache[realm].key)
return; // key error detected in previous iteration
var t = store.getTiddler(name);
if (t && ("*"+t.tags.join("*")+"*").indexOf("*"+"decrypt:"+realm)!=-1)
config.commands.decryptTiddler.handler(null, null, name);
});
};
// Clear cache and recrypt decrypted tiddlers.
function clearCryptCache(realm)
{
realm = realm && realm.replace(" ","");
if (!realm)
cache = {};
else
delete cache[realm];
if (!realm)
story.forEachTiddler(function(title) {
var t = store.getTiddler(title);
if (t && config.commands.hideCryptedTiddler.isEnabled(t))
config.commands.hideCryptedTiddler.handler(null, null, title);
});
else
story.forEachTiddler(function(title) {
var t = store.getTiddler(title);
if (t && ("*"+t.tags.join("*")+"*").indexOf("*"+"encrypt:"+realm)!=-1)
config.commands.hideCryptedTiddler.handler(null, null, title);
});
};
// Create a button "clear crypt" for realm p0 (default all) with text p1 and tooltip p2
config.macros.clearCryptCache = {
handler: function (place, macroName, params, wikifier, paramString, tiddler) {
var realm = params[0];
var theButton = createTiddlyButton(place,
(params[1] && params[1].length > 0) ? params[1] : (params[0]? ("Clear crypt " + params[0]): "Clear all crypt data"),
(params[2] && params[2].length > 0) ? params[2] : "Clear cached password and recrypt tiddlers.",
function() { clearCryptCache(realm)});
}
};
config.macros.decryptRealm = {
handler: function (place, macroName, params, wikifier, paramString, tiddler) {
var realm = params[0];
var theButton = createTiddlyButton(place,
(params[1] && params[1].length > 0) ? params[1] : "Decrypt realm " + realm,
(params[2] && params[2].length > 0) ? params[2] : "Decrypt all tiddlers for realm.",
function() { decryptAll(realm)});
}
};
config.commands.decryptTiddler =
{
text: "decrypt",
tooltip: "Decrypt this tiddler",
isEnabled: function(tiddler) {
return tiddler.tags.join("*").indexOf('decrypt:') != -1;
},
handler: function(event, src, title, fromEdit) {
var tiddler = store.getTiddler(title);
if (!tiddler)
return true; // new tiddler
var tags = tiddler.tags;
for (var i=0; i<tags.length; ++i)
{
var t = tags[i];
var tt = t.split(":");
if (tt[0] != "decrypt")
continue;
var realm = tt[1];
var key = fetchOrMark(realm, fromEdit?"toEdit":"toDecrypt", title);
if (key)
{
var data = tiddler.text;
tiddler.cipherText = data;
var ds = data.split("---");
if (!ds[1])
{
alert("Tiddler " + title + " does not appear encrypted");
return true;
}
var decrypted = '';
try {
// Wrong key can cause a utf8 decode exception.
decrypted = CryptoJS.AES.decrypt(ds[1], key).toString(CryptoJS.enc.Utf8);
if (decrypted.substr(decrypted.length - 5, decrypted.length) != "CRYPT")
decrypted = '';
else
decrypted = decrypted.substr(0, decrypted.length-5);
}
catch(e) {}
if (!decrypted)
{
alert("Tiddler " + title + " decryption failed");
cache[realm].key = '';
return true;
}
// ... now how do I inject that...
tiddler.text = decrypted;
tiddler.tags = ["encrypt:" + realm].concat(tags.slice(1,tags.length));
if (!fromEdit)
{
// Redisplay tiddler
story.refreshAllTiddlers();
}
return true;
}
else
return false;
}
return true;
}
};
// Override edit to decrypt first
config.commands.editTiddler.handler_crypt = config.commands.editTiddler.handler;
config.commands.editTiddler.handler = function(ev, src, title) {
if (config.commands.decryptTiddler.handler(ev, src, title, true))
return config.commands.editTiddler.handler_crypt(ev, src, title);
};
// Override save frontend in addition to backend
config.commands.saveTiddler.handler_crypt = config.commands.saveTiddler.handler;
config.commands.saveTiddler.handler = function(ev, src, title) {
var newTitle = story.saveTiddler(title, ev.shiftKey, true);
if (newTitle)
story.displayTiddler(null,newTitle);
return false;
};
})();
//}}}
/***
! CryptoJS
***/
//{{{
/*
CryptoJS v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var CryptoJS=CryptoJS||function(u,p){var d={},l=d.lib={},s=function(){},t=l.Base={extend:function(a){s.prototype=this;var c=new s;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
r=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=p?c:4*a.length},toString:function(a){return(a||v).stringify(this)},concat:function(a){var c=this.words,e=a.words,j=this.sigBytes;a=a.sigBytes;this.clamp();if(j%4)for(var k=0;k<a;k++)c[j+k>>>2]|=(e[k>>>2]>>>24-8*(k%4)&255)<<24-8*((j+k)%4);else if(65535<e.length)for(k=0;k<a;k+=4)c[j+k>>>2]=e[k>>>2];else c.push.apply(c,e);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
32-8*(c%4);a.length=u.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],e=0;e<a;e+=4)c.push(4294967296*u.random()|0);return new r.init(c,a)}}),w=d.enc={},v=w.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++){var k=c[j>>>2]>>>24-8*(j%4)&255;e.push((k>>>4).toString(16));e.push((k&15).toString(16))}return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j+=2)e[j>>>3]|=parseInt(a.substr(j,
2),16)<<24-4*(j%8);return new r.init(e,c/2)}},b=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++)e.push(String.fromCharCode(c[j>>>2]>>>24-8*(j%4)&255));return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j++)e[j>>>2]|=(a.charCodeAt(j)&255)<<24-8*(j%4);return new r.init(e,c)}},x=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(b.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return b.parse(unescape(encodeURIComponent(a)))}},
q=l.BufferedBlockAlgorithm=t.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=x.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,e=c.words,j=c.sigBytes,k=this.blockSize,b=j/(4*k),b=a?u.ceil(b):u.max((b|0)-this._minBufferSize,0);a=b*k;j=u.min(4*a,j);if(a){for(var q=0;q<a;q+=k)this._doProcessBlock(e,q);q=e.splice(0,a);c.sigBytes-=j}return new r.init(q,j)},clone:function(){var a=t.clone.call(this);
a._data=this._data.clone();return a},_minBufferSize:0});l.Hasher=q.extend({cfg:t.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){q.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,e){return(new a.init(e)).finalize(b)}},_createHmacHelper:function(a){return function(b,e){return(new n.HMAC.init(a,
e)).finalize(b)}}});var n=d.algo={};return d}(Math);
(function(){var u=CryptoJS,p=u.lib.WordArray;u.enc.Base64={stringify:function(d){var l=d.words,p=d.sigBytes,t=this._map;d.clamp();d=[];for(var r=0;r<p;r+=3)for(var w=(l[r>>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+0.75*v<p;v++)d.push(t.charAt(w>>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join("")},parse:function(d){var l=d.length,s=this._map,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w<
l;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();
(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<<j|b>>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<<j|b>>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<<j|b>>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<<j|b>>>32-j)+n}for(var t=CryptoJS,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({_doReset:function(){this._hash=new w.init([1732584193,4023233417,2562383102,271733878])},
_doProcessBlock:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this._hash.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]),
f=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f,
m,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m,
E,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},_doFinalize:function(){var b=this._data,n=b.words,a=8*this._nDataBytes,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/
4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this._process();b=this._hash;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b._hash=this._hash.clone();return b}});t.MD5=v._createHelper(r);t.HmacMD5=v._createHmacHelper(r)})(Math);
(function(){var u=CryptoJS,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length<q;){n&&s.update(n);var n=s.update(d).finalize(r);s.reset();for(var a=1;a<p;a++)n=s.finalize(n),s.reset();b.concat(n)}b.sigBytes=4*q;return b}});u.EvpKDF=function(d,l,p){return s.create(p).compute(d,
l)}})();
CryptoJS.lib.Cipher||function(u){var p=CryptoJS,d=p.lib,l=d.Base,s=d.WordArray,t=d.BufferedBlockAlgorithm,r=p.enc.Base64,w=p.algo.EvpKDF,v=d.Cipher=t.extend({cfg:l.extend(),createEncryptor:function(e,a){return this.create(this._ENC_XFORM_MODE,e,a)},createDecryptor:function(e,a){return this.create(this._DEC_XFORM_MODE,e,a)},init:function(e,a,b){this.cfg=this.cfg.extend(b);this._xformMode=e;this._key=a;this.reset()},reset:function(){t.reset.call(this);this._doReset()},process:function(e){this._append(e);return this._process()},
finalize:function(e){e&&this._append(e);return this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(e){return{encrypt:function(b,k,d){return("string"==typeof k?c:a).encrypt(e,b,k,d)},decrypt:function(b,k,d){return("string"==typeof k?c:a).decrypt(e,b,k,d)}}}});d.StreamCipher=v.extend({_doFinalize:function(){return this._process(!0)},blockSize:1});var b=p.mode={},x=function(e,a,b){var c=this._iv;c?this._iv=u:c=this._prevBlock;for(var d=0;d<b;d++)e[a+d]^=
c[d]},q=(d.BlockCipherMode=l.extend({createEncryptor:function(e,a){return this.Encryptor.create(e,a)},createDecryptor:function(e,a){return this.Decryptor.create(e,a)},init:function(e,a){this._cipher=e;this._iv=a}})).extend();q.Encryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize;x.call(this,e,a,c);b.encryptBlock(e,a);this._prevBlock=e.slice(a,a+c)}});q.Decryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize,d=e.slice(a,a+c);b.decryptBlock(e,a);x.call(this,
e,a,c);this._prevBlock=d}});b=b.CBC=q;q=(p.pad={}).Pkcs7={pad:function(a,b){for(var c=4*b,c=c-a.sigBytes%c,d=c<<24|c<<16|c<<8|c,l=[],n=0;n<c;n+=4)l.push(d);c=s.create(l,c);a.concat(c)},unpad:function(a){a.sigBytes-=a.words[a.sigBytes-1>>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a,
this,b&&b.words)},_doProcessBlock:function(a,b){this._mode.processBlock(a,b)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var b=this._process(!0)}else b=this._process(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684,
1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})},
decrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this._parse(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},_parse:function(a,b){return"string"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d,
b.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this._parse(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}();
(function(){for(var u=CryptoJS,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8,
16,32,64,128,27,54],d=d.AES=p.extend({_doReset:function(){for(var a=this._key,c=a.words,d=a.sigBytes/4,a=4*((this._nRounds=d+6)+1),e=this._keySchedule=[],j=0;j<a;j++)if(j<d)e[j]=c[j];else{var k=e[j-1];j%d?6<d&&4==j%d&&(k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this._invKeySchedule=[];for(d=0;d<a;d++)j=a-d,k=d%4?e[j]:e[j-4],c[d]=4>d||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>>
8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this._doCryptBlock(a,b,this._keySchedule,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this._doCryptBlock(a,c,this._invKeySchedule,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},_doCryptBlock:function(a,b,c,d,e,j,l,f){for(var m=this._nRounds,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r<m;r++)var q=d[g>>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t=
d[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p._createHelper(d)})();
//}}}
/***
! Prompt
***/
//{{{
// Shamefully stolen from http://www.Remotely-Helpful.com/TiddlyWiki/TiddlerEncryptionPlugin.html
// Heavily leveraged from http://trac.tiddlywiki.org/browser/Trunk/contributors/SaqImtiaz/verticals/Hesperian/PasswordPromptPlugin.js Revision 5635
//
PasswordPrompt ={
prompt : function(callback,context){
if (!context) {
context = {};
}
var box = createTiddlyElement(document.getElementById("contentWrapper"),'div','passwordPromptBox');
box.innerHTML = store.getTiddlerText('PasswordPromptTemplate');
box.style.position = 'absolute';
this.center(box);
document.getElementById('promptDisplayField').value = context.passwordPrompt;
var passwordInputField = document.getElementById('passwordInputField');
passwordInputField.onkeyup = function(ev) {
var e = ev || window.event;
if(e.keyCode == 10 || e.keyCode == 13) { // Enter
PasswordPrompt.submit(callback, context);
}
};
passwordInputField.focus();
document.getElementById('passwordPromptSubmitBtn').onclick = function(){PasswordPrompt.submit(callback,context);};
document.getElementById('passwordPromptCancelBtn').onclick = function(){PasswordPrompt.cancel(callback,context);};
},
center : function(el){
var size = this.getsize(el);
el.style.left = (Math.round(findWindowWidth()/2) - (size.width /2) + findScrollX())+'px';
el.style.top = (Math.round(findWindowHeight()/2) - (size.height /2) + findScrollY())+'px';
},
getsize : function (el){
var x = {};
x.width = el.offsetWidth || el.style.pixelWidth;
x.height = el.offsetHeight || el.style.pixelHeight;
return x;
},
submit : function(cb,context){
context.passwordPrompt = document.getElementById('promptDisplayField').value;
context.password = document.getElementById('passwordInputField').value;
var box = document.getElementById('passwordPromptBox');
box.parentNode.removeChild(box);
cb(context);
return false;
},
cancel : function(cb,context){
var box = document.getElementById('passwordPromptBox');
box.parentNode.removeChild(box);
return false;
},
setStyles : function(){
setStylesheet(
"#passwordPromptBox dd.submit {margin-left:0; font-weight: bold; margin-top:1em;}\n"+
"#passwordPromptBox dd.submit .button {padding:0.5em 1em; border:1px solid #ccc;}\n"+
"#passwordPromptBox dt.heading {margin-bottom:0.5em; font-size:1.2em;}\n"+
"#passwordPromptBox {border:1px solid #ccc;background-color: #eee;padding:1em 2em;}",'passwordPromptStyles');
},
template : '<form action="" onsubmit="return false;" id="passwordPromptForm">\n'+
' <dl>\n'+
' <dt class="heading">Please enter the password:</dt>\n'+
' <dt>Prompt:</dt>\n'+
' <dd><input type="text" readonly id="promptDisplayField" class="display"/></dd>\n'+
' <dt>Password:</dt>\n'+
' <dd><input type="password" tabindex="1" class="input" id="passwordInputField"/></dd>\n'+
' <dd class="submit">\n'+
' <a tabindex="2" href="javascript:;" class="button" id="passwordPromptSubmitBtn">OK</a>\n'+
' <a tabindex="3" href="javascript:;" class="button" id="passwordPromptCancelBtn">Cancel</a>\n'+
' </dd>\n'+
' </dl>\n'+
'</form>',
init : function(){
config.shadowTiddlers.PasswordPromptTemplate = this.template;
this.setStyles();
}
};
PasswordPrompt.init();
//}}}
/%
!info
|Name|SetTiddlerColumns|
|Source|http://www.TiddlyTools.com/#SetTiddlerColumns|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|use CSS3 '-moz-column-count' to set single or multi-column tiddler layout|
Usage
<<<
{{{
<<tiddler SetTiddlerColumns>>
}}}
*note: '-moz-column-count' not available in InternetExplorer
Try it:
<<tiddler SetTiddlerColumns##show>>
<<<
!end
!show
<<tiddler {{
if (config.options.txtTiddlerColumns===undefined)
config.options.txtTiddlerColumns='1';
'';}}>>tiddler columns: {{smallform{<<option txtTiddlerColumns>><<tiddler {{
var t=place.lastChild;
t.style.width='4em'; t.style.textAlign='center';
t.title='enter number of columns';
t.onfocus=function(){this.select();};
t.onblur=function(){this.onchange();}; /* for IE */
if (!t.coreOnChange) t.coreOnChange=t.onchange;
t.onchange=function() { // hijack: update CSS when field changes
if (this.coreOnChange) this.coreOnChange();
window.setTiddlerColumns();
};
window.setTiddlerColumns=function() {
var opt='txtTiddlerColumns';
var cols=config.options[opt]||''; if (!cols.length) cols='1';
config.macros.option.propagateOption(opt,'value',cols,'input');
if (cols=='1') removeCookie(opt);
if (!config.browser.isIE)
{
document.getElementById('tiddlerDisplay').style.MozColumnCount=cols;
document.getElementById('tiddlerDisplay').style.webkitColumnCount=cols;
}
}
if (window.removeCookie===undefined) { // if not already defined by TW core...
window.removeCookie=function(name) {
document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;';
}
}
window.setTiddlerColumns(); // apply CSS during startup
'';}}>>
!end
%/<<tiddler {{var src='SetTiddlerColumns'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}>>
/***
''NestedSlidersPlugin for TiddlyWiki version 1.2.x and 2.0''
^^author: Eric Shulman
source: http://www.TiddlyTools.com/#NestedSlidersPlugin
license: [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]^^
Quickly make any tiddler content into an expandable 'slider' panel, without needing to create a separate tiddler to contain the slider content. Optional syntax allows ''default to open'', ''custom button label/tooltip'' and ''automatic blockquote formatting.''
You can also 'nest' these sliders as deep as you like (see complex nesting example below), so that expandable 'tree-like' hierarchical displays can be created. This is most useful when converting existing in-line text content to create in-line annotations, footnotes, context-sensitive help, or other subordinate information displays.
For more details, please click on a section headline below:
++++!!!!![Configuration]>
Debugging messages for 'lazy sliders' deferred rendering:
<<option chkDebugLazySliderDefer>> show debugging alert when deferring slider rendering
<<option chkDebugLazySliderRender>> show debugging alert when deferred slider is actually rendered
===
++++!!!!![Usage]>
When installed, this plugin adds new wiki syntax for embedding 'slider' panels directly into tiddler content. Use {{{+++}}} and {{{===}}} to delimit the slider content. Additional optional syntax elements let you specify
*default to open
*cookiename
*heading level
*floater (with optional CSS width value)
*mouse auto rollover
*custom label/tooltip/accesskey
*automatic blockquote
*deferred rendering
The complete syntax, using all options, is:
//{{{
++++(cookiename)!!!!!^width^*[label=key|tooltip]>...
content goes here
===
//}}}
where:
* {{{+++}}} (or {{{++++}}}) and {{{===}}}^^
marks the start and end of the slider definition, respectively. When the extra {{{+}}} is used, the slider will be open when initially displayed.^^
* {{{(cookiename)}}}^^
saves the slider opened/closed state, and restores this state whenever the slider is re-rendered.^^
* {{{!}}} through {{{!!!!!}}}^^
displays the slider label using a formatted headline (Hn) style instead of a button/link style^^
* {{{^width^}}} (or just {{{^}}})^^
makes the slider 'float' on top of other content rather than shifting that content downward. 'width' must be a valid CSS value (e.g., "30em", "180px", "50%", etc.). If omitted, the default width is "auto" (i.e., fit to content)^^
* {{{*}}}^^
automatically opens/closes slider on "rollover" as well as when clicked^^
* {{{[label=key|tooltip]}}}^^
uses custom label/tooltip/accesskey. {{{=key}}} and {{{|tooltip}}} are optional. 'key' is must be a ''single letter only''. Default labels/tootips are: ">" (more) and "<" (less), with no default access key assignment.^^
* {{{">"}}} //(without the quotes)//^^
automatically adds blockquote formatting to slider content^^
* {{{"..."}}} //(without the quotes)//^^
defers rendering of closed sliders until the first time they are opened. //Note: deferred rendering may produce unexpected results in some cases. Use with care.//^^
//Note: to make slider definitions easier to read and recognize when editing a tiddler, newlines immediately following the {{{+++}}} 'start slider' or preceding the {{{===}}} 'end slider' sequence are automatically supressed so that excess whitespace is eliminated from the output.//
===
++++!!!!![Examples]>
simple in-line slider:
{{{
+++
content
===
}}}
+++
content
===
----
use a custom label and tooltip:
{{{
+++[label|tooltip]
content
===
}}}
+++[label|tooltip]
content
===
----
content automatically blockquoted:
{{{
+++>
content
===
}}}
+++>
content
===
----
all options combined //(default open, cookie, heading, sized floater, rollover, label/tooltip/key, blockquoted, deferred)//
{{{
++++(testcookie)!!!^30em^*[label=Z|click or press Alt-Z to open]>...
content
===
}}}
++++(testcookie)!!!^30em^*[label=Z|click or press Alt-Z to open]>...
content
===
----
complex nesting example:
{{{
+++^[get info...=I|click for information or press Alt-I]
put some general information here, plus a floating slider with more specific info:
+++^10em^[view details...|click for details]
put some detail here, which could include a rollover with a +++^25em^*[glossary definition]explaining technical terms===
===
===
}}}
+++^[get info...=I|click for information or press Alt-I]
put some general information here, plus a floating slider with more specific info:
+++^10em^[view details...|click for details]
put some detail here, which could include a rollover with a +++^25em^*[glossary definition]explaining technical terms===
===
===
----
nested floaters
>menu: <<tiddler NestedSlidersExample>>
(see [[NestedSlidersExample]] for definition)
----
===
!!!!!Installation
<<<
import (or copy/paste) the following tiddlers into your document:
''NestedSlidersPlugin'' (tagged with <<tag systemConfig>>)
<<<
!!!!!Revision History
<<<
''2006.05.11 - 1.9.0'' added optional '^width^' syntax for floating sliders and '=key' syntax for setting an access key on a slider label
''2006.05.09 - 1.8.0'' in onClickNestedSlider(), when showing panel, set focus to first child input/textarea/select element
''2006.04.24 - 1.7.8'' in adjustSliderPos(), if floating panel is contained inside another floating panel, subtract offset of containing panel to find correct position
''2006.02.16 - 1.7.7'' corrected deferred rendering to account for use-case where show/hide state is tracked in a cookie
''2006.02.15 - 1.7.6'' in adjustSliderPos(), ensure that floating panel is positioned completely within the browser window (i.e., does not go beyond the right edge of the browser window)
''2006.02.04 - 1.7.5'' add 'var' to unintended global variable declarations to avoid FireFox 1.5.0.1 crash bug when assigning to globals
''2006.01.18 - 1.7.4'' only define adjustSliderPos() function if it has not already been provided by another plugin. This lets other plugins 'hijack' the function even when they are loaded first.
''2006.01.16 - 1.7.3'' added adjustSliderPos(place,btn,panel,panelClass) function to permit specialized logic for placement of floating panels. While it provides improved placement for many uses of floating panels, it exhibits a relative offset positioning error when used within *nested* floating panels. Short-term workaround is to only adjust the position for 'top-level' floaters.
''2006.01.16 - 1.7.2'' added button property to slider panel elements so that slider panel can tell which button it belongs to. Also, re-activated and corrected animation handling so that nested sliders aren't clipped by hijacking Slider.prototype.stop so that "overflow:hidden" can be reset to "overflow:visible" after animation ends
''2006.01.14 - 1.7.1'' added optional "^" syntax for floating panels. Defines new CSS class, ".floatingPanel", as an alternative for standard in-line ".sliderPanel" styles.
''2006.01.14 - 1.7.0'' added optional "*" syntax for rollover handling to show/hide slider without requiring a click (Based on a suggestion by tw4efl)
''2006.01.03 - 1.6.2'' When using optional "!" heading style, instead of creating a clickable "Hn" element, create an "A" element inside the "Hn" element. (allows click-through in SlideShowPlugin, which captures nearly all click events, except for hyperlinks)
''2005.12.15 - 1.6.1'' added optional "..." syntax to invoke deferred ('lazy') rendering for initially hidden sliders
removed checkbox option for 'global' application of lazy sliders
''2005.11.25 - 1.6.0'' added optional handling for 'lazy sliders' (deferred rendering for initially hidden sliders)
''2005.11.21 - 1.5.1'' revised regular expressions: if present, a single newline //preceding// and/or //following// a slider definition will be suppressed so start/end syntax can be place on separate lines in the tiddler 'source' for improved readability. Similarly, any whitespace (newlines, tabs, spaces, etc.) trailing the 'start slider' syntax or preceding the 'end slider' syntax is also suppressed.
''2005.11.20 - 1.5.0'' added (cookiename) syntax for optional tracking and restoring of slider open/close state
''2005.11.11 - 1.4.0'' added !!!!! syntax to render slider label as a header (Hn) style instead of a button/link style
''2005.11.07 - 1.3.0'' removed alternative syntax {{{(((}}} and {{{)))}}} (so they can be used by other
formatting extensions) and simplified/improved regular expressions to trim multiple excess newlines
''2005.11.05 - 1.2.1'' changed name to NestedSlidersPlugin
more documentation
''2005.11.04 - 1.2.0'' added alternative character-mode syntax {{{(((}}} and {{{)))}}}
tweaked "eat newlines" logic for line-mode {{{+++}}} and {{{===}}} syntax
''2005.11.03 - 1.1.1'' fixed toggling of default tooltips ("more..." and "less...") when a non-default button label is used
code cleanup, added documentation
''2005.11.03 - 1.1.0'' changed delimiter syntax from {{{(((}}} and {{{)))}}} to {{{+++}}} and {{{===}}}
changed name to EasySlidersPlugin
''2005.11.03 - 1.0.0'' initial public release
<<<
!!!!!Credits
<<<
This feature was implemented by EricShulman from [[ELS Design Studios|http:/www.elsdesign.com]] with initial research and suggestions from RodneyGomes, GeoffSlocock, and PaulPetterson.
<<<
!!!!!Code
***/
//{{{
version.extensions.nestedSliders = {major: 1, minor: 9, revision: 0, date: new Date(2006,5,11)};
//}}}
//{{{
// options for deferred rendering of sliders that are not initially displayed
if (config.options.chkDebugLazySliderDefer==undefined) config.options.chkDebugLazySliderDefer=false;
if (config.options.chkDebugLazySliderRender==undefined) config.options.chkDebugLazySliderRender=false;
// default styles for 'floating' class
setStylesheet(".floatingPanel { position:absolute; z-index:10; padding:0.5em; margin:0em; \
background-color:#eee; color:#000; border:1px solid #000; text-align:left; }","floatingPanelStylesheet");
//}}}
//{{{
config.formatters.push( {
name: "nestedSliders",
match: "\\n?\\+{3}",
terminator: "\\s*\\={3}\\n?",
lookahead: "\\n?\\+{3}(\\+)?(\\([^\\)]*\\))?(\\!*)?(\\^(?:[^\\^\\*\\[\\>]*\\^)?)?(\\*)?(\\[[^\\]]*\\])?(\\>)?(\\.\\.\\.)?\\s*",
handler: function(w)
{
var lookaheadRegExp = new RegExp(this.lookahead,"mg");
lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
{
// location for rendering button and panel
var place=w.output;
// default to closed, no cookie, no accesskey
var show="none"; var title=">"; var tooltip="show"; var cookie=""; var key="";
// extra "+", default to open
if (lookaheadMatch[1])
{ show="block"; title="<"; tooltip="hide"; }
// cookie, use saved open/closed state
if (lookaheadMatch[2]) {
cookie=lookaheadMatch[2].trim().slice(1,-1);
cookie="chkSlider"+cookie;
if (config.options[cookie]==undefined)
{ config.options[cookie] = (show=="block") }
if (config.options[cookie])
{ show="block"; title="<"; tooltip="hide"; }
else
{ show="none"; title=">"; tooltip="show"; }
}
// parse custom label/tooltip/accesskey: [label=X|tooltip]
if (lookaheadMatch[6]) {
title = lookaheadMatch[6].trim().slice(1,-1);
var pos=title.indexOf("|");
if (pos!=-1) { tooltip = title.substr(pos+1,title.length); title=title.substr(0,pos); }
if (title.substr(title.length-2,1)=="=") { key=title.substr(title.length-1,1); title=title.slice(0,-2); }
if (pos==-1) tooltip += " "+title; // default tooltip: "show/hide <title>"
}
// create the button
if (lookaheadMatch[3]) { // use "Hn" header format instead of button/link
var lvl=(lookaheadMatch[3].length>6)?6:lookaheadMatch[3].length;
var btn = createTiddlyElement(createTiddlyElement(place,"h"+lvl,null,null,null),"a",null,null,title);
btn.onclick=onClickNestedSlider;
btn.setAttribute("href","javascript:;");
btn.setAttribute("title",tooltip);
}
else
var btn = createTiddlyButton(place,title,tooltip,onClickNestedSlider);
btn.sliderCookie = cookie; // save the cookiename (if any) in the button object
btn.keyparam=key; // save the access key letter ("" if none)
if (key.length) {
btn.setAttribute("accessKey",key); // init access key
btn.onfocus=function(){this.setAttribute("accessKey",this.keyparam);}; // **reclaim** access key on focus
}
// "non-click" MouseOver open/close slider
if (lookaheadMatch[5]) btn.onmouseover=onClickNestedSlider;
// create slider panel
var panelClass=lookaheadMatch[4]?"floatingPanel":"sliderPanel";
var panel=createTiddlyElement(place,"div",null,panelClass,null);
panel.style.display = show;
if (lookaheadMatch[4] && lookaheadMatch[4].length>2) panel.style.width=lookaheadMatch[4].slice(1,-1); // custom width
panel.button = btn; // so the slider panel know which button it belongs to
btn.sliderPanel=panel;
// render slider (or defer until shown)
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
if ((show=="block")||!lookaheadMatch[8]) {
// render now if panel is supposed to be shown or NOT deferred rendering
w.subWikify(lookaheadMatch[7]?createTiddlyElement(panel,"blockquote"):panel,this.terminator);
// align slider/floater position with button
adjustSliderPos(place,btn,panel,panelClass);
}
else {
var src = w.source.substr(w.nextMatch);
var endpos=findMatchingDelimiter(src,"+++","===");
panel.setAttribute("raw",src.substr(0,endpos));
panel.setAttribute("blockquote",lookaheadMatch[7]?"true":"false");
panel.setAttribute("rendered","false");
w.nextMatch += endpos+3;
if (w.source.substr(w.nextMatch,1)=="\n") w.nextMatch++;
if (config.options.chkDebugLazySliderDefer) alert("deferred '"+title+"':\n\n"+panel.getAttribute("raw"));
}
}
}
}
)
// TBD: ignore 'quoted' delimiters (e.g., "{{{+++foo===}}}" isn't really a slider)
function findMatchingDelimiter(src,starttext,endtext) {
var startpos = 0;
var endpos = src.indexOf(endtext);
// check for nested delimiters
while (src.substring(startpos,endpos-1).indexOf(starttext)!=-1) {
// count number of nested 'starts'
var startcount=0;
var temp = src.substring(startpos,endpos-1);
var pos=temp.indexOf(starttext);
while (pos!=-1) { startcount++; pos=temp.indexOf(starttext,pos+starttext.length); }
// set up to check for additional 'starts' after adjusting endpos
startpos=endpos+endtext.length;
// find endpos for corresponding number of matching 'ends'
while (startcount && endpos!=-1) {
endpos = src.indexOf(endtext,endpos+endtext.length);
startcount--;
}
}
return (endpos==-1)?src.length:endpos;
}
//}}}
//{{{
window.onClickNestedSlider=function(e)
{
if (!e) var e = window.event;
var theTarget = resolveTarget(e);
var theLabel = theTarget.firstChild.data;
var theSlider = theTarget.sliderPanel
var isOpen = theSlider.style.display!="none";
// if using default button labels, toggle labels
if (theLabel==">") theTarget.firstChild.data = "<";
else if (theLabel=="<") theTarget.firstChild.data = ">";
// if using default tooltips, toggle tooltips
if (theTarget.getAttribute("title")=="show")
theTarget.setAttribute("title","hide");
else if (theTarget.getAttribute("title")=="hide")
theTarget.setAttribute("title","show");
if (theTarget.getAttribute("title")=="show "+theLabel)
theTarget.setAttribute("title","hide "+theLabel);
else if (theTarget.getAttribute("title")=="hide "+theLabel)
theTarget.setAttribute("title","show "+theLabel);
// deferred rendering (if needed)
if (theSlider.getAttribute("rendered")=="false") {
if (config.options.chkDebugLazySliderRender)
alert("rendering '"+theLabel+"':\n\n"+theSlider.getAttribute("raw"));
var place=theSlider;
if (theSlider.getAttribute("blockquote")=="true")
place=createTiddlyElement(place,"blockquote");
wikify(theSlider.getAttribute("raw"),place);
theSlider.setAttribute("rendered","true");
}
// show/hide the slider
if(config.options.chkAnimate)
anim.startAnimating(new Slider(theSlider,!isOpen,e.shiftKey || e.altKey,"none"));
else
theSlider.style.display = isOpen ? "none" : "block";
// if showing panel, set focus to first 'focus-able' element in panel
if (theSlider.style.display!="none") {
var ctrls=theSlider.getElementsByTagName("*");
for (var c=0; c<ctrls.length; c++) {
var t=ctrls[c].tagName.toLowerCase();
if (t=="input" || t=="textarea" || t=="select")
{ ctrls[c].focus(); break; }
}
}
if (this.sliderCookie && this.sliderCookie.length)
{ config.options[this.sliderCookie]=!isOpen; saveOptionCookie(this.sliderCookie); }
// align slider/floater position with target button
adjustSliderPos(theSlider.parentNode,theTarget,theSlider,theSlider.className);
return false;
}
// hijack animation handler 'stop' handler so overflow is visible after animation has completed
Slider.prototype.coreStop = Slider.prototype.stop;
Slider.prototype.stop = function() { this.coreStop(); this.element.style.overflow = "visible"; }
// adjust panel position based on button position
if (window.adjustSliderPos==undefined) window.adjustSliderPos=function(place,btn,panel,panelClass) {
if (panelClass=="floatingPanel") {
var left=0;
var top=btn.offsetHeight;
if (place.style.position!="relative") {
var left=findPosX(btn);
var top=findPosY(btn)+btn.offsetHeight;
var p=place; while (p && p.className!='floatingPanel') p=p.parentNode;
if (p) { left-=findPosX(p); top-=findPosY(p); }
}
if (left+panel.offsetWidth > getWindowWidth()) left=getWindowWidth()-panel.offsetWidth-10;
panel.style.left=left+"px"; panel.style.top=top+"px";
}
}
function getWindowWidth() {
if(document.width!=undefined)
return document.width; // moz (FF)
if(document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) )
return document.documentElement.clientWidth; // IE6
if(document.body && ( document.body.clientWidth || document.body.clientHeight ) )
return document.body.clientWidth; // IE4
if(window.innerWidth!=undefined)
return window.innerWidth; // IE - general
return 0; // unknown
}
//}}}
/%
!info
|Name|ToggleLeftSidebar|
|Source|http://www.TiddlyTools.com/#ToggleLeftSidebar|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|show/hide left sidebar (MainMenu)|
Usage
<<<
{{{
<<tiddler ToggleLeftSidebar>>
<<tiddler ToggleLeftSidebar with: label tooltip>>
}}}
Try it: <<tiddler ToggleLeftSidebar##show
with: {{config.options.chkShowLeftSidebar?'â—„':'â–º'}}>>
<<<
Configuration:
<<<
{{{
config.options.chkShowLeftSidebar (true)
config.options.txtToggleLeftSideBarLabelShow (â–º)
config.options.txtToggleLeftSideBarLabelHide (â—„)
}}}
<<<
!end
!show
<<tiddler {{
var co=config.options;
if (co.chkShowLeftSidebar===undefined) co.chkShowLeftSidebar=true;
var mm=document.getElementById('mainMenu');
var da=document.getElementById('displayArea');
if (mm) {
mm.style.display=co.chkShowLeftSidebar?'block':'none';
da.style.marginLeft=co.chkShowLeftSidebar?'':'1em';
}
'';}}>><html><nowiki><a href='javascript:;' title="$2"
onmouseover="
this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
+encodeURIComponent(encodeURIComponent(this.onclick))
+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
var co=config.options;
var opt='chkShowLeftSidebar';
var show=co[opt]=!co[opt];
var mm=document.getElementById('mainMenu');
var da=document.getElementById('displayArea');
if (mm) {
mm.style.display=show?'block':'none';
da.style.marginLeft=show?'':'1em';
}
saveOptionCookie(opt);
var labelShow=co.txtToggleLeftSideBarLabelShow||'►';
var labelHide=co.txtToggleLeftSideBarLabelHide||'◄';
if (this.innerHTML==labelShow||this.innerHTML==labelHide)
this.innerHTML=show?labelHide:labelShow;
this.title=(show?'hide':'show')+' left sidebar';
var sm=document.getElementById('storyMenu');
if (sm) config.refreshers.content(sm);
return false;
">$1</a></html>
!end
%/<<tiddler {{
var src='ToggleLeftSidebar';
src+(tiddler&&tiddler.title==src?'##info':'##show');
}} with: {{
var co=config.options;
var labelShow=co.txtToggleLeftSideBarLabelShow||'►';
var labelHide=co.txtToggleLeftSideBarLabelHide||'◄';
'$1'!='$'+'1'?'$1':(co.chkShowLeftSidebar?labelHide:labelShow);
}} {{
var tip=(config.options.chkShowLeftSidebar?'hide':'show')+' left sidebar';
'$2'!='$'+'2'?'$2':tip;
}}>>
/***
|''Name:''|FootnotesPlugin|
|''Description:''|Create automated tiddler footnotes.|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#FootnotesPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.01|
|''Date:''|10/25/07|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.2|
!!Usage:
*To create a footnote, just put the footnote text inside triple backticks.
*Footnotes are numbered automatically, and listed at the bottom of the tiddler.
*{{{Creating a footnote is easy. ```This is the text for my footnote```}}}
*[[Example|FootnotesDemo]]
***/
// /%
//!BEGIN-PLUGIN-CODE
config.footnotesPlugin = {
backLabel: "back",
prompt:"show footnote"
};
config.formatters.unshift( {
name: "footnotes",
match: "```",
lookaheadRegExp: /```((?:.|\n)*?)```/g,
handler: function(w)
{
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
if(lookaheadMatch && lookaheadMatch.index == w.matchStart )
{
var tiddler = story.findContainingTiddler(w.output);
if (!tiddler.notes)
tiddler.notes = [];
var title = tiddler.getAttribute("tiddler");
tiddler.notes.pushUnique(lookaheadMatch[1]);
var pos = tiddler.notes.indexOf(lookaheadMatch[1]) + 1;
createTiddlyButton(w.output,pos,config.footnotesPlugin.prompt,function(){var x = document.getElementById(title+"ftn"+pos);window.scrollTo(0,ensureVisible(x)+(ensureVisible(x)<findScrollY()?(findWindowHeight()-x.offsetHeight):0));return false;},"ftnlink",title+"ftnlink"+pos);
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
}
}
});
old_footnotes_refreshTiddler = Story.prototype.refreshTiddler;
Story.prototype.refreshTiddler = function(title,template,force)
{
var tiddler = old_footnotes_refreshTiddler.apply(this,arguments);
if (tiddler.notes && tiddler.notes.length)
{
var holder = createTiddlyElement(null,"div",null,"footnoteholder");
var list = createTiddlyElement(holder,"ol",title+"footnoteholder");
for (var i=0; i<tiddler.notes.length; i++)
{
var ftn = createTiddlyElement(list,"li",title+"ftn"+(i+1),"footnote");
wikify(tiddler.notes[i]+" ",ftn);
createTiddlyButton(ftn,"["+config.footnotesPlugin.backLabel+"]",config.footnotesPlugin.backLabel,function(){window.scrollTo(0,ensureVisible(document.getElementById(this.parentNode.id.replace("ftn","ftnlink"))));return false;},"ftnbklink");
}
var count = tiddler.childNodes.length;
for (var j=0; j<count; j++){
if(hasClass(tiddler.childNodes[j],"viewer")){
var viewer = tiddler.childNodes[j];
}
}
viewer.appendChild(holder);
tiddler.notes = [];
}
return tiddler;
};
setStylesheet(
".tiddler a.ftnlink {vertical-align: super; font-size: 0.8em; color:red;}\n"+
".tiddler a.ftnlink:hover, .tiddler .footnoteholder a.ftnbklink:hover{color:#fff;background:red;}\n"+
".tiddler div.footnoteholder{margin:1.8em 1.0em; padding:0.1em 1.0em 0.1em 1.0em ;border-left: 1px solid #ccc;}"+
".tiddler footnoteholder ol {font-size: 0.9em; line-height: 1.2em;}\n"+
".tiddler .footnoteholder li.footnote {margin: 0 0 5px 0;}\n"+
".tiddler .footnoteholder a.ftnbklink{color:red;}\n","FootNotesStyles");
//!END-PLUGIN-CODE
// %/
{{floatleft{<<tiddler ToggleLeftSidebar>>}}}{{floatright{<<tiddler ToggleRightSidebar>>}}}
/***
| Name:|WYSIWYGPlugin|
| Purpose:|WYSIWYG editor|
| Creator:|Chris Pietschmann for jHtmlArea|
| Source:|http://jhtmlarea.codeplex.com/|
| Requires:|Javascript|
| Version|0.1|
***/
//{{{
/*
* jHtmlArea 0.7.5 - WYSIWYG Html Editor jQuery Plugin
* Copyright (c) 2012 Chris Pietschmann
* http://jhtmlarea.codeplex.com
* Licensed under the Microsoft Reciprocal License (Ms-RL)
* http://jhtmlarea.codeplex.com/license
*
* ... with the following patches:
* - reinject all css data from this into the iframe to get the same rendering
* - intercept ctrl-returrn, meta-return and ESC and propagate it to edit pane for closing
*/
(function ($) {
$.fn.htmlarea = function (opts) {
if (opts && typeof (opts) === "string") {
var args = [];
for (var i = 1; i < arguments.length; i++) { args.push(arguments[i]); }
var htmlarea = jHtmlArea(this[0]);
var f = htmlarea[opts];
if (f) { return f.apply(htmlarea, args); }
}
return this.each(function () { jHtmlArea(this, opts); });
};
var jHtmlArea = window.jHtmlArea = function (elem, options) {
if (elem.jquery) {
return jHtmlArea(elem[0]);
}
if (elem.jhtmlareaObject) {
return elem.jhtmlareaObject;
} else {
return new jHtmlArea.fn.init(elem, options);
}
};
jHtmlArea.fn = jHtmlArea.prototype = {
// The current version of jHtmlArea being used
jhtmlarea: "0.7.5",
init: function (elem, options) {
if (elem.nodeName.toLowerCase() === "textarea") {
var opts = $.extend({}, jHtmlArea.defaultOptions, options);
elem.jhtmlareaObject = this;
var textarea = this.textarea = $(elem);
var container = this.container = $("<div/>").addClass("jHtmlArea").width(textarea.width()).insertAfter(textarea);
var toolbar = this.toolbar = $("<div/>").addClass("ToolBar").appendTo(container);
priv.initToolBar.call(this, opts);
console.log("engaging");
console.log(textarea.height());
var iframe = this.iframe = $("<iframe/>").height(textarea.height());
iframe.width(textarea.width() - ($.browser.msie ? 0 : 4));
var htmlarea = this.htmlarea = $("<div/>").append(iframe);
container.append(htmlarea).append(textarea.hide());
priv.initEditor.call(this, opts);
priv.attachEditorEvents.call(this);
// Inject our styles into the iframe
var oHead = iframe[0].contentDocument.getElementsByTagName("head")[0];
var arrStyleSheets = document.getElementsByTagName("style");
for (var i = 0; i < arrStyleSheets.length; i++)
oHead.appendChild(arrStyleSheets[i].cloneNode(true));
// Fix total height to match TextArea
iframe.height(textarea.height() - toolbar.height());
console.log(iframe.height());
console.log(toolbar.height());
toolbar.width(textarea.width() - 2);
if (opts.loaded) { opts.loaded.call(this); }
}
},
dispose: function () {
this.textarea.show().insertAfter(this.container);
this.container.remove();
this.textarea[0].jhtmlareaObject = null;
},
execCommand: function (a, b, c) {
this.iframe[0].contentWindow.focus();
this.editor.execCommand(a, b || false, c || null);
this.updateTextArea();
},
ec: function (a, b, c) {
this.execCommand(a, b, c);
},
queryCommandValue: function (a) {
this.iframe[0].contentWindow.focus();
return this.editor.queryCommandValue(a);
},
qc: function (a) {
return this.queryCommandValue(a);
},
getSelectedHTML: function () {
if ($.browser.msie) {
return this.getRange().htmlText;
} else {
var elem = this.getRange().cloneContents();
return $("<p/>").append($(elem)).html();
}
},
getSelection: function () {
if ($.browser.msie) {
//return (this.editor.parentWindow.getSelection) ? this.editor.parentWindow.getSelection() : this.editor.selection;
return this.editor.selection;
} else {
return this.iframe[0].contentDocument.defaultView.getSelection();
}
},
getRange: function () {
var s = this.getSelection();
if (!s) { return null; }
//return (s.rangeCount > 0) ? s.getRangeAt(0) : s.createRange();
return (s.getRangeAt) ? s.getRangeAt(0) : s.createRange();
},
html: function (v) {
if (v) {
this.textarea.val(v);
this.updateHtmlArea();
} else {
return this.toHtmlString();
}
},
pasteHTML: function (html) {
this.iframe[0].contentWindow.focus();
var r = this.getRange();
if ($.browser.msie) {
r.pasteHTML(html);
} else if ($.browser.mozilla) {
r.deleteContents();
r.insertNode($((html.indexOf("<") != 0) ? $("<span/>").append(html) : html)[0]);
} else { // Safari
r.deleteContents();
r.insertNode($(this.iframe[0].contentWindow.document.createElement("span")).append($((html.indexOf("<") != 0) ? "<span>" + html + "</span>" : html))[0]);
}
r.collapse(false);
r.select();
},
cut: function () {
this.ec("cut");
},
copy: function () {
this.ec("copy");
},
paste: function () {
this.ec("paste");
},
bold: function () { this.ec("bold"); },
italic: function () { this.ec("italic"); },
underline: function () { this.ec("underline"); },
strikeThrough: function () { this.ec("strikethrough"); },
image: function (url) {
if ($.browser.msie && !url) {
this.ec("insertImage", true);
} else {
this.ec("insertImage", false, (url || prompt("Image URL:", "http://")));
}
},
removeFormat: function () {
this.ec("removeFormat", false, []);
this.unlink();
},
link: function () {
if ($.browser.msie) {
this.ec("createLink", true);
} else {
this.ec("createLink", false, prompt("Link URL:", "http://"));
}
},
unlink: function () { this.ec("unlink", false, []); },
orderedList: function () { this.ec("insertorderedlist"); },
unorderedList: function () { this.ec("insertunorderedlist"); },
superscript: function () { this.ec("superscript"); },
subscript: function () { this.ec("subscript"); },
p: function () {
this.formatBlock("<p>");
},
h1: function () {
this.heading(1);
},
h2: function () {
this.heading(2);
},
h3: function () {
this.heading(3);
},
h4: function () {
this.heading(4);
},
h5: function () {
this.heading(5);
},
h6: function () {
this.heading(6);
},
heading: function (h) {
this.formatBlock($.browser.msie ? "Heading " + h : "h" + h);
},
indent: function () {
this.ec("indent");
},
outdent: function () {
this.ec("outdent");
},
insertHorizontalRule: function () {
this.ec("insertHorizontalRule", false, "ht");
},
justifyLeft: function () {
this.ec("justifyLeft");
},
justifyCenter: function () {
this.ec("justifyCenter");
},
justifyRight: function () {
this.ec("justifyRight");
},
increaseFontSize: function () {
if ($.browser.msie) {
this.ec("fontSize", false, this.qc("fontSize") + 1);
} else if ($.browser.safari) {
this.getRange().surroundContents($(this.iframe[0].contentWindow.document.createElement("span")).css("font-size", "larger")[0]);
} else {
this.ec("increaseFontSize", false, "big");
}
},
decreaseFontSize: function () {
if ($.browser.msie) {
this.ec("fontSize", false, this.qc("fontSize") - 1);
} else if ($.browser.safari) {
this.getRange().surroundContents($(this.iframe[0].contentWindow.document.createElement("span")).css("font-size", "smaller")[0]);
} else {
this.ec("decreaseFontSize", false, "small");
}
},
forecolor: function (c) {
this.ec("foreColor", false, c || prompt("Enter HTML Color:", "#"));
},
formatBlock: function (v) {
this.ec("formatblock", false, v || null);
},
showHTMLView: function () {
this.updateTextArea();
this.textarea.show();
this.htmlarea.hide();
$("ul li:not(li:has(a.html))", this.toolbar).hide();
$("ul:not(:has(:visible))", this.toolbar).hide();
$("ul li a.html", this.toolbar).addClass("highlighted");
},
hideHTMLView: function () {
this.updateHtmlArea();
this.textarea.hide();
this.htmlarea.show();
$("ul", this.toolbar).show();
$("ul li", this.toolbar).show().find("a.html").removeClass("highlighted");
},
toggleHTMLView: function () {
(this.textarea.is(":hidden")) ? this.showHTMLView() : this.hideHTMLView();
},
toHtmlString: function () {
return this.editor.body.innerHTML;
},
toString: function () {
return this.editor.body.innerText;
},
updateTextArea: function () {
this.textarea.val(this.toHtmlString());
},
updateHtmlArea: function () {
this.editor.body.innerHTML = this.textarea.val();
}
};
jHtmlArea.fn.init.prototype = jHtmlArea.fn;
jHtmlArea.defaultOptions = {
toolbar: [
["html"], ["bold", "italic", "underline", "strikethrough", "|", "subscript", "superscript"],
["increasefontsize", "decreasefontsize"],
["orderedlist", "unorderedlist"],
["justifyleft", "justifycenter", "justifyright"],
["link", "unlink", "image", "horizontalrule"],
["p", "h1", "h2", "h3", "h4", "h5", "h6"],
["cut", "copy", "paste"],
["indent", "outdent"],
],
css: null,
toolbarText: {
bold: "Bold", italic: "Italic", underline: "Underline", strikethrough: "Strike-Through",
cut: "Cut", copy: "Copy", paste: "Paste",
h1: "Heading 1", h2: "Heading 2", h3: "Heading 3", h4: "Heading 4", h5: "Heading 5", h6: "Heading 6", p: "Paragraph",
indent: "Indent", outdent: "Outdent", horizontalrule: "Insert Horizontal Rule",
justifyleft: "Left Justify", justifycenter: "Center Justify", justifyright: "Right Justify",
increasefontsize: "Increase Font Size", decreasefontsize: "Decrease Font Size", forecolor: "Text Color",
link: "Insert Link", unlink: "Remove Link", image: "Insert Image",
orderedlist: "Insert Ordered List", unorderedlist: "Insert Unordered List",
subscript: "Subscript", superscript: "Superscript",
html: "Show/Hide HTML Source View"
}
};
var priv = {
toolbarButtons: {
strikethrough: "strikeThrough", orderedlist: "orderedList", unorderedlist: "unorderedList",
horizontalrule: "insertHorizontalRule",
justifyleft: "justifyLeft", justifycenter: "justifyCenter", justifyright: "justifyRight",
increasefontsize: "increaseFontSize", decreasefontsize: "decreaseFontSize",
html: function (btn) {
this.toggleHTMLView();
}
},
initEditor: function (options) {
var edit = this.editor = this.iframe[0].contentWindow.document;
edit.designMode = 'on';
edit.open();
edit.write(this.textarea.val());
edit.close();
if (options.css) {
var e = edit.createElement('link'); e.rel = 'stylesheet'; e.type = 'text/css'; e.href = options.css; edit.getElementsByTagName('head')[0].appendChild(e);
}
},
initToolBar: function (options) {
var that = this;
var menuItem = function (className, altText, action) {
return $("<li/>").append($("<a href='javascript:void(0);'/>").addClass(className).attr("title", altText).click(function () { action.call(that, $(this)); }));
};
function addButtons(arr) {
var ul = $("<ul/>").appendTo(that.toolbar);
for (var i = 0; i < arr.length; i++) {
var e = arr[i];
if ((typeof (e)).toLowerCase() === "string") {
if (e === "|") {
ul.append($('<li class="separator"/>'));
} else {
var f = (function (e) {
// If button name exists in priv.toolbarButtons then call the "method" defined there, otherwise call the method with the same name
var m = priv.toolbarButtons[e] || e;
if ((typeof (m)).toLowerCase() === "function") {
return function (btn) { m.call(this, btn); };
} else {
return function () { this[m](); this.editor.body.focus(); };
}
})(e.toLowerCase());
var t = options.toolbarText[e.toLowerCase()];
ul.append(menuItem(e.toLowerCase(), t || e, f));
}
} else {
ul.append(menuItem(e.css, e.text, e.action));
}
}
};
if (options.toolbar.length !== 0 && priv.isArray(options.toolbar[0])) {
for (var i = 0; i < options.toolbar.length; i++) {
addButtons(options.toolbar[i]);
}
} else {
addButtons(options.toolbar);
}
},
attachEditorEvents: function () {
var t = this;
var fnHA = function () {
t.updateHtmlArea();
};
this.textarea.click(fnHA).
keyup(fnHA).
keydown(fnHA).
mousedown(fnHA).
blur(fnHA);
var fnTA = function (e) {
t.updateTextArea();
// Handle exit
var match = (e.type == "keydown" && (e.ctrlKey||e.metaKey) && e.keyCode == 13);
match = match || (e.type == "keydown" && e.keyCode == 27);
if (match)
{
console.log("bip");
t.textarea.val("<html>" + t.toHtmlString() + "</html>");
// propagate event to textarea
t.textarea.trigger(e); // is that valid?
}
};
$(this.editor.body).click(fnTA).
keyup(fnTA).
keydown(fnTA).
mousedown(fnTA).
blur(fnTA);
$('form').submit(function () { t.toggleHTMLView(); t.toggleHTMLView(); });
//$(this.textarea[0].form).submit(function() { //this.textarea.closest("form").submit(function() {
// Fix for ASP.NET Postback Model
if (window.__doPostBack) {
var old__doPostBack = __doPostBack;
window.__doPostBack = function () {
if (t) {
if (t.toggleHTMLView) {
t.toggleHTMLView();
t.toggleHTMLView();
}
}
return old__doPostBack.apply(window, arguments);
};
}
},
isArray: function (v) {
return v && typeof v === 'object' && typeof v.length === 'number' && typeof v.splice === 'function' && !(v.propertyIsEnumerable('length'));
}
};
})(jQuery);
//}}}
/***
!! Auto-enable
***/
//{{{
config.commands.editTiddler.handler_wysiwig = config.commands.editTiddler.handler;
config.commands.editTiddler.handler = function(event, src, title)
{
config.commands.editTiddler.handler_wysiwig(event, src, title);
var txt = store.getTiddlerText(title);
if (txt.substring(0,6) == "<html>")
{
var ta = document.activeElement;
jQuery(document.activeElement).htmlarea();
setTimeout(function() {
var ifr = ta.parentElement.children[1].children[0];
console.log("h " + ifr.contentDocument.height);
jQuery(ifr).height(ifr.contentDocument.height);
}, 100);
}
}
//}}}
/***
!! CSS data
***/
//{{{
document.getElementsByTagName('head')[0].innerHTML += '<style type="text/css">' +
'div.jHtmlArea { display: inline block; }\ndiv.jHtmlArea div { padding: 0px; margin: 0px; }\ndiv.jHtmlArea .ToolBar { }\ndiv.jHtmlArea .ToolBar ul { border: solid 1px #ccc; margin: 1px; padding: 1px; float: left; background: #fff url(http://www.nottale.net/jHtmlArea_Toolbar_Group_BG.png) repeat-x;}\ndiv.jHtmlArea .ToolBar ul li { list-style-type: none; float: left; border: none; padding: 1px; margin: 1px; }\ndiv.jHtmlArea .ToolBar ul li:hover { border: solid 1px #ccc; background: #ddd url(http://www.nottale.net/jHtmlArea_Toolbar_Group__Btn_Select_BG.png); padding: 0; }\ndiv.jHtmlArea .ToolBar ul li a { display: block; width: 16px; height: 16px; background: url(http://www.nottale.net/jHtmlArea.png) no-repeat -16px -500px; border: none; cursor: pointer; padding: 0px; }\ndiv.jHtmlArea .ToolBar ul li a.highlighted { border: solid 1px #aaa; background-color: #bbb; padding: 0; }\ndiv.jHtmlArea .ToolBar ul li.separator {height: 16px; margin: 0 2px 0 3px; border-left: 1px solid #ccc;}\ndiv.jHtmlArea .ToolBar ul li.separator:hover { padding: 1px; background-color: #fff; border-top:none; border-bottom:none; border-right:none;}\n\ndiv.jHtmlArea .ToolBar ul li a:hover { }\ndiv.jHtmlArea .ToolBar ul li a.bold { background-position: 0 0; }\ndiv.jHtmlArea .ToolBar ul li a.italic { background-position: -16px 0; }\ndiv.jHtmlArea .ToolBar ul li a.underline { background-position: -32px 0; }\ndiv.jHtmlArea .ToolBar ul li a.strikethrough { background-position: -48px 0; }\ndiv.jHtmlArea .ToolBar ul li a.link { background-position: -64px 0; }\ndiv.jHtmlArea .ToolBar ul li a.unlink { background-position: -80px 0; }\ndiv.jHtmlArea .ToolBar ul li a.orderedlist { background-position: -96px 0; }\ndiv.jHtmlArea .ToolBar ul li a.unorderedlist { background-position: -112px 0; }\ndiv.jHtmlArea .ToolBar ul li a.image { background-position: -128px 0; }\ndiv.jHtmlArea .ToolBar ul li a.cut { background-position: -144px 0; }\ndiv.jHtmlArea .ToolBar ul li a.copy { background-position: -160px 0; }\ndiv.jHtmlArea .ToolBar ul li a.paste { background-position: -176px 0; }\n\ndiv.jHtmlArea .ToolBar ul li a.html { background-position: -192px 0; opacity:0.6; filter:alpha(opacity=60);}\ndiv.jHtmlArea .ToolBar ul li a.html.highlighted { opacity:1.0; filter:alpha(opacity=100);}\n\ndiv.jHtmlArea .ToolBar ul li a.h1 { background-position: 0 -16px;}\ndiv.jHtmlArea .ToolBar ul li a.h2 { background-position: -16px -16px;}\ndiv.jHtmlArea .ToolBar ul li a.h3 { background-position: -32px -16px;}\ndiv.jHtmlArea .ToolBar ul li a.h4 { background-position: -48px -16px;}\ndiv.jHtmlArea .ToolBar ul li a.h5 { background-position: -64px -16px;}\ndiv.jHtmlArea .ToolBar ul li a.h6 { background-position: -80px -16px;}\ndiv.jHtmlArea .ToolBar ul li a.subscript { background-position: -96px -16px;}\ndiv.jHtmlArea .ToolBar ul li a.superscript { background-position: -112px -16px;}\ndiv.jHtmlArea .ToolBar ul li a.indent { background-position: -128px -16px;}\ndiv.jHtmlArea .ToolBar ul li a.outdent { background-position: -144px -16px;}\ndiv.jHtmlArea .ToolBar ul li a.horizontalrule { background-position: -160px -16px;}\ndiv.jHtmlArea .ToolBar ul li a.p { background-position: -176px -16px;}\n\n\ndiv.jHtmlArea .ToolBar ul li a.justifyleft { background-position: 0 -32px;}\ndiv.jHtmlArea .ToolBar ul li a.justifycenter { background-position: -16px -32px;}\ndiv.jHtmlArea .ToolBar ul li a.justifyright { background-position: -32px -32px;}\ndiv.jHtmlArea .ToolBar ul li a.increasefontsize { background-position: -48px -32px;}\ndiv.jHtmlArea .ToolBar ul li a.decreasefontsize { background-position: -64px -32px;}\ndiv.jHtmlArea .ToolBar ul li a.forecolor { background-position: -80px -32px;}' +
'</style>';
//}}}
|~ViewToolbar|closeTiddler closeOthers +editTiddler decryptTiddler > fields revisions syncing permalink references jump|
|~EditToolbar|+saveTiddler -cancelTiddler deleteTiddler|
[[Welcome]]
[[GettingStarted]]
/***
|''Name:''|TiddlersBarPlugin|
|''Description:''|A bar to switch between tiddlers through tabs (like browser tabs bar).|
|''Version:''|1.2.5|
|''Date:''|Jan 18,2008|
|''Source:''|http://visualtw.ouvaton.org/VisualTW.html|
|''Author:''|Pascal Collin|
|''License:''|[[BSD open source license|License]]|
|''~CoreVersion:''|2.1.0|
|''Browser:''|Firefox 2.0; InternetExplorer 6.0, others|
!Demos
On [[homepage|http://visualtw.ouvaton.org/VisualTW.html]], open several tiddlers to use the tabs bar.
!Installation
#import this tiddler from [[homepage|http://visualtw.ouvaton.org/VisualTW.html]] (tagged as systemConfig)
#save and reload
#''if you're using a custom [[PageTemplate]]'', add {{{<div id='tiddlersBar' refresh='none' ondblclick='config.macros.tiddlersBar.onTiddlersBarAction(event)'></div>}}} before {{{<div id='tiddlerDisplay'></div>}}}
#optionally, adjust StyleSheetTiddlersBar
!Tips
*Doubleclick on the tiddlers bar (where there is no tab) create a new tiddler.
*Tabs include a button to close {{{x}}} or save {{{!}}} their tiddler.
*By default, click on the current tab close all others tiddlers.
!Configuration options
<<option chkDisableTabsBar>> Disable the tabs bar (to print, by example).
<<option chkHideTabsBarWhenSingleTab >> Automatically hide the tabs bar when only one tiddler is displayed.
<<option txtSelectedTiddlerTabButton>> ''selected'' tab command button.
<<option txtPreviousTabKey>> previous tab access key.
<<option txtNextTabKey>> next tab access key.
!Code
***/
//{{{
config.options.chkDisableTabsBar = config.options.chkDisableTabsBar ? config.options.chkDisableTabsBar : false;
config.options.chkHideTabsBarWhenSingleTab = config.options.chkHideTabsBarWhenSingleTab ? config.options.chkHideTabsBarWhenSingleTab : false;
config.options.txtSelectedTiddlerTabButton = config.options.txtSelectedTiddlerTabButton ? config.options.txtSelectedTiddlerTabButton : "closeOthers";
config.options.txtPreviousTabKey = config.options.txtPreviousTabKey ? config.options.txtPreviousTabKey : "";
config.options.txtNextTabKey = config.options.txtNextTabKey ? config.options.txtNextTabKey : "";
config.macros.tiddlersBar = {
tooltip : "see ",
tooltipClose : "click here to close this tab",
tooltipSave : "click here to save this tab",
promptRename : "Enter tiddler new name",
currentTiddler : "",
previousState : false,
previousKey : config.options.txtPreviousTabKey,
nextKey : config.options.txtNextTabKey,
tabsAnimationSource : null, //use document.getElementById("tiddlerDisplay") if you need animation on tab switching.
handler: function(place,macroName,params) {
var previous = null;
if (config.macros.tiddlersBar.isShown())
story.forEachTiddler(function(title,e){
if (title==config.macros.tiddlersBar.currentTiddler){
var d = createTiddlyElement(null,"span",null,"tab tabSelected");
config.macros.tiddlersBar.createActiveTabButton(d,title);
if (previous && config.macros.tiddlersBar.previousKey) previous.setAttribute("accessKey",config.macros.tiddlersBar.nextKey);
previous = "active";
}
else {
var d = createTiddlyElement(place,"span",null,"tab tabUnselected");
var btn = createTiddlyButton(d,title,config.macros.tiddlersBar.tooltip + title,config.macros.tiddlersBar.onSelectTab);
btn.setAttribute("tiddler", title);
if (previous=="active" && config.macros.tiddlersBar.nextKey) btn.setAttribute("accessKey",config.macros.tiddlersBar.previousKey);
previous=btn;
}
var isDirty =story.isDirty(title);
var c = createTiddlyButton(d,isDirty ?"!":"x",isDirty?config.macros.tiddlersBar.tooltipSave:config.macros.tiddlersBar.tooltipClose, isDirty ? config.macros.tiddlersBar.onTabSave : config.macros.tiddlersBar.onTabClose,"tabButton");
c.setAttribute("tiddler", title);
if (place.childNodes) {
place.insertBefore(document.createTextNode(" "),place.firstChild); // to allow break line here when many tiddlers are open
place.insertBefore(d,place.firstChild);
}
else place.appendChild(d);
})
},
refresh: function(place,params){
removeChildren(place);
config.macros.tiddlersBar.handler(place,"tiddlersBar",params);
if (config.macros.tiddlersBar.previousState!=config.macros.tiddlersBar.isShown()) {
story.refreshAllTiddlers();
if (config.macros.tiddlersBar.previousState) story.forEachTiddler(function(t,e){e.style.display="";});
config.macros.tiddlersBar.previousState = !config.macros.tiddlersBar.previousState;
}
},
isShown : function(){
if (config.options.chkDisableTabsBar) return false;
if (!config.options.chkHideTabsBarWhenSingleTab) return true;
var cpt=0;
story.forEachTiddler(function(){cpt++});
return (cpt>1);
},
selectNextTab : function(){ //used when the current tab is closed (to select another tab)
var previous="";
story.forEachTiddler(function(title){
if (!config.macros.tiddlersBar.currentTiddler) {
story.displayTiddler(null,title);
return;
}
if (title==config.macros.tiddlersBar.currentTiddler) {
if (previous) {
story.displayTiddler(null,previous);
return;
}
else config.macros.tiddlersBar.currentTiddler=""; // so next tab will be selected
}
else previous=title;
});
},
onSelectTab : function(e){
var t = this.getAttribute("tiddler");
if (t) story.displayTiddler(null,t);
return false;
},
onTabClose : function(e){
var t = this.getAttribute("tiddler");
if (t) {
if(story.hasChanges(t) && !readOnly) {
if(!confirm(config.commands.cancelTiddler.warning.format([t])))
return false;
}
story.closeTiddler(t);
}
return false;
},
onTabSave : function(e) {
var t = this.getAttribute("tiddler");
if (!e) e=window.event;
if (t) config.commands.saveTiddler.handler(e,null,t);
return false;
},
onSelectedTabButtonClick : function(event,src,title) {
var t = this.getAttribute("tiddler");
if (!event) event=window.event;
if (t && config.options.txtSelectedTiddlerTabButton && config.commands[config.options.txtSelectedTiddlerTabButton])
config.commands[config.options.txtSelectedTiddlerTabButton].handler(event, src, t);
return false;
},
onTiddlersBarAction: function(event) {
var source = event.target ? event.target.id : event.srcElement.id; // FF uses target and IE uses srcElement;
if (source=="tiddlersBar") story.displayTiddler(null,'New Tiddler',DEFAULT_EDIT_TEMPLATE,false,null,null);
},
createActiveTabButton : function(place,title) {
if (config.options.txtSelectedTiddlerTabButton && config.commands[config.options.txtSelectedTiddlerTabButton]) {
var btn = createTiddlyButton(place, title, config.commands[config.options.txtSelectedTiddlerTabButton].tooltip ,config.macros.tiddlersBar.onSelectedTabButtonClick);
btn.setAttribute("tiddler", title);
}
else
createTiddlyText(place,title);
}
}
story.coreCloseTiddler = story.coreCloseTiddler? story.coreCloseTiddler : story.closeTiddler;
story.coreDisplayTiddler = story.coreDisplayTiddler ? story.coreDisplayTiddler : story.displayTiddler;
story.closeTiddler = function(title,animate,unused) {
if (title==config.macros.tiddlersBar.currentTiddler)
config.macros.tiddlersBar.selectNextTab();
story.coreCloseTiddler(title,false,unused); //disable animation to get it closed before calling tiddlersBar.refresh
var e=document.getElementById("tiddlersBar");
if (e) config.macros.tiddlersBar.refresh(e,null);
}
story.displayTiddler = function(srcElement,tiddler,template,animate,unused,customFields,toggle){
story.coreDisplayTiddler(config.macros.tiddlersBar.tabsAnimationSource,tiddler,template,animate,unused,customFields,toggle);
var title = (tiddler instanceof Tiddler)? tiddler.title : tiddler;
if (config.macros.tiddlersBar.isShown()) {
story.forEachTiddler(function(t,e){
if (t!=title) e.style.display="none";
else e.style.display="";
})
config.macros.tiddlersBar.currentTiddler=title;
}
var e=document.getElementById("tiddlersBar");
if (e) config.macros.tiddlersBar.refresh(e,null);
}
var coreRefreshPageTemplate = coreRefreshPageTemplate ? coreRefreshPageTemplate : refreshPageTemplate;
refreshPageTemplate = function(title) {
coreRefreshPageTemplate(title);
if (config.macros.tiddlersBar) config.macros.tiddlersBar.refresh(document.getElementById("tiddlersBar"));
}
ensureVisible=function (e) {return 0} //disable bottom scrolling (not useful now)
config.shadowTiddlers.StyleSheetTiddlersBar = "/*{{{*/\n";
config.shadowTiddlers.StyleSheetTiddlersBar += "#tiddlersBar .button {border:0}\n";
config.shadowTiddlers.StyleSheetTiddlersBar += "#tiddlersBar .tab {white-space:nowrap}\n";
config.shadowTiddlers.StyleSheetTiddlersBar += "#tiddlersBar {padding : 1em 0.5em 2px 0.5em}\n";
config.shadowTiddlers.StyleSheetTiddlersBar += ".tabUnselected .tabButton, .tabSelected .tabButton {padding : 0 2px 0 2px; margin: 0 0 0 4px;}\n";
config.shadowTiddlers.StyleSheetTiddlersBar += ".tiddler, .tabContents {border:1px [[ColorPalette::TertiaryPale]] solid;}\n";
config.shadowTiddlers.StyleSheetTiddlersBar +="/*}}}*/";
store.addNotification("StyleSheetTiddlersBar", refreshStyles);
config.refreshers.none = function(){return true;}
config.shadowTiddlers.PageTemplate=config.shadowTiddlers.PageTemplate.replace(/<div id='tiddlerDisplay'><\/div>/m,"<div id='tiddlersBar' refresh='none' ondblclick='config.macros.tiddlersBar.onTiddlersBarAction(event)'></div>\n<div id='tiddlerDisplay'></div>");
//}}}
/***
|''Name:''|MathSVGPlugin|
|''Description:''|This plugin translates a subset of the LaTeX math notation to MathML with a customisable image fallback when MathML is not supported. It also provides an easy way to produce mathematical SVG graphics with dynamical features and animation.|
|''Version:''|1.4.6|
|''Date:''|2012-12-29|
|''Source:''|http://www.math.ist.utl.pt/~psoares/MathSVG.html|
|''Author:''|Paulo Soares|
|''License:''|[[GNU Lesser General Public License|http://www.gnu.org/licences/lgpl.html]]|
|''~CoreVersion:''|2.5.0|
!Original copyright notice
{{{
ASCIIMathML.js
==============
Version 2.1 Oct 8, 2008, (c) Peter Jipsen http://www.chapman.edu/~jipsen
This version extends ASCIIMathML.js with LaTeXMathML.js and ASCIIsvg.js.
Latest version at http://www.chapman.edu/~jipsen/mathml/ASCIIMathML.js
If you use it on a webpage, please send the URL to jipsen@chapman.edu
The LaTeXMathML modifications were made by Douglas Woodall, June 2006.
(for details see header on the LaTeXMathML part in middle of file)
Extensive clean-up and improvements by Paulo Soares, Oct 2007.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
(at http://www.gnu.org/licences/lgpl.html) for more details.
}}}
!~MathSVG code (minified)
***/
//{{{
Math.sec=function(a){return 1/Math.cos(a)};Math.csc=function(a){return 1/Math.sin(a)};Math.cot=function(a){return 1/Math.tan(a)};Math.asec=function(a){return Math.acos(1/a)};Math.acsc=function(a){return Math.asin(1/a)};Math.acot=function(a){return Math.atan(1/a)};Math.sinh=function(a){return(Math.exp(a)-Math.exp(-a))/2};Math.cosh=function(a){return(Math.exp(a)+Math.exp(-a))/2};Math.tanh=function(a){return(Math.exp(a)-Math.exp(-a))/(Math.exp(a)+Math.exp(-a))};Math.sech=function(a){return 1/Math.cosh(a)};Math.csch=function(a){return 1/Math.sinh(a)};Math.coth=function(a){return 1/Math.tanh(a)};Math.asinh=function(a){return Math.log(a+Math.sqrt(a*a+1))};Math.acosh=function(a){return Math.log(a+Math.sqrt(a*a-1))};Math.atanh=function(a){return Math.log((1+a)/(1-a))/2};Math.sech=function(a){return 1/Math.cosh(a)};Math.csch=function(a){return 1/Math.sinh(a)};Math.coth=function(a){return 1/Math.tanh(a)};Math.asech=function(a){return Math.acosh(1/a)};Math.acsch=function(a){return Math.asinh(1/a)};Math.acoth=function(a){return Math.atanh(1/a)};Math.sign=function(a){return(a===0?0:(a<0?-1:1))};Math.step=function(a,c,b){return(a<0?(b?b:0):(c?c:1))};Math.root=function(a,b){return Math.pow(a,1/b)};Math.factorial=function(b){if(b===0){return 1}if(b<0){if((b%1)===0){return}if(b>-1){return Math.factorial(b+1)/(b+1)}return -Math.PI/(Math.factorial(-1-b)*Math.sin(Math.PI*b))}var a=b;if((b%1)===0){while(b>1){b=b-1;a=a*b}}else{a=Math.exp((b+0.5)*Math.log(b+1)-b-b*(0.1121105+b*0.08106103)/(1.452342+b*(2.410858+b)))}return a};Math.Gamma=function(a){return Math.factorial(a-1)};Math.Beta=function(a,b){return Math.Gamma(a)*Math.Gamma(b)/Math.Gamma(a+b)};Math.C=function(a,b){var c=1/((a+1)*Math.Beta(b+1,a-b+1));return c};Math.truncate=function(a,c){var b=c||0;return Math.floor(a*Math.pow(10,b))/Math.pow(10,b)};Math.randomString=function(a,g){var f=(g||"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz").split("");var e=[],c=Math.random;var d=f.length;for(var b=0;b<a;b++){e[b]=f[0|c()*d]}return e.join("")};Math.runif=function(d,c,f){var e=f||0;return Math.truncate((c+Math.pow(10,-e)-d)*Math.random()+d,e)};Math.rnormal=function(a,b){a=a||0;b=b||1;var d=0,c=0;while(d*c===0){d=Math.random();c=Math.random()}return b*(Math.sqrt(-2*Math.log(d))*Math.cos(2*Math.PI*c))+a};(function(){var a=jQuery.fn.attr,b="http://www.w3.org/2000/svg";jQuery.fn.attr=function(m,l){var g=this.length;if(!g){return this}for(var f=0;f<g;f++){var c=this[f];if(c.namespaceURI===b){if(l!==undefined){c.setAttribute(m,l)}else{if($.isArray(m)){var d=m.length,e={};while(d--){var k=m[d];var h=c.getAttribute(k);if(h||h==="0"){h=isNaN(h)?h:h-0}e[k]=h}return e}else{if(typeof m==="object"){for(v in m){c.setAttribute(v,m[v])}}else{var h=c.getAttribute(m);if(h||h==="0"){h=isNaN(h)?h:h-0}return h}}}}else{return a.apply(this,arguments)}}return this}}());var MSVG=function($){var cal=["\uD835\uDC9C","\u212C","\uD835\uDC9E","\uD835\uDC9F","\u2130","\u2131","\uD835\uDCA2","\u210B","\u2110","\uD835\uDCA5","\uD835\uDCA6","\u2112","\u2133","\uD835\uDCA9","\uD835\uDCAA","\uD835\uDCAB","\uD835\uDCAC","\u211B","\uD835\uDCAE","\uD835\uDCAF","\uD835\uDCB0","\uD835\uDCB1","\uD835\uDCB2","\uD835\uDCB3","\uD835\uDCB4","\uD835\uDCB5","\uD835\uDCB6","\uD835\uDCB7","\uD835\uDCB8","\uD835\uDCB9","\u212F","\uD835\uDCBB","\u210A","\uD835\uDCBD","\uD835\uDCBE","\uD835\uDCBF","\uD835\uDCC0","\uD835\uDCC1","\uD835\uDCC2","\uD835\uDCC3","\u2134","\uD835\uDCC5","\uD835\uDCC6","\uD835\uDCC7","\uD835\uDCC8","\uD835\uDCC9","\uD835\uDCCA","\uD835\uDCCB","\uD835\uDCCC","\uD835\uDCCD","\uD835\uDCCE","\uD835\uDCCF"];var frk=["\uD835\uDD04","\uD835\uDD05","\u212D","\uD835\uDD07","\uD835\uDD08","\uD835\uDD09","\uD835\uDD0A","\u210C","\u2111","\uD835\uDD0D","\uD835\uDD0E","\uD835\uDD0F","\uD835\uDD10","\uD835\uDD11","\uD835\uDD12","\uD835\uDD13","\uD835\uDD14","\u211C","\uD835\uDD16","\uD835\uDD17","\uD835\uDD18","\uD835\uDD19","\uD835\uDD1A","\uD835\uDD1B","\uD835\uDD1C","\u2128","\uD835\uDD1E","\uD835\uDD1F","\uD835\uDD20","\uD835\uDD21","\uD835\uDD22","\uD835\uDD23","\uD835\uDD24","\uD835\uDD25","\uD835\uDD26","\uD835\uDD27","\uD835\uDD28","\uD835\uDD29","\uD835\uDD2A","\uD835\uDD2B","\uD835\uDD2C","\uD835\uDD2D","\uD835\uDD2E","\uD835\uDD2F","\uD835\uDD30","\uD835\uDD31","\uD835\uDD32","\uD835\uDD33","\uD835\uDD34","\uD835\uDD35","\uD835\uDD36","\uD835\uDD37"];var bbb=["\uD835\uDD38","\uD835\uDD39","\u2102","\uD835\uDD3B","\uD835\uDD3C","\uD835\uDD3D","\uD835\uDD3E","\u210D","\uD835\uDD40","\uD835\uDD41","\uD835\uDD42","\uD835\uDD43","\uD835\uDD44","\u2115","\uD835\uDD46","\u2119","\u211A","\u211D","\uD835\uDD4A","\uD835\uDD4B","\uD835\uDD4C","\uD835\uDD4D","\uD835\uDD4E","\uD835\uDD4F","\uD835\uDD50","\u2124","\uD835\uDD52","\uD835\uDD53","\uD835\uDD54","\uD835\uDD55","\uD835\uDD56","\uD835\uDD57","\uD835\uDD58","\uD835\uDD59","\uD835\uDD5A","\uD835\uDD5B","\uD835\uDD5C","\uD835\uDD5D","\uD835\uDD5E","\uD835\uDD5F","\uD835\uDD60","\uD835\uDD61","\uD835\uDD62","\uD835\uDD63","\uD835\uDD64","\uD835\uDD65","\uD835\uDD66","\uD835\uDD67","\uD835\uDD68","\uD835\uDD69","\uD835\uDD6A","\uD835\uDD6B"];var CONST=0,UNARY=1,BINARY=2,INFIX=3,LEFTBRACKET=4,RIGHTBRACKET=5,SPACE=6,UNDEROVER=7,DEFINITION=8,LEFTRIGHT=9,TEXT=10,BIG=11,STRETCHY=13,MATRIX=14;var symbols=[{input:"\\varepsilon",tag:"mi",output:"\u025B",ttype:CONST},{input:"\\varsigma",tag:"mi",output:"\u03C2",ttype:CONST},{input:"\\vartheta",tag:"mi",output:"\u03D1",ttype:CONST},{input:"\\varphi",tag:"mi",output:"\u03D5",ttype:CONST},{input:"\\varpi",tag:"mi",output:"\u03D6",ttype:CONST},{input:"\\varrho",tag:"mi",output:"\u03F1",ttype:CONST},{input:"\\alpha",tag:"mi",output:"\u03B1",ttype:CONST},{input:"\\beta",tag:"mi",output:"\u03B2",ttype:CONST},{input:"\\gamma",tag:"mi",output:"\u03B3",ttype:CONST},{input:"\\delta",tag:"mi",output:"\u03B4",ttype:CONST},{input:"\\epsilon",tag:"mi",output:"\u03B5",ttype:CONST},{input:"\\zeta",tag:"mi",output:"\u03B6",ttype:CONST},{input:"\\eta",tag:"mi",output:"\u03B7",ttype:CONST},{input:"\\theta",tag:"mi",output:"\u03B8",ttype:CONST},{input:"\\iota",tag:"mi",output:"\u03B9",ttype:CONST},{input:"\\kappa",tag:"mi",output:"\u03BA",ttype:CONST},{input:"\\lambda",tag:"mi",output:"\u03BB",ttype:CONST},{input:"\\mu",tag:"mi",output:"\u03BC",ttype:CONST},{input:"\\nu",tag:"mi",output:"\u03BD",ttype:CONST},{input:"\\xi",tag:"mi",output:"\u03BE",ttype:CONST},{input:"\\omicron",tag:"mi",output:"\u03BF",ttype:CONST},{input:"\\pi",tag:"mi",output:"\u03C0",ttype:CONST},{input:"\\rho",tag:"mi",output:"\u03C1",ttype:CONST},{input:"\\sigma",tag:"mi",output:"\u03C3",ttype:CONST},{input:"\\tau",tag:"mi",output:"\u03C4",ttype:CONST},{input:"\\upsilon",tag:"mi",output:"\u03C5",ttype:CONST},{input:"\\phi",tag:"mi",output:"\u03C6",ttype:CONST},{input:"\\chi",tag:"mi",output:"\u03C7",ttype:CONST},{input:"\\psi",tag:"mi",output:"\u03C8",ttype:CONST},{input:"\\omega",tag:"mi",output:"\u03C9",ttype:CONST},{input:"\\Alpha",tag:"mo",output:"\u0391",ttype:CONST},{input:"\\Beta",tag:"mo",output:"\u0392",ttype:CONST},{input:"\\Gamma",tag:"mo",output:"\u0393",ttype:CONST},{input:"\\Delta",tag:"mo",output:"\u0394",ttype:CONST},{input:"\\Epsilon",tag:"mo",output:"\u0395",ttype:CONST},{input:"\\Zeta",tag:"mo",output:"\u0396",ttype:CONST},{input:"\\Eta",tag:"mo",output:"\u0397",ttype:CONST},{input:"\\Theta",tag:"mo",output:"\u0398",ttype:CONST},{input:"\\Iota",tag:"mo",output:"\u0399",ttype:CONST},{input:"\\Kappa",tag:"mo",output:"\u039A",ttype:CONST},{input:"\\Lambda",tag:"mo",output:"\u039B",ttype:CONST},{input:"\\Mu",tag:"mo",output:"\u039C",ttype:CONST},{input:"\\Nu",tag:"mo",output:"\u039D",ttype:CONST},{input:"\\Xi",tag:"mo",output:"\u039E",ttype:CONST},{input:"\\Omicron",tag:"mo",output:"\u039F",ttype:CONST},{input:"\\Pi",tag:"mo",output:"\u03A0",ttype:CONST},{input:"\\Rho",tag:"mo",output:"\u03A1",ttype:CONST},{input:"\\Sigma",tag:"mo",output:"\u03A3",ttype:CONST},{input:"\\Tau",tag:"mo",output:"\u03A4",ttype:CONST},{input:"\\Upsilon",tag:"mo",output:"\u03A5",ttype:CONST},{input:"\\Phi",tag:"mo",output:"\u03A6",ttype:CONST},{input:"\\Chi",tag:"mo",output:"\u03A7",ttype:CONST},{input:"\\Psi",tag:"mo",output:"\u03A8",ttype:CONST},{input:"\\Omega",tag:"mo",output:"\u03A9",ttype:CONST},{input:"\\frac12",tag:"mo",output:"\u00BD",ttype:CONST},{input:"\\frac14",tag:"mo",output:"\u00BC",ttype:CONST},{input:"\\frac34",tag:"mo",output:"\u00BE",ttype:CONST},{input:"\\frac13",tag:"mo",output:"\u2153",ttype:CONST},{input:"\\frac23",tag:"mo",output:"\u2154",ttype:CONST},{input:"\\frac15",tag:"mo",output:"\u2155",ttype:CONST},{input:"\\frac25",tag:"mo",output:"\u2156",ttype:CONST},{input:"\\frac35",tag:"mo",output:"\u2157",ttype:CONST},{input:"\\frac45",tag:"mo",output:"\u2158",ttype:CONST},{input:"\\frac16",tag:"mo",output:"\u2159",ttype:CONST},{input:"\\frac56",tag:"mo",output:"\u215A",ttype:CONST},{input:"\\frac18",tag:"mo",output:"\u215B",ttype:CONST},{input:"\\frac38",tag:"mo",output:"\u215C",ttype:CONST},{input:"\\frac58",tag:"mo",output:"\u215D",ttype:CONST},{input:"\\frac78",tag:"mo",output:"\u215E",ttype:CONST},{input:"\\pm",tag:"mo",output:"\u00B1",ttype:CONST},{input:"\\mp",tag:"mo",output:"\u2213",ttype:CONST},{input:"\\triangleleft",tag:"mo",output:"\u22B2",ttype:CONST},{input:"\\triangleright",tag:"mo",output:"\u22B3",ttype:CONST},{input:"\\cdot",tag:"mo",output:"\u22C5",ttype:CONST},{input:"\\star",tag:"mo",output:"\u22C6",ttype:CONST},{input:"\\ast",tag:"mo",output:"\u002A",ttype:CONST},{input:"\\times",tag:"mo",output:"\u00D7",ttype:CONST},{input:"\\div",tag:"mo",output:"\u00F7",ttype:CONST},{input:"\\circ",tag:"mo",output:"\u2218",ttype:CONST},{input:"\\bullet",tag:"mo",output:"\u2022",ttype:CONST},{input:"\\oplus",tag:"mo",output:"\u2295",ttype:CONST},{input:"\\ominus",tag:"mo",output:"\u2296",ttype:CONST},{input:"\\otimes",tag:"mo",output:"\u2297",ttype:CONST},{input:"\\bigcirc",tag:"mo",output:"\u25CB",ttype:CONST},{input:"\\oslash",tag:"mo",output:"\u2298",ttype:CONST},{input:"\\odot",tag:"mo",output:"\u2299",ttype:CONST},{input:"\\land",tag:"mo",output:"\u2227",ttype:CONST},{input:"\\wedge",tag:"mo",output:"\u2227",ttype:CONST},{input:"\\lor",tag:"mo",output:"\u2228",ttype:CONST},{input:"\\vee",tag:"mo",output:"\u2228",ttype:CONST},{input:"\\cap",tag:"mo",output:"\u2229",ttype:CONST},{input:"\\cup",tag:"mo",output:"\u222A",ttype:CONST},{input:"\\sqcap",tag:"mo",output:"\u2293",ttype:CONST},{input:"\\sqcup",tag:"mo",output:"\u2294",ttype:CONST},{input:"\\uplus",tag:"mo",output:"\u228E",ttype:CONST},{input:"\\amalg",tag:"mo",output:"\u2210",ttype:CONST},{input:"\\bigtriangleup",tag:"mo",output:"\u25B3",ttype:CONST},{input:"\\bigtriangledown",tag:"mo",output:"\u25BD",ttype:CONST},{input:"\\dag",tag:"mo",output:"\u2020",ttype:CONST},{input:"\\dagger",tag:"mo",output:"\u2020",ttype:CONST},{input:"\\ddag",tag:"mo",output:"\u2021",ttype:CONST},{input:"\\ddagger",tag:"mo",output:"\u2021",ttype:CONST},{input:"\\lhd",tag:"mo",output:"\u22B2",ttype:CONST},{input:"\\rhd",tag:"mo",output:"\u22B3",ttype:CONST},{input:"\\unlhd",tag:"mo",output:"\u22B4",ttype:CONST},{input:"\\unrhd",tag:"mo",output:"\u22B5",ttype:CONST},{input:"\\sum",tag:"mo",output:"\u2211",ttype:UNDEROVER},{input:"\\prod",tag:"mo",output:"\u220F",ttype:UNDEROVER},{input:"\\bigcap",tag:"mo",output:"\u22C2",ttype:UNDEROVER},{input:"\\bigcup",tag:"mo",output:"\u22C3",ttype:UNDEROVER},{input:"\\bigwedge",tag:"mo",output:"\u22C0",ttype:UNDEROVER},{input:"\\bigvee",tag:"mo",output:"\u22C1",ttype:UNDEROVER},{input:"\\bigsqcap",tag:"mo",output:"\u2A05",ttype:UNDEROVER},{input:"\\bigsqcup",tag:"mo",output:"\u2A06",ttype:UNDEROVER},{input:"\\coprod",tag:"mo",output:"\u2210",ttype:UNDEROVER},{input:"\\bigoplus",tag:"mo",output:"\u2A01",ttype:UNDEROVER},{input:"\\bigotimes",tag:"mo",output:"\u2A02",ttype:UNDEROVER},{input:"\\bigodot",tag:"mo",output:"\u2A00",ttype:UNDEROVER},{input:"\\biguplus",tag:"mo",output:"\u2A04",ttype:UNDEROVER},{input:"\\int",tag:"mo",output:"\u222B",ttype:CONST},{input:"\\oint",tag:"mo",output:"\u222E",ttype:CONST},{input:":=",tag:"mo",output:":=",ttype:CONST},{input:"\\lt",tag:"mo",output:"<",ttype:CONST},{input:"\\gt",tag:"mo",output:">",ttype:CONST},{input:"\\ne",tag:"mo",output:"\u2260",ttype:CONST},{input:"\\neq",tag:"mo",output:"\u2260",ttype:CONST},{input:"\\le",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\leq",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\leqslant",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\ge",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\geq",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\geqslant",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\equiv",tag:"mo",output:"\u2261",ttype:CONST},{input:"\\ll",tag:"mo",output:"\u226A",ttype:CONST},{input:"\\gg",tag:"mo",output:"\u226B",ttype:CONST},{input:"\\doteq",tag:"mo",output:"\u2250",ttype:CONST},{input:"\\prec",tag:"mo",output:"\u227A",ttype:CONST},{input:"\\succ",tag:"mo",output:"\u227B",ttype:CONST},{input:"\\preceq",tag:"mo",output:"\u227C",ttype:CONST},{input:"\\succeq",tag:"mo",output:"\u227D",ttype:CONST},{input:"\\subset",tag:"mo",output:"\u2282",ttype:CONST},{input:"\\supset",tag:"mo",output:"\u2283",ttype:CONST},{input:"\\subseteq",tag:"mo",output:"\u2286",ttype:CONST},{input:"\\supseteq",tag:"mo",output:"\u2287",ttype:CONST},{input:"\\sqsubset",tag:"mo",output:"\u228F",ttype:CONST},{input:"\\sqsupset",tag:"mo",output:"\u2290",ttype:CONST},{input:"\\sqsubseteq",tag:"mo",output:"\u2291",ttype:CONST},{input:"\\sqsupseteq",tag:"mo",output:"\u2292",ttype:CONST},{input:"\\sim",tag:"mo",output:"\u223C",ttype:CONST},{input:"\\simeq",tag:"mo",output:"\u2243",ttype:CONST},{input:"\\approx",tag:"mo",output:"\u2248",ttype:CONST},{input:"\\cong",tag:"mo",output:"\u2245",ttype:CONST},{input:"\\Join",tag:"mo",output:"\u22C8",ttype:CONST},{input:"\\bowtie",tag:"mo",output:"\u22C8",ttype:CONST},{input:"\\in",tag:"mo",output:"\u2208",ttype:CONST},{input:"\\ni",tag:"mo",output:"\u220B",ttype:CONST},{input:"\\owns",tag:"mo",output:"\u220B",ttype:CONST},{input:"\\propto",tag:"mo",output:"\u221D",ttype:CONST},{input:"\\vdash",tag:"mo",output:"\u22A2",ttype:CONST},{input:"\\dashv",tag:"mo",output:"\u22A3",ttype:CONST},{input:"\\models",tag:"mo",output:"\u22A8",ttype:CONST},{input:"\\perp",tag:"mo",output:"\u22A5",ttype:CONST},{input:"\\smile",tag:"mo",output:"\u2323",ttype:CONST},{input:"\\frown",tag:"mo",output:"\u2322",ttype:CONST},{input:"\\asymp",tag:"mo",output:"\u224D",ttype:CONST},{input:"\\notin",tag:"mo",output:"\u2209",ttype:CONST},{input:"\\begin{eqnarray}",output:"X",ttype:MATRIX,invisible:true},{input:"\\begin{array}",output:"X",ttype:MATRIX,invisible:true},{input:"\\\\",output:"}&{",ttype:DEFINITION},{input:"\\end{eqnarray}",output:"}}",ttype:DEFINITION},{input:"\\end{array}",output:"}}",ttype:DEFINITION},{input:"\\big",tag:"mo",output:"X",atval:"1.2",ttype:BIG},{input:"\\Big",tag:"mo",output:"X",atval:"1.8",ttype:BIG},{input:"\\bigg",tag:"mo",output:"X",atval:"2.3",ttype:BIG},{input:"\\Bigg",tag:"mo",output:"X",atval:"2.9",ttype:BIG},{input:"\\left",tag:"mo",output:"X",ttype:LEFTBRACKET},{input:"\\right",tag:"mo",output:"X",ttype:RIGHTBRACKET},{input:"{",output:"{",ttype:LEFTBRACKET,invisible:true},{input:"}",output:"}",ttype:RIGHTBRACKET,invisible:true},{input:"(",tag:"mo",output:"(",atval:"1",ttype:STRETCHY},{input:"[",tag:"mo",output:"[",atval:"1",ttype:STRETCHY},{input:"\\lbrack",tag:"mo",output:"[",atval:"1",ttype:STRETCHY},{input:"\\{",tag:"mo",output:"{",atval:"1",ttype:STRETCHY},{input:"\\lbrace",tag:"mo",output:"{",atval:"1",ttype:STRETCHY},{input:"\\langle",tag:"mo",output:"\u2329",atval:"1",ttype:STRETCHY},{input:"\\lfloor",tag:"mo",output:"\u230A",atval:"1",ttype:STRETCHY},{input:"\\lceil",tag:"mo",output:"\u2308",atval:"1",ttype:STRETCHY},{input:")",tag:"mo",output:")",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"]",tag:"mo",output:"]",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rbrack",tag:"mo",output:"]",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\}",tag:"mo",output:"}",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rbrace",tag:"mo",output:"}",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rangle",tag:"mo",output:"\u232A",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rfloor",tag:"mo",output:"\u230B",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rceil",tag:"mo",output:"\u2309",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"|",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\|",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"\\vert",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\Vert",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"\\mid",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\parallel",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"/",tag:"mo",output:"/",atval:"1.01",ttype:STRETCHY},{input:"\\backslash",tag:"mo",output:"\u2216",atval:"1",ttype:STRETCHY},{input:"\\setminus",tag:"mo",output:"\\",ttype:CONST},{input:"\\!",tag:"mspace",atname:"width",atval:"-0.167em",ttype:SPACE},{input:"\\,",tag:"mspace",atname:"width",atval:"0.167em",ttype:SPACE},{input:"\\>",tag:"mspace",atname:"width",atval:"0.222em",ttype:SPACE},{input:"\\:",tag:"mspace",atname:"width",atval:"0.222em",ttype:SPACE},{input:"\\;",tag:"mspace",atname:"width",atval:"0.278em",ttype:SPACE},{input:"~",tag:"mspace",atname:"width",atval:"0.333em",ttype:SPACE},{input:"\\quad",tag:"mspace",atname:"width",atval:"1em",ttype:SPACE},{input:"\\qquad",tag:"mspace",atname:"width",atval:"2em",ttype:SPACE},{input:"\\prime",tag:"mo",output:"\u2032",ttype:CONST},{input:"'",tag:"mo",output:"\u02B9",ttype:CONST},{input:"''",tag:"mo",output:"\u02BA",ttype:CONST},{input:"'''",tag:"mo",output:"\u2034",ttype:CONST},{input:"''''",tag:"mo",output:"\u2057",ttype:CONST},{input:"\\ldots",tag:"mo",output:"\u2026",ttype:CONST},{input:"\\cdots",tag:"mo",output:"\u22EF",ttype:CONST},{input:"\\vdots",tag:"mo",output:"\u22EE",ttype:CONST},{input:"\\ddots",tag:"mo",output:"\u22F1",ttype:CONST},{input:"\\forall",tag:"mo",output:"\u2200",ttype:CONST},{input:"\\exists",tag:"mo",output:"\u2203",ttype:CONST},{input:"\\Re",tag:"mo",output:"\u211C",ttype:CONST},{input:"\\Im",tag:"mo",output:"\u2111",ttype:CONST},{input:"\\aleph",tag:"mo",output:"\u2135",ttype:CONST},{input:"\\hbar",tag:"mo",output:"\u210F",ttype:CONST},{input:"\\ell",tag:"mo",output:"\u2113",ttype:CONST},{input:"\\wp",tag:"mo",output:"\u2118",ttype:CONST},{input:"\\emptyset",tag:"mo",output:"\u2205",ttype:CONST},{input:"\\infty",tag:"mo",output:"\u221E",ttype:CONST},{input:"\\surd",tag:"mo",output:"\\sqrt{}",ttype:DEFINITION},{input:"\\partial",tag:"mo",output:"\u2202",ttype:CONST},{input:"\\nabla",tag:"mo",output:"\u2207",ttype:CONST},{input:"\\triangle",tag:"mo",output:"\u25B3",ttype:CONST},{input:"\\therefore",tag:"mo",output:"\u2234",ttype:CONST},{input:"\\angle",tag:"mo",output:"\u2220",ttype:CONST},{input:"\\diamond",tag:"mo",output:"\u22C4",ttype:CONST},{input:"\\Diamond",tag:"mo",output:"\u25C7",ttype:CONST},{input:"\\neg",tag:"mo",output:"\u00AC",ttype:CONST},{input:"\\lnot",tag:"mo",output:"\u00AC",ttype:CONST},{input:"\\bot",tag:"mo",output:"\u22A5",ttype:CONST},{input:"\\top",tag:"mo",output:"\u22A4",ttype:CONST},{input:"\\square",tag:"mo",output:"\u25AB",ttype:CONST},{input:"\\Box",tag:"mo",output:"\u25A1",ttype:CONST},{input:"\\wr",tag:"mo",output:"\u2240",ttype:CONST},{input:"\\arccos",tag:"mi",output:"arccos",ttype:UNARY,func:true},{input:"\\arcsin",tag:"mi",output:"arcsin",ttype:UNARY,func:true},{input:"\\arctan",tag:"mi",output:"arctan",ttype:UNARY,func:true},{input:"\\arg",tag:"mi",output:"arg",ttype:UNARY,func:true},{input:"\\cos",tag:"mi",output:"cos",ttype:UNARY,func:true},{input:"\\cosh",tag:"mi",output:"cosh",ttype:UNARY,func:true},{input:"\\cot",tag:"mi",output:"cot",ttype:UNARY,func:true},{input:"\\coth",tag:"mi",output:"coth",ttype:UNARY,func:true},{input:"\\csc",tag:"mi",output:"csc",ttype:UNARY,func:true},{input:"\\deg",tag:"mi",output:"deg",ttype:UNARY,func:true},{input:"\\det",tag:"mi",output:"det",ttype:UNARY,func:true},{input:"\\dim",tag:"mi",output:"dim",ttype:UNARY,func:true},{input:"\\exp",tag:"mi",output:"exp",ttype:UNARY,func:true},{input:"\\gcd",tag:"mi",output:"gcd",ttype:UNARY,func:true},{input:"\\hom",tag:"mi",output:"hom",ttype:UNARY,func:true},{input:"\\inf",tag:"mo",output:"inf",ttype:UNDEROVER},{input:"\\ker",tag:"mi",output:"ker",ttype:UNARY,func:true},{input:"\\lg",tag:"mi",output:"lg",ttype:UNARY,func:true},{input:"\\lim",tag:"mo",output:"lim",ttype:UNDEROVER},{input:"\\liminf",tag:"mo",output:"liminf",ttype:UNDEROVER},{input:"\\limsup",tag:"mo",output:"limsup",ttype:UNDEROVER},{input:"\\ln",tag:"mi",output:"ln",ttype:UNARY,func:true},{input:"\\log",tag:"mi",output:"log",ttype:UNARY,func:true},{input:"\\max",tag:"mo",output:"max",ttype:UNDEROVER},{input:"\\min",tag:"mo",output:"min",ttype:UNDEROVER},{input:"\\Pr",tag:"mi",output:"Pr",ttype:UNARY,func:true},{input:"\\sec",tag:"mi",output:"sec",ttype:UNARY,func:true},{input:"\\sin",tag:"mi",output:"sin",ttype:UNARY,func:true},{input:"\\sinh",tag:"mi",output:"sinh",ttype:UNARY,func:true},{input:"\\sup",tag:"mo",output:"sup",ttype:UNDEROVER},{input:"\\tan",tag:"mi",output:"tan",ttype:UNARY,func:true},{input:"\\tanh",tag:"mi",output:"tanh",ttype:UNARY,func:true},{input:"\\gets",tag:"mo",output:"\u2190",ttype:CONST},{input:"\\leftarrow",tag:"mo",output:"\u2190",ttype:CONST},{input:"\\to",tag:"mo",output:"\u2192",ttype:CONST},{input:"\\rightarrow",tag:"mo",output:"\u2192",ttype:CONST},{input:"\\leftrightarrow",tag:"mo",output:"\u2194",ttype:CONST},{input:"\\uparrow",tag:"mo",output:"\u2191",ttype:CONST},{input:"\\downarrow",tag:"mo",output:"\u2193",ttype:CONST},{input:"\\updownarrow",tag:"mo",output:"\u2195",ttype:CONST},{input:"\\Leftarrow",tag:"mo",output:"\u21D0",ttype:CONST},{input:"\\Rightarrow",tag:"mo",output:"\u21D2",ttype:CONST},{input:"\\Leftrightarrow",tag:"mo",output:"\u21D4",ttype:CONST},{input:"\\iff",tag:"mo",output:"~\\Longleftrightarrow~",ttype:DEFINITION},{input:"\\Uparrow",tag:"mo",output:"\u21D1",ttype:CONST},{input:"\\Downarrow",tag:"mo",output:"\u21D3",ttype:CONST},{input:"\\Updownarrow",tag:"mo",output:"\u21D5",ttype:CONST},{input:"\\mapsto",tag:"mo",output:"\u21A6",ttype:CONST},{input:"\\longleftarrow",tag:"mo",output:"\u27F5",ttype:CONST},{input:"\\longrightarrow",tag:"mo",output:"\u27F6",ttype:CONST},{input:"\\longleftrightarrow",tag:"mo",output:"\u27F7",ttype:CONST},{input:"\\Longleftarrow",tag:"mo",output:"\u27F8",ttype:CONST},{input:"\\Longrightarrow",tag:"mo",output:"\u27F9",ttype:CONST},{input:"\\Longleftrightarrow",tag:"mo",output:"\u27FA",ttype:CONST},{input:"\\longmapsto",tag:"mo",output:"\u27FC",ttype:CONST},{input:"\\sqrt",tag:"msqrt",output:"sqrt",ttype:UNARY},{input:"\\root",tag:"mroot",output:"root",ttype:BINARY},{input:"\\frac",tag:"mfrac",output:"/",ttype:BINARY},{input:"\\bfrac",tag:"mfrac",output:"/",ttype:BINARY},{input:"\\stackrel",tag:"mover",output:"stackrel",ttype:BINARY},{input:"\\atop",tag:"mfrac",output:"",ttype:INFIX},{input:"\\choose",tag:"mfrac",output:"",ttype:INFIX},{input:"\\over",tag:"mfrac",output:"/",ttype:INFIX},{input:"_",tag:"msub",output:"_",ttype:INFIX},{input:"^",tag:"msup",output:"^",ttype:INFIX},{input:"\\mbox",tag:"mtext",output:"mbox",ttype:TEXT},{input:"\\acute",tag:"mover",output:"\u00B4",ttype:UNARY,acc:true},{input:"\\grave",tag:"mover",output:"\u0060",ttype:UNARY,acc:true},{input:"\\breve",tag:"mover",output:"\u02D8",ttype:UNARY,acc:true},{input:"\\check",tag:"mover",output:"\u02C7",ttype:UNARY,acc:true},{input:"\\dot",tag:"mover",output:".",ttype:UNARY,acc:true},{input:"\\ddot",tag:"mover",output:"..",ttype:UNARY,acc:true},{input:"\\mathring",tag:"mover",output:"\u00B0",ttype:UNARY,acc:true},{input:"\\vec",tag:"mover",output:"\u2192",ttype:UNARY,acc:true},{input:"\\overrightarrow",tag:"mover",output:"\u2192",ttype:UNARY,acc:true},{input:"\\overleftarrow",tag:"mover",output:"\u2190",ttype:UNARY,acc:true},{input:"\\hat",tag:"mover",output:"\u005E",ttype:UNARY,acc:true},{input:"\\widehat",tag:"mover",output:"\u0302",ttype:UNARY,acc:true},{input:"\\tilde",tag:"mover",output:"~",ttype:UNARY,acc:true},{input:"\\widetilde",tag:"mover",output:"\u02DC",ttype:UNARY,acc:true},{input:"\\bar",tag:"mover",output:"\u203E",ttype:UNARY,acc:true},{input:"\\overbrace",tag:"mover",output:"\u23B4",ttype:UNARY,acc:true},{input:"\\overline",tag:"mover",output:"\u00AF",ttype:UNARY,acc:true},{input:"\\underbrace",tag:"munder",output:"\u23B5",ttype:UNARY,acc:true},{input:"\\underline",tag:"munder",output:"\u00AF",ttype:UNARY,acc:true},{input:"\\displaystyle",tag:"mstyle",atname:"displaystyle",atval:"true",ttype:UNARY},{input:"\\textstyle",tag:"mstyle",atname:"displaystyle",atval:"false",ttype:UNARY},{input:"\\scriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"1",ttype:UNARY},{input:"\\scriptscriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"2",ttype:UNARY},{input:"\\mathrm",tag:"mtext",output:"text",ttype:TEXT},{input:"\\textrm",tag:"mtext",output:"text",ttype:TEXT},{input:"\\mathbf",tag:"mstyle",atname:"mathvariant",atval:"bold",ttype:UNARY},{input:"\\textbf",tag:"mstyle",atname:"mathvariant",atval:"bold",ttype:UNARY},{input:"\\mathit",tag:"mstyle",atname:"mathvariant",atval:"italic",ttype:UNARY},{input:"\\textit",tag:"mstyle",atname:"mathvariant",atval:"italic",ttype:UNARY},{input:"\\mathtt",tag:"mstyle",atname:"mathvariant",atval:"monospace",ttype:UNARY},{input:"\\texttt",tag:"mstyle",atname:"mathvariant",atval:"monospace",ttype:UNARY},{input:"\\mathsf",tag:"mstyle",atname:"mathvariant",atval:"sans-serif",ttype:UNARY},{input:"\\mathbb",tag:"mstyle",atname:"mathvariant",atval:"double-struck",ttype:UNARY,codes:bbb},{input:"\\mathcal",tag:"mstyle",atname:"mathvariant",atval:"script",ttype:UNARY,codes:cal},{input:"\\mathfrak",tag:"mstyle",atname:"mathvariant",atval:"fraktur",ttype:UNARY,codes:frk}];var names=[];var mathVariant="italic";if(!document.createElementNS){document.createElementNS=function(link,type){return this.createElement(type)}}function compareNames(x,y){if(x.input>y.input){return 1}else{return -1}}function refreshSymbols(){var len=symbols.length;symbols.sort(compareNames);for(var i=0;i<len;i++){names[i]=symbols[i].input}}function strim(str,n){return $.trim(str.slice(n))}function createElementXHTML(elType){return document.createElementNS("http://www.w3.org/1999/xhtml",elType)}function position(str,n){var pos=$.inArray(str,names.slice(n));if(pos<0){var narr=names.concat([str]);narr.sort();pos=$.inArray(str,narr.slice(n))}return n+pos}function getSymbol(str){var k=0;var j=0;var mk;var st;var tagst;var match="";var more=true;var sLen=str.length;for(var i=1;i<=sLen&&more;i++){st=str.slice(0,i);j=k;k=position(st,j);if(k<names.length&&str.slice(0,names[k].length)==names[k]){match=names[k];mk=k;i=match.length}more=k<names.length&&str.slice(0,names[k].length)>=names[k]}if(match!==""){return symbols[mk]}k=1;st=str.slice(0,1);if("0"<=st&&st<="9"){tagst="mn"}else{tagst=(("A">st||st>"Z")&&("a">st||st>"z")?"mo":"mi")}return{input:st,tag:tagst,output:st,ttype:CONST}}function parseSexpr(str){var symbol,node,result,result2,i,st,newFrag=document.createDocumentFragment();var ch,newst,text="";symbol=getSymbol(str);if(symbol===null||symbol.ttype==RIGHTBRACKET){return[null,str,null]}if(symbol.ttype==DEFINITION){str=symbol.output+strim(str,symbol.input.length);symbol=getSymbol(str);if(symbol===null||symbol.ttype==RIGHTBRACKET){return[null,str,null]}}if(symbol.ttype==CONST&&symbol.tag=="mi"&&str!=""){while(symbol.ttype==CONST&&symbol.tag=="mi"&&str!=""){text+=symbol.output;str=strim(str,symbol.input.length);symbol=getSymbol(str)}node=createMmlNode("mi",document.createTextNode(text));node.setAttribute("mathvariant",mathVariant);return[node,str,"mi"]}else{str=strim(str,symbol.input.length)}switch(symbol.ttype){case SPACE:node=createMmlNode(symbol.tag);node.setAttribute(symbol.atname,symbol.atval);return[node,str,symbol.tag];case UNDEROVER:return[createMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];case CONST:node=createMmlNode(symbol.tag,document.createTextNode(symbol.output));return[node,str,symbol.tag];case STRETCHY:node=createMmlNode(symbol.tag,document.createTextNode(symbol.output));if(symbol.input=="|"||symbol.input=="\\vert"||symbol.input=="\\|"||symbol.input=="\\Vert"){node.setAttribute("lspace","0em");node.setAttribute("rspace","0em")}node.setAttribute("maxsize",symbol.atval);if(symbol.rtag!==null){return[node,str,symbol.rtag]}else{return[node,str,symbol.tag]}break;case BIG:var atval=symbol.atval;symbol=getSymbol(str);if(symbol===null){return[null,str,null]}str=strim(str,symbol.input.length);node=createMmlNode(symbol.tag,document.createTextNode(symbol.output));node.setAttribute("minsize",atval);node.setAttribute("maxsize",atval);return[node,str,symbol.tag];case LEFTBRACKET:if(symbol.input=="\\left"){symbol=getSymbol(str);if(symbol!==null){if(symbol.input=="."){symbol.invisible=true}str=strim(str,symbol.input.length)}}result=parseExpr(str,true,false);if(symbol===null||(typeof symbol.invisible=="boolean"&&symbol.invisible)){node=createMmlNode("mrow",result[0])}else{node=createMmlNode("mo",document.createTextNode(symbol.output));node=createMmlNode("mrow",node);node.appendChild(result[0])}return[node,result[1],result[2]];case MATRIX:if(symbol.input=="\\begin{array}"){var mask="";symbol=getSymbol(str);str=$.trim(str);if(symbol===null){mask="l"}else{str=strim(str,symbol.input.length);if(symbol.input!="{"){mask="l"}else{do{symbol=getSymbol(str);if(symbol!==null){str=strim(str,symbol.input.length);if(symbol.input!="}"){mask=mask+symbol.input}}}while(symbol!==null&&symbol.input!==""&&symbol.input!="}")}}result=parseExpr("{"+str,true,true);node=createMmlNode("mtable",result[0]);mask=mask.replace(/l/g,"left ");mask=mask.replace(/r/g,"right ");mask=mask.replace(/c/g,"center ");node.setAttribute("columnalign",mask);node.setAttribute("displaystyle","false");return[node,result[1],null]}else{result=parseExpr("{"+str,true,true);node=createMmlNode("mtable",result[0]);node.setAttribute("columnalign","right center left");node.setAttribute("displaystyle","true");node=createMmlNode("mrow",node);return[node,result[1],null]}break;case TEXT:if(str.charAt(0)=="{"){i=str.indexOf("}")}else{i=0}if(i==-1){i=str.length}st=str.slice(1,i);node=createMmlNode(symbol.tag,document.createTextNode(st));newFrag.appendChild(node);str=strim(str,i+1);return[createMmlNode("mrow",newFrag),str,null];case UNARY:if(symbol.atname=="mathvariant"){mathVariant=symbol.atval}result=parseSexpr(str);if(result[0]===null){return[createMmlNode(symbol.tag,document.createTextNode(symbol.output)),str]}if(typeof symbol.func=="boolean"&&symbol.func){st=str.charAt(0);if(st=="^"||st=="_"||st==","){return[createMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag]}else{node=createMmlNode("mrow",createMmlNode(symbol.tag,document.createTextNode(symbol.output)));node.appendChild(result[0]);return[node,result[1],symbol.tag]}}if(symbol.input=="\\sqrt"){return[createMmlNode(symbol.tag,result[0]),result[1],symbol.tag]}else{if(typeof symbol.acc=="boolean"&&symbol.acc){node=createMmlNode(symbol.tag,result[0]);var output=symbol.output;var node1=createMmlNode("mo",document.createTextNode(output));if(symbol.input=="\\vec"||symbol.input=="\\check"){node1.setAttribute("maxsize","1.2")}if(symbol.input=="\\underbrace"||symbol.input=="\\underline"){node1.setAttribute("accentunder","true")}else{node1.setAttribute("accent","true")}node.appendChild(node1);if(symbol.input=="\\overbrace"||symbol.input=="\\underbrace"){node.ttype=UNDEROVER}return[node,result[1],symbol.tag]}else{if(typeof symbol.codes!="undefined"){for(i=0;i<result[0].childNodes.length;i++){if(result[0].childNodes[i].nodeName=="mi"||result[0].nodeName=="mi"){st=(result[0].nodeName=="mi"?result[0].firstChild.nodeValue:result[0].childNodes[i].firstChild.nodeValue);newst="";for(var j=0;j<st.length;j++){ch=st.charCodeAt(j);if(ch>64&&ch<91){newst=newst+symbol.codes[ch-65]}else{if(ch>96&&ch<123){newst=newst+symbol.codes[ch-71]}}}if(result[0].nodeName=="mi"){result[0]=createMmlNode("mo").appendChild(document.createTextNode(newst))}else{result[0].replaceChild(createMmlNode("mo").appendChild(document.createTextNode(newst)),result[0].childNodes[i])}}}}node=createMmlNode(symbol.tag,result[0]);node.setAttribute(symbol.atname,symbol.atval);if(symbol.input=="\\scriptstyle"||symbol.input=="\\scriptscriptstyle"){node.setAttribute("displaystyle","false")}return[node,result[1],symbol.tag]}}break;case BINARY:result=parseSexpr(str);if(result[0]===null){return[createMmlNode("mo",document.createTextNode(symbol.input)),str,null]}result2=parseSexpr(result[1]);if(result2[0]===null){return[createMmlNode("mo",document.createTextNode(symbol.input)),str,null]}if(symbol.input=="\\root"||symbol.input=="\\stackrel"){newFrag.appendChild(result2[0])}newFrag.appendChild(result[0]);if(symbol.input=="\\frac"||symbol.input=="\\bfrac"){newFrag.appendChild(result2[0])}node=createMmlNode(symbol.tag,newFrag);if(symbol.input=="\\bfrac"){node.setAttribute("bevelled","true")}return[node,result2[1],symbol.tag];case INFIX:str=strim(str,symbol.input.length);return[createMmlNode("mo",document.createTextNode(symbol.output)),str,symbol.tag];default:return[createMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag]}}function parseIexpr(str){var symbol,sym1,sym2,node,result,tag,underover;sym1=getSymbol(str);result=parseSexpr(str);node=result[0];str=result[1];tag=result[2];symbol=getSymbol(str);if(symbol.ttype==INFIX){str=strim(str,symbol.input.length);result=parseSexpr(str);if(result[0]===null){result[0]=createMmlNode("mo",document.createTextNode("\u25A1"))}str=result[1];tag=result[2];if(symbol.input=="_"||symbol.input=="^"){sym2=getSymbol(str);tag=null;underover=((sym1.ttype==UNDEROVER)||(node.ttype==UNDEROVER));if((symbol.input=="_"&&sym2.input=="^")||(symbol.input=="^"&&sym2.input=="_")){str=strim(str,sym2.input.length);var res2=parseSexpr(str);str=res2[1];tag=res2[2];node=createMmlNode((underover?"munderover":"msubsup"),node);if(symbol.input=="_"){node.appendChild(result[0]);node.appendChild(res2[0])}else{node.appendChild(res2[0]);node.appendChild(result[0])}}else{if(symbol.input=="_"){node=createMmlNode((underover?"munder":"msub"),node);node.appendChild(result[0])}else{node=createMmlNode((underover?"mover":"msup"),node);node.appendChild(result[0])}}node=createMmlNode("mrow",node)}else{node=createMmlNode(symbol.tag,node);if(symbol.input=="\\atop"||symbol.input=="\\choose"){node.setAttribute("linethickness","0ex")}node.appendChild(result[0]);if(symbol.input=="\\choose"){node=createMmlNode("mfenced",node)}}}return[node,str,tag]}function parseExpr(str,rightbracket,matrix){var symbol,node,result,i,tag,newFrag=document.createDocumentFragment();do{str=$.trim(str);result=parseIexpr(str);node=result[0];str=result[1];tag=result[2];symbol=getSymbol(str);if(node){if((tag=="mn"||tag=="mi")&&symbol!==null&&typeof symbol.func=="boolean"&&symbol.func){var space=createMmlNode("mspace");space.setAttribute("width","0.167em");node=createMmlNode("mrow",node);node.appendChild(space)}if(tag=="mstyle"){mathVariant="italic"}newFrag.appendChild(node)}}while((symbol.ttype!=RIGHTBRACKET)&&symbol!==null&&symbol.output!=="");tag=null;if(symbol.ttype==RIGHTBRACKET){if(symbol.input=="\\right"){str=strim(str,symbol.input.length);symbol=getSymbol(str);if(symbol!==null&&symbol.input=="."){symbol.invisible=true}if(symbol!==null){tag=symbol.rtag}}if(symbol!==null){str=strim(str,symbol.input.length)}var len=newFrag.childNodes.length;if(matrix&&len>0&&newFrag.childNodes[len-1].nodeName=="mrow"){var pos=[];var m=newFrag.childNodes.length;for(i=0;matrix&&i<m;i=i+2){pos[i]=[];node=newFrag.childNodes[i];for(var j=0;j<node.childNodes.length;j++){if(node.childNodes[j].firstChild&&node.childNodes[j].firstChild.nodeValue=="&"){pos[i][pos[i].length]=j}}}var row,frag,n,k,table=document.createDocumentFragment();for(i=0;i<m;i=i+2){row=document.createDocumentFragment();frag=document.createDocumentFragment();node=newFrag.firstChild;n=node.childNodes.length;k=0;for(j=0;j<n;j++){if(typeof pos[i][k]!="undefined"&&j==pos[i][k]){node.removeChild(node.firstChild);row.appendChild(createMmlNode("mtd",frag));k++}else{frag.appendChild(node.firstChild)}}row.appendChild(createMmlNode("mtd",frag));if(newFrag.childNodes.length>2){newFrag.removeChild(newFrag.firstChild);newFrag.removeChild(newFrag.firstChild)}table.appendChild(createMmlNode("mtr",row))}return[table,str]}if(typeof symbol.invisible!="boolean"||!symbol.invisible){node=createMmlNode("mo",document.createTextNode(symbol.output));newFrag.appendChild(node)}}return[newFrag,str,tag]}function createMmlNode(t,frag){var node=document.createElementNS("http://www.w3.org/1998/Math/MathML",t);if(frag){$(node).append(frag)}return node}var SVG,canvas;var collection=[];function createSVGElement(elType){return document.createElementNS("http://www.w3.org/2000/svg",elType)}function getSVGElement(id,el){var res={node:null,newEl:false};if(id){id=SVG.id+"_"+id;res.node=$("#"+id)[0]}if(!res.node){res.node=createSVGElement(el);if(id){res.node.id=id}res.newEl=true}return res}function openGroup(id,clear){var newEl=getSVGElement(id,"g");appendSVG(newEl);canvas=$("#"+SVG.id+"_"+id)[0];if(clear){$(canvas).empty()}}function closeGroup(){canvas=$("#"+SVG.id+"_Canvas")[0]}function appendSVG(elmt){if(elmt.newEl){$(canvas).append(elmt.node)}}function addButton(parent,text,title,func,id){var node=createElementXHTML("span");node.className="svgButton";node.title=title;node.onclick=func;if(id){node.id=id}$(node).append(text);$(node).css({paddingRight:"0.5em",paddingLeft:"0.5em",fontSize:"1em",fontFamily:"monospace",background:"blue",color:"yellow",cursor:"pointer"});$(node).mouseover(function(){$(this).css({background:"yellow",color:"blue"})});$(node).mouseout(function(){$(this).css({background:"blue",color:"yellow"})});$(parent).append(node);return parent}function pictureAttributes(){this.id=null;this.stroke="blue";this.strokewidth=1;this.strokeopacity=1;this.strokedasharray="none";this.fill="none";this.fillopacity=1;this.fixed=false;this.fontstyle="normal";this.fontfamily="serif";this.fontweight="normal";this.fontsize=12;this.fontstroke="none";this.fontstrokewidth=1;this.fontstrokeopacity=1;this.fontstrokedasharray="none";this.fontfill="black";this.fontfillopacity=1;this.sector=false;this.largearc=0;this.marker="o";this.orient="auto";this.size=8;this.units="userSpaceOnUse";this.markerstroke="blue";this.markerstrokewidth=1;this.markerstrokeopacity=1;this.markerstrokedasharray="none";this.markerfill="none";this.markerfillopacity=1;this.sweep=0;this.rx=0;this.ry=0;this.closed=false;this.curve="";this.direction=[1,0];this.ticklabels="";this.pos="";this.points=200;this.backgroundcolor="none";this.backgroundopacity=1}function pictureObject(){this.id=null;this.src="";this.width=320;this.height=null;this.factor=1;this.xmin=-5;this.xmax=5;this.ymin=null;this.ymax=null;this.xunitlength=null;this.yunitlength=null;this.origin=[0,0];this.mouse=[null,null];this.coords="cartesian";this.drag=null;this.pan=true;this.locked=false;this.attr=new pictureAttributes()}function drawPicture(){$(canvas).empty();$("#"+SVG.id+" .svgMarker").remove();SVG.attr=new pictureAttributes();try{this.code=function(){with(Math){eval(SVG.src)}}();this.code=null}catch(err){var errstr;if(typeof err=="object"){errstr=err.name+" "+err.message+" "+err.number+" "+err.description}else{errstr=err}alert(errstr+"\n"+SVG.src)}collection[SVG.id]=SVG}function setOptions(atr){for(var i in atr){SVG.attr[i]=atr[i]}}function getOptions(attr,options,prefix){var pref=prefix||"";if(typeof attr=="string"){return(options[pref+attr]==undefined?SVG.attr[pref+attr]:options[pref+attr])}else{var i,newAttr={},len=attr.length,item;for(i=0;i<len;i++){item=attr[i];newAttr[item]=options[pref+item]==undefined?SVG.attr[pref+item]:options[pref+item]}return newAttr}}function setAction(evt,fn,id){if(!$.isFunction(fn)){return}var node=id?$("#"+SVG.id+"_"+id):$("#"+SVG.id);$(node).bind(evt,fn)}function getAngle(p){p=p||[0,0];var res=Math.atan2(SVG.mouse[1]-p[1],SVG.mouse[0]-p[0]);res=(res<0)?res+2*Math.PI:res;return res}function getDistance(p){p=p||[0,0];return Math.sqrt(Math.pow(SVG.mouse[0]-p[0],2)+Math.pow(SVG.mouse[1]-p[1],2))}function updateButton(){var obj=$("#SVGtoolbar #SVGupdateButton");if(obj.text()=="Edit"){obj.text("Update");obj.attr("title","Update picture");$("#SVGsrc").val(SVG.src).css("display","block")}else{SVG.src=$("#SVGsrc").val();drawPicture()}}function closeEditor(){$("#SVGtoolbar").slideUp();$("#SVGsrc").val("");SVG.locked=false}function switchTo(evt){var name=evt.currentTarget.id;if(SVG.id==name||SVG.locked){return false}SVG=collection[name];canvas=$("#"+SVG.id+"_Canvas")[0];return false}function onWheel(evt){if(SVG.locked){return false}evt=evt||window.event;var factor=1;evt.preventDefault();evt.stopPropagation();if(evt.wheelDelta){factor=(evt.wheelDelta>0)?0.8:1.25}else{if(evt.detail){factor=(evt.detail<0)?0.8:1.25}}if(evt.altKey){resize(factor)}else{zoom(factor)}return false}function onClick(evt){if(SVG.locked){return false}if(evt.button===0){if(evt.shiftKey){$("#SVGtoolbar #SVGupdateButton").text("Update");$("#SVGsrc").val(SVG.src);$("#SVGtoolbar").css({top:evt.pageY,left:evt.pageX}).slideDown();SVG.locked=true;evt.stopImmediatePropagation()}else{if(SVG.pan){SVG.drag=[evt.clientX,evt.clientY];document.body.style.cursor="move"}}}return false}function onDrop(evt){if(SVG.drag==null){return false}document.body.style.cursor="default";var xlen=(SVG.drag[0]-evt.clientX)/SVG.xunitlength;var ylen=(-SVG.drag[1]+evt.clientY)/SVG.yunitlength;SVG.drag=null;if(xlen!=0||ylen!=0){setScales([SVG.xmin+xlen,SVG.xmax+xlen,SVG.ymin+ylen,SVG.ymax+ylen])}return false}function setScales(scales){if(scales){SVG.xmin=scales[0];SVG.xmax=scales[1];SVG.ymin=scales[2];SVG.ymax=scales[3]}SVG.xunitlength=SVG.width/(SVG.xmax-SVG.xmin);SVG.yunitlength=SVG.height/(SVG.ymax-SVG.ymin);SVG.origin=[-SVG.xmin*SVG.xunitlength,-SVG.ymin*SVG.yunitlength];drawPicture()}function getScales(scales){scales=scales||[];var res=[null,null,null,null,0];if(scales.length==0){res[0]=SVG.xmin;res[1]=SVG.xmax}if(scales.length>1){if(typeof scales[0]=="number"&&typeof scales[1]=="number"&&scales[1]>scales[0]){res[0]=scales[0];res[1]=scales[1];res[4]=4}else{res[0]=SVG.xmin;res[1]=SVG.xmax}}if(scales.length==4){if(typeof scales[2]=="number"&&typeof scales[3]=="number"&&scales[3]>scales[2]){res[2]=scales[2];res[3]=scales[3];res[4]+=8}}return res}function resize(factor){SVG.factor=(SVG.factor*factor).toFixed(3);SVG.width/=factor;SVG.height/=factor;var picture=$("#"+SVG.id);picture.attr("width",SVG.width);picture.attr("height",SVG.height);var parent=picture[0].parentNode;if(parent.nodeName=="DIV"){parent.style.width=SVG.width+"px";parent.style.height=SVG.height+"px"}setScales()}function zoom(factor,center){var px,py;if(center){px=(SVG.xmax+SVG.xmin)*0.5;py=(SVG.ymax+SVG.ymin)*0.5}else{px=SVG.mouse[0];py=SVG.mouse[1]}SVG.factor=(SVG.factor*factor).toFixed(3);var dx=(SVG.xmax-SVG.xmin)*factor;var dy=(SVG.ymax-SVG.ymin)*factor;var xmin=(1-factor)*px+factor*SVG.xmin;var ymin=(1-factor)*py+factor*SVG.ymin;setScales([xmin,xmin+dx,ymin,ymin+dy])}function updateCartesianCoord(){if(!SVG.locked){$("#"+SVG.id+"_Coords").text("("+SVG.mouse[0].toFixed(2)+", "+SVG.mouse[1].toFixed(2)+")")}return false}function updatePolarCoord(){if(!SVG.locked){$("#"+SVG.id+"_Coords").text("("+getDistance().toFixed(2)+", "+getAngle().toFixed(2)+")")}return false}function getPosition(evt){var a=[null,null];var off=$(evt.currentTarget.parentNode).offset();a[0]=(evt.pageX-off.left-SVG.origin[0])/SVG.xunitlength;a[1]=(SVG.height-SVG.origin[1]-evt.pageY+off.top)/SVG.yunitlength;return a}function updatePosition(evt){SVG.mouse=getPosition(evt);return false}function removeCoord(){$("#"+SVG.id+"_Coords").text("");return false}function tracker(pos,options){options=options||{};var coords=options.coords||SVG.coords;var func=(coords=="polar")?updatePolarCoord:updateCartesianCoord;options.id="Coords";options.fixed=true;text(pos,"",options);setAction("mousemove",func);setAction("mouseout",removeCoord)}function exportSVG(){var svg="<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n";svg+=$("#"+SVG.id).parent().html();svg=svg.replace(/ /g,"");svg=svg.replace(/><(?!\/)/g,">\n<");$("#SVGtoolbar #SVGupdateButton").text("Edit").attr("title","Edit script");$("#SVGsrc").val(svg).css("display","block")}function toSVG(p){var x=p[0]*SVG.xunitlength+SVG.origin[0];var y=SVG.height-p[1]*SVG.yunitlength-SVG.origin[1];return[x,y]}function toSVGPair(p){var q=toSVG(p);return q[0]+" "+q[1]}function setStrokeAndFill(node,options,prefix){var attributes=["stroke","strokewidth","strokedasharray","strokeopacity","fill","fillopacity"];var attr=getOptions(attributes,options,prefix);var elem=$(node);elem.attr("stroke",attr.stroke);elem.attr("stroke-width",attr.strokewidth/SVG.factor);elem.attr("stroke-dasharray",attr.strokedasharray);elem.attr("stroke-opacity",attr.strokeopacity);elem.attr("fill",attr.fill);elem.attr("fill-opacity",attr.fillopacity)}function button(p,q,txt,action,options){options=options||{};options.id=(options.id||Math.randomString(8));rect(p,q,options);setAction("click",action,options.id);options.fill=null;options.fillopacity=1;options.id+="_t";text([(p[0]+q[0])*0.5,(p[1]+q[1])*0.5],txt,options);setAction("click",action,options.id)}function setMarkers(obj,options){var markerChars="o*sSx+<>|";var attributes=["marker","size","units","orient","markerstroke","markerstrokewidth","markerstrokeopacity"];var attr=getOptions(attributes,options);var node,node2,i,id,pos=["marker-start","marker-mid","marker-end"];var lim=attr.marker.length;for(i=0;i<lim;i++){var type=attr.marker.charAt(i);if(type=="-"||markerChars.indexOf(type)<0){continue}id=(options.id||Math.randomString(8))+"Marker_"+markerChars.indexOf(type);node=$("#"+SVG.id+"_"+id);if(node.length===0){node=$(getSVGElement(id,"marker").node);node.attr("class","svgMarker");node.attr("viewBox","0 0 10 10");node.attr("refX",5);node.attr("refY",5);node.attr("orient",attr.orient);node.attr("markerUnits",attr.units);switch(type){case"*":case"o":node2=$(createSVGElement("circle"));node2.attr("cx",5);node2.attr("cy",5);node2.attr("r",4);break;case">":node2=$(createSVGElement("path"));node2.attr("d","M0 0 L10 5 L0 10 z");node.attr("refX",10);break;case"<":node2=$(createSVGElement("path"));node2.attr("d","M10 0 L10 10 L0 5 z");node.attr("refX",0);break;case"x":node2=$(createSVGElement("path"));node2.attr("d","M0 0 L10 10 M0 10 L10 0");break;case"+":node2=$(createSVGElement("path"));node2.attr("d","M5 0 L5 10 M0 5 L10 5");break;case"|":node2=$(createSVGElement("path"));node2.attr("d","M5 0 L5 10");break;case"S":case"s":node2=$(createSVGElement("rect"));node2.attr("x",0);node2.attr("y",0);node2.attr("width",10);node2.attr("height",10)}setStrokeAndFill(node2,options,"marker");node2.attr("stroke-width",attr.markerstrokewidth);if("*<>S".indexOf(type)>-1){node2.attr("fill",attr.markerstroke);node2.attr("fill-opacity",attr.markerstrokeopacity)}node.append(node2);$("#"+SVG.id+"_Defs").append(node)}node.attr("markerWidth",attr.size/SVG.factor);node.attr("markerHeight",attr.size/SVG.factor);$(obj).attr(pos[i],"url(#"+SVG.id+"_"+id+")")}}function setLabels(p,options){var i,point=[0,0],pos;var label=(typeof options.label=="string")?[options.label]:options.label;var labelpos=getOptions("pos",options);labelpos=(typeof labelpos=="string")?[labelpos]:labelpos;var poslen=labelpos.length;var size=options.size||SVG.attr.size;var dx=(0.5*size/SVG.xunitlength)/SVG.factor;var dy=(0.5*size/SVG.yunitlength)/SVG.factor;for(i=0;i<label.length;i++){options.isLabel="_label"+i;point[0]=p[i][0];point[1]=p[i][1];pos=(poslen>i)?labelpos[i].toUpperCase():pos;if(/E/.test(pos)){point[0]+=dx}if(/W/.test(pos)){point[0]-=dx}if(/N/.test(pos)){point[1]+=dy}if(/S/.test(pos)){point[1]-=dy}options.pos=pos;text(point,label[i],options)}}function line(p,q,options){options=options||{};options.closed=false;options.curve="";path([p,q],options)}function dot(p,options){options=options||{};var direction=getOptions("direction",options);var q=[p[0]+direction[0]/SVG.xunitlength,p[1]+direction[1]/SVG.yunitlength];var st="M"+toSVGPair(p)+" "+toSVGPair(q);var elmt=getSVGElement(options.id,"path");var elem=$(elmt.node);elem.attr("d",st);elem.attr("stroke","none");setMarkers(elem,options);appendSVG(elmt);if(options.label){setLabels([p],options)}}function path(list,options,append){options=options||{};var i,elmt=getSVGElement(options.id,"path");var attr=getOptions(["curve","closed"],options);var len=list.length;if(len>0){var node=$(elmt.node);var st=(append&&!elmt.newEl)?elmt.node.getAttribute("d"):"";st+="M"+toSVGPair(list[0])+" "+attr.curve;for(i=1;i<len;i++){st+=toSVGPair(list[i])+" "}if(attr.closed){st+="Z"}node.attr("d",st);setStrokeAndFill(node,options);if(options.marker){setMarkers(node,options)}appendSVG(elmt);if(options.label){setLabels(list,options)}}}function rotate(id,angle,options){if(!id||!angle){return}var node=$("#"+SVG.id+"_"+id)[0];if(node){options=options||{};var center=options.center?toSVG(options.center):SVG.origin;angle=-angle*180/Math.PI;var transform=node.getAttribute("transform")||"";transform="rotate("+angle+" "+center+") "+(options.replace?"":transform);$(node).attr("transform",transform)}}function translate(id,delta,options){if(!id||!delta){return}var node=$("#"+SVG.id+"_"+id)[0];if(node){options=options||{};delta=toSVG(delta);var transform=node.getAttribute("transform")||"";transform="translate("+(delta[0]-SVG.origin[0])+" "+(SVG.origin[1]+delta[1]-SVG.height)+") "+(options.replace?"":transform);$(node).attr("transform",transform)}}function curve(list,options){options=options||{};options.curve=options.curve||"T";path(list,options)}function circle(center,radius,options){ellipse(center,radius,radius,options)}function loop(p,options){options=options||{};var d=options.direction||[1,0];options.curve="C";options.closed=false;path([p,[p[0]+d[0],p[1]+d[1]],[p[0]-d[1],p[1]+d[0]],p],options)}function arc(options){options=options||{};var start=options.start;var end=options.end;var center=options.center;var startangle=options.startangle;var endangle=options.endangle;var st="M",elmt=getSVGElement(options.id,"path");var attr=getOptions(["largearc","sweep","closed","sector"],options);var radius=options.radius;if(center!=null&&startangle!=null&&endangle!=null&&radius!=null){start=[radius*Math.cos(startangle)+center[0],radius*Math.sin(startangle)+center[1]];end=[radius*Math.cos(endangle)+center[0],radius*Math.sin(endangle)+center[1]]}if(start==null||end==null){return}if(!radius){var v=[end[0]-start[0],end[1]-start[1]];radius=Math.sqrt(v[0]*v[0]+v[1]*v[1])}if(attr.sector){st+=toSVGPair(center)+" "}st+=toSVGPair(start)+" A"+radius*SVG.xunitlength+","+radius*SVG.yunitlength+" 0 "+attr.largearc+","+attr.sweep+" "+toSVGPair(end);if(attr.sector||attr.closed){st+=" z"}var node=$(elmt.node);node.attr("d",st);setStrokeAndFill(node,options);if(options.marker){setMarkers(node,options)}appendSVG(elmt);if(options.label){setLabels([start,end],options)}}function sector(options){if(!options.center||!options.startangle||!options.endangle||!options.radius){return}options.sector=true;arc(options)}function ellipse(center,rx,ry,options){options=options||{};var elmt=getSVGElement(options.id,"ellipse");center=toSVG(center);var node=$(elmt.node);node.attr("cx",center[0]);node.attr("cy",center[1]);node.attr("rx",rx*SVG.xunitlength);node.attr("ry",ry*SVG.yunitlength);setStrokeAndFill(node,options);appendSVG(elmt)}function polygon(list,options){options=options||{};options.closed=true;path(list,options)}function rect(p,q,options){options=options||{};var elmt=getSVGElement(options.id,"rect");var attr=getOptions(["rx","ry"],options);var node=$(elmt.node);node.attr("x",toSVG(p)[0]);node.attr("y",toSVG(q)[1]);node.attr("width",(q[0]-p[0])*SVG.xunitlength);node.attr("height",(q[1]-p[1])*SVG.yunitlength);node.attr("rx",attr.rx*SVG.xunitlength);node.attr("ry",attr.ry*SVG.yunitlength);setStrokeAndFill(node,options);appendSVG(elmt)}function text(p,st,options){options=options||{};var id=options.id;var attr=getOptions(["fontstyle","fontfamily","fontweight","fontfill","fontsize","fixed","pos"],options);if(id&&options.isLabel){id+=options.isLabel}var pos=attr.pos.toUpperCase();if(!attr.fixed){attr.fontsize/=SVG.factor}var elem,node,dx,dy,latex=false,str=$.trim(st.toString()),q=toSVG(p);if(str.charAt(0)=="$"){str=str.substr(1,str.length-2);latex=true}if(latex){if(p[0]>SVG.xmax||p[0]<SVG.xmin||p[1]>SVG.ymax||p[1]<SVG.ymin){return}node=createElementXHTML("div");node.style.position="absolute";node.style.left="-1000px";node.style.top="-1000px";$("body").append(node);var math=MSVG.parseMath(str,true,attr.fontsize+"px",attr.fontfill);var mathNode=$(node);mathNode.append($(math).clone());dx=-node.offsetWidth/2;dy=-node.offsetHeight/2;if(/N/.test(pos)){dy=-node.offsetHeight}if(/S/.test(pos)){dy=0}if(/E/.test(pos)){dx=0}if(/W/.test(pos)){dx=-node.offsetWidth}var width=mathNode.width(),height=mathNode.height();mathNode.remove();q[0]+=dx;q[1]+=dy;var elmt=getSVGElement(id,"foreignObject");elem=$(elmt.node);elem.empty().append(math);elem.attr("width",width);elem.attr("height",height)}else{var baseline="middle",textanchor="middle";if(/E/.test(pos)){textanchor="start"}if(/W/.test(pos)){textanchor="end"}if(/N/.test(pos)){baseline="text-after-edge"}if(/S/.test(pos)){baseline="text-before-edge"}var elmt=getSVGElement(id,"text");elem=$(elmt.node);elem.empty().text(str);elem.attr("font-style",attr.fontstyle);elem.attr("font-family",attr.fontfamily);elem.attr("font-weight",attr.fontweight);elem.attr("font-size",attr.fontsize);elem.attr("text-anchor",textanchor);elem.attr("dominant-baseline",baseline);setStrokeAndFill(elem,options,"font")}elem.attr("x",q[0]);elem.attr("y",q[1]);appendSVG(elmt)}function image(url,options){options=options||{};var elmt=getSVGElement(options.id,"image");var elem=$(elmt.node);var height=options.height?options.height/SVG.factor:SVG.height;var width=options.width?options.width/SVG.factor:SVG.width;var origin=toSVG(options.origin||[SVG.xmin,SVG.ymin]);var pos=(options.pos||"").toUpperCase();var x=origin[0]-width*0.5;var y=origin[1]-height*0.5;if(/N/.test(pos)){y-=height*0.5}if(/S/.test(pos)){y+=height*0.5}if(/E/.test(pos)){x+=width*0.5}if(/W/.test(pos)){x-=width*0.5}elem.attr("x",x);elem.attr("y",y);elem.attr("width",width);elem.attr("height",height);elem.attr("preserveAspectRatio","none");elmt.node.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",url);appendSVG(elmt)}function grid(options){options=options||{};var dx,dy,x,y,k;var orig=options.origin||[0,0];var id=options.id||"Grid";options.stroke=options.stroke||"grey";options.strokewidth=(options.strokewidth||SVG.attr.strokewidth*0.5);var coords=options.coords||SVG.coords;var lim=getScales(options.scales);openGroup(id,true);lim[2]=(typeof lim[2]=="number")?lim[2]:SVG.ymin;lim[3]=(typeof lim[3]=="number")?lim[3]:SVG.ymax;if(coords=="polar"){dx=options.dx||1;dy=options.dy||3;var limit=Math.max(Math.abs(lim[0]),Math.abs(lim[1]),Math.abs(lim[2]),Math.abs(lim[3]));for(x=dx;x<limit;x+=dx){circle(orig,x,options)}if(dy>1){for(y=1;y<dy;y++){k=Math.tan(y*Math.PI/(2*dy));line([lim[0],(lim[0]-orig[0])*k+orig[1]],[SVG.xmax,(lim[1]-orig[0])*k+orig[1]],options);line([lim[0],-(lim[0]-orig[0])*k+orig[1]],[SVG.xmax,-(lim[1]-orig[0])*k+orig[1]],options)}}}else{dx=options.dx||1;dy=options.dy||dx;for(x=orig[0];x<SVG.xmax;x+=dx){if(x>lim[0]&&x<lim[1]){line([x,lim[2]],[x,lim[3]],options)}}for(x=orig[0]-dx;x>SVG.xmin;x-=dx){if(x>lim[0]&&x<lim[1]){line([x,lim[2]],[x,lim[3]],options)}}for(y=orig[1];y<SVG.ymax;y+=dy){if(y>lim[2]&&y<lim[3]){line([lim[0],y],[lim[1],y],options)}}for(y=orig[1]-dy;y>SVG.ymin;y-=dy){if(y>lim[2]&&y<lim[3]){line([lim[0],y],[lim[1],y],options)}}}closeGroup()}function axes(options){options=options||{};options.marker="-|"+(options.marker?options.marker.charAt(0):"-");var i,x,y,start,stop,label;var dx=options.dx||1;var dy=options.dy||dx;var id=options.id||"Axes";var fontsize=getOptions("fontsize",options);var coords=options.coords||SVG.coords;var orig=(coords=="polar")?[0,0]:(options.origin||[0,0]);var ddx=options.decx||Math.max(0,-Math.floor(Math.log(dx)/Math.log(10)));var ddy=options.decy||Math.max(0,-Math.floor(Math.log(dy)/Math.log(10)));options.stroke=options.stroke||"black";options.strokewidth=(options.strokewidth||SVG.attr.strokewidth*0.5);options.markerstroke=options.stroke;options.markerstrokewidth=options.strokewidth;openGroup(id,true);var lim=getScales(options.scales);lim[2]=lim[2]||SVG.ymin;lim[3]=lim[3]||SVG.ymax;if($.isArray(options.xticks)){var xticks=options.xticks.sort();var list2=[[lim[0],orig[1]]];label=[""];for(i=0;i<xticks.length;i++){list2.push([xticks[i],orig[1]]);label.push(String(xticks[i].toFixed(ddx)))}list2.push([lim[1],orig[1]]);label.push("")}else{var list1=[],label1=[];var list2=[],label2=[];start=SVG.xmin+0.25*dx;stop=SVG.xmax-0.25*dx;i=1;var cand,leftExit=0,rightExit=0;while(leftExit*rightExit==0){cand=orig[0]+i*dx;if(cand>start){if(cand<stop){list1.push([cand,orig[1]]);label1.push(String(cand.toFixed(ddx)))}else{rightExit=1}}cand=orig[0]-i*dx;if(cand<stop){if(cand>start){list2.push([cand,orig[1]]);label=(coords=="polar")?"":cand.toFixed(ddx);label2.push(String(label))}else{leftExit=1}}i++}list1.push([lim[1],orig[1]]);label1.push("");list2.push([lim[0],orig[1]]);label2.push("");list2.reverse();list2=list2.concat(list1);label2.reverse();label=label2.concat(label1)}if(options.ticklabels!=false){options.label=label;options.pos="S"}path(list2,options);if($.isArray(options.yticks)){var yticks=options.yticks.sort();var list2=[[orig[0],lim[2]]];label=[""];for(i=0;i<yticks.length;i++){list2.push([orig[0],yticks[i]]);label.push(String(yticks[i].toFixed(ddy)))}list2.push([orig[0],lim[3]]);label.push("")}else{list1=[],label1=[];list2=[];label2=[];start=SVG.ymin+0.25*dy;stop=SVG.ymax-0.25*dy;i=1;leftExit=0;rightExit=0;while(leftExit*rightExit==0){cand=orig[1]+i*dy;if(cand>start){if(cand<stop){list1.push([orig[0],cand]);label1.push(String(cand.toFixed(ddy)))}else{rightExit=1}}cand=orig[1]-i*dy;if(cand<stop){if(cand>start){list2.push([orig[0],cand]);label=(coords=="polar")?"":cand.toFixed(ddy);label2.push(String(label))}else{leftExit=1}}i++}list1.push([orig[0],lim[3]]);label1.push("");list2.push([orig[0],lim[2]]);label2.push("");list2.reverse();list2=list2.concat(list1);label2.reverse();label=label2.concat(label1)}if(options.ticklabels!=false){options.label=label;options.pos="W"}options.stroke=options.markerstroke;path(list2,options);closeGroup()}function list(fun,tmin,tmax,options){var inc=(tmax-tmin)/getOptions("points",options);if(inc<=0||fun.length==0){return}var t,pth,g=[],xt,yt;for(t=1;t>=0;t--){if($.isFunction(fun[t])){g[t]=fun[t]}else{if(typeof fun[t]=="string"){with(Math){eval("g["+t+"] = function(x){return "+fun[t]+"}")}}else{return}}}if(g.length<2){return}pth=[];for(t=tmin;t<=tmax;t+=inc){xt=g[0](t);yt=g[1](t);if(isFinite(xt)&&isFinite(yt)){pth[pth.length]=[xt,yt]}}return pth}function plot(fun,options){options=options||{};var append,pth,steps=options.steps||[];var n_steps=steps.length;options.closed=false;options.curve="";var xmin=(options.min==null)?SVG.xmin:Math.max(SVG.xmin,options.min);var xmax=(options.max==null)?SVG.xmax:Math.min(SVG.xmax,options.max);if(n_steps===0){pth=list(["x",fun],xmin,xmax,options);if(pth){path(pth,options)}}else{options.id=options.id||Math.randomString(6);steps.sort();var steps_a=[];steps_a.push(xmin);for(i=0;i<n_steps;i++){if(steps[i]>xmin&&steps[i]<xmax){steps_a.push(steps[i])}}steps_a.push(xmax);n_steps=steps_a.length-1;for(i=0;i<n_steps;i++){xmax=steps_a[i+1];xmin=steps_a[i];pth=list(["x",fun],xmin,xmax,options);append=(i>0);if(pth){path(pth,options,append)}}}}function area(fun1,fun2,options){options=options||{};options.curve="";options.closed=true;var xmin=(options.min==null)?SVG.xmin:options.min;var xmax=(options.max==null)?SVG.xmax:options.max;var pth1=list(["x",fun1],xmin,xmax,options);var pth2=list(["x",fun2],xmin,xmax,options);if(pth1&&pth2){pth1=pth1.concat(pth2.reverse());path(pth1,options)}}function polarPlot(fun,options){var g1,g2;if(typeof fun=="string"){with(Math){eval("g1 = function(x){return ("+fun+")*cos(x)}");eval("g2 = function(x){return ("+fun+")*sin(x)}")}}else{if($.isFunction(fun)){with(Math){eval("g1 = function(x){return fun(x)*cos(x)}");eval("g2 = function(x){return fun(x)*sin(x)}")}}}parametricPlot(g1,g2,options)}function parametricPlot(fun1,fun2,options){options=options||{};options.closed=false;options.curve="";var xmin=(options.min==null)?0:options.min;var xmax=(options.max==null)?2*Math.PI:options.max;var pth=list([fun1,fun2],xmin,xmax,options);if(pth){path(pth,options)}}function slopeField(fun,options){options=options||{};var g=fun;if(typeof fun=="string"){with(Math){eval("g = function(x,y){return "+fun+"}")}}var gxy,x,y,u,v,dz;var dx=(options.dx==null)?1:options.dx;var dy=(options.dy==null)?1:options.dy;dz=Math.sqrt(dx*dx+dy*dy)/6;var xmin=Math.ceil(SVG.xmin/dx);var ymin=Math.ceil(SVG.ymin/dy);for(x=xmin;x<=SVG.xmax;x+=dx){for(y=ymin;y<=SVG.ymax;y+=dy){gxy=g(x,y);if(!isNaN(gxy)){if(Math.abs(gxy)=="Infinity"){u=0;v=dz}else{u=dz/Math.sqrt(1+gxy*gxy);v=gxy*u}line([x-u,y-v],[x+u,y+v],options)}}}}return{showFormulaOnMouseOver:false,latexImages:false,latexConverter:"?" /*"http://chart.apis.google.com/chart?cht=tx&chs=1x0&chf=bg,s,FFFFFF00&chco=000000&chl="*/,mathColor:"",mathFontSize:"",mathFontFamily:"",define:function(oldstr,newstr){if(MSVG.latexImages){return}if((typeof oldstr)=="string"){oldstr=[oldstr];newstr=[newstr]}var i,len=oldstr.length;if(len!=newstr.length){return}for(i=0;i<len;i++){symbols=symbols.concat([{input:"\\"+oldstr[i],tag:"mo",output:newstr[i],ttype:DEFINITION}])}refreshSymbols()},parseMath:function(str,displaystyle,size,color){if(str===null){return null}str=str.replace(/_([^\{])/gm,"_{$1}");str=str.replace(/\^([^\{])/gm,"^{$1}");var frag=parseExpr(str.replace(/^\s+/g,""),false,false)[0];var node=createMmlNode("mstyle",frag);$(node).attr({displaystyle:displaystyle,mathcolor:color||MSVG.mathColor,mathsize:size||MSVG.mathFontSize,fontfamily:MSVG.mathFontFamily});node=createMmlNode("math",node);if(MSVG.showFormulaOnMouseOver){$(node).attr({title:str.replace(/\s+/g," ")})}return node},parseMathExternal:function(str,displaystyle,size,color){if(str===null){return null}var node=createElementXHTML("img");var snip=MSVG.latexConverter+str;$(node).attr({src:snip});if(MSVG.showFormulaOnMouseOver){$(node).attr({title:str.replace(/\s+/g," ")})}return node},generic:function(){if(!$.browser.mozilla){MSVG.latexImages=true}if(MSVG.latexImages){MSVG.parseMath=MSVG.parseMathExternal}else{refreshSymbols()}if(!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1")){MSVG.initPictures=MSVG.removePictures}},removePictures:function(obj){var pictures=obj?$(obj):$(".SVGgraph");$(pictures).each(function(){var that=$(this);this.id=null;that.empty();that.css({color:"red",background:"yellow"});that.text("Missing picture: your browser does not support inline SVG");window.setTimeout(function(){that.remove()},10000)})},initPictures:function(obj){var options,scales,qnode,node,node2,status,elem;var pictures=obj?$(obj):$(".SVGgraph");$(pictures).each(function(){var that=$(this);status=0;SVG=new pictureObject();options=$(this).attr("options");that.removeAttr("id");if(options){with(Math){eval("options={"+options+"}")}setOptions(options)}else{options={}}if(options.pan==false){SVG.pan=false}SVG.coords=options.coords||SVG.coords;SVG.src=$.trim($(this).text());that.empty();if(typeof options.width=="number"&&options.width>0){SVG.width=options.width;status+=1}if(typeof options.height=="number"&&options.height>0){SVG.height=options.height;status+=2}var scales=getScales(options.scales);SVG.xmin=scales[0];SVG.xmax=scales[1];SVG.ymin=scales[2];SVG.ymax=scales[3];status+=scales[4];SVG.height=options.height;if(status%4!=0){SVG.width=options.width}if(!SVG.width){SVG.width=1.6*SVG.height}else{if(!SVG.height){SVG.height=0.625*SVG.width}}if(status<8){SVG.ymax=0.5*SVG.height*(SVG.xmax-SVG.xmin)/SVG.width;SVG.ymin=-SVG.ymax}else{if(status<12){SVG.xmax=0.5*SVG.width*(SVG.ymax-SVG.ymin)/SVG.height;SVG.xmin=-SVG.xmax}}if(status==12||status==13){SVG.height=SVG.width*(SVG.ymax-SVG.ymin)/(SVG.xmax-SVG.xmin)}else{if(status==14){SVG.width=SVG.height*(SVG.xmax-SVG.xmin)/(SVG.ymax-SVG.ymin)}}SVG.id=options.id||Math.randomString(16);qnode=createSVGElement("svg");elem=$(qnode);qnode.id=SVG.id;elem.attr("xmlns","http://www.w3.org/2000/svg");elem.attr("xmlns:ev","http://www.w3.org/2001/xml-events");elem.attr("xmlns:xlink","http://www.w3.org/1999/xlink");elem.attr("version","1.1");elem.attr("baseProfile","full");if(options.border){elem.attr("style","border:"+options.border)}node2=createSVGElement("defs");node2.id=SVG.id+"_Defs";$(qnode).append(node2);node2=createSVGElement("g");node2.id=SVG.id+"_Canvas";$(qnode).append(node2);that.append(qnode);this.style.position="relative";if(!(this.nodeName=="SPAN")){setAction("mousemove",updatePosition);if(SVG.pan){setAction("mouseup",onDrop)}if(window.addEventListener){var evt=$.browser.mozilla?"DOMMouseScroll":"mousewheel";qnode.addEventListener(evt,onWheel,false)}}setAction("mousedown",onClick);setAction("mouseover",switchTo);canvas=$("#"+SVG.id+"_Canvas")[0];resize(1)});if(pictures.length>0&&$("#SVGtoolbar").length===0){node=createElementXHTML("span");node.id="SVGtoolbar";node.style.position="absolute";node.style.textAlign="left";node.style.zIndex=10;node=addButton(node,"X","Close editor",closeEditor);node=addButton(node,"Update","Update picture",updateButton,"SVGupdateButton");node=addButton(node,"SVG","View SVG code",exportSVG);node=addButton(node,"-","Zoom out",function(){zoom(1.25,true)});node=addButton(node,"+","Zoom in",function(){zoom(0.8,true)});node=addButton(node,"\u2191","Enlarge picture",function(){resize(0.8)});node=addButton(node,"\u2193","Reduce picture",function(){resize(1.25)});$(node).append("<br />");node2=createElementXHTML("textarea");$(node2).attr({id:"SVGsrc",rows:8,cols:60});$(node).append(node2);$(node).hide();$("body").append(node)}}}}(jQuery);
//}}}
/***
!~TiddlyWiki formatters
***/
//{{{
if(!version.extensions.MathSVGPlugin) { //# ensure that the plugin is only installed once
version.extensions.MathSVGPlugin = {installed: true};
MSVG.generic();
config.formatterHelpers.MathSVGHelper = function(z) {
if(z.tiddler && MSVG.noMathTag && jQuery.inArray(MSVG.noMathTag,z.tiddler.tags)>-1) return;
this.lookaheadRegExp.lastIndex = z.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(z.source);
if(lookaheadMatch){
var eq = MSVG.parseMath(lookaheadMatch[1],this.displaystyle);
if(this.displaystyle){
var node = createTiddlyElement(z.output,"div");
node.style.textAlign='center';
node.appendChild(eq);
z.output.appendChild(node);
} else {z.output.appendChild(eq);}
z.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
}
}
config.formatters.push( {
name: "clatex",
match: "\\$\\$",
lookaheadRegExp: /\$\$((?:.|\n)*?)\$\$/mg,
displaystyle: true,
handler: config.formatterHelpers.MathSVGHelper
})
config.formatters.push( {
name: "clatex2",
match: "\\\\\\\[",
lookaheadRegExp: /\\\[((?:.|\n)*?)\\\]/mg,
displaystyle: true,
handler: config.formatterHelpers.MathSVGHelper
})
config.formatters.push( {
name: "latex",
match: "\\$",
lookaheadRegExp: /\$((?:.|\n)*?)\$/mg,
displaystyle: false,
handler: config.formatterHelpers.MathSVGHelper
})
config.formatters.push( {
name: "latex2",
match: "\\\\\\\(",
lookaheadRegExp: /\\\(((?:.|\n)*?)\\\)/mg,
displaystyle: false,
handler: config.formatterHelpers.MathSVGHelper
})
config.formatters.push( {
name: "graph",
match: "<div",
lookaheadRegExp: /<div.+SVGgraph.+?>((?:.|\n)*?)<\/div>/mg,
handler: function(z){
if(z.tiddler && MSVG.noSvgTag && jQuery.inArray(MSVG.noSvgTag,z.tiddler.tags)>-1) return;
this.lookaheadRegExp.lastIndex = z.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(z.source);
if(lookaheadMatch){
var text = lookaheadMatch[0].replace('<div','<div id="currentGraph"');
jQuery(z.output).append(text);
MSVG.initPictures("#currentGraph");
z.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
}
}
})
config.formatters.push( {
name: "inlineGraph",
match: "<span",
lookaheadRegExp: /<span.+SVGgraph.+?>((?:.|\n)*?)<\/span>/mg,
handler: function(z){
if(z.tiddler && MSVG.noSvgTag && jQuery.inArray(MSVG.noSvgTag,z.tiddler.tags)>-1) return;
this.lookaheadRegExp.lastIndex = z.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(z.source);
if(lookaheadMatch){
var text = lookaheadMatch[0].replace('<span','<span id="currentGraph"');
jQuery(z.output).append(text);
MSVG.initPictures("#currentGraph");
z.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
}
}
})
}
//}}}
/%
!info
|Name|ToggleRightSidebar|
|Source|http://www.TiddlyTools.com/#ToggleRightSidebar|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|show/hide right sidebar (SideBarOptions)|
Usage
<<<
{{{
<<tiddler ToggleRightSidebar>>
<<tiddler ToggleRightSidebar with: label tooltip>>
}}}
Try it: <<tiddler ToggleRightSidebar##show
with: {{config.options.chkShowRightSidebar?'â–º':'â—„'}}>>
<<<
Configuration:
<<<
copy/paste the following settings into a tiddler tagged with <<tag systemConfig>> and then modify the values to suit your preferences:
{{{
config.options.chkShowRightSidebar=true;
config.options.txtToggleRightSideBarLabelShow="â—„";
config.options.txtToggleRightSideBarLabelHide="â–º";
}}}
<<<
!end
!show
<<tiddler {{
var co=config.options;
if (co.chkShowRightSidebar===undefined) co.chkShowRightSidebar=true;
var sb=document.getElementById('sidebar');
var da=document.getElementById('displayArea');
if (sb) {
sb.style.display=co.chkShowRightSidebar?'block':'none';
da.style.marginRight=co.chkShowRightSidebar?'':'1em';
}
'';}}>><html><nowiki><a href='javascript:;' title="$2"
onmouseover="
this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
+encodeURIComponent(encodeURIComponent(this.onclick))
+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
var co=config.options;
var opt='chkShowRightSidebar';
var show=co[opt]=!co[opt];
var sb=document.getElementById('sidebar');
var da=document.getElementById('displayArea');
if (sb) {
sb.style.display=show?'block':'none';
da.style.marginRight=show?'':'1em';
}
saveOptionCookie(opt);
var labelShow=co.txtToggleRightSideBarLabelShow||'◄';
var labelHide=co.txtToggleRightSideBarLabelHide||'►';
if (this.innerHTML==labelShow||this.innerHTML==labelHide)
this.innerHTML=show?labelHide:labelShow;
this.title=(show?'hide':'show')+' right sidebar';
var sm=document.getElementById('storyMenu');
if (sm) config.refreshers.content(sm);
return false;
">$1</a></html>
!end
%/<<tiddler {{
var src='ToggleRightSidebar';
src+(tiddler&&tiddler.title==src?'##info':'##show');
}} with: {{
var co=config.options;
var labelShow=co.txtToggleRightSideBarLabelShow||'◄';
var labelHide=co.txtToggleRightSideBarLabelHide||'►';
'$1'!='$'+'1'?'$1':(co.chkShowRightSidebar?labelHide:labelShow);
}} {{
var tip=(config.options.chkShowRightSidebar?'hide':'show')+' right sidebar';
'$2'!='$'+'2'?'$2':tip;
}}>>
/***
|''Name''|RevisionsCommandPlugin|
|''Description''|provides access to tiddler revisions|
|''Author''|FND|
|''Contributors''|Martin Budden|
|''Version''|0.3.3|
|''Status''|@@beta@@|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/plugins/RevisionsCommandPlugin.js|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/association/plugins/|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.6.0|
|''Keywords''|serverSide|
!Usage
Extend [[ToolbarCommands]] with {{{revisions}}}.
!Revision History
!!v0.1 (2009-07-23)
* initial release (renamed from experimental ServerCommandsPlugin)
!!v0.2 (2010-03-04)
* suppressed wikification in diff view
!!v0.3 (2010-04-07)
* restored wikification in diff view
* added link to side-by-side diff view
!To Do
* strip server.* fields from revision tiddlers
* resolve naming conflicts
* i18n, l10n
* code sanitizing
* documentation
!Code
***/
//{{{
(function($) {
jQuery.twStylesheet(".diff { white-space: pre, font-family: monospace }",
{ id: "diff" });
var cmd = config.commands.revisions = {
type: "popup",
hideShadow: true,
text: "revisions",
tooltip: "display tiddler revisions",
revTooltip: "", // TODO: populate dynamically?
loadLabel: "loading...",
loadTooltip: "loading revision list",
selectLabel: "select",
selectTooltip: "select revision for comparison",
selectedLabel: "selected",
compareLabel: "compare",
linkLabel: "side-by-side view",
revSuffix: " [rev. #%0]",
diffSuffix: " [diff: #%0 #%1]",
dateFormat: "YYYY-0MM-0DD 0hh:0mm",
listError: "revisions could not be retrieved",
handlePopup: function(popup, title) {
title = this.stripSuffix("rev", title);
title = this.stripSuffix("diff", title);
var tiddler = store.getTiddler(title);
var type = _getField("server.type", tiddler);
var adaptor = new config.adaptors[type]();
var limit = null; // TODO: customizable
var context = {
host: _getField("server.host", tiddler),
workspace: _getField("server.workspace", tiddler)
};
var loading = createTiddlyButton(popup, cmd.loadLabel, cmd.loadTooltip);
var params = { popup: popup, loading: loading, origin: title };
adaptor.getTiddlerRevisionList(title, limit, context, params, this.displayRevisions);
},
displayRevisions: function(context, userParams) {
removeNode(userParams.loading);
if(context.status) {
var callback = function(ev) {
var e = ev || window.event;
var revision = resolveTarget(e).getAttribute("revision");
context.adaptor.getTiddlerRevision(tiddler.title, revision, context,
userParams, cmd.displayTiddlerRevision);
};
var table = createTiddlyElement(userParams.popup, "table");
for(var i = 0; i < context.revisions.length; i++) {
var tiddler = context.revisions[i];
var row = createTiddlyElement(table, "tr");
var timestamp = tiddler.modified.formatString(cmd.dateFormat);
var revision = tiddler.fields["server.page.revision"];
var cell = createTiddlyElement(row, "td");
createTiddlyButton(cell, timestamp, cmd.revTooltip, callback, null,
null, null, { revision: revision });
cell = createTiddlyElement(row, "td", null, null, tiddler.modifier);
cell = createTiddlyElement(row, "td");
createTiddlyButton(cell, cmd.selectLabel, cmd.selectTooltip,
cmd.revisionSelected, null, null, null,
{ index:i, revision: revision, col: 2 });
cmd.context = context; // XXX: unsafe (singleton)!?
}
} else {
$("<li />").text(cmd.listError).appendTo(userParams.popup);
}
},
revisionSelected: function(ev) {
var e = ev || window.event;
e.cancelBubble = true;
if(e.stopPropagation) {
e.stopPropagation();
}
var n = resolveTarget(e);
var index = n.getAttribute("index");
var col = n.getAttribute("col");
while(!index || !col) {
n = n.parentNode;
index = n.getAttribute("index");
col = n.getAttribute("col");
}
cmd.revision = n.getAttribute("revision");
var table = n.parentNode.parentNode.parentNode;
var rows = table.childNodes;
for(var i = 0; i < rows.length; i++) {
var c = rows[i].childNodes[col].firstChild;
if(i == index) {
if(c.textContent) {
c.textContent = cmd.selectedLabel;
} else {
c.text = cmd.selectedLabel;
}
} else {
if(c.textContent) {
c.textContent = cmd.compareLabel;
} else {
c.text = cmd.compareLabel;
}
c.onclick = cmd.compareSelected;
}
}
},
compareSelected: function(ev) {
var e = ev || window.event;
var n = resolveTarget(e);
var context = cmd.context;
context.rev1 = n.getAttribute("revision");
context.rev2 = cmd.revision;
context.tiddler = context.revisions[n.getAttribute("index")];
context.format = "unified";
context.adaptor.getTiddlerDiff(context.tiddler.title, context,
context.userParams, cmd.displayTiddlerDiffs);
},
displayTiddlerDiffs: function(context, userParams) {
var tiddler = context.tiddler;
tiddler.title += cmd.diffSuffix.format([context.rev1, context.rev2]);
tiddler.text = "{{diff{\n" + context.diff + "\n}}}";
tiddler.tags = ["diff"];
tiddler.fields.doNotSave = "true"; // XXX: correct?
if(!store.getTiddler(tiddler.title)) {
store.addTiddler(tiddler);
}
var src = story.getTiddler(userParams.origin);
var tiddlerEl = story.displayTiddler(src, tiddler);
var uri = context.uri.replace("format=unified", "format=horizontal");
var link = $('<a target="_blank" />').attr("href", uri).text(cmd.linkLabel);
$(".viewer", tiddlerEl).prepend(link);
},
displayTiddlerRevision: function(context, userParams) {
var tiddler = context.tiddler;
tiddler.title += cmd.revSuffix.format([tiddler.fields["server.page.revision"]]);
tiddler.fields.doNotSave = "true"; // XXX: correct?
if(!store.getTiddler(tiddler.title)) {
store.addTiddler(tiddler);
}
var src = story.getTiddler(userParams.origin);
story.displayTiddler(src, tiddler);
},
stripSuffix: function(type, title) {
var str = cmd[type + "Suffix"];
var i = str.indexOf("%0");
i = title.indexOf(str.substr(0, i));
if(i != -1) {
title = title.substr(0, i);
}
return title;
}
};
var _getField = function(name, tiddler) {
return tiddler.fields[name] || config.defaultCustomFields[name];
};
})(jQuery);
//}}}
.headerShadow { padding: 0}
.headerForeground { padding: 0}
.siteTitle { font-size: 1.1em;}
.siteTitle br {display:none;}
ul.suckerfish { display:inline-block;}
.tiddler { border: 1px solid rgb(170, 170, 170); margin: 0pt 10px 20px; padding: 8px; font-family: georgia,times; background-color: rgb(243, 243, 243); }
.tiddlerSelected { border: 1px solid rgb(170, 170, 170); margin: 0pt 10px 20px; padding: 8px; font-family: georgia,times; background-color: rgb(255, 255, 255); }
.title { border-bottom: 1px solid rgb(204, 204, 204); font-family: tahoma,arial,helvetica; font-size: 12pt; color: rgb(68, 102, 153); font-weight: bold; display: block; padding-bottom: 5px; margin-bottom: 4px; }
h1 { font-size: 1.5em;}
h1, h2, h3 {
border-bottom: none;
margin-top: 0px; padding-bottom: 0px; margin-bottom: 0px;
}
/***
|''Name''|DiffFormatter|
|''Description''|highlighting of text comparisons|
|''Author''|FND|
|''Version''|0.9.0|
|''Status''|beta|
|''Source''|http://svn.tiddlywiki.org/Trunk/contributors/FND/formatters/DiffFormatter.js|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/contributors/FND/|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''Keywords''|formatting|
!Description
Highlights changes in a unified [[diff|http://en.wikipedia.org/wiki/Diff#Unified_format]].
!Notes
Based on Martin Budden's [[DiffFormatterPlugin|http://svn.tiddlywiki.org/Trunk/contributors/MartinBudden/formatters/DiffFormatterPlugin.js]].
!Usage
The formatter is applied to blocks wrapped in <html><code>{{{diff{..}}}</code></html> within tiddlers tagged with "diff".
!Revision History
!!v0.9 (2010-04-07)
* initial release; fork of DiffFormatterPlugin
!StyleSheet
.diff { white-space: pre; font-family: monospace; }
.diff ins, .diff del { display: block; text-decoration: none; }
.diff ins { background-color: #dfd; }
.diff del { background-color: #fdd; }
.diff .highlight { background-color: [[ColorPalette::SecondaryPale]]; }
!Code
***/
//{{{
(function() {
config.shadowTiddlers.StyleSheetDiffFormatter = store.getTiddlerText(tiddler.title + "##StyleSheet");
store.addNotification("StyleSheetDiffFormatter", refreshStyles);
var formatters = [{
name: "diffWrapper",
match: "^\\{\\{diff\\{\n", // XXX: suboptimal
termRegExp: /(.*\}\}\})$/mg,
handler: function(w) {
var el = createTiddlyElement(w.output, "div", null, "diff");
w.subWikifyTerm(el, this.termRegExp);
}
}, {
name: "diffRange",
match: "^(?:@@|[+\\-]{3}) ",
lookaheadRegExp: /^(?:@@|[+\-]{3}) .*\n/mg,
handler: function(w) {
createTiddlyElement(w.output, "div", null, "highlight").
innerHTML = "…";
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
w.nextMatch = this.lookaheadRegExp.lastIndex;
}
}
}, {
name: "diffAdded",
match: "^\\+",
termRegExp: /(\n)/mg,
handler: function(w) {
var el = createTiddlyElement(w.output, "ins", null, "added");
w.subWikifyTerm(el, this.termRegExp);
}
}, {
name: "diffRemoved",
match: "^-",
termRegExp: /(\n)/mg,
handler: function(w) {
var el = createTiddlyElement(w.output, "del", null, "removed");
w.subWikifyTerm(el, this.termRegExp);
}
}
];
config.parsers.diffFormatter = new Formatter(formatters);
config.parsers.diffFormatter.format = "diff";
config.parsers.diffFormatter.formatTag = "diff";
})();
//}}}
/***
|''Name:''|GraphPlugin|
|''Description:''|Draw graph data using graphviz syntax in your tiddlers.|
|''Version:''|0.1|
|''Date:''|Dec 27,2013|
|''Source:''||
|''Author:''|Matthieu Nottale|
|''License:''|[[BSD open source license|License]]|
|''~CoreVersion:''|2.1.0|
|''Browser:''|Firefox 2.0; InternetExplorer 6.0, others|
Based on viz.js from https://github.com/mdaines/viz.js
!! Usage:
{{{
<<digraph $directive
a->b;
>>
<<graph $directive digraph { a->b -> c;} >>
}}}
\$directive is an optional option. Supported values:
- \$fright : make the graph a float right
- \$fleft : make the graph a float left
! The code
!! Load viz.js, emscripten-ized version of graphviz
***/
//{{{
jQuery.getScript("https://www.nottale.net/viz.js");
//}}}
/***
!! The macro
***/
//{{{
config.macros.graph = {};
graphHandler = function(place, paramString, preDot, postDot, preHtml, postHtml)
{
directive = paramString.split(" ", 1)[0].split("\n", 1)[0];
if (directive[0] == "$")
{
paramString = paramString.substr(directive.length + 1);
if (directive == "$fleft")
{
preHtml += '<div style="float: left">'; postHtml = '</div>';
}
if (directive == "$fright")
{
preHtml += '<div style="float: right">'; postHtml = '</div>';
}
}
var svg = Viz(preDot + paramString + postDot, "svg");
wikify("<html>" + preHtml + svg + postHtml + "</html>", place);
}
config.macros.graph.handler = function(place, macroName, params, wikifier, paramString, tiddler)
{
graphHandler(place, paramString, "","","","");
}
config.macros.digraph = {};
config.macros.digraph.handler = function(place, macroName, params, wikifier, paramString, tiddler)
{
graphHandler(place, paramString, "digraph {", "}", "", "");
}
//}}}
/***
|''Name:''|DropDownMenuPlugin|
|''Description:''|Create dropdown menus from unordered lists|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#DropDownMenuPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.1|
|''Date:''|11/04/2007|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.5|
!!Usage:
* create a two-level unordered list using wiki syntax, and place {{{<<dropMenu>>}}} on the line after it.
* to create a vertical menu use {{{<<dropMenu vertical>>}}} instead.
* to assign custom classes to the list, just pass them as parameters to the macro {{{<<dropMenu className1 className2 className3>>}}}
!!Features:
*Supports just a single level of drop-downs, as anything more usually provides a poor experience for the user.
* Very light weight, about 1.5kb of JavaScript and 4kb of CSS.
* Comes with two built in css 'themes', the default horizontal and vertical.
!!Customizing:
* to customize the appearance of the menu's, you can either add a custom class as described above or, you can edit the CSS via the [[StyleSheetDropDownMenuPlugin]] shadow tiddler.
!!Examples:
* [[DropDownMenuDemo]]
***/
// /%
//!BEGIN-PLUGIN-CODE
config.macros.dropMenu={
dropdownchar: "\u25bc",
handler : function(place,macroName,params,wikifier,paramString,tiddler){
list = findRelated(place.lastChild,"UL","tagName","previousSibling");
if (!list)
return;
addClass(list,"suckerfish");
if (params.length){
addClass(list,paramString);
}
this.fixLinks(list);
},
fixLinks : function(el){
var els = el.getElementsByTagName("li");
for(var i = 0; i < els.length; i++) {
if(els[i].getElementsByTagName("ul").length>0){
var link = findRelated(els[i].firstChild,"A","tagName","nextSibling");
if(!link){
var ih = els[i].firstChild.data;
els[i].removeChild(els[i].firstChild);
var d = createTiddlyElement(null,"a",null,null,ih+this.dropdownchar,{href:"javascript:;"});
els[i].insertBefore(d,els[i].firstChild);
}
else{
link.firstChild.data = link.firstChild.data + this.dropdownchar;
removeClass(link,"tiddlyLinkNonExisting");
}
}
els[i].onmouseover = function() {
addClass(this, "sfhover");
};
els[i].onmouseout = function() {
removeClass(this, "sfhover");
};
}
}
};
config.shadowTiddlers["StyleSheetDropDownMenuPlugin"] =
"/*{{{*/\n"+
"/***** LAYOUT STYLES - DO NOT EDIT! *****/\n"+
"ul.suckerfish, ul.suckerfish ul {\n"+
" margin: 0;\n"+
" padding: 0;\n"+
" list-style: none;\n"+
" line-height:1.4em;\n"+
"}\n\n"+
"ul.suckerfish li {\n"+
" display: inline-block; \n"+
" display: block;\n"+
" float: left; \n"+
"}\n\n"+
"ul.suckerfish li ul {\n"+
" position: absolute;\n"+
" left: -999em;\n"+
"}\n\n"+
"ul.suckerfish li:hover ul, ul.suckerfish li.sfhover ul {\n"+
" left: auto;\n"+
"}\n\n"+
"ul.suckerfish ul li {\n"+
" float: none;\n"+
" border-right: 0;\n"+
" border-left:0;\n"+
"}\n\n"+
"ul.suckerfish a, ul.suckerfish a:hover {\n"+
" display: block;\n"+
"}\n\n"+
"ul.suckerfish li a.tiddlyLink, ul.suckerfish li a, #mainMenu ul.suckerfish li a {font-weight:bold;}\n"+
"/**** END LAYOUT STYLES *****/\n"+
"\n\n"+
"/**** COLORS AND APPEARANCE - DEFAULT *****/\n"+
"ul.suckerfish li a {\n"+
" padding: 0.5em 1.5em;\n"+
" color: #FFF;\n"+
" background: #0066aa;\n"+
" border-bottom: 0;\n"+
" font-weight:bold;\n"+
"}\n\n"+
"ul.suckerfish li:hover a, ul.suckerfish li.sfhover a{\n"+
" background: #00558F;\n"+
"}\n\n"+
"ul.suckerfish li:hover ul a, ul.suckerfish li.sfhover ul a{\n"+
" color: #000;\n"+
" background: #eff3fa;\n"+
" border-top:1px solid #FFF;\n"+
"}\n\n"+
"ul.suckerfish ul li a:hover {\n"+
" background: #e0e8f5;\n"+
"}\n\n"+
"ul.suckerfish li a{\n"+
" width:9em;\n"+
"}\n\n"+
"ul.suckerfish ul li a, ul.suckerfish ul li a:hover{\n"+
" display:inline-block;\n"+
" width:9em;\n"+
"}\n\n"+
"ul.suckerfish li {\n"+
" border-left: 1px solid #00558F;\n"+
"}\n"+
"/***** END COLORS AND APPEARANCE - DEFAULT *****/\n"+
"\n\n"+
"/***** LAYOUT AND APPEARANCE: VERTICAL *****/\n"+
"ul.suckerfish.vertical li{\n"+
" width:10em;\n"+
" border-left: 0px solid #00558f;\n"+
"}\n\n"+
"ul.suckerfish.vertical ul li, ul.suckerfish.vertical li a, ul.suckerfish.vertical li:hover a, ul.suckerfish.vertical li.sfhover a {\n"+
" border-left: 0.8em solid #00558f;\n"+
"}\n\n"+
"ul.suckerfish.vertical li a, ul.suckerfish.vertical li:hover a, ul.suckerfish.vertical li.sfhover a, ul.suckerfish.vertical li.sfhover a:hover{\n"+
" width:8em;\n"+
"}\n\n"+
"ul.suckerfish.vertical {\n"+
" width:10em; text-align:left;\n"+
" float:left;\n"+
"}\n\n"+
"ul.suckerfish.vertical li a {\n"+
" padding: 0.5em 1em 0.5em 1em;\n"+
" border-top:1px solid #fff;\n"+
"}\n\n"+
"ul.suckerfish.vertical, ul.suckerfish.vertical ul {\n"+
" line-height:1.4em;\n"+
"}\n\n"+
"ul.suckerfish.vertical li:hover ul, ul.suckerfish.vertical li.sfhover ul { \n"+
" margin: -2.4em 0 0 10.9em;\n"+
"}\n\n"+
"ul.suckerfish.vertical li:hover ul li a, ul.suckerfish.vertical li.sfhover ul li a {\n"+
" border: 0px solid #FFF;\n"+
"}\n\n"+
"ul.suckerfish.vertical li:hover a, ul.suckerfish.vertical li.sfhover a{\n"+
" padding-right:1.1em;\n"+
"}\n\n"+
"ul.suckerfish.vertical li:hover ul li, ul.suckerfish.vertical li.sfhover ul li {\n"+
" border-bottom:1px solid #fff;\n"+
"}\n\n"+
"/***** END LAYOUT AND APPEARANCE: VERTICAL *****/\n"+
"/*}}}*/";
store.addNotification("StyleSheetDropDownMenuPlugin",refreshStyles);
//!END-PLUGIN-CODE
// %/
/***
|''Name''|BinaryTiddlersPlugin|
|''Description''|renders base64-encoded binary tiddlers as images or links|
|''Author''|FND|
|''Version''|0.3.2|
|''Status''|@@beta@@|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/plugins/BinaryTiddlersPlugin.js|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5|
!Code
***/
//{{{
(function($) {
"use strict";
var ctfield = "server.content-type";
var plugin = config.extensions.BinaryTiddlersPlugin = {
isWikiText: function(tiddler) {
var ctype = tiddler.fields[ctfield];
if(ctype) {
if (ctype === 'text/x-tiddlywiki') {
return true;
}
return !this.isBinary(tiddler) && !this.isTextual(ctype);
} else {
return true;
}
},
// NB: pseudo-binaries are considered non-binary here
isBinary: function(tiddler) {
var ctype = tiddler.fields[ctfield];
return ctype ? !this.isTextual(ctype) : false;
},
isTextual: function(ctype) {
return ctype.indexOf("text/") === 0
|| this.endsWith(ctype, "+xml")
|| ctype === 'application/json'
|| ctype === 'application/javascript';
},
endsWith: function(str, suffix) {
return str.length >= suffix.length &&
str.substr(str.length - suffix.length) === suffix;
},
isLink: function(tiddler) {
return this.isBinary(tiddler) && tiddler.text.indexOf("<html>") !== -1;
}
};
// Disable edit for linked tiddlers (for now)
// This will be changed to a GET then PUT
config.commands.editTiddler.isEnabled = function(tiddler) {
var existingTest = config.commands.editTiddler.isEnabled;
if (existingTest) {
return existingTest && !plugin.isLink(tiddler);
} else {
return !plugin.isLink(tiddler);
}
};
// hijack text viewer to add special handling for binary tiddlers
var _view = config.macros.view.views.wikified;
config.macros.view.views.wikified = function(value, place, params, wikifier,
paramString, tiddler) {
var ctype = tiddler.fields["server.content-type"];
if(params[0] === "text" && ctype && ctype !== 'text/x-tiddlywiki' &&
!tiddler.tags.contains("systemConfig") && !plugin.isLink(tiddler)) {
var el;
if(plugin.isBinary(tiddler)) {
var uri = "data:%0;base64,%1".format([ctype, tiddler.text]); // TODO: fallback for legacy browsers
if(ctype.indexOf("image/") === 0) {
el = $("<img />").attr("alt", tiddler.title).attr("src", uri);
} else {
el = $("<a />").attr("href", uri).text(tiddler.title);
}
} else {
el = $("<pre />").text(tiddler.text);
}
el.appendTo(place);
} else {
_view.apply(this, arguments);
}
};
// hijack edit macro to disable editing of binary tiddlers' body
var _editHandler = config.macros.edit.handler;
config.macros.edit.handler = function(place, macroName, params, wikifier,
paramString, tiddler) {
if(params[0] === "text" && plugin.isBinary(tiddler)) {
return false;
} else {
_editHandler.apply(this, arguments);
}
};
// hijack autoLinkWikiWords to ignore binary tiddlers
var _autoLink = Tiddler.prototype.autoLinkWikiWords;
Tiddler.prototype.autoLinkWikiWords = function() {
return plugin.isWikiText(this) ? _autoLink.apply(this, arguments) : false;
};
}(jQuery));
//}}}